summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xBUILD/SETUP.sh2
-rwxr-xr-xBUILD/compile-amd64-debug-wsrep11
-rwxr-xr-xBUILD/compile-amd64-wsrep9
-rw-r--r--BUILD/compile-pentium-debug-wsrep12
-rw-r--r--BUILD/compile-pentium-wsrep11
-rw-r--r--BUILD/compile-pentium64-wsrep28
-rw-r--r--CMakeLists.txt17
-rw-r--r--Docs/README-wsrep488
-rw-r--r--README55
-rw-r--r--client/mysql_upgrade.c5
-rw-r--r--client/mysqlcheck.c6
-rw-r--r--cmake/configure.pl10
-rw-r--r--cmake/cpack_rpm.cmake19
-rw-r--r--cmake/install_macros.cmake30
-rw-r--r--cmake/os/FreeBSD.cmake6
-rw-r--r--cmake/os/WindowsCache.cmake1
-rw-r--r--cmake/package_name.cmake2
-rw-r--r--cmake/plugin.cmake12
-rw-r--r--cmake/wsrep.cmake64
-rw-r--r--cmake/wsrep.cmake.moved59
-rw-r--r--config.h.cmake1
-rw-r--r--configure.cmake2
-rw-r--r--debian/additions/my.cnf16
-rw-r--r--debian/control350
-rw-r--r--debian/dist/Debian/mariadb-galera-server-10.0.README.Debian (renamed from debian/dist/Debian/mariadb-server-10.0.README.Debian)0
-rw-r--r--debian/dist/Debian/mariadb-galera-server-10.0.dirs (renamed from debian/dist/Ubuntu/mariadb-server-10.0.dirs)2
-rw-r--r--debian/dist/Debian/mariadb-galera-server-10.0.files.in (renamed from debian/dist/Debian/mariadb-server-10.0.files.in)42
-rw-r--r--debian/dist/Debian/mariadb-galera-server-10.0.postinst (renamed from debian/dist/Debian/mariadb-server-10.0.postinst)0
-rw-r--r--debian/dist/Debian/mariadb-galera-server-10.0.postrm (renamed from debian/dist/Debian/mariadb-server-10.0.postrm)0
-rwxr-xr-xdebian/dist/Debian/rules20
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-10.0.README.Debian (renamed from debian/dist/Ubuntu/mariadb-server-10.0.README.Debian)0
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-10.0.dirs (renamed from debian/dist/Debian/mariadb-server-10.0.dirs)2
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-10.0.files.in (renamed from debian/dist/Ubuntu/mariadb-server-10.0.files.in)42
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-10.0.postinst (renamed from debian/dist/Ubuntu/mariadb-server-10.0.postinst)0
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-10.0.postrm (renamed from debian/dist/Ubuntu/mariadb-server-10.0.postrm)0
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-10.0.py (renamed from debian/dist/Ubuntu/mariadb-server-10.0.py)2
-rwxr-xr-xdebian/dist/Ubuntu/rules22
-rw-r--r--debian/libmariadbclient-dev.README.Maintainer4
-rw-r--r--debian/libmariadbclient-dev.dirs2
-rw-r--r--debian/libmariadbclient-dev.examples1
-rw-r--r--debian/libmariadbclient-dev.files7
-rw-r--r--debian/libmariadbclient-dev.links2
-rw-r--r--debian/libmariadbclient18.dirs1
-rw-r--r--debian/libmariadbclient18.files3
-rw-r--r--debian/libmariadbclient18.postinst12
-rw-r--r--debian/libmariadbd-dev.files2
-rw-r--r--debian/mariadb-client-10.0.README.Debian4
-rw-r--r--debian/mariadb-client-10.0.dirs3
-rw-r--r--debian/mariadb-client-10.0.docs2
-rw-r--r--debian/mariadb-client-10.0.files28
-rw-r--r--debian/mariadb-client-10.0.links6
-rw-r--r--debian/mariadb-client-10.0.lintian-overrides3
-rw-r--r--debian/mariadb-client-10.0.menu3
-rw-r--r--debian/mariadb-client-core-10.0.files4
-rw-r--r--debian/mariadb-common.files1
-rw-r--r--debian/mariadb-common.postrm8
-rw-r--r--debian/mariadb-connect-engine-10.0.files2
-rw-r--r--debian/mariadb-galera-server-10.0.NEWS (renamed from debian/mariadb-server-10.0.NEWS)0
-rw-r--r--debian/mariadb-galera-server-10.0.config (renamed from debian/mariadb-server-10.0.config)0
-rw-r--r--debian/mariadb-galera-server-10.0.lintian-overrides5
-rw-r--r--debian/mariadb-galera-server-10.0.logcheck.ignore.paranoid (renamed from debian/mariadb-server-10.0.logcheck.ignore.paranoid)0
-rw-r--r--debian/mariadb-galera-server-10.0.logcheck.ignore.server (renamed from debian/mariadb-server-10.0.logcheck.ignore.server)0
-rw-r--r--debian/mariadb-galera-server-10.0.logcheck.ignore.workstation (renamed from debian/mariadb-server-10.0.logcheck.ignore.workstation)0
-rw-r--r--debian/mariadb-galera-server-10.0.mysql-server.logrotate (renamed from debian/mariadb-server-10.0.mysql-server.logrotate)0
-rw-r--r--debian/mariadb-galera-server-10.0.mysql.init (renamed from debian/mariadb-server-10.0.mysql.init)12
-rw-r--r--debian/mariadb-galera-server-10.0.preinst (renamed from debian/mariadb-server-10.0.preinst)0
-rw-r--r--debian/mariadb-galera-server-10.0.prerm (renamed from debian/mariadb-server-10.0.prerm)0
-rw-r--r--debian/mariadb-galera-server-10.0.templates (renamed from debian/mariadb-server-10.0.templates)0
-rw-r--r--debian/mariadb-galera-test-10.0.dirs (renamed from debian/mariadb-test-10.0.dirs)6
-rw-r--r--debian/mariadb-galera-test-10.0.files (renamed from debian/mariadb-test-10.0.files)4
-rw-r--r--debian/mariadb-galera-test-10.0.links (renamed from debian/mariadb-test-10.0.links)0
-rw-r--r--debian/mariadb-oqgraph-engine-10.0.files1
-rw-r--r--debian/mariadb-server-10.0.lintian-overrides5
-rw-r--r--debian/mariadb-server-core-10.0.files26
-rw-r--r--debian/mysql-common.dirs1
-rw-r--r--debian/mysql-common.files3
-rw-r--r--debian/mysql-common.lintian-overrides2
-rw-r--r--debian/mysql-common.postrm7
-rw-r--r--debian/po/POTFILES.in2
-rw-r--r--debian/po/ar.po48
-rw-r--r--debian/po/ca.po48
-rw-r--r--debian/po/cs.po48
-rw-r--r--debian/po/da.po48
-rw-r--r--debian/po/de.po48
-rw-r--r--debian/po/es.po48
-rw-r--r--debian/po/eu.po48
-rw-r--r--debian/po/fr.po48
-rw-r--r--debian/po/gl.po48
-rw-r--r--debian/po/it.po53
-rw-r--r--debian/po/ja.po48
-rw-r--r--debian/po/nb.po48
-rw-r--r--debian/po/nl.po48
-rw-r--r--debian/po/pt.po48
-rw-r--r--debian/po/pt_BR.po48
-rw-r--r--debian/po/ro.po48
-rw-r--r--debian/po/ru.po48
-rw-r--r--debian/po/sv.po53
-rw-r--r--debian/po/templates.pot48
-rw-r--r--debian/po/tr.po48
-rw-r--r--extra/my_print_defaults.c11
-rw-r--r--include/my_global.h13
-rw-r--r--include/mysql/psi/mysql_socket.h30
-rw-r--r--include/mysqld_default_groups.h3
-rw-r--r--include/thr_lock.h13
-rw-r--r--mysql-test/extra/binlog_tests/binlog.test9
-rw-r--r--mysql-test/include/assert_grep.inc154
-rw-r--r--mysql-test/include/check-testcase.test2
-rw-r--r--mysql-test/include/check-warnings.test4
-rw-r--r--mysql-test/include/diff_servers.inc67
-rw-r--r--mysql-test/include/galera_clear_sync_point.inc1
-rw-r--r--mysql-test/include/galera_cluster.inc12
-rw-r--r--mysql-test/include/galera_connect.inc45
-rw-r--r--mysql-test/include/galera_diff.inc100
-rw-r--r--mysql-test/include/galera_end.inc25
-rw-r--r--mysql-test/include/galera_init.inc27
-rw-r--r--mysql-test/include/galera_set_sync_point.inc1
-rw-r--r--mysql-test/include/galera_signal_sync_point.inc1
-rw-r--r--mysql-test/include/galera_wait_ready.inc2
-rw-r--r--mysql-test/include/galera_wait_sync_point.inc6
-rw-r--r--mysql-test/include/have_innodb_disallow_writes.inc6
-rw-r--r--mysql-test/include/have_wsrep.inc8
-rw-r--r--mysql-test/include/have_wsrep_enabled.inc9
-rw-r--r--mysql-test/include/have_wsrep_provider.inc6
-rw-r--r--mysql-test/include/mtr_check.sql6
-rw-r--r--mysql-test/include/mysqlhotcopy.inc2
-rw-r--r--mysql-test/include/not_wsrep.inc7
-rw-r--r--mysql-test/include/restart_mysqld.inc3
-rw-r--r--mysql-test/include/start_mysqld.inc3
-rw-r--r--mysql-test/include/wait_condition.inc1
-rw-r--r--mysql-test/include/wait_until_ready.inc34
-rw-r--r--mysql-test/include/wait_wsrep_ready.inc15
-rw-r--r--mysql-test/include/write_var_to_file.inc2
-rw-r--r--mysql-test/lib/mtr_cases.pm2
-rwxr-xr-xmysql-test/mysql-test-run.pl22
-rw-r--r--mysql-test/r/have_wsrep_on.require2
-rw-r--r--mysql-test/r/information_schema.result48
-rw-r--r--mysql-test/r/innodb_load_xa_with_wsrep.result21
-rw-r--r--mysql-test/r/mysql_tzinfo_to_sql_symlink.result1
-rw-r--r--mysql-test/r/mysqld--help.result133
-rw-r--r--mysql-test/r/not_wsrep.require2
-rw-r--r--mysql-test/r/read_only_innodb.result8
-rw-r--r--mysql-test/r/show_check.result6
-rw-r--r--mysql-test/std_data/binlog-header.logbin0 -> 120 bytes
-rw-r--r--mysql-test/std_data/galera-cert.pem26
-rw-r--r--mysql-test/std_data/galera-key.pem28
-rw-r--r--mysql-test/std_data/galera-upgrade-ca-cert.pem40
-rw-r--r--mysql-test/std_data/galera-upgrade-server-cert.pem20
-rw-r--r--mysql-test/std_data/galera-upgrade-server-key.pem28
-rwxr-xr-xmysql-test/std_data/wsrep_notify.sh99
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_binlog.result12
-rw-r--r--mysql-test/suite/binlog/r/binlog_stm_binlog.result12
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_is.result16
-rw-r--r--mysql-test/suite/galera/disabled.def53
-rw-r--r--mysql-test/suite/galera/galera_2nodes.cnf43
-rw-r--r--mysql-test/suite/galera/galera_2nodes_as_master.cnf69
-rw-r--r--mysql-test/suite/galera/galera_2nodes_as_slave.cnf73
-rw-r--r--mysql-test/suite/galera/galera_3nodes_as_slave.cnf97
-rw-r--r--mysql-test/suite/galera/galera_4nodes.cnf73
-rw-r--r--mysql-test/suite/galera/include/auto_increment_offset_restore.inc41
-rw-r--r--mysql-test/suite/galera/include/auto_increment_offset_save.inc45
-rw-r--r--mysql-test/suite/galera/include/galera_have_debug_sync.inc9
-rw-r--r--mysql-test/suite/galera/include/galera_load_provider.inc10
-rw-r--r--mysql-test/suite/galera/include/galera_reset_cluster_address.inc12
-rw-r--r--mysql-test/suite/galera/include/galera_resume.inc9
-rw-r--r--mysql-test/suite/galera/include/galera_sst_restore.inc29
-rw-r--r--mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc23
-rw-r--r--mysql-test/suite/galera/include/galera_st_clean_slave.inc113
-rw-r--r--mysql-test/suite/galera/include/galera_st_disconnect_slave.inc105
-rw-r--r--mysql-test/suite/galera/include/galera_st_kill_slave.inc108
-rw-r--r--mysql-test/suite/galera/include/galera_st_kill_slave_ddl.inc123
-rw-r--r--mysql-test/suite/galera/include/galera_st_shutdown_slave.inc105
-rw-r--r--mysql-test/suite/galera/include/galera_unload_provider.inc7
-rw-r--r--mysql-test/suite/galera/include/galera_wsrep_recover.inc23
-rw-r--r--mysql-test/suite/galera/include/kill_galera.inc21
-rw-r--r--mysql-test/suite/galera/include/shutdown_mysqld.inc18
-rw-r--r--mysql-test/suite/galera/include/start_mysqld.inc22
-rw-r--r--mysql-test/suite/galera/my.cnf1
-rw-r--r--mysql-test/suite/galera/r/GAL-382.result6
-rw-r--r--mysql-test/suite/galera/r/GAL-401.result23
-rw-r--r--mysql-test/suite/galera/r/GAL-419.result4
-rw-r--r--mysql-test/suite/galera/r/GAL-480.result39
-rw-r--r--mysql-test/suite/galera/r/MW-252.result7
-rw-r--r--mysql-test/suite/galera/r/MW-258.result34
-rw-r--r--mysql-test/suite/galera/r/MW-259.result12
-rw-r--r--mysql-test/suite/galera/r/MW-284.result14
-rw-r--r--mysql-test/suite/galera/r/MW-285.result19
-rw-r--r--mysql-test/suite/galera/r/MW-286.result13
-rw-r--r--mysql-test/suite/galera/r/MW-292.result30
-rw-r--r--mysql-test/suite/galera/r/MW-309.result22
-rw-r--r--mysql-test/suite/galera/r/MW-313.result32
-rw-r--r--mysql-test/suite/galera/r/MW-328A.result21
-rw-r--r--mysql-test/suite/galera/r/MW-328B.result17
-rw-r--r--mysql-test/suite/galera/r/MW-328C.result17
-rw-r--r--mysql-test/suite/galera/r/MW-328D.result15
-rw-r--r--mysql-test/suite/galera/r/MW-328E.result15
-rw-r--r--mysql-test/suite/galera/r/MW-329.result21
-rw-r--r--mysql-test/suite/galera/r/MW-336.result42
-rw-r--r--mysql-test/suite/galera/r/MW-357.result6
-rw-r--r--mysql-test/suite/galera/r/MW-369.result155
-rw-r--r--mysql-test/suite/galera/r/MW-388.result46
-rw-r--r--mysql-test/suite/galera/r/MW-402.result192
-rw-r--r--mysql-test/suite/galera/r/MW-416.result114
-rw-r--r--mysql-test/suite/galera/r/MW-44.result14
-rw-r--r--mysql-test/suite/galera/r/MW-86-wait1.result48
-rw-r--r--mysql-test/suite/galera/r/MW-86-wait8.result50
-rw-r--r--mysql-test/suite/galera/r/basic.result30
-rw-r--r--mysql-test/suite/galera/r/binlog_checksum.result36
-rw-r--r--mysql-test/suite/galera/r/create.result59
-rw-r--r--mysql-test/suite/galera/r/ev51914.result162
-rw-r--r--mysql-test/suite/galera/r/fk.result96
-rw-r--r--mysql-test/suite/galera/r/galera#414.result7
-rw-r--r--mysql-test/suite/galera/r/galera#500.result10
-rw-r--r--mysql-test/suite/galera/r/galera_account_management.result47
-rw-r--r--mysql-test/suite/galera/r/galera_admin.result43
-rw-r--r--mysql-test/suite/galera/r/galera_alter_engine_innodb.result10
-rw-r--r--mysql-test/suite/galera/r/galera_alter_engine_myisam.result11
-rw-r--r--mysql-test/suite/galera/r/galera_alter_table_force.result10
-rw-r--r--mysql-test/suite/galera/r/galera_applier_ftwrl_table.result15
-rw-r--r--mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result26
-rw-r--r--mysql-test/suite/galera/r/galera_as_master.result8
-rw-r--r--mysql-test/suite/galera/r/galera_as_master_gtid.result59
-rw-r--r--mysql-test/suite/galera/r/galera_as_master_gtid_change_master.result15
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave.result15
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_autoinc.result80
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_gtid.result16
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_nonprim.result18
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_preordered.result19
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_replication_bundle.result15
-rw-r--r--mysql-test/suite/galera/r/galera_autoinc_sst_xtrabackup.result36
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort.result10
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result15
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_for_update.result10
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result8
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_get_lock.result12
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_lock_table.result12
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_sleep.result9
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_cache_size.result12
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_checksum.result10
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result9
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result6
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_row_image.result79
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_rows_query_log_events.result12
-rw-r--r--mysql-test/suite/galera/r/galera_concurrent_ctas.result1
-rw-r--r--mysql-test/suite/galera/r/galera_create_function.result58
-rw-r--r--mysql-test/suite/galera/r/galera_create_procedure.result53
-rw-r--r--mysql-test/suite/galera/r/galera_create_table_like.result47
-rw-r--r--mysql-test/suite/galera/r/galera_create_trigger.result42
-rw-r--r--mysql-test/suite/galera/r/galera_ddl_multiline.result80
-rw-r--r--mysql-test/suite/galera/r/galera_defaults.result119
-rw-r--r--mysql-test/suite/galera/r/galera_delete_limit.result19
-rw-r--r--mysql-test/suite/galera/r/galera_desync_overlapped.result45
-rw-r--r--mysql-test/suite/galera/r/galera_drop_multi.result20
-rw-r--r--mysql-test/suite/galera/r/galera_enum.result37
-rw-r--r--mysql-test/suite/galera/r/galera_events.result18
-rw-r--r--mysql-test/suite/galera/r/galera_fk_cascade_delete.result30
-rw-r--r--mysql-test/suite/galera/r/galera_fk_cascade_update.result30
-rw-r--r--mysql-test/suite/galera/r/galera_fk_conflict.result23
-rw-r--r--mysql-test/suite/galera/r/galera_fk_mismatch.result25
-rw-r--r--mysql-test/suite/galera/r/galera_fk_multicolumn.result35
-rw-r--r--mysql-test/suite/galera/r/galera_fk_multitable.result22
-rw-r--r--mysql-test/suite/galera/r/galera_fk_no_pk.result28
-rw-r--r--mysql-test/suite/galera/r/galera_fk_selfreferential.result13
-rw-r--r--mysql-test/suite/galera/r/galera_fk_setnull.result30
-rw-r--r--mysql-test/suite/galera/r/galera_flush.result88
-rw-r--r--mysql-test/suite/galera/r/galera_flush_local.result145
-rw-r--r--mysql-test/suite/galera/r/galera_forced_binlog_format.result43
-rw-r--r--mysql-test/suite/galera/r/galera_ftwrl.result16
-rw-r--r--mysql-test/suite/galera/r/galera_ftwrl_drain.result26
-rw-r--r--mysql-test/suite/galera/r/galera_fulltext.result26
-rw-r--r--mysql-test/suite/galera/r/galera_gcache_recover.result18
-rw-r--r--mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result19
-rw-r--r--mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result107
-rw-r--r--mysql-test/suite/galera/r/galera_gcs_fc_limit.result17
-rw-r--r--mysql-test/suite/galera/r/galera_gcs_fragment.result24
-rw-r--r--mysql-test/suite/galera/r/galera_gcs_max_packet_size.result15
-rw-r--r--mysql-test/suite/galera/r/galera_gra_log.result41
-rw-r--r--mysql-test/suite/galera/r/galera_gtid.result12
-rw-r--r--mysql-test/suite/galera/r/galera_insert_ignore.result52
-rw-r--r--mysql-test/suite/galera/r/galera_insert_multi.result58
-rw-r--r--mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result184
-rw-r--r--mysql-test/suite/galera/r/galera_ist_mysqldump.result284
-rw-r--r--mysql-test/suite/galera/r/galera_ist_progress.result19
-rw-r--r--mysql-test/suite/galera/r/galera_ist_recv_bind.result13
-rw-r--r--mysql-test/suite/galera/r/galera_ist_restart_joiner.result32
-rw-r--r--mysql-test/suite/galera/r/galera_ist_rsync.result358
-rw-r--r--mysql-test/suite/galera/r/galera_ist_xtrabackup-v2.result357
-rw-r--r--mysql-test/suite/galera/r/galera_kill_applier.result4
-rw-r--r--mysql-test/suite/galera/r/galera_kill_ddl.result8
-rw-r--r--mysql-test/suite/galera/r/galera_kill_largechanges.result14
-rw-r--r--mysql-test/suite/galera/r/galera_kill_nochanges.result10
-rw-r--r--mysql-test/suite/galera/r/galera_kill_smallchanges.result11
-rw-r--r--mysql-test/suite/galera/r/galera_lock_table.result21
-rw-r--r--mysql-test/suite/galera/r/galera_log_bin.result59
-rw-r--r--mysql-test/suite/galera/r/galera_log_output_csv.result18
-rw-r--r--mysql-test/suite/galera/r/galera_many_columns.result32
-rw-r--r--mysql-test/suite/galera/r/galera_many_indexes.result123
-rw-r--r--mysql-test/suite/galera/r/galera_many_rows.result32
-rw-r--r--mysql-test/suite/galera/r/galera_many_tables_nopk.result17
-rw-r--r--mysql-test/suite/galera/r/galera_many_tables_pk.result21
-rw-r--r--mysql-test/suite/galera/r/galera_mdl_race.result38
-rw-r--r--mysql-test/suite/galera/r/galera_migrate.result79
-rw-r--r--mysql-test/suite/galera/r/galera_multi_database.result28
-rw-r--r--mysql-test/suite/galera/r/galera_myisam_autocommit.result24
-rw-r--r--mysql-test/suite/galera/r/galera_myisam_transactions.result34
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_bit.result27
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_blob.result27
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_large_varchar.result30
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_unicode.result24
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result33
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result18
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result15
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_simple.result28
-rw-r--r--mysql-test/suite/galera/r/galera_pc_ignore_sb.result12
-rw-r--r--mysql-test/suite/galera/r/galera_pk_bigint_signed.result26
-rw-r--r--mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result23
-rw-r--r--mysql-test/suite/galera/r/galera_prepared_statement.result33
-rw-r--r--mysql-test/suite/galera/r/galera_query_cache.result57
-rw-r--r--mysql-test/suite/galera/r/galera_query_cache_sync_wait.result53
-rw-r--r--mysql-test/suite/galera/r/galera_read_only.result18
-rw-r--r--mysql-test/suite/galera/r/galera_repl_key_format_flat16.result18
-rw-r--r--mysql-test/suite/galera/r/galera_repl_max_ws_size.result12
-rw-r--r--mysql-test/suite/galera/r/galera_restart_nochanges.result9
-rw-r--r--mysql-test/suite/galera/r/galera_restart_on_unknown_option.result40
-rw-r--r--mysql-test/suite/galera/r/galera_roles.result195
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_add_pk.result26
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_drop_pk.result42
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_error.result21
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_simple.result21
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result41
-rw-r--r--mysql-test/suite/galera/r/galera_sbr.result14
-rw-r--r--mysql-test/suite/galera/r/galera_sbr_binlog.result14
-rw-r--r--mysql-test/suite/galera/r/galera_serializable.result27
-rw-r--r--mysql-test/suite/galera/r/galera_split_brain.result4
-rw-r--r--mysql-test/suite/galera/r/galera_sql_log_bin_zero.result12
-rw-r--r--mysql-test/suite/galera/r/galera_ssl.result18
-rw-r--r--mysql-test/suite/galera/r/galera_ssl_compression.result22
-rw-r--r--mysql-test/suite/galera/r/galera_ssl_upgrade.result15
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mysqldump.result459
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result108
-rw-r--r--mysql-test/suite/galera/r/galera_sst_rsync.result359
-rw-r--r--mysql-test/suite/galera/r/galera_sst_xtrabackup-v2-options.result3
-rw-r--r--mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result359
-rw-r--r--mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_encrypt_with_key.result3
-rw-r--r--mysql-test/suite/galera/r/galera_status_cluster.result12
-rw-r--r--mysql-test/suite/galera/r/galera_status_local_index.result13
-rw-r--r--mysql-test/suite/galera/r/galera_status_local_state.result14
-rw-r--r--mysql-test/suite/galera/r/galera_suspend_slave.result13
-rw-r--r--mysql-test/suite/galera/r/galera_sync_wait_show.result39
-rw-r--r--mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result42
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_error.result19
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result31
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result23
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_locking.result41
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result23
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_sequential.result35
-rw-r--r--mysql-test/suite/galera/r/galera_toi_drop_database.result24
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ftwrl.result12
-rw-r--r--mysql-test/suite/galera/r/galera_toi_lock_exclusive.result17
-rw-r--r--mysql-test/suite/galera/r/galera_toi_lock_shared.result12
-rw-r--r--mysql-test/suite/galera/r/galera_toi_truncate.result15
-rw-r--r--mysql-test/suite/galera/r/galera_transaction_read_only.result21
-rw-r--r--mysql-test/suite/galera/r/galera_transaction_replay.result59
-rw-r--r--mysql-test/suite/galera/r/galera_truncate.result29
-rw-r--r--mysql-test/suite/galera/r/galera_truncate_temporary.result63
-rw-r--r--mysql-test/suite/galera/r/galera_unicode_identifiers.result46
-rw-r--r--mysql-test/suite/galera/r/galera_unicode_pk.result31
-rw-r--r--mysql-test/suite/galera/r/galera_update_limit.result17
-rw-r--r--mysql-test/suite/galera/r/galera_v1_row_events.result10
-rw-r--r--mysql-test/suite/galera/r/galera_var_OSU_method.result16
-rw-r--r--mysql-test/suite/galera/r/galera_var_OSU_method2.result19
-rw-r--r--mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result61
-rw-r--r--mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result30
-rw-r--r--mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result21
-rw-r--r--mysql-test/suite/galera/r/galera_var_cluster_address.result39
-rw-r--r--mysql-test/suite/galera/r/galera_var_desync_on.result31
-rw-r--r--mysql-test/suite/galera/r/galera_var_dirty_reads.result45
-rw-r--r--mysql-test/suite/galera/r/galera_var_fkchecks.result26
-rw-r--r--mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result12
-rw-r--r--mysql-test/suite/galera/r/galera_var_load_data_splitting.result9
-rw-r--r--mysql-test/suite/galera/r/galera_var_log_bin.result10
-rw-r--r--mysql-test/suite/galera/r/galera_var_max_ws_rows.result115
-rw-r--r--mysql-test/suite/galera/r/galera_var_max_ws_size.result17
-rw-r--r--mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result12
-rw-r--r--mysql-test/suite/galera/r/galera_var_node_address.result11
-rw-r--r--mysql-test/suite/galera/r/galera_var_notify_cmd.result10
-rw-r--r--mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result8
-rw-r--r--mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result78
-rw-r--r--mysql-test/suite/galera/r/galera_var_retry_autocommit.result32
-rw-r--r--mysql-test/suite/galera/r/galera_var_slave_threads.result114
-rw-r--r--mysql-test/suite/galera/r/galera_var_sync_wait.result18
-rw-r--r--mysql-test/suite/galera/r/galera_var_wsrep_on_off.result19
-rw-r--r--mysql-test/suite/galera/r/galera_wan.result14
-rw-r--r--mysql-test/suite/galera/r/galera_wan_restart_ist.result53
-rw-r--r--mysql-test/suite/galera/r/galera_wan_restart_sst.result54
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result33
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_log_conficts.result18
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_new_cluster.result36
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result5
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result14
-rw-r--r--mysql-test/suite/galera/r/galera_zero_length_column.result38
-rw-r--r--mysql-test/suite/galera/r/grant.result17
-rw-r--r--mysql-test/suite/galera/r/lp1276424.result11
-rw-r--r--mysql-test/suite/galera/r/lp1347768.result17
-rw-r--r--mysql-test/suite/galera/r/lp1376747-2.result19
-rw-r--r--mysql-test/suite/galera/r/lp1376747-3.result21
-rw-r--r--mysql-test/suite/galera/r/lp1376747-4.result36
-rw-r--r--mysql-test/suite/galera/r/lp1376747.result19
-rw-r--r--mysql-test/suite/galera/r/lp1438990.result21
-rw-r--r--mysql-test/suite/galera/r/lp959512.result24
-rw-r--r--mysql-test/suite/galera/r/mdev_9290.result14
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#110.result38
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#198.result21
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#201.result3
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#237.result11
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#247.result11
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#31.result10
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#33.result103
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#90.result31
-rw-r--r--mysql-test/suite/galera/r/partition.result140
-rw-r--r--mysql-test/suite/galera/r/pxc-421.result38
-rw-r--r--mysql-test/suite/galera/r/query_cache.result1645
-rw-r--r--mysql-test/suite/galera/r/rename.result38
-rw-r--r--mysql-test/suite/galera/r/rpl_row_annotate.result66
-rw-r--r--mysql-test/suite/galera/r/unique_key.result47
-rw-r--r--mysql-test/suite/galera/r/view.result52
-rw-r--r--mysql-test/suite/galera/suite.pm86
-rw-r--r--mysql-test/suite/galera/t/GAL-382.test16
-rw-r--r--mysql-test/suite/galera/t/GAL-401.test56
-rw-r--r--mysql-test/suite/galera/t/GAL-419.test35
-rw-r--r--mysql-test/suite/galera/t/GAL-480.test47
-rw-r--r--mysql-test/suite/galera/t/MW-252.test42
-rw-r--r--mysql-test/suite/galera/t/MW-258.test42
-rw-r--r--mysql-test/suite/galera/t/MW-259.test42
-rw-r--r--mysql-test/suite/galera/t/MW-284.cnf1
-rw-r--r--mysql-test/suite/galera/t/MW-284.test58
-rw-r--r--mysql-test/suite/galera/t/MW-285.test31
-rw-r--r--mysql-test/suite/galera/t/MW-286.test32
-rw-r--r--mysql-test/suite/galera/t/MW-292.test79
-rw-r--r--mysql-test/suite/galera/t/MW-309.test32
-rw-r--r--mysql-test/suite/galera/t/MW-313-master.opt1
-rw-r--r--mysql-test/suite/galera/t/MW-313.test51
-rw-r--r--mysql-test/suite/galera/t/MW-328-footer.inc18
-rw-r--r--mysql-test/suite/galera/t/MW-328-header.inc29
-rw-r--r--mysql-test/suite/galera/t/MW-328A.test56
-rw-r--r--mysql-test/suite/galera/t/MW-328B.test36
-rw-r--r--mysql-test/suite/galera/t/MW-328C.test36
-rw-r--r--mysql-test/suite/galera/t/MW-328D.test40
-rw-r--r--mysql-test/suite/galera/t/MW-328E.test41
-rw-r--r--mysql-test/suite/galera/t/MW-329-master.opt1
-rw-r--r--mysql-test/suite/galera/t/MW-329.test85
-rw-r--r--mysql-test/suite/galera/t/MW-336.test64
-rw-r--r--mysql-test/suite/galera/t/MW-357.test13
-rw-r--r--mysql-test/suite/galera/t/MW-369.inc75
-rw-r--r--mysql-test/suite/galera/t/MW-369.test246
-rw-r--r--mysql-test/suite/galera/t/MW-388.test76
-rw-r--r--mysql-test/suite/galera/t/MW-402.test228
-rw-r--r--mysql-test/suite/galera/t/MW-416.test134
-rw-r--r--mysql-test/suite/galera/t/MW-44-master.opt1
-rw-r--r--mysql-test/suite/galera/t/MW-44.test25
-rw-r--r--mysql-test/suite/galera/t/MW-86-wait1-master.opt1
-rw-r--r--mysql-test/suite/galera/t/MW-86-wait1.test106
-rw-r--r--mysql-test/suite/galera/t/MW-86-wait8-master.opt1
-rw-r--r--mysql-test/suite/galera/t/MW-86-wait8.test128
-rw-r--r--mysql-test/suite/galera/t/basic.test26
-rw-r--r--mysql-test/suite/galera/t/binlog_checksum.test36
-rw-r--r--mysql-test/suite/galera/t/create.test58
-rw-r--r--mysql-test/suite/galera/t/ev51914.test214
-rw-r--r--mysql-test/suite/galera/t/fk.test116
-rw-r--r--mysql-test/suite/galera/t/galera#414.cnf8
-rw-r--r--mysql-test/suite/galera/t/galera#414.test43
-rw-r--r--mysql-test/suite/galera/t/galera#500.test38
-rw-r--r--mysql-test/suite/galera/t/galera_account_management.test99
-rw-r--r--mysql-test/suite/galera/t/galera_admin.test86
-rw-r--r--mysql-test/suite/galera/t/galera_alter_engine_innodb.test17
-rw-r--r--mysql-test/suite/galera/t/galera_alter_engine_myisam.test25
-rw-r--r--mysql-test/suite/galera/t/galera_alter_table_force.test17
-rw-r--r--mysql-test/suite/galera/t/galera_applier_ftwrl_table.test34
-rw-r--r--mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter.test37
-rw-r--r--mysql-test/suite/galera/t/galera_as_master.cnf1
-rw-r--r--mysql-test/suite/galera/t/galera_as_master.test41
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid.cnf8
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid.test70
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf8
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test54
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave.cnf1
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave.test50
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_autoinc.cnf1
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_autoinc.test83
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_gtid.cnf6
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_gtid.test67
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_nonprim.cnf1
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_nonprim.test96
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_preordered.cnf3
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_preordered.test84
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_replication_bundle.cnf4
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test48
-rw-r--r--mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.cnf12
-rw-r--r--mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test95
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort.test34
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_flush_for_export.test39
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_for_update.test29
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_ftwrl.test30
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_get_lock.test36
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_lock_table.test36
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_sleep.test30
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_cache_size.test35
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_checksum-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_checksum.test22
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_event_max_size_max-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_event_max_size_max.test21
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_event_max_size_min-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_event_max_size_min.test15
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_row_image.test100
-rw-r--r--mysql-test/suite/galera/t/galera_binlog_rows_query_log_events.test28
-rw-r--r--mysql-test/suite/galera/t/galera_concurrent_ctas.test57
-rw-r--r--mysql-test/suite/galera/t/galera_create_function.test53
-rw-r--r--mysql-test/suite/galera/t/galera_create_procedure.test52
-rw-r--r--mysql-test/suite/galera/t/galera_create_table_like.test50
-rw-r--r--mysql-test/suite/galera/t/galera_create_trigger.test43
-rw-r--r--mysql-test/suite/galera/t/galera_ddl_multiline.test54
-rw-r--r--mysql-test/suite/galera/t/galera_defaults.test70
-rw-r--r--mysql-test/suite/galera/t/galera_delete_limit.test52
-rw-r--r--mysql-test/suite/galera/t/galera_desync_overlapped.test59
-rw-r--r--mysql-test/suite/galera/t/galera_drop_multi.test41
-rw-r--r--mysql-test/suite/galera/t/galera_enum.test62
-rw-r--r--mysql-test/suite/galera/t/galera_events.test53
-rw-r--r--mysql-test/suite/galera/t/galera_fk_cascade_delete.test41
-rw-r--r--mysql-test/suite/galera/t/galera_fk_cascade_update.test41
-rw-r--r--mysql-test/suite/galera/t/galera_fk_conflict.test41
-rw-r--r--mysql-test/suite/galera/t/galera_fk_mismatch.test38
-rw-r--r--mysql-test/suite/galera/t/galera_fk_multicolumn.test42
-rw-r--r--mysql-test/suite/galera/t/galera_fk_multitable.test32
-rw-r--r--mysql-test/suite/galera/t/galera_fk_no_pk.test37
-rw-r--r--mysql-test/suite/galera/t/galera_fk_selfreferential.test24
-rw-r--r--mysql-test/suite/galera/t/galera_fk_setnull.test36
-rw-r--r--mysql-test/suite/galera/t/galera_flush-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_flush.test273
-rw-r--r--mysql-test/suite/galera/t/galera_flush_local.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_flush_local.test142
-rw-r--r--mysql-test/suite/galera/t/galera_forced_binlog_format-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_forced_binlog_format.test45
-rw-r--r--mysql-test/suite/galera/t/galera_ftwrl.test39
-rw-r--r--mysql-test/suite/galera/t/galera_ftwrl_drain.test69
-rw-r--r--mysql-test/suite/galera/t/galera_fulltext.test62
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover.cnf7
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover.test77
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.cnf9
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test59
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover_manytrx.cnf9
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test225
-rw-r--r--mysql-test/suite/galera/t/galera_gcs_fc_limit.test59
-rw-r--r--mysql-test/suite/galera/t/galera_gcs_fragment.cnf5
-rw-r--r--mysql-test/suite/galera/t/galera_gcs_fragment.test66
-rw-r--r--mysql-test/suite/galera/t/galera_gcs_max_packet_size.cnf5
-rw-r--r--mysql-test/suite/galera/t/galera_gcs_max_packet_size.test26
-rw-r--r--mysql-test/suite/galera/t/galera_gra_log.test38
-rw-r--r--mysql-test/suite/galera/t/galera_gtid-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_gtid.test27
-rw-r--r--mysql-test/suite/galera/t/galera_insert_ignore.test60
-rw-r--r--mysql-test/suite/galera/t/galera_insert_multi.test122
-rw-r--r--mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.cnf14
-rw-r--r--mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.test12
-rw-r--r--mysql-test/suite/galera/t/galera_ist_mysqldump.cnf12
-rw-r--r--mysql-test/suite/galera/t/galera_ist_mysqldump.test17
-rw-r--r--mysql-test/suite/galera/t/galera_ist_progress.cnf5
-rw-r--r--mysql-test/suite/galera/t/galera_ist_progress.test76
-rw-r--r--mysql-test/suite/galera/t/galera_ist_recv_bind.cnf8
-rw-r--r--mysql-test/suite/galera/t/galera_ist_recv_bind.test55
-rw-r--r--mysql-test/suite/galera/t/galera_ist_restart_joiner.cnf4
-rw-r--r--mysql-test/suite/galera/t/galera_ist_restart_joiner.test113
-rw-r--r--mysql-test/suite/galera/t/galera_ist_rsync.cnf13
-rw-r--r--mysql-test/suite/galera/t/galera_ist_rsync.test13
-rw-r--r--mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.cnf12
-rw-r--r--mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.test9
-rw-r--r--mysql-test/suite/galera/t/galera_kill_applier.test26
-rw-r--r--mysql-test/suite/galera/t/galera_kill_ddl.test44
-rw-r--r--mysql-test/suite/galera/t/galera_kill_largechanges.test43
-rw-r--r--mysql-test/suite/galera/t/galera_kill_nochanges.test24
-rw-r--r--mysql-test/suite/galera/t/galera_kill_smallchanges.test39
-rw-r--r--mysql-test/suite/galera/t/galera_lock_table.test43
-rw-r--r--mysql-test/suite/galera/t/galera_log_bin-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_log_bin.test39
-rw-r--r--mysql-test/suite/galera/t/galera_log_output_csv-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_log_output_csv.test24
-rw-r--r--mysql-test/suite/galera/t/galera_many_columns.test63
-rw-r--r--mysql-test/suite/galera/t/galera_many_indexes.test74
-rw-r--r--mysql-test/suite/galera/t/galera_many_rows.test54
-rw-r--r--mysql-test/suite/galera/t/galera_many_tables_nopk.test103
-rw-r--r--mysql-test/suite/galera/t/galera_many_tables_pk.test101
-rw-r--r--mysql-test/suite/galera/t/galera_mdl_race.test79
-rw-r--r--mysql-test/suite/galera/t/galera_migrate.cnf59
-rw-r--r--mysql-test/suite/galera/t/galera_migrate.test204
-rw-r--r--mysql-test/suite/galera/t/galera_multi_database.test43
-rw-r--r--mysql-test/suite/galera/t/galera_myisam_autocommit.test45
-rw-r--r--mysql-test/suite/galera/t/galera_myisam_transactions.test36
-rw-r--r--mysql-test/suite/galera/t/galera_nopk_bit.test46
-rw-r--r--mysql-test/suite/galera/t/galera_nopk_blob.test46
-rw-r--r--mysql-test/suite/galera/t/galera_nopk_large_varchar.test50
-rw-r--r--mysql-test/suite/galera/t/galera_nopk_unicode.test43
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test51
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test51
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test54
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_simple.test56
-rw-r--r--mysql-test/suite/galera/t/galera_pc_ignore_sb.test46
-rw-r--r--mysql-test/suite/galera/t/galera_pk_bigint_signed.test46
-rw-r--r--mysql-test/suite/galera/t/galera_pk_bigint_unsigned.test45
-rw-r--r--mysql-test/suite/galera/t/galera_prepared_statement.test45
-rw-r--r--mysql-test/suite/galera/t/galera_query_cache-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_query_cache.test67
-rw-r--r--mysql-test/suite/galera/t/galera_query_cache_sync_wait-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_query_cache_sync_wait.test89
-rw-r--r--mysql-test/suite/galera/t/galera_read_only.test39
-rw-r--r--mysql-test/suite/galera/t/galera_repl_key_format_flat16.test34
-rw-r--r--mysql-test/suite/galera/t/galera_repl_max_ws_size.test29
-rw-r--r--mysql-test/suite/galera/t/galera_restart_nochanges.test40
-rw-r--r--mysql-test/suite/galera/t/galera_restart_on_unknown_option.test157
-rw-r--r--mysql-test/suite/galera/t/galera_roles.test201
-rw-r--r--mysql-test/suite/galera/t/galera_rsu_add_pk.test43
-rw-r--r--mysql-test/suite/galera/t/galera_rsu_drop_pk.test58
-rw-r--r--mysql-test/suite/galera/t/galera_rsu_error.test31
-rw-r--r--mysql-test/suite/galera/t/galera_rsu_simple.test34
-rw-r--r--mysql-test/suite/galera/t/galera_rsu_wsrep_desync.test86
-rw-r--r--mysql-test/suite/galera/t/galera_sbr.test27
-rw-r--r--mysql-test/suite/galera/t/galera_sbr_binlog-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_sbr_binlog.test28
-rw-r--r--mysql-test/suite/galera/t/galera_serializable.test76
-rw-r--r--mysql-test/suite/galera/t/galera_split_brain.test47
-rw-r--r--mysql-test/suite/galera/t/galera_sql_log_bin_zero.test25
-rw-r--r--mysql-test/suite/galera/t/galera_ssl.cnf7
-rw-r--r--mysql-test/suite/galera/t/galera_ssl.test25
-rw-r--r--mysql-test/suite/galera/t/galera_ssl_compression.cnf7
-rw-r--r--mysql-test/suite/galera/t/galera_ssl_compression.test35
-rw-r--r--mysql-test/suite/galera/t/galera_ssl_upgrade.cnf7
-rw-r--r--mysql-test/suite/galera/t/galera_ssl_upgrade.test49
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump.cnf11
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump.test18
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf22
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test29
-rw-r--r--mysql-test/suite/galera/t/galera_sst_rsync.cnf11
-rw-r--r--mysql-test/suite/galera/t/galera_sst_rsync.test9
-rw-r--r--mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf24
-rw-r--r--mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test13
-rw-r--r--mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.cnf13
-rw-r--r--mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test19
-rw-r--r--mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf11
-rw-r--r--mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test13
-rw-r--r--mysql-test/suite/galera/t/galera_status_cluster.test18
-rw-r--r--mysql-test/suite/galera/t/galera_status_local_index.test21
-rw-r--r--mysql-test/suite/galera/t/galera_status_local_state.test28
-rw-r--r--mysql-test/suite/galera/t/galera_suspend_slave.test64
-rw-r--r--mysql-test/suite/galera/t/galera_sync_wait_show.test70
-rw-r--r--mysql-test/suite/galera/t/galera_toi_alter_auto_increment.test120
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_error.test29
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_fk_insert.test70
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_fk_update.test49
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_locking.test76
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_nonconflicting.test30
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_sequential.test29
-rw-r--r--mysql-test/suite/galera/t/galera_toi_drop_database.test56
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ftwrl.test22
-rw-r--r--mysql-test/suite/galera/t/galera_toi_lock_exclusive.test38
-rw-r--r--mysql-test/suite/galera/t/galera_toi_lock_shared.test23
-rw-r--r--mysql-test/suite/galera/t/galera_toi_truncate.test43
-rw-r--r--mysql-test/suite/galera/t/galera_transaction_read_only.test58
-rw-r--r--mysql-test/suite/galera/t/galera_transaction_replay.test124
-rw-r--r--mysql-test/suite/galera/t/galera_truncate.test57
-rw-r--r--mysql-test/suite/galera/t/galera_truncate_temporary.test82
-rw-r--r--mysql-test/suite/galera/t/galera_udf-master.opt2
-rw-r--r--mysql-test/suite/galera/t/galera_unicode_identifiers.test72
-rw-r--r--mysql-test/suite/galera/t/galera_unicode_pk.test64
-rw-r--r--mysql-test/suite/galera/t/galera_update_limit.test55
-rw-r--r--mysql-test/suite/galera/t/galera_v1_row_events-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_v1_row_events.test21
-rw-r--r--mysql-test/suite/galera/t/galera_var_OSU_method.test45
-rw-r--r--mysql-test/suite/galera/t/galera_var_OSU_method2.test47
-rw-r--r--mysql-test/suite/galera/t/galera_var_auto_inc_control_off.test105
-rw-r--r--mysql-test/suite/galera/t/galera_var_auto_inc_control_on.test53
-rw-r--r--mysql-test/suite/galera/t/galera_var_certify_nonPK_off.test39
-rw-r--r--mysql-test/suite/galera/t/galera_var_cluster_address.test76
-rw-r--r--mysql-test/suite/galera/t/galera_var_desync_on.test62
-rw-r--r--mysql-test/suite/galera/t/galera_var_dirty_reads.test77
-rw-r--r--mysql-test/suite/galera/t/galera_var_fkchecks.test40
-rw-r--r--mysql-test/suite/galera/t/galera_var_innodb_disallow_writes.test33
-rw-r--r--mysql-test/suite/galera/t/galera_var_load_data_splitting.test39
-rw-r--r--mysql-test/suite/galera/t/galera_var_log_bin.cnf5
-rw-r--r--mysql-test/suite/galera/t/galera_var_log_bin.test22
-rw-r--r--mysql-test/suite/galera/t/galera_var_max_ws_rows.test155
-rw-r--r--mysql-test/suite/galera/t/galera_var_max_ws_size.test46
-rw-r--r--mysql-test/suite/galera/t/galera_var_mysql_replication_bundle.test30
-rw-r--r--mysql-test/suite/galera/t/galera_var_node_address.cnf10
-rw-r--r--mysql-test/suite/galera/t/galera_var_node_address.test25
-rw-r--r--mysql-test/suite/galera/t/galera_var_notify_cmd-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_var_notify_cmd.test14
-rw-r--r--mysql-test/suite/galera/t/galera_var_replicate_myisam_off.test21
-rw-r--r--mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test139
-rw-r--r--mysql-test/suite/galera/t/galera_var_retry_autocommit.test98
-rw-r--r--mysql-test/suite/galera/t/galera_var_slave_threads.test84
-rw-r--r--mysql-test/suite/galera/t/galera_var_sync_wait.test46
-rw-r--r--mysql-test/suite/galera/t/galera_var_wsrep_on_off.test32
-rw-r--r--mysql-test/suite/galera/t/galera_wan.cnf14
-rw-r--r--mysql-test/suite/galera/t/galera_wan.test30
-rw-r--r--mysql-test/suite/galera/t/galera_wan_restart_ist.cnf14
-rw-r--r--mysql-test/suite/galera/t/galera_wan_restart_ist.test161
-rw-r--r--mysql-test/suite/galera/t/galera_wan_restart_sst.cnf14
-rw-r--r--mysql-test/suite/galera/t/galera_wan_restart_sst.test149
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_desync_wsrep_on.test57
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_log_conficts-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_log_conficts.test55
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_new_cluster-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_new_cluster.test24
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_provider_options_syntax.test20
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_provider_unset_set.test50
-rw-r--r--mysql-test/suite/galera/t/galera_zero_length_column.test41
-rw-r--r--mysql-test/suite/galera/t/grant.test25
-rw-r--r--mysql-test/suite/galera/t/lp1276424.test17
-rw-r--r--mysql-test/suite/galera/t/lp1347768.test24
-rw-r--r--mysql-test/suite/galera/t/lp1376747-2.test22
-rw-r--r--mysql-test/suite/galera/t/lp1376747-3.test28
-rw-r--r--mysql-test/suite/galera/t/lp1376747-4.test53
-rw-r--r--mysql-test/suite/galera/t/lp1376747.test24
-rw-r--r--mysql-test/suite/galera/t/lp1438990.test38
-rw-r--r--mysql-test/suite/galera/t/lp959512.test26
-rw-r--r--mysql-test/suite/galera/t/mdev_9290.test24
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#110.test51
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#198.test39
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#201-master.opt1
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#201.test32
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#237.test36
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#247.test23
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#31.test53
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#33.cnf8
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#33.test18
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#90.test65
-rw-r--r--mysql-test/suite/galera/t/partition.test207
-rw-r--r--mysql-test/suite/galera/t/pxc-421.test65
-rw-r--r--mysql-test/suite/galera/t/query_cache.test1002
-rw-r--r--mysql-test/suite/galera/t/rename.test52
-rw-r--r--mysql-test/suite/galera/t/rpl_row_annotate.cnf6
-rw-r--r--mysql-test/suite/galera/t/rpl_row_annotate.test42
-rw-r--r--mysql-test/suite/galera/t/unique_key.test54
-rw-r--r--mysql-test/suite/galera/t/view.test50
-rw-r--r--mysql-test/suite/galera_3nodes/disabled.def3
-rw-r--r--mysql-test/suite/galera_3nodes/galera_3nodes.cnf64
-rw-r--r--mysql-test/suite/galera_3nodes/include/galera_suspend.inc14
-rw-r--r--mysql-test/suite/galera_3nodes/include/have_ipv6.inc15
-rw-r--r--mysql-test/suite/galera_3nodes/my.cnf1
-rw-r--r--mysql-test/suite/galera_3nodes/r/GAL-501.result14
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result17
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result12
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result20
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_garbd.result17
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result11
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result26
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result14
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result18
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result46
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result13
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result26
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_pc_weight.result121
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result26
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_slave_options_do.result28
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_slave_options_ignore.result28
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result48
-rw-r--r--mysql-test/suite/galera_3nodes/suite.pm55
-rw-r--r--mysql-test/suite/galera_3nodes/t/GAL-501.cnf26
-rw-r--r--mysql-test/suite/galera_3nodes/t/GAL-501.test38
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_certification_ccc.test53
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test33
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test68
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_garbd.test64
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test58
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf22
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test56
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf22
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test32
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf26
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test62
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.cnf11
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test101
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test38
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.cnf5
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.test91
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf5
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_pc_weight.test128
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test164
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_slave_options_do.cnf7
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_slave_options_do.test34
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.cnf7
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test34
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test112
-rw-r--r--mysql-test/suite/innodb/r/innodb-autoinc.result45
-rw-r--r--mysql-test/suite/innodb/r/innodb_uninstall.result4
-rw-r--r--mysql-test/suite/innodb/t/galera.skip49
-rw-r--r--mysql-test/suite/innodb/t/innodb-autoinc.test46
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug27216817.test28
-rw-r--r--mysql-test/suite/jp/disabled.def2
-rwxr-xr-xmysql-test/suite/parts/r/partition_exch_qa_10.result2
-rw-r--r--mysql-test/suite/parts/t/partition_exch_qa_10.test2
-rw-r--r--mysql-test/suite/perfschema/r/rpl_statements.result4
-rw-r--r--mysql-test/suite/perfschema/t/rpl_statements.test4
-rw-r--r--mysql-test/suite/rpl/r/mysql-wsrep#110-2.result24
-rw-r--r--mysql-test/suite/rpl/t/mysql-wsrep#110-2.test44
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/log_tc_size_basic.result4
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result50
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result54
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result43
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result59
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result47
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_debug_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_desync_basic.result56
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result54
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result51
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result51
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result60
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result52
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result49
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result56
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result61
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result47
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_on_basic.result50
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result61
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_provider_basic.result40
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result48
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_recover_basic.result22
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result31
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result31
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result63
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result49
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result52
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result50
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result45
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result54
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result64
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result57
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result54
-rw-r--r--mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/log_tc_size_basic.test5
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test45
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test48
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test40
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test49
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_debug_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_desync_basic.test49
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test48
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test46
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test45
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test47
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test45
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test45
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test47
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test54
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test43
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_on_basic.test45
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test49
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_provider_basic.test39
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test44
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_recover_basic.test26
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test36
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test36
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test52
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test43
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test45
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test43
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test42
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test47
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test53
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test56
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test47
-rw-r--r--mysql-test/suite/wsrep/README7
-rw-r--r--mysql-test/suite/wsrep/disabled.def1
-rw-r--r--mysql-test/suite/wsrep/include/check_galera_version.inc39
-rw-r--r--mysql-test/suite/wsrep/my.cnf9
-rw-r--r--mysql-test/suite/wsrep/r/alter_table_innodb.result8
-rw-r--r--mysql-test/suite/wsrep/r/binlog_format.result61
-rw-r--r--mysql-test/suite/wsrep/r/foreign_key.result19
-rw-r--r--mysql-test/suite/wsrep/r/mdev_6832.result11
-rw-r--r--mysql-test/suite/wsrep/r/mdev_7798.result13
-rw-r--r--mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result70
-rw-r--r--mysql-test/suite/wsrep/r/pool_of_threads.result8
-rw-r--r--mysql-test/suite/wsrep/r/trans.result9
-rw-r--r--mysql-test/suite/wsrep/r/variables.result237
-rw-r--r--mysql-test/suite/wsrep/r/wsrep_rpl.result22
-rw-r--r--mysql-test/suite/wsrep/suite.pm38
-rw-r--r--mysql-test/suite/wsrep/t/alter_table_innodb.opt1
-rw-r--r--mysql-test/suite/wsrep/t/alter_table_innodb.test10
-rw-r--r--mysql-test/suite/wsrep/t/binlog_format.opt1
-rw-r--r--mysql-test/suite/wsrep/t/binlog_format.test47
-rw-r--r--mysql-test/suite/wsrep/t/foreign_key.opt1
-rw-r--r--mysql-test/suite/wsrep/t/foreign_key.test20
-rw-r--r--mysql-test/suite/wsrep/t/mdev_6832.opt1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_6832.test15
-rw-r--r--mysql-test/suite/wsrep/t/mdev_7798.opt1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_7798.test17
-rw-r--r--mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test40
-rw-r--r--mysql-test/suite/wsrep/t/pool_of_threads.opt1
-rw-r--r--mysql-test/suite/wsrep/t/pool_of_threads.test12
-rw-r--r--mysql-test/suite/wsrep/t/trans.test14
-rw-r--r--mysql-test/suite/wsrep/t/variables.test153
-rw-r--r--mysql-test/suite/wsrep/t/wsrep_rpl.cnf1
-rw-r--r--mysql-test/suite/wsrep/t/wsrep_rpl.test44
-rw-r--r--mysql-test/t/file_contents.test2
-rw-r--r--mysql-test/t/information_schema.test24
-rw-r--r--mysql-test/t/innodb_load_xa.test1
-rw-r--r--mysql-test/t/innodb_load_xa_with_wsrep.opt1
-rw-r--r--mysql-test/t/innodb_load_xa_with_wsrep.test22
-rw-r--r--mysql-test/t/mysql_tzinfo_to_sql_symlink.test5
-rw-r--r--mysql-test/t/mysqld--help.test4
-rw-r--r--mysql-test/t/read_only_innodb.test9
-rw-r--r--mysql-test/valgrind.supp231
-rw-r--r--mysys/my_alloc.c5
-rw-r--r--mysys/my_create.c2
-rw-r--r--mysys/my_fopen.c8
-rw-r--r--mysys/my_symlink.c2
-rw-r--r--mysys/thr_lock.c173
-rw-r--r--mysys_ssl/my_md5.cc1
-rw-r--r--policy/apparmor/README5
-rw-r--r--policy/apparmor/usr.sbin.mysqld150
-rw-r--r--policy/apparmor/usr.sbin.mysqld.local4
-rw-r--r--policy/selinux/README20
-rw-r--r--policy/selinux/mariadb-server.fc10
-rw-r--r--policy/selinux/mariadb-server.te99
-rw-r--r--scripts/CMakeLists.txt26
-rw-r--r--scripts/mysqld_multi.sh123
-rw-r--r--scripts/mysqld_safe.sh128
-rw-r--r--scripts/wsrep_sst_common.sh278
-rw-r--r--scripts/wsrep_sst_mysqldump.sh168
-rw-r--r--scripts/wsrep_sst_rsync.sh342
-rw-r--r--scripts/wsrep_sst_xtrabackup-v2.sh1189
-rw-r--r--scripts/wsrep_sst_xtrabackup.sh686
-rw-r--r--sql/CMakeLists.txt25
-rw-r--r--sql/event_data_objects.cc16
-rw-r--r--sql/events.cc75
-rw-r--r--sql/ha_partition.cc8
-rw-r--r--sql/ha_partition.h4
-rw-r--r--sql/handler.cc172
-rw-r--r--sql/handler.h20
-rw-r--r--sql/item_func.cc12
-rw-r--r--sql/keycaches.cc1
-rw-r--r--sql/lock.cc93
-rw-r--r--sql/log.cc249
-rw-r--r--sql/log.h23
-rw-r--r--sql/log_event.cc242
-rw-r--r--sql/mdl.cc181
-rw-r--r--sql/mdl.h17
-rw-r--r--sql/mysqld.cc895
-rw-r--r--sql/mysqld.h19
-rw-r--r--sql/protocol.cc8
-rw-r--r--sql/rpl_gtid.cc12
-rw-r--r--sql/rpl_mi.cc8
-rw-r--r--sql/rpl_record.cc20
-rw-r--r--sql/set_var.cc4
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/slave.cc92
-rw-r--r--sql/sp.cc35
-rw-r--r--sql/sql_acl.cc42
-rw-r--r--sql/sql_admin.cc3
-rw-r--r--sql/sql_alter.cc21
-rw-r--r--sql/sql_base.cc58
-rw-r--r--sql/sql_builtin.cc.in9
-rw-r--r--sql/sql_cache.cc20
-rw-r--r--sql/sql_class.cc347
-rw-r--r--sql/sql_class.h79
-rw-r--r--sql/sql_connect.cc27
-rw-r--r--sql/sql_delete.cc12
-rw-r--r--sql/sql_insert.cc151
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_parse.cc683
-rw-r--r--sql/sql_parse.h28
-rw-r--r--sql/sql_partition_admin.cc29
-rw-r--r--sql/sql_plugin.cc25
-rw-r--r--sql/sql_prepare.cc22
-rw-r--r--sql/sql_reload.cc30
-rw-r--r--sql/sql_repl.cc9
-rw-r--r--sql/sql_show.cc101
-rw-r--r--sql/sql_show.h2
-rw-r--r--sql/sql_table.cc103
-rw-r--r--sql/sql_trigger.cc69
-rw-r--r--sql/sql_truncate.cc10
-rw-r--r--sql/sql_update.cc12
-rw-r--r--sql/sql_view.cc5
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/sys_vars.cc307
-rw-r--r--sql/table.cc3
-rw-r--r--sql/transaction.cc51
-rw-r--r--sql/tztime.cc11
-rw-r--r--sql/wsrep_applier.cc403
-rw-r--r--sql/wsrep_applier.h39
-rw-r--r--sql/wsrep_binlog.cc412
-rw-r--r--sql/wsrep_binlog.h56
-rw-r--r--sql/wsrep_check_opts.cc396
-rw-r--r--sql/wsrep_hton.cc638
-rw-r--r--sql/wsrep_mysqld.cc1742
-rw-r--r--sql/wsrep_mysqld.h358
-rw-r--r--sql/wsrep_notify.cc111
-rw-r--r--sql/wsrep_priv.h51
-rw-r--r--sql/wsrep_sst.cc1232
-rw-r--r--sql/wsrep_sst.h71
-rw-r--r--sql/wsrep_thd.cc666
-rw-r--r--sql/wsrep_thd.h40
-rw-r--r--sql/wsrep_utils.cc570
-rw-r--r--sql/wsrep_utils.h232
-rw-r--r--sql/wsrep_var.cc681
-rw-r--r--sql/wsrep_var.h88
-rw-r--r--sql/wsrep_xid.cc150
-rw-r--r--sql/wsrep_xid.h33
-rw-r--r--storage/innobase/CMakeLists.txt27
-rw-r--r--storage/innobase/buf/buf0dump.cc32
-rw-r--r--storage/innobase/dict/dict0dict.cc24
-rw-r--r--storage/innobase/handler/ha_innodb.cc1585
-rw-r--r--storage/innobase/handler/ha_innodb.h42
-rw-r--r--storage/innobase/handler/handler0alter.cc4
-rw-r--r--storage/innobase/include/dict0mem.h3
-rw-r--r--storage/innobase/include/ha_prototypes.h16
-rw-r--r--storage/innobase/include/hash0hash.h27
-rw-r--r--storage/innobase/include/lock0lock.h28
-rw-r--r--storage/innobase/include/rem0rec.h9
-rw-r--r--storage/innobase/include/srv0srv.h12
-rw-r--r--storage/innobase/include/sync0sync.ic3
-rw-r--r--storage/innobase/include/trx0sys.h102
-rw-r--r--storage/innobase/include/trx0sys.ic3
-rw-r--r--storage/innobase/include/trx0trx.h34
-rw-r--r--storage/innobase/lock/lock0lock.cc550
-rw-r--r--storage/innobase/lock/lock0wait.cc37
-rw-r--r--storage/innobase/os/os0file.cc31
-rw-r--r--storage/innobase/rem/rem0rec.cc133
-rw-r--r--storage/innobase/row/row0ins.cc35
-rw-r--r--storage/innobase/row/row0upd.cc292
-rw-r--r--storage/innobase/srv/srv0conc.cc93
-rw-r--r--storage/innobase/srv/srv0srv.cc29
-rw-r--r--storage/innobase/srv/srv0start.cc16
-rw-r--r--storage/innobase/trx/trx0roll.cc16
-rw-r--r--storage/innobase/trx/trx0sys.cc147
-rw-r--r--storage/innobase/trx/trx0trx.cc149
-rw-r--r--storage/innobase/wsrep/md5.cc74
-rw-r--r--storage/innobase/wsrep/wsrep_md5.h26
-rw-r--r--storage/maria/ma_control_file.c2
-rw-r--r--storage/maria/ma_loghandler.c6
-rw-r--r--storage/maria/ma_open.c8
-rw-r--r--storage/myisam/mi_open.c8
-rw-r--r--storage/tokudb/ha_tokudb.cc298
-rw-r--r--storage/tokudb/ha_tokudb.h5
-rw-r--r--storage/xtradb/CMakeLists.txt27
-rw-r--r--storage/xtradb/buf/buf0dump.cc28
-rw-r--r--storage/xtradb/dict/dict0dict.cc24
-rw-r--r--storage/xtradb/handler/ha_innodb.cc1591
-rw-r--r--storage/xtradb/handler/ha_innodb.h41
-rw-r--r--storage/xtradb/handler/handler0alter.cc4
-rw-r--r--storage/xtradb/include/dict0mem.h3
-rw-r--r--storage/xtradb/include/ha_prototypes.h16
-rw-r--r--storage/xtradb/include/hash0hash.h27
-rw-r--r--storage/xtradb/include/lock0lock.h19
-rw-r--r--storage/xtradb/include/rem0rec.h9
-rw-r--r--storage/xtradb/include/srv0srv.h13
-rw-r--r--storage/xtradb/include/sync0sync.ic3
-rw-r--r--storage/xtradb/include/trx0sys.h101
-rw-r--r--storage/xtradb/include/trx0sys.ic3
-rw-r--r--storage/xtradb/include/trx0trx.h36
-rw-r--r--storage/xtradb/lock/lock0lock.cc545
-rw-r--r--storage/xtradb/lock/lock0wait.cc37
-rw-r--r--storage/xtradb/os/os0file.cc35
-rw-r--r--storage/xtradb/rem/rem0rec.cc138
-rw-r--r--storage/xtradb/row/row0ins.cc35
-rw-r--r--storage/xtradb/row/row0upd.cc292
-rw-r--r--storage/xtradb/srv/srv0conc.cc93
-rw-r--r--storage/xtradb/srv/srv0srv.cc39
-rw-r--r--storage/xtradb/srv/srv0start.cc14
-rw-r--r--storage/xtradb/trx/trx0roll.cc16
-rw-r--r--storage/xtradb/trx/trx0sys.cc147
-rw-r--r--storage/xtradb/trx/trx0trx.cc156
-rw-r--r--storage/xtradb/wsrep/md5.cc74
-rw-r--r--storage/xtradb/wsrep/wsrep_md5.h26
-rw-r--r--support-files/CMakeLists.txt6
-rw-r--r--support-files/mysql.server.sh24
-rw-r--r--support-files/mysql.spec.sh69
-rw-r--r--support-files/rpm/server.cnf16
-rw-r--r--support-files/wsrep.cnf.sh125
-rw-r--r--support-files/wsrep_notify.sh102
-rw-r--r--wsrep/CMakeLists.txt24
-rw-r--r--wsrep/wsrep_api.h1118
-rw-r--r--wsrep/wsrep_dummy.c414
-rw-r--r--wsrep/wsrep_gtid.c74
-rw-r--r--wsrep/wsrep_loader.c225
-rw-r--r--wsrep/wsrep_uuid.c83
1103 files changed, 63560 insertions, 1490 deletions
diff --git a/.gitignore b/.gitignore
index b8d5ea0f803..2b25ccc6fdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,6 +114,7 @@ scripts/mytop
scripts/wsrep_sst_common
scripts/wsrep_sst_mysqldump
scripts/wsrep_sst_rsync
+scripts/wsrep_sst_rsync_wan
scripts/wsrep_sst_xtrabackup
scripts/wsrep_sst_xtrabackup-v2
sql-bench/bench-count-distinct
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 858f42320b8..ba2256d8269 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -216,7 +216,7 @@ all_configs="$SSL_LIBRARY --with-plugins=max --with-plugin-ndbcluster --with-emb
alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag"
amd64_cflags="$check_cpu_cflags"
amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES"
-pentium_cflags="$check_cpu_cflags"
+pentium_cflags="$check_cpu_cflags -m32"
pentium64_cflags="$check_cpu_cflags -m64"
ppc_cflags="$check_cpu_cflags"
sparc_cflags=""
diff --git a/BUILD/compile-amd64-debug-wsrep b/BUILD/compile-amd64-debug-wsrep
new file mode 100755
index 00000000000..995a8afcca9
--- /dev/null
+++ b/BUILD/compile-amd64-debug-wsrep
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$amd64_cflags $debug_cflags -g -O0 $wsrep_cflags"
+c_warnings="$c_warnings $debug_extra_warnings"
+cxx_warnings="$cxx_warnings $debug_extra_warnings"
+extra_configs="$amd64_configs $debug_configs $wsrep_configs --with-wsrep"
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-amd64-wsrep b/BUILD/compile-amd64-wsrep
new file mode 100755
index 00000000000..57dfbdd6da2
--- /dev/null
+++ b/BUILD/compile-amd64-wsrep
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$amd64_cflags $fast_cflags -g $wsrep_cflags"
+extra_configs="$amd64_configs $wsrep_configs --with-wsrep"
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-debug-wsrep b/BUILD/compile-pentium-debug-wsrep
new file mode 100644
index 00000000000..ee68e3fd0c1
--- /dev/null
+++ b/BUILD/compile-pentium-debug-wsrep
@@ -0,0 +1,12 @@
+#! /bin/sh -x
+
+path=`dirname $0`
+set -- "$@" --with-debug=full
+. "$path/SETUP.sh"
+
+extra_flags="$pentium_cflags $debug_cflags -g -O0 $wsrep_cflags"
+c_warnings="$c_warnings $debug_extra_warnings"
+cxx_warnings="$cxx_warnings $debug_extra_warnings"
+extra_configs="$pentium_configs $debug_configs $wsrep_configs --with-wsrep"
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium-wsrep b/BUILD/compile-pentium-wsrep
new file mode 100644
index 00000000000..eeb14310e4e
--- /dev/null
+++ b/BUILD/compile-pentium-wsrep
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium_cflags $fast_cflags $wsrep_cflags"
+extra_configs="$pentium_configs $wsrep_configs --with-wsrep"
+
+#strip=yes
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-pentium64-wsrep b/BUILD/compile-pentium64-wsrep
new file mode 100644
index 00000000000..0bccb34e753
--- /dev/null
+++ b/BUILD/compile-pentium64-wsrep
@@ -0,0 +1,28 @@
+#! /bin/sh
+
+# Copyright (C) 2006, 2007 MySQL AB
+#
+# 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 Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium64_cflags $fast_cflags -g $wsrep_cflags"
+extra_configs="$pentium_configs $static_link $wsrep_configs --with-wsrep"
+CC="$CC --pipe"
+strip=yes
+
+. "$path/FINISH.sh"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a9ec265de0..70c8c50946e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -135,6 +135,7 @@ INCLUDE(cpack_rpm)
INCLUDE(cpack_deb)
# Add macros
+INCLUDE(wsrep)
INCLUDE(character_sets)
INCLUDE(cpu_info)
INCLUDE(zlib)
@@ -271,6 +272,13 @@ MARK_AS_ADVANCED(ENABLED_LOCAL_INFILE)
OPTION(WITH_FAST_MUTEXES "Compile with fast mutexes" OFF)
MARK_AS_ADVANCED(WITH_FAST_MUTEXES)
+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()
+
# Set DBUG_OFF and other optional release-only flags for non-debug project types
FOREACH(BUILD_TYPE RELEASE RELWITHDEBINFO MINSIZEREL)
FOREACH(LANG C CXX)
@@ -407,6 +415,9 @@ ADD_SUBDIRECTORY(vio)
ADD_SUBDIRECTORY(mysys)
ADD_SUBDIRECTORY(mysys_ssl)
ADD_SUBDIRECTORY(libmysql)
+IF(WITH_WSREP)
+ADD_SUBDIRECTORY(wsrep)
+ENDIF()
ADD_SUBDIRECTORY(client)
ADD_SUBDIRECTORY(extra)
ADD_SUBDIRECTORY(libservices)
@@ -466,8 +477,8 @@ CONFIGURE_FILE(
IF(DEB)
CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/debian/mariadb-server-10.0.files.in
- ${CMAKE_SOURCE_DIR}/debian/mariadb-server-10.0.files)
+ ${CMAKE_SOURCE_DIR}/debian/mariadb-galera-server-10.0.files.in
+ ${CMAKE_SOURCE_DIR}/debian/mariadb-galera-server-10.0.files)
ENDIF(DEB)
# Handle the "INFO_*" files.
@@ -493,7 +504,7 @@ INSTALL_DOCUMENTATION(README CREDITS COPYING EXCEPTIONS-CLIENT COMPONENT Readme)
# ${CMAKE_BINARY_DIR}/Docs/INFO_BIN)
IF(UNIX)
- INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY COMPONENT Readme)
+ INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY Docs/README-wsrep COMPONENT Readme)
ENDIF()
INCLUDE(CPack)
diff --git a/Docs/README-wsrep b/Docs/README-wsrep
new file mode 100644
index 00000000000..422ec52f48a
--- /dev/null
+++ b/Docs/README-wsrep
@@ -0,0 +1,488 @@
+Codership Oy
+http://www.codership.com
+<info@codership.com>
+
+DISCLAIMER
+
+THIS SOFTWARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES
+RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE.
+
+Trademark Information.
+
+MySQL is a trademark or registered trademark of Oracle and/or its affiliates.
+Other trademarks are the property of their respective owners.
+
+Licensing Information.
+
+Please see file COPYING that came with this distribution
+
+Source code can be found at
+wsrep API: https://launchpad.net/wsrep
+MySQL patch: https://launchpad.net/codership-mysql
+
+
+ABOUT THIS DOCUMENT
+
+This document covers installation and configuration issues specific to this
+wsrep-patched MySQL distribution by Codership. It does not cover the use or
+administration of MySQL server per se. The reader is assumed to know how to
+install, configure, administer and use standard MySQL server version 5.1.xx.
+
+
+ MYSQL-5.5.x/wsrep-23.x
+
+CONTENTS:
+=========
+1. WHAT IS WSREP PATCH FOR MYSQL
+2. INSTALLATION
+3. FIRST TIME SETUP
+ 3.1 CONFIGURATION FILES
+ 3.2 DATABASE PRIVILEGES
+ 3.3 CHECK AND CORRECT FIREWALL SETTINGS
+ 3.4 SELINUX
+ 3.5 APPARMOR
+ 3.6 CONNECT TO CLUSTER
+4. UPGRADING FROM MySQL 5.1.x
+5. CONFIGURATION OPTIONS
+ 5.1 MANDATORY MYSQL OPTIONS
+ 5.2 WSREP OPTIONS
+6. ONLINE SCHEMA UPGRADE
+ 6.1 TOTAL ORDER ISOLATION (TOI)
+ 6.2 ROLLING SCHEMA UPGRADE (RSU)
+7. LIMITATIONS
+
+
+1. WHAT IS WSREP PATCH FOR MYSQL/INNODB
+
+Wsrep API developed by Codership Oy is a modern generic (database-agnostic)
+replication API for transactional databases with a goal to make database
+replication/logging subsystem completely modular and pluggable. It is developed
+with flexibility and completeness in mind to satisfy broad range of modern
+replication scenarios. It is equally suitable for synchronous and asynchronous,
+master-slave and multi-master replication.
+
+wsrep stands for Write Set REPlication.
+
+Wsrep patch for MySQL/InnoDB allows MySQL server to load and use various wsrep
+API implementations ("wsrep providers") with different qualities of service.
+Without wsrep provider MySQL-wsrep server will function like a regular
+standalone server.
+
+
+2. INSTALLATION
+
+In the examples below mysql authentication options are omitted for brevity.
+
+2.1 Download and install mysql-wsrep package.
+
+Download binary package for your Linux distribution from
+https://launchpad.net/codership-mysql/
+
+2.1.1 On Debian and Debian-derived distributions.
+
+Upgrade from mysql-server-5.0 to mysql-wsrep is not supported yet, please
+upgrade to mysql-server-5.1 first.
+
+If you're installing over an existing mysql installation, mysql-server-wsrep
+will conflict with mysql-server-5.1 package, so remove it first:
+
+$ sudo apt-get remove mysql-server-5.1 mysql-server-core-5.1
+
+mysql-server-wsrep requires psmisc and mysql-client-5.1.47 (or later).
+MySQL 5.1 packages can be found from backports repositories.
+For further information about configuring and using Debian or Ubuntu
+backports, see:
+
+* http://backports.debian.org
+
+* https://help.ubuntu.com/community/UbuntuBackports
+
+For example, installation of required packages on Debian Lenny:
+
+$ sudo apt-get install psmisc
+$ sudo apt-get -t lenny-backports install mysql-client-5.1
+
+Now you should be able to install mysql-wsrep package:
+
+$ sudo dpkg -i <mysql-server-wsrep DEB>
+
+2.1.2 On CentOS and similar RPM-based distributions.
+
+If you're migrating from existing MySQL installation, there are two variants:
+
+ a) If you're already using official MySQL-server-community 5.1.x RPM from
+ Oracle:
+
+ # rpm -e mysql-server
+
+ b) If you're upgrading from the stock mysql-5.0.77 on CentOS:
+
+ 1) Make sure that the following packages are not installed:
+ # rpm --nodeps --allmatches -e mysql-server mysql-test mysql-bench
+
+ 2) Install *official* MySQL-shared-compat-5.1.x from
+ http://dev.mysql.com/downloads/mysql/5.1.html
+
+Actual installation:
+
+ # rpm -Uvh <MySQL-server-wsrep RPM>
+
+ If this fails due to unsatisfied dependencies, install missing packages
+ (e.g. yum install perl-DBI) and retry.
+
+Additional packages to consider (if not yet installed):
+ * galera (multi-master replication provider, https://launchpad.net/galera)
+ * MySQL-client-community (for connecting to server and mysqldump-based SST)
+ * rsync (for rsync-based SST)
+ * xtrabackup and nc (for xtrabackup-based SST)
+
+2.2 Upgrade system tables.
+
+If you're upgrading a previous MySQL installation, it might be advisable to
+upgrade system tables. To do that start mysqld and run mysql_upgrade command.
+Consult MySQL documentation in case of errors. Normally they are not critical
+and can be ignored unless specific functionality is needed.
+
+
+3. FIRST TIME SETUP
+
+Unless you're upgrading an already installed mysql-wsrep package, you will need
+to set up a few things to prepare server for operation.
+
+3.1 CONFIGURATION FILES
+
+* Make sure system-wide my.cnf does not bind mysqld to 127.0.0.1. That is, if
+ you have the following line in [mysqld] section, comment it out:
+
+ #bind-address = 127.0.0.1
+
+* Make sure system-wide my.cnf contains "!includedir /etc/mysql/conf.d/" line.
+
+* Edit /etc/mysql/conf.d/wsrep.cnf and set wsrep_provider option by specifying
+ a path to provider library. If you don't have a provider, leave it as it is.
+
+* When a new node joins the cluster it'll have to receive a state snapshot from
+ one of the peers. This requires a privileged MySQL account with access from
+ the rest of the cluster. Edit /etc/mysql/conf.d/wsrep.cnf and set mysql
+ login/password pair for SST, for example:
+
+ wsrep_sst_auth=wsrep_sst:wspass
+
+* See CONFIGURATION section below about other configuration parameters that you
+ might want to change at this point.
+
+3.2 DATABASE PRIVILEGES
+
+Restart MySQL server and connect to it as root to grant privileges to SST
+account (empty users confuse MySQL authentication matching rules, we need to
+delete them too):
+
+$ mysql -e "SET wsrep_on=OFF; DELETE FROM mysql.user WHERE user='';"
+$ mysql -e "SET wsrep_on=OFF; GRANT ALL ON *.* TO wsrep_sst@'%' IDENTIFIED BY 'wspass'";
+
+3.3 CHECK AND CORRECT FIREWALL SETTINGS.
+
+MySQL-wsrep server needs to be accessible from other cluster members through
+its client listening socket and through wsrep provider socket. See your
+distribution and wsrep provider documentation for details. For example on
+CentOS you might need to do something along these lines:
+
+# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source <my IP>/24 --destination <my IP>/32 --dport 3306 -j ACCEPT
+# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source <my IP>/24 --destination <my IP>/32 --dport 4567 -j ACCEPT
+
+If there is a NAT firewall between the nodes, it must be configured to allow
+direct connections between the nodes (e.g. via port forwarding).
+
+3.4 SELINUX
+
+If you have SELinux enabled, it may block mysqld from doing required operations.
+You'll need to either disable it or configure to allow mysqld to run external
+programs and open listen sockets at unprivileged ports (i.e. things that
+an unprivileged user can do). See SELinux documentation about it.
+
+To quickly disable SELinux:
+1) run 'setenforce 0' as root.
+2) set 'SELINUX=permissive' in /etc/selinux/config
+
+3.5 APPARMOR
+
+AppArmor automatically comes with Ubuntu and may also prevent mysqld to from
+opening additional ports or run scripts. See AppArmor documentation about its
+configuration. To disable AppArmor for mysqld:
+
+$ cd /etc/apparmor.d/disable/
+$ sudo ln -s /etc/apparmor.d/usr.sbin.mysqld
+$ sudo service apparmor restart
+
+
+3.6 CONNECT TO CLUSTER
+
+Now you're ready to connect to cluster by setting wsrep_cluster_address variable
+and monitor status of wsrep provider:
+
+mysql> SET GLOBAL wsrep_cluster_address='<cluster address string>';
+mysql> SHOW STATUS LIKE 'wsrep%';
+
+
+4 UPGRADING FROM MySQL 5.1.x
+
+!!! THESE INSTRUCTIONS ARE PRELIMINARY AND INCOMPLETE !!!
+
+1) BEFORE UPGRADE (while running 5.1.x):
+ - comment out 'wsrep_provider' setting from configuration files
+ (my.cnf and/or wsrep.cnf)
+ - If performing a rolling upgrade on a running cluster, set
+ wsrep_sst_method=mysqldump.
+ You might also need to configure wsrep_sst_receive_address and
+ wsrep_sst_auth appropriately. mysqldump is the only way to transfer data
+ from 5.1.x to 5.5.x reliably.
+ - remove innodb_plugin settings from configuration files.
+
+2) Perform upgrade as usual:
+ http://dev.mysql.com/doc/refman/5.5/en/upgrading-from-previous-series.html
+ Don't forget to run 'mysql_upgrade' command.
+
+3) AFTER UPGRADING individual node:
+ - uncomment 'wsrep_provider' line in configuration file.
+ - restart the server and join the cluster.
+
+4) AFTER UPGRADING the whole cluster:
+ - revert to usual wsrep SST settings if not 'mysqldump'.
+
+
+5. CONFIGURATION OPTIONS
+
+5.1 MANDATORY MYSQL OPTIONS
+
+binlog_format=ROW
+ This option is required to use row-level replication as opposed to
+ statement-level. For performance and consistency considerations don't change
+ that. As a side effect, binlog, if turned on, can be ROW only. In future this
+ option won't have special meaning.
+
+innodb_autoinc_lock_mode=2
+ This is a required parameter. Without it INSERTs into tables with
+ AUTO_INCREMENT column may fail.
+ autoinc lock modes 0 and 1 can cause unresolved deadlock, and make
+ system unresponsive.
+
+innodb_locks_unsafe_for_binlog=1
+ This option is required for parallel applying.
+
+5.2 WSREP OPTIONS
+
+All options are optional except for wsrep_provider, wsrep_cluster_address, and
+wsrep_sst_auth.
+
+wsrep_provider=none
+ A full path to the library that implements WSREP interface. If none is
+ specified, the server behaves like a regular mysqld.
+
+wsrep_provider_options=
+ Provider-specific option string. Check wsrep provider documentation or
+ http://www.codership.com/wiki
+
+wsrep_cluster_address=
+ Provider-specific cluster address string. This is used to connect a node to
+ the desired cluster. This option can be given either on mysqld startup or set
+ during runtime. See wsrep provider documentation for possible values.
+
+wsrep_cluster_name="my_wsrep_cluster"
+ Logical cluster name, must be the same for all nodes of the cluster.
+
+wsrep_node_address=
+ An option to explicitly specify the network address of the node in the form
+ <address>[:port] if autoguessing for some reason does not produce desirable
+ results (multiple network interfaces, NAT, etc.)
+ If not explicitly overridden by wsrep_sst_receive_address, the <address> part
+ will be used to listen for SST (see below). And the whole <address>[:port]
+ will be passed to wsrep provider to be used as a base address in its
+ communications.
+
+wsrep_node_name=
+ Human readable node name (for easier log reading only). Defaults to hostname.
+
+wsrep_slave_threads=1
+ Number of threads dedicated to processing of writesets from other nodes.
+ For best performance should be few per CPU core.
+
+wsrep_dbug_option
+ Options for the built-in DBUG library (independent from what MySQL uses).
+ Empty by default. Not currently in use.
+
+wsrep_debug=0
+ Enable debug-level logging.
+
+wsrep_convert_LOCK_to_trx=0
+ Implicitly convert locking sessions into transactions inside mysqld. By
+ itself it does not mean support for locking sessions, but it prevents the
+ database from going into logically inconsistent state. Note however, that
+ loading large database dump with LOCK statements might result in abnormally
+ large transactions and cause an out-of-memory condition
+
+wsrep_retry_autocommit=1
+ Retry autocommit queries and single statement transactions should they fail
+ certification test. This is analogous to rescheduling an autocommit query
+ should it go into deadlock with other transactions in the database lock
+ manager.
+
+wsrep_auto_increment_control=1
+ Automatically adjust auto_increment_increment and auto_increment_offset
+ variables based on the number of nodes in the cluster. Significantly reduces
+ certification conflict rate for INSERTS.
+
+wsrep_drupal_282555_workaround=1
+ MySQL seems to have an obscure bug when INSERT into table with
+ AUTO_INCREMENT column with NULL value for that column can fail with a
+ duplicate key error. When this option is on, it retries such INSERTs.
+ Required for stable Drupal operation. Documented at:
+ http://bugs.mysql.com/bug.php?id=41984
+ http://drupal.org/node/282555
+
+wsrep_causal_reads=0
+ Enforce strict READ COMMITTED semantics on reads and transactions. May
+ result in additional latencies. It is a session variable.
+
+wsrep_OSU_method=TOI
+ Online Schema Upgrade (OSU) can be performed with two alternative methods:
+ Total Order Isolation (TOI) runs DDL statement in all cluster nodes in
+ same total order sequence locking the affected table for the duration of the
+ operation. This may result in the whole cluster being blocked for the
+ duration of the operation.
+ Rolling Schema Upgrade (RSU) executes the DDL statement only locally, thus
+ blocking only one cluster node. During the DDL processing, the node
+ is not replicating and may be unable to process replication events (due to
+ table lock). Once DDL operation is complete, the node will catch up and sync
+ with the cluster to become fully operational again. The DDL statement or
+ its effects are not replicated, so it is user's responsibility to manually
+ perform this operation on each of the nodes.
+
+wsrep_forced_binlog_format=none
+ Force every transaction to use given binlog format. When this variable is
+ set to something else than NONE, all transactions will use the given forced
+ format, regardless of what the client session has specified in binlog_format.
+ Valid choices for wsrep_forced_binlog_format are: ROW, STATEMENT, MIXED and
+ special value NONE, meaning that there is no forced binlog format in effect.
+ This variable was intruduced to support STATEMENT format replication during
+ rolling schema upgrade processing. However, in most cases ROW replication
+ is valid for asymmetrict schema replication.
+
+State snapshot transfer options.
+
+When a new node joins the cluster it has to synchronize its initial state with
+the other cluster members by transferring state snapshot from one of them.
+The options below govern how this happens and should be set up before attempting
+to join or start a cluster.
+
+wsrep_sst_method=rsync
+ What method to use to copy database state to a newly joined node. Supported
+ methods:
+ - mysqldump: slow (except for small datasets) but allows for upgrade
+ between major MySQL versions or InnoDB features.
+ - rsync: much faster on large datasets (default).
+ - rsync_wan: same as rsync but with deltaxfer to minimize network traffic.
+ - xtrabackup: very fast and practically non-blocking SST method based on
+ Percona's xtrabackup tool.
+
+ (for xtrabackup to work the following settings must be present in my.cnf
+ on all nodes:
+ [mysqld]
+ wsrep_sst_auth=root:<root password>
+ datadir=<path to data dir>
+ [client]
+ socket=<path to socket>
+ )
+
+wsrep_sst_receive_address=
+ Address (hostname:port) at which this node wants to receive state snapshot.
+ Defaults to mysqld bind address, and if that is not specified (0.0.0.0) -
+ to the first IP of eth0 + mysqld bind port.
+ NOTE: check that your firewall allows connections to this address from other
+ cluster nodes.
+
+wsrep_sst_auth=
+ Authentication information needed for state transfer. Depends on the state
+ transfer method. For mysqldump-based SST it is
+ <mysql_root_user>:<mysql_root_password>
+ and should be the same on all nodes - it is used to authenticate with both
+ state snapshot receiver and state snapshot donor.
+
+wsrep_sst_donor=
+ A name of the node which should serve as state snapshot donor. This allows
+ to control which node will serve state snapshot request. By default the
+ most suitable node is chosen by wsrep provider. This is the same as given in
+ wsrep_node_name.
+
+
+6. ONLINE SCHEMA UPGRADE
+
+ Schema upgrades mean any data definition statements (DDL statemnents) run
+ for the database. They change the database structure and are non-
+ transactional.
+
+ Release 22.3 brings a new method for performing schema upgrades. User can
+ now choose whether to use the traditional total order isolation or new
+ rolling schema upgrade method. The OSU method choice is done by global
+ parameter: 'wsrep_OSU_method'.
+
+6.1 Total Order Isolation (TOI)
+
+ With earlier releases, DDL processing happened always by Total Order
+ Isolation (TOI) method. With TOI, the DDL was scheduled to be processed in
+ same transaction seqeuncing 'slot' in each cluster node.
+ The processing is secured by locking the affected table from any other use.
+ With TOI method, the whole cluster has part of the database locked for the
+ duration of the DDL processing.
+
+6.2 Rolling Schema Upgrade (RSU)
+
+ Rolling schema upgrade is new DDL processing method, where DDL will be
+ processed locally for the node. The node is disconnected of the replication
+ for the duration of the DDL processing, so that there is only DDL statement
+ processing in the node and it does not block the rest of the cluster. When
+ the DDL processing is complete, the node applies delayed replication events
+ and synchronizes back with the cluster.
+ The DDL can then be executed cluster-wide by running the same DDL statement
+ for each node in turn. When this rolling schema upgrade proceeds, part of
+ the cluster will have old schema structure and part of the cluster will have
+ new schema structure.
+
+
+7. LIMITATIONS
+
+1) Currently replication works only with InnoDB storage engine. Any writes to
+ tables of other types, including system (mysql.*) tables are not replicated.
+ However, DDL statements are replicated in statement level, and changes
+ to mysql.* tables will get replicated that way.
+ So, you can safely issue: CREATE USER...,
+ but issuing: INSERT INTO mysql.user..., will not be replicated.
+
+2) DELETE operation is unsupported on tables without primary key. Also rows in
+ tables without primary key may appear in different order on different nodes.
+ As a result SELECT...LIMIT... may return slightly different sets.
+
+3) Unsupported queries:
+ * LOCK/UNLOCK TABLES cannot be supported in multi-master setups.
+ * lock functions (GET_LOCK(), RELEASE_LOCK()... )
+
+4) Query log cannot be directed to table. If you enable query logging,
+ you must forward the log to a file:
+ log_output = FILE
+ Use general_log and general_log_file to choose query logging and the
+ log file name
+
+5) Maximum allowed transaction size is defined by wsrep_max_ws_rows and
+ wsrep_max_ws_size. Anything bigger (e.g. huge LOAD DATA) will be rejected.
+
+6) Due to cluster level optimistic concurrency control, transaction issuing
+ COMMIT may still be aborted at that stage. There can be two transactions.
+ writing to same rows and committing in separate cluster nodes, and only one
+ of the them can successfully commit. The failing one will be aborted.
+ For cluster level aborts, MySQL/galera cluster gives back deadlock error.
+ code (Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)).
+
+7) XA transactions can not be supported due to possible rollback on commit.
+
diff --git a/README b/README
index 8cd1152003c..b48ff32f187 100644
--- a/README
+++ b/README
@@ -1,4 +1,57 @@
-This is a release of MariaDB.
+This is a release of MariaDB Galera Cluster.
+
+ * https://kb.askmonty.org/en/galera/
+ * https://kb.askmonty.org/en/what-is-mariadb-galera-cluster/
+
+MariaDB Galera Cluster is a synchronous multi-master cluster for MariaDB.
+
+Features:
+
+ * Synchronous replication
+ * Active-active multi-master topology
+ * Read and write to any cluster node
+ * Automatic membership control, failed nodes drop from the cluster
+ * Automatic node joining
+ * True parallel replication, on row level
+ * Direct client connections, native MySQL look & feel
+
+Benefits:
+
+The above features yield several benefits for a DBMS clustering solution,
+including:
+
+* No slave lag
+* No lost transactions
+* Both read and write scalability
+* Smaller client latencies
+* Technology
+
+MariaDB Galera Cluster uses the Galera library for the replication
+implementation. To interface with Galera replication, we have enhanced MariaDB
+to support the replication API definition in the wsrep API project.
+
+ * http://codership.com/products/galera_replication
+ * https://launchpad.net/wsrep
+
+The implementation of the replication API in MariaDB happens in the open source
+MySQL-wsrep project.
+
+ * http://www.codership.com/products/mysql-write-set-replication-project
+
+See Also:
+
+* About Galera Replication:
+ https://kb.askmonty.org/en/about-galera-replication/
+* Codership: Using Galera Cluster:
+ http://codership.com/content/using-galera-cluster
+* Galera Use Cases:
+ https://kb.askmonty.org/en/galera-use-cases/
+* Getting Started with MariaDB Galera Cluster:
+ https://kb.askmonty.org/en/getting-started-with-mariadb-galera-cluster/
+
+***************************************************************************
+
+About MariaDB
MariaDB is designed as a drop-in replacement of MySQL(R) with more
features, new storage engines, fewer bugs, and better performance.
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index cecf212ad92..0b81a131124 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -536,7 +536,12 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res,
int ret;
File fd;
char query_file_path[FN_REFLEN];
+#ifdef WITH_WSREP
+ /* Note: wsrep_on=ON implicitly enables binary logging. */
+ const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0, WSREP_ON=OFF;";
+#else
const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;";
+#endif /* WITH_WSREP */
DBUG_ENTER("run_query");
DBUG_PRINT("enter", ("query: %s", query));
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index e436492d58e..40130b13b3a 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -857,9 +857,15 @@ static int use_db(char *database)
DBUG_RETURN(0);
} /* use_db */
+/* Do not send commands to replication slaves. */
static int disable_binlog()
{
+#ifdef WITH_WSREP
+ /* Additionally turn off @@wsrep_on to disable implicit binary logging. */
+ const char *stmt= "SET SQL_LOG_BIN=0, WSREP_ON=OFF";
+#else
const char *stmt= "SET SQL_LOG_BIN=0";
+#endif /* WITH_WSREP */
return run_query(stmt, 0);
}
diff --git a/cmake/configure.pl b/cmake/configure.pl
index a71795a3bc8..9e4aafdc05e 100644
--- a/cmake/configure.pl
+++ b/cmake/configure.pl
@@ -216,6 +216,16 @@ foreach my $option (@ARGV)
$cmakeargs = $cmakeargs." -DMYSQL_DATADIR=".substr($option,14);
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/cpack_rpm.cmake b/cmake/cpack_rpm.cmake
index e5206d9690c..4764e7a873f 100644
--- a/cmake/cpack_rpm.cmake
+++ b/cmake/cpack_rpm.cmake
@@ -24,11 +24,8 @@ SET(CPACK_COMPONENT_COMMON_GROUP "common")
SET(CPACK_COMPONENT_CLIENTPLUGINS_GROUP "common")
SET(CPACK_COMPONENT_COMPAT_GROUP "compat")
SET(CPACK_COMPONENTS_ALL Server ManPagesServer IniFiles Server_Scripts
- SupportFiles Development ManPagesDevelopment
- ManPagesTest Readme ManPagesClient Test
- Common Client SharedLibraries ClientPlugins)
-
-SET(CPACK_RPM_PACKAGE_NAME "MariaDB")
+ SupportFiles Readme Test)
+SET(CPACK_RPM_PACKAGE_NAME "MariaDB-Galera")
IF(CMAKE_VERSION VERSION_LESS "3.6.0")
SET(CPACK_PACKAGE_FILE_NAME "${CPACK_RPM_PACKAGE_NAME}-${VERSION}-${RPM}-${CMAKE_SYSTEM_PROCESSOR}")
ELSE()
@@ -131,9 +128,15 @@ SETA(CPACK_RPM_server_PACKAGE_OBSOLETES
SETA(CPACK_RPM_server_PACKAGE_PROVIDES
"MariaDB"
"MySQL"
+ "MariaDB-server"
+ "mariadb-server"
"MySQL-server"
"msqlormysql"
"mysql-server")
+SETA(CPACK_RPM_server_PACKAGE_REQUIRES
+ "${CPACK_RPM_PACKAGE_REQUIRES}"
+ "MariaDB-client" "galera" "rsync" "lsof" "grep" "gawk" "iproute"
+ "coreutils" "findutils" "tar")
SETA(CPACK_RPM_shared_PACKAGE_OBSOLETES
"mysql-shared"
@@ -153,10 +156,8 @@ SETA(CPACK_RPM_test_PACKAGE_OBSOLETES
"MySQL-OurDelta-test")
SETA(CPACK_RPM_test_PACKAGE_PROVIDES
"MySQL-test")
-
-SETA(CPACK_RPM_server_PACKAGE_REQUIRES
- ${CPACK_RPM_PACKAGE_REQUIRES}
- "MariaDB-client")
+SET(CPACK_RPM_test_PACKAGE_CONFLICTS
+ "MariaDB-test")
SET(CPACK_RPM_server_PRE_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-prein.sh)
SET(CPACK_RPM_server_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-preun.sh)
diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake
index ff4ba593415..4305c8daf73 100644
--- a/cmake/install_macros.cmake
+++ b/cmake/install_macros.cmake
@@ -13,8 +13,33 @@
# 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(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 ${ARG_DESTINATION} COMPONENT Debuginfo)
+ ENDIF()
+ ENDFOREACH()
+ ENDIF()
+ENDMACRO()
FUNCTION (INSTALL_DEBUG_SYMBOLS)
IF(MSVC)
@@ -154,9 +179,9 @@ FUNCTION(INSTALL_DOCUMENTATION)
ENDIF()
IF(RPM)
- SET(destination "${destination}/MariaDB-${group}-${VERSION}")
+ SET(destination "${destination}/MariaDB-Galera-${group}-${VERSION}")
ELSEIF(DEB)
- SET(destination "${destination}/mariadb-${group}-${MAJOR_VERSION}.${MINOR_VERSION}")
+ SET(destination "${destination}/mariadb-galera-${group}-${MAJOR_VERSION}.${MINOR_VERSION}")
ENDIF()
INSTALL(FILES ${files} DESTINATION ${destination} COMPONENT ${ARG_COMPONENT})
@@ -271,6 +296,7 @@ FUNCTION(MYSQL_INSTALL_TARGETS)
INSTALL(TARGETS ${TARGETS} DESTINATION ${ARG_DESTINATION} ${COMP})
INSTALL_DEBUG_SYMBOLS(${TARGETS} ${COMP} INSTALL_LOCATION ${ARG_DESTINATION})
+ INSTALL_DSYM_DIRECTORIES("${TARGETS}")
ENDFUNCTION()
diff --git a/cmake/os/FreeBSD.cmake b/cmake/os/FreeBSD.cmake
index ffb89c81206..28c3a3aad98 100644
--- a/cmake/os/FreeBSD.cmake
+++ b/cmake/os/FreeBSD.cmake
@@ -33,3 +33,9 @@ IF(EXECINFO)
SET(LIBEXECINFO ${EXECINFO})
ENDIF()
+<<<<<<< TREE
+=======
+
+SET(HAVE_SYS_TIMEB_H CACHE INTERNAL "")
+
+>>>>>>> MERGE-SOURCE
diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake
index 2808a6f749f..b36978a4604 100644
--- a/cmake/os/WindowsCache.cmake
+++ b/cmake/os/WindowsCache.cmake
@@ -76,6 +76,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 48ca3a4814d..30f5199441f 100644
--- a/cmake/package_name.cmake
+++ b/cmake/package_name.cmake
@@ -127,7 +127,7 @@ IF(NOT VERSION)
ELSEIF(MYSQL_SERVER_SUFFIX)
SET(PRODUCT_TAG "${MYSQL_SERVER_SUFFIX}") # Already has a leading dash
ELSE()
- SET(PRODUCT_TAG)
+ SET(PRODUCT_TAG "-galera")
ENDIF()
IF("${VERSION}" MATCHES "-ndb-")
diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake
index f14edf0cd20..702f8190e89 100644
--- a/cmake/plugin.cmake
+++ b/cmake/plugin.cmake
@@ -200,9 +200,15 @@ MACRO(MYSQL_ADD_PLUGIN)
OUTPUT_NAME "${ARG_MODULE_OUTPUT_NAME}")
# Install dynamic library
IF(ARG_COMPONENT)
- IF(CPACK_COMPONENTS_ALL AND NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT}
- AND INSTALL_SYSCONF2DIR)
-
+ # CPACK_COMPONENTS_ALL contains a list of components for which the
+ # packages would be generated (defined with the initial list under
+ # cpack_rpm.cmake and cpack_deb.cmake). The following lines would
+ # append the current component to this list if it is already not present.
+ # We should avoid this for wsrep builds (WITH_WSREP) as with wsrep build
+ # only server package is required to be generated.
+ IF(CPACK_COMPONENTS_ALL AND
+ NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT} AND
+ NOT WITH_WSREP AND INSTALL_SYSCONF2DIR)
IF (ARG_STORAGE_ENGINE)
SET(ver " = %{version}-%{release}")
ENDIF()
diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake
new file mode 100644
index 00000000000..2ba32b469e0
--- /dev/null
+++ b/cmake/wsrep.cmake
@@ -0,0 +1,64 @@
+# Copyright (c) 2011, Codership Oy <info@codership.com>.
+# Copyright (c) 2013, Monty Program Ab.
+#
+# 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 "23")
+
+# MariaDB addition: Revision number of the last revision merged from
+# codership branch visible in @@visible_comment.
+# Branch : https://github.com/codership/mysql-wsrep/tree/5.6
+SET(WSREP_PATCH_REVNO "c3fc46e") # Should be updated on every merge.
+
+# MariaDB: Obtain patch revision number:
+# Update WSREP_PATCH_REVNO if WSREP_REV environment variable is set.
+IF (DEFINED ENV{WSREP_REV})
+ SET(WSREP_PATCH_REVNO $ENV{WSREP_REV})
+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}")
+
+IF(NOT WSREP_PATCH_REVNO)
+ MESSAGE(WARNING "Could not determine bzr revision number, WSREP_VERSION will "
+ "not contain the revision number.")
+ SET(WSREP_VERSION
+ "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}"
+ )
+ELSE()
+ SET(WSREP_VERSION
+ "${WSREP_API_VERSION}.${WSREP_PATCH_VERSION}.r${WSREP_PATCH_REVNO}"
+ )
+ENDIF()
+
+OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ON)
+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 CACHE INTERNAL "" FORCE)
+ENDIF()
+
+#
diff --git a/cmake/wsrep.cmake.moved b/cmake/wsrep.cmake.moved
new file mode 100644
index 00000000000..608b33b31a1
--- /dev/null
+++ b/cmake/wsrep.cmake.moved
@@ -0,0 +1,59 @@
+# 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 "7.5")
+
+# Obtain patch revision number
+SET(WSREP_PATCH_REVNO $ENV{WSREP_REV})
+IF(NOT WSREP_PATCH_REVNO)
+ EXECUTE_PROCESS(
+ COMMAND bzr revno
+ OUTPUT_VARIABLE WSREP_PATCH_REVNO
+ RESULT_VARIABLE RESULT
+ )
+STRING(REGEX REPLACE "(\r?\n)+$" "" WSREP_PATCH_REVNO "${WSREP_PATCH_REVNO}")
+#FILE(WRITE "wsrep_config" "Debug: WSREP_PATCH_REVNO result: ${RESULT}\n")
+ENDIF()
+IF(NOT WSREP_PATCH_REVNO)
+ SET(WSREP_PATCH_REVNO "XXXX")
+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}.r${WSREP_PATCH_REVNO}"
+)
+
+OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ON)
+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 CACHE INTERNAL "" FORCE)
+ENDIF()
+
+#
diff --git a/config.h.cmake b/config.h.cmake
index e039cf12fca..e4efdaaef12 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -164,6 +164,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 0d730d4942f..6c59beb64e6 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -314,6 +314,7 @@ ENDIF()
#
# Tests for functions
#
+CHECK_FUNCTION_EXISTS (accept4 HAVE_ACCEPT4)
CHECK_FUNCTION_EXISTS (access HAVE_ACCESS)
#CHECK_FUNCTION_EXISTS (aiowait HAVE_AIOWAIT)
CHECK_FUNCTION_EXISTS (aio_read HAVE_AIO_READ)
@@ -359,6 +360,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/debian/additions/my.cnf b/debian/additions/my.cnf
index a27f8543f0b..1f8bc0209eb 100644
--- a/debian/additions/my.cnf
+++ b/debian/additions/my.cnf
@@ -151,7 +151,21 @@ innodb_flush_method = O_DIRECT
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem
-
+#
+# * Galera-related settings
+#
+[galera]
+# Mandatory settings
+#wsrep_provider=
+#wsrep_cluster_address=
+#binlog_format=row
+#default_storage_engine=InnoDB
+#innodb_autoinc_lock_mode=2
+#bind-address=0.0.0.0
+#
+# Optional setting
+#wsrep_slave_threads=1
+#innodb_flush_log_at_trx_commit=0
[mysqldump]
quick
diff --git a/debian/control b/debian/control
index 79ccf8c8fd4..bb52fe0ec4d 100644
--- a/debian/control
+++ b/debian/control
@@ -27,254 +27,28 @@ Homepage: http://mariadb.org/
Vcs-Browser: https://github.com/MariaDB/server/
Vcs-Git: https://github.com/MariaDB/server.git
-Package: libmariadbclient18
-Section: libs
-Architecture: any
-Depends: libmysqlclient18 (= ${source:Version}),
- mariadb-common (>= ${source:Version}),
- ${misc:Depends},
- ${shlibs:Depends}
-Conflicts: mariadb-galera-server-10.0 (<< 10.0.5),
- mariadb-galera-server-5.5 (<< 5.5.33),
- mariadb-server-10.0 (<< 10.0.5),
- mariadb-server-5.1,
- mariadb-server-5.2,
- mariadb-server-5.3,
- mariadb-server-5.5 (<< 5.5.33)
-Description: MariaDB database client library
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes the client library.
-
-Package: libmysqlclient18
-Section: libs
-Architecture: any
-Depends: libmariadbclient18 (= ${source:Version})
-Replaces: libmysqlclient18 (<< ${source:Version})
-Description: Virtual package to satisfy external depends
- This is an empty package that provides an updated "best" version of
- libmysqlclient18 that does not conflict with the libmariadbclient18
- package.
- .
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
-
-Package: libmariadbd-dev
-Architecture: any
-Section: libdevel
-Depends: libmariadbclient-dev (>= ${source:Version}), ${misc:Depends}
-Provides: libmysqld-dev
-Conflicts: libmysqld-dev
-Replaces: libmysqld-dev
-Description: MariaDB embedded database development files
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes the embedded server library and header files.
-
-Package: libmariadbclient-dev
-Architecture: any
-Section: libdevel
-Depends: libmariadbclient18 (>= ${source:Version}),
- zlib1g-dev,
- ${misc:Depends},
- ${shlibs:Depends}
-Replaces: libmariadbclient16-dev, libmysqlclient16-dev
-Conflicts: libmariadbclient16-dev,
- libmysqlclient-dev,
- libmysqlclient10-dev,
- libmysqlclient12-dev,
- libmysqlclient14-dev,
- libmysqlclient15-dev,
- libmysqlclient16-dev
-Provides: libmysqlclient-dev
-Description: MariaDB database development files
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes development libraries and header files.
-
-Package: mysql-common
-Section: database
-Architecture: all
-Depends: ${misc:Depends}, ${shlibs:Depends}
-Description: MariaDB database common files (e.g. /etc/mysql/my.cnf)
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes files needed by all versions of the client library
- (e.g. /etc/mysql/my.cnf).
-
-Package: mariadb-common
-Section: database
-Architecture: all
-Depends: mysql-common (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends}
-Description: MariaDB database common files (e.g. /etc/mysql/conf.d/mariadb.cnf)
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes files needed by all versions of the client library
- (e.g. /etc/mysql/conf.d/mariadb.cnf).
-
-Package: mariadb-client-core-10.0
-Architecture: any
-Depends: libmariadbclient18 (>= ${source:Version}),
- mariadb-common (>= ${source:Version}),
- ${misc:Depends},
- ${shlibs:Depends}
-Provides: mysql-client-core,
- mysql-client-core-5.1,
- mysql-client-core-5.5,
- mysql-client-core-5.6
-Conflicts: mariadb-client-5.1,
- mariadb-client-5.2,
- mariadb-client-5.3,
- mariadb-client-5.5,
- mariadb-client-core-5.1,
- mariadb-client-core-5.2,
- mariadb-client-core-5.3,
- mariadb-client-core-5.5,
- mysql-client (<< 5.0.51),
- mysql-client-5.0,
- mysql-client-5.1 (<< ${source:Version}),
- mysql-client-5.5 (<< ${source:Version}),
- mysql-client-core-5.1,
- mysql-client-core-5.5,
- mysql-client-core-5.6
-Replaces: mariadb-client-5.1,
- mariadb-client-5.2,
- mariadb-client-5.3,
- mariadb-client-5.5,
- mariadb-client-core-5.1,
- mariadb-client-core-5.2,
- mariadb-client-core-5.3,
- mariadb-client-core-5.5,
- mysql-client (<< 5.0.51),
- mysql-client-5.0,
- mysql-client-5.1,
- mysql-client-5.5,
- mysql-client-core-5.1,
- mysql-client-core-5.5,
- mysql-client-core-5.6
-Description: MariaDB database core client binaries
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes the core client files, as used by Akonadi.
-
-Package: mariadb-client-10.0
-Architecture: any
-Depends: debianutils (>=1.6),
- libdbd-mysql-perl (>= 1.2202),
- libdbi-perl,
- libmariadbclient18 (>= ${source:Version}),
- mariadb-client-core-10.0 (>= ${source:Version}),
- mariadb-common (>= ${source:Version}),
- ${misc:Depends},
- ${perl:Depends},
- ${shlibs:Depends}
-Suggests: libterm-readkey-perl
-Provides: mysql-client,
- mysql-client-4.1,
- mysql-client-5.1,
- mysql-client-5.5,
- mysql-client-5.6,
- virtual-mysql-client
-Conflicts: mariadb-client (<< ${source:Version}),
- mariadb-client-5.1,
- mariadb-client-5.2,
- mariadb-client-5.3,
- mariadb-client-5.5,
- mysql-client (<< 5.0.51),
- mysql-client-5.0,
- mysql-client-5.1,
- mysql-client-5.5,
- mysql-client-5.6
-Replaces: mariadb-client (<< ${source:Version}),
- mariadb-client-5.1,
- mariadb-client-5.2,
- mariadb-client-5.3,
- mariadb-client-5.5,
- mysql-client (<< 5.0.51),
- mysql-client-5.0,
- mysql-client-5.1,
- mysql-client-5.5,
- mysql-client-5.6
-Description: MariaDB database client binaries
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes the client binaries and the additional tools
- innotop and mysqlreport.
-
-Package: mariadb-server-core-10.0
-Architecture: any
-Depends: libmariadbclient18 (>= ${binary:Version}),
- ${misc:Depends},
- ${shlibs:Depends}
-Provides: mysql-server-core,
- mysql-server-core-5.1,
- mysql-server-core-5.5,
- mysql-server-core-5.6
-Conflicts: mariadb-server-core-5.1,
- mariadb-server-core-5.2,
- mariadb-server-core-5.3,
- mariadb-server-core-5.5,
- mysql-server-5.0,
- mysql-server-core-5.0,
- mysql-server-core-5.1,
- mysql-server-core-5.5,
- mysql-server-core-5.6
-Replaces: mariadb-server-core-5.1,
- mariadb-server-core-5.2,
- mariadb-server-core-5.3,
- mariadb-server-core-5.5,
- mysql-server-5.0,
- mysql-server-core-5.0,
- mysql-server-core-5.1,
- mysql-server-core-5.5,
- mysql-server-core-5.6
-Description: MariaDB database core server files
- MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
- server. SQL (Structured Query Language) is the most popular database query
- language in the world. The main goals of MariaDB are speed, robustness and
- ease of use.
- .
- This package includes the core server files, as used by Akonadi.
-
-Package: mariadb-test-10.0
+Package: mariadb-galera-test-10.0
Section: database
Architecture: any
-Depends: mariadb-client-10.0 (= ${source:Version}),
- mariadb-server-10.0 (= ${source:Version})
+Depends: mariadb-galera-server-10.0 (= ${source:Version}),
+ mariadb-client-10.0 (>= ${source:Version})
Suggests: patch
-Conflicts: mariadb-galera-server-5.5 (<< 5.5.33),
- mariadb-server-5.5 (<< 5.5.33),
- mariadb-test (<< ${source:Version}),
+Conflicts: mariadb-test,
+ mariadb-galera-test (<< ${source:Version}),
mariadb-test-5.1,
mariadb-test-5.2,
- mariadb-test-5.3
+ mariadb-test-5.3,
+ mariadb-test-5.5,
+ mariadb-test-10.0,
+ mariadb-server-5.5,
+ mariadb-galera-server-5.5,
+ mariadb-server-10.0
Replaces: mariadb-test (<< ${source:Version}),
+ mariadb-galera-test (<< ${source:Version}),
mariadb-test-5.1,
mariadb-test-5.2,
- mariadb-test-5.3
+ mariadb-test-5.3,
+ mariadb-test-5.5
Description: MariaDB database regression test suite
MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
server. SQL (Structured Query Language) is the most popular database query
@@ -283,23 +57,40 @@ Description: MariaDB database regression test suite
.
This package includes the regression test suite.
-Package: mariadb-server-10.0
+Package: mariadb-galera-server-10.0
Architecture: any
-Suggests: mailx, mariadb-test, tinyca
+Suggests: mailx, mariadb-galera-test, tinyca, netcat-openbsd, socat
Recommends: libhtml-template-perl
-Pre-Depends: mariadb-common (>= ${source:Version}), adduser (>= 3.40), debconf
+Pre-Depends: mariadb-common, adduser (>= 3.40), debconf
Depends: bsdutils,
libdbi-perl,
lsb-base (>= 3.0-10),
mariadb-client-10.0 (>= ${source:Version}),
- mariadb-server-core-10.0 (>= ${binary:Version}),
passwd,
perl (>= 5.6),
psmisc,
${misc:Depends},
- ${shlibs:Depends}
-Provides: mariadb-server, mysql-server, virtual-mysql-server
-Conflicts: mariadb-server (<< ${source:Version}),
+ ${shlibs:Depends},
+ libmariadbclient18 (>= ${binary:Version}),
+ coreutils,
+ findutils,
+ galera-3 (>=25.3),
+ gawk,
+ grep,
+ iproute,
+ lsof,
+ rsync,
+ tar
+Provides: mariadb-server,
+ mariadb-galera-server,
+ mysql-server,
+ virtual-mysql-server,
+ mysql-server-core,
+ mysql-server-core-5.1,
+ mysql-server-core-5.5,
+ mysql-server-core-10.0
+Conflicts: mariadb-galera-server (<< ${source:Version}),
+ mariadb-server,
mariadb-server-5.1,
mariadb-server-5.2,
mariadb-server-5.3,
@@ -311,23 +102,40 @@ Conflicts: mariadb-server (<< ${source:Version}),
mysql-server-5.0,
mysql-server-5.1,
mysql-server-5.5,
- mysql-server-5.6
+ mysql-server-5.6,
+ mariadb-server-core-5.1,
+ mariadb-server-core-5.2,
+ mariadb-server-core-5.5,
+ mariadb-server-core-10.0,
+ mysql-server-core-5.0,
+ mysql-server-core-5.1,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6
Replaces: libmariadbclient-dev (<< 5.5.0),
libmariadbclient16 (<< 5.3.4),
- mariadb-server (<< ${source:Version}),
+ mariadb-galera-server (<< ${source:Version}),
+ mariadb-server,
mariadb-server-5.1,
mariadb-server-5.2,
mariadb-server-5.3,
mariadb-server-5.5,
mariadb-tokudb-engine-10.0,
mariadb-tokudb-engine-5.5,
- mysql-server (<< ${source:Version}),
+ mysql-server,
mysql-server-4.1,
mysql-server-5.0,
mysql-server-5.1,
mysql-server-5.5,
- mysql-server-5.6
-Description: MariaDB database server binaries
+ mysql-server-5.6,
+ mariadb-server-core-5.1,
+ mariadb-server-core-5.2,
+ mariadb-server-core-5.5,
+ mariadb-server-core-10.0,
+ mysql-server-core-5.0,
+ mysql-server-core-5.1,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6
+Description: MariaDB database server with Galera cluster binaries
MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
server. SQL (Structured Query Language) is the most popular database query
language in the world. The main goals of MariaDB are speed, robustness and
@@ -335,14 +143,14 @@ Description: MariaDB database server binaries
.
This package includes the server binaries.
-Package: mariadb-server
+Package: mariadb-galera-server
Section: database
Architecture: all
-Depends: mariadb-server-10.0 (= ${source:Version}), ${misc:Depends}
-Description: MariaDB database server (metapackage depending on the latest version)
+Depends: mariadb-galera-server-10.0 (= ${source:Version}), ${misc:Depends}
+Description: MariaDB database server with Galera cluster (metapackage depending on the latest version)
This is an empty package that depends on the current "best" version of
- mariadb-server (currently mariadb-server-10.0), as determined by the MariaDB
- maintainers. Install this package if in doubt about which MariaDB
+ mariadb-galera-server (currently mariadb-galera-server-10.0), as determined by the MariaDB
+ maintainers. Install this package if in doubt about which MariaDB-Galera
version you need. That will install the version recommended by the
package maintainers.
.
@@ -361,31 +169,11 @@ Description: MariaDB database client (metapackage depending on the latest versio
maintainers. Install this package if in doubt about which MariaDB version
you want, as this is the one we consider to be in the best shape.
-Package: mariadb-test
+Package: mariadb-galera-test
Section: database
Architecture: all
-Depends: mariadb-test-10.0 (= ${source:Version})
+Depends: mariadb-galera-test-10.0 (= ${source:Version})
Description: MariaDB database regression test suite (metapackage depending on the latest version)
This is an empty package that depends on the current "best" version of
- mariadb-test (currently mariadb-test-10.0), as determined by the MariaDB
- maintainers.
-
-Package: mariadb-connect-engine-10.0
-Section: database
-Architecture: any
-Depends: libxml2, mariadb-server-10.0|mariadb-galera-server-10.0, unixodbc
-Build-depends: libxml2-dev,
- mariadb-server-10.0|mariadb-galera-server-10.0,
- unixodbc-dev
-Description: Connect storage engine for MariaDB
- Connect engine supports a number of file formats (dbf, xml, txt, bin, etc),
- connections to ODBC tables and remote MySQL tables, as well as a number of
- other interesting features.
-
-Package: mariadb-oqgraph-engine-10.0
-Section: database
-Architecture: any
-Depends: libjudydebian1, mariadb-server-10.0|mariadb-galera-server-10.0
-Description: Oqgraph storage engine for MariaDB
- The OQGRAPH engine is a computation engine plugin for handling hierarchies
- (trees) and graphs (friend-of-a-friend, etc) cleanly through standard SQL.
+ mariadb-galera-test (currently mariadb-galera-test-10.0), as determined by the MariaDB
+ maintainers. \ No newline at end of file
diff --git a/debian/dist/Debian/mariadb-server-10.0.README.Debian b/debian/dist/Debian/mariadb-galera-server-10.0.README.Debian
index f398f2fa236..f398f2fa236 100644
--- a/debian/dist/Debian/mariadb-server-10.0.README.Debian
+++ b/debian/dist/Debian/mariadb-galera-server-10.0.README.Debian
diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.dirs b/debian/dist/Debian/mariadb-galera-server-10.0.dirs
index 320299b17ca..8260f7f17ee 100644
--- a/debian/dist/Ubuntu/mariadb-server-10.0.dirs
+++ b/debian/dist/Debian/mariadb-galera-server-10.0.dirs
@@ -5,6 +5,6 @@ usr/bin
usr/sbin
usr/share/man/man8
usr/share/mysql
-usr/share/doc/mariadb-server-10.0
+usr/share/doc/mariadb-galera-server-10.0
var/run/mysqld
var/lib/mysql-upgrade
diff --git a/debian/dist/Debian/mariadb-server-10.0.files.in b/debian/dist/Debian/mariadb-galera-server-10.0.files.in
index 9feec684ff0..433febd0f86 100644
--- a/debian/dist/Debian/mariadb-server-10.0.files.in
+++ b/debian/dist/Debian/mariadb-galera-server-10.0.files.in
@@ -1,3 +1,4 @@
+usr/sbin/mysqld
usr/lib/mysql/plugin/auth_pam.so
usr/lib/mysql/plugin/auth_socket.so
usr/lib/mysql/plugin/ha_mroonga.so
@@ -44,10 +45,16 @@ usr/bin/perror
usr/bin/replace
usr/bin/resolve_stack_dump
usr/bin/resolveip
-usr/share/doc/mariadb-server-10.0/mysqld.sym.gz
-usr/share/doc/mariadb-server-10.0/INFO_SRC
-usr/share/doc/mariadb-server-10.0/INFO_BIN
-usr/share/lintian/overrides/mariadb-server-10.0
+usr/bin/wsrep_sst_common
+usr/bin/wsrep_sst_mysqldump
+usr/bin/wsrep_sst_rsync
+usr/bin/wsrep_sst_xtrabackup
+usr/bin/wsrep_sst_xtrabackup-v2
+usr/share/doc/mariadb-galera-server-10.0/mysqld.sym.gz
+usr/share/doc/mariadb-galera-server-10.0/INFO_SRC
+usr/share/doc/mariadb-galera-server-10.0/INFO_BIN
+usr/share/doc/mariadb-galera-server-10.0/README-wsrep
+usr/share/lintian/overrides/mariadb-galera-server-10.0
usr/share/man/man1/msql2mysql.1
usr/share/man/man1/myisamchk.1
usr/share/man/man1/myisam_ftdump.1
@@ -70,6 +77,31 @@ usr/share/man/man1/resolveip.1
usr/share/man/man1/resolve_stack_dump.1
usr/share/man/man1/innochecksum.1
usr/share/man/man1/mysql_tzinfo_to_sql.1
+usr/share/man/man8/mysqld.8
+usr/share/mysql/charsets
+usr/share/mysql/czech
+usr/share/mysql/danish
+usr/share/mysql/dutch
+usr/share/mysql/english
+usr/share/mysql/estonian
+usr/share/mysql/french
+usr/share/mysql/german
+usr/share/mysql/greek
+usr/share/mysql/hungarian
+usr/share/mysql/italian
+usr/share/mysql/japanese
+usr/share/mysql/korean
+usr/share/mysql/norwegian
+usr/share/mysql/norwegian-ny
+usr/share/mysql/polish
+usr/share/mysql/portuguese
+usr/share/mysql/romanian
+usr/share/mysql/russian
+usr/share/mysql/serbian
+usr/share/mysql/slovak
+usr/share/mysql/spanish
+usr/share/mysql/swedish
+usr/share/mysql/ukrainian
usr/share/mysql/debian-start.inc.sh
usr/share/mysql/echo_stderr
usr/share/mysql/errmsg-utf8.txt
@@ -81,3 +113,5 @@ usr/share/mysql/mysql_test_data_timezone.sql
@CASSANDRA_DEB_FILES@
@SPIDER_DEB_FILES@
@TOKUDB_DEB_FILES@
+usr/share/mysql/wsrep.cnf
+usr/share/mysql/wsrep_notify
diff --git a/debian/dist/Debian/mariadb-server-10.0.postinst b/debian/dist/Debian/mariadb-galera-server-10.0.postinst
index 5179fd4944a..5179fd4944a 100644
--- a/debian/dist/Debian/mariadb-server-10.0.postinst
+++ b/debian/dist/Debian/mariadb-galera-server-10.0.postinst
diff --git a/debian/dist/Debian/mariadb-server-10.0.postrm b/debian/dist/Debian/mariadb-galera-server-10.0.postrm
index 469b1627aff..469b1627aff 100644
--- a/debian/dist/Debian/mariadb-server-10.0.postrm
+++ b/debian/dist/Debian/mariadb-galera-server-10.0.postrm
diff --git a/debian/dist/Debian/rules b/debian/dist/Debian/rules
index 8366d997979..e050fd7cc95 100755
--- a/debian/dist/Debian/rules
+++ b/debian/dist/Debian/rules
@@ -160,39 +160,37 @@ install: build
install -m 0755 debian/additions/innotop/innotop $(TMP)/usr/bin/
install -m 0644 debian/additions/innotop/innotop.1 $(TMP)/usr/share/man/man1/
- # mariadb-server
+ # mariadb-galera-server
install -m 0755 $(BUILDDIR)/scripts/mysqld_safe $(TMP)/usr/bin/mysqld_safe
- mkdir -p $(TMP)/usr/share/doc/mariadb-server-10.0/examples
+ mkdir -p $(TMP)/usr/share/doc/mariadb-galera-server-10.0/examples
# We have a sane my.cnf, cruft not needed (remove my-*.cnf and config-*.cnf)
- # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-server-10.0/examples/
+ # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-galera-server-10.0/examples/
rm -vf $(TMP)/usr/share/mysql/my-*.cnf \
$(TMP)/usr/share/mysql/config-*.cnf \
$(TMP)/usr/share/mysql/mi_test_all* \
$(TMP)/usr/share/mysql/mysql-log-rotate \
$(TMP)/usr/share/mysql/mysql.server \
$(TMP)/usr/share/mysql/binary-configure
- nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-server-10.0/mysqld.sym.gz
+ nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-galera-server-10.0/mysqld.sym.gz
install -m 0755 debian/additions/echo_stderr $(TMP)/usr/share/mysql/
install -m 0755 debian/additions/debian-start $(TMP)/etc/mysql/
install -m 0755 debian/additions/debian-start.inc.sh $(TMP)/usr/share/mysql/
- install -m 0644 $(builddir)/Docs/INFO_SRC $(TMP)/usr/share/doc/mariadb-server-10.0/INFO_SRC
- install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-server-10.0/INFO_BIN
+ install -m 0644 $(builddir)/Docs/INFO_SRC $(TMP)/usr/share/doc/mariadb-galera-server-10.0/INFO_SRC
+ install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-galera-server-10.0/INFO_BIN
# mariadb-test
mv $(TMP)/usr/mysql-test $(TMP)/usr/share/mysql
# lintian overrides
mkdir -p $(TMP)/usr/share/lintian/overrides/
- cp debian/mysql-common.lintian-overrides $(TMP)/usr/share/lintian/overrides/mysql-common
- cp debian/mariadb-server-10.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-server-10.0
- cp debian/mariadb-client-10.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-client-10.0
+ cp debian/mariadb-galera-server-10.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-galera-server-10.0
# For 5.0 -> 10.0 transition
d=$(TMP)/usr/share/mysql-common/internal-use-only/; \
mkdir -p $$d; \
- cp debian/mariadb-server-10.0.mysql.init $$d/_etc_init.d_mysql; \
- cp debian/mariadb-server-10.0.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \
+ cp debian/mariadb-galera-server-10.0.mysql.init $$d/_etc_init.d_mysql; \
+ cp debian/mariadb-galera-server-10.0.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \
cp debian/additions/debian-start $$d/_etc_mysql_debian-start;
autorm=debian/autorm-file; \
diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.README.Debian b/debian/dist/Ubuntu/mariadb-galera-server-10.0.README.Debian
index 741243f1ec3..741243f1ec3 100644
--- a/debian/dist/Ubuntu/mariadb-server-10.0.README.Debian
+++ b/debian/dist/Ubuntu/mariadb-galera-server-10.0.README.Debian
diff --git a/debian/dist/Debian/mariadb-server-10.0.dirs b/debian/dist/Ubuntu/mariadb-galera-server-10.0.dirs
index 320299b17ca..8260f7f17ee 100644
--- a/debian/dist/Debian/mariadb-server-10.0.dirs
+++ b/debian/dist/Ubuntu/mariadb-galera-server-10.0.dirs
@@ -5,6 +5,6 @@ usr/bin
usr/sbin
usr/share/man/man8
usr/share/mysql
-usr/share/doc/mariadb-server-10.0
+usr/share/doc/mariadb-galera-server-10.0
var/run/mysqld
var/lib/mysql-upgrade
diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.files.in b/debian/dist/Ubuntu/mariadb-galera-server-10.0.files.in
index a5e8bd6e717..7fa0dd05cfb 100644
--- a/debian/dist/Ubuntu/mariadb-server-10.0.files.in
+++ b/debian/dist/Ubuntu/mariadb-galera-server-10.0.files.in
@@ -1,3 +1,4 @@
+usr/sbin/mysqld
usr/lib/mysql/plugin/auth_pam.so
usr/lib/mysql/plugin/auth_socket.so
usr/lib/mysql/plugin/ha_mroonga.so
@@ -46,10 +47,16 @@ usr/bin/perror
usr/bin/replace
usr/bin/resolve_stack_dump
usr/bin/resolveip
-usr/share/doc/mariadb-server-10.0/mysqld.sym.gz
-usr/share/doc/mariadb-server-10.0/INFO_SRC
-usr/share/doc/mariadb-server-10.0/INFO_BIN
-usr/share/lintian/overrides/mariadb-server-10.0
+usr/bin/wsrep_sst_common
+usr/bin/wsrep_sst_mysqldump
+usr/bin/wsrep_sst_rsync
+usr/bin/wsrep_sst_xtrabackup
+usr/bin/wsrep_sst_xtrabackup-v2
+usr/share/doc/mariadb-galera-server-10.0/mysqld.sym.gz
+usr/share/doc/mariadb-galera-server-10.0/INFO_SRC
+usr/share/doc/mariadb-galera-server-10.0/INFO_BIN
+usr/share/doc/mariadb-galera-server-10.0/README-wsrep
+usr/share/lintian/overrides/mariadb-galera-server-10.0
usr/share/man/man1/msql2mysql.1
usr/share/man/man1/myisamchk.1
usr/share/man/man1/myisam_ftdump.1
@@ -72,6 +79,31 @@ usr/share/man/man1/resolveip.1
usr/share/man/man1/resolve_stack_dump.1
usr/share/man/man1/innochecksum.1
usr/share/man/man1/mysql_tzinfo_to_sql.1
+usr/share/man/man8/mysqld.8
+usr/share/mysql/charsets
+usr/share/mysql/czech
+usr/share/mysql/danish
+usr/share/mysql/dutch
+usr/share/mysql/english
+usr/share/mysql/estonian
+usr/share/mysql/french
+usr/share/mysql/german
+usr/share/mysql/greek
+usr/share/mysql/hungarian
+usr/share/mysql/italian
+usr/share/mysql/japanese
+usr/share/mysql/korean
+usr/share/mysql/norwegian
+usr/share/mysql/norwegian-ny
+usr/share/mysql/polish
+usr/share/mysql/portuguese
+usr/share/mysql/romanian
+usr/share/mysql/russian
+usr/share/mysql/serbian
+usr/share/mysql/slovak
+usr/share/mysql/spanish
+usr/share/mysql/swedish
+usr/share/mysql/ukrainian
usr/share/mysql/debian-start.inc.sh
usr/share/mysql/echo_stderr
usr/share/mysql/errmsg-utf8.txt
@@ -83,3 +115,5 @@ usr/share/mysql/mysql_test_data_timezone.sql
@CASSANDRA_DEB_FILES@
@SPIDER_DEB_FILES@
@TOKUDB_DEB_FILES@
+usr/share/mysql/wsrep.cnf
+usr/share/mysql/wsrep_notify
diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.postinst b/debian/dist/Ubuntu/mariadb-galera-server-10.0.postinst
index e90ef045e2c..e90ef045e2c 100644
--- a/debian/dist/Ubuntu/mariadb-server-10.0.postinst
+++ b/debian/dist/Ubuntu/mariadb-galera-server-10.0.postinst
diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.postrm b/debian/dist/Ubuntu/mariadb-galera-server-10.0.postrm
index 7cee5150ef9..7cee5150ef9 100644
--- a/debian/dist/Ubuntu/mariadb-server-10.0.postrm
+++ b/debian/dist/Ubuntu/mariadb-galera-server-10.0.postrm
diff --git a/debian/dist/Ubuntu/mariadb-server-10.0.py b/debian/dist/Ubuntu/mariadb-galera-server-10.0.py
index b0537b4bd6b..d5b94f6e951 100644
--- a/debian/dist/Ubuntu/mariadb-server-10.0.py
+++ b/debian/dist/Ubuntu/mariadb-galera-server-10.0.py
@@ -20,7 +20,7 @@ def _add_my_conf_files(report, filename):
continue
def add_info(report):
- attach_conffiles(report, 'mariadb-server-10.0', conffiles=None)
+ attach_conffiles(report, 'mariadb-galera-server-10.0', conffiles=None)
key = 'Logs' + path_to_key('/var/log/daemon.log')
report[key] = ""
for line in read_file('/var/log/daemon.log').split('\n'):
diff --git a/debian/dist/Ubuntu/rules b/debian/dist/Ubuntu/rules
index 6f34d2eac5c..76b9dc93fb6 100755
--- a/debian/dist/Ubuntu/rules
+++ b/debian/dist/Ubuntu/rules
@@ -160,45 +160,43 @@ install: build
install -m 0755 debian/additions/innotop/innotop $(TMP)/usr/bin/
install -m 0644 debian/additions/innotop/innotop.1 $(TMP)/usr/share/man/man1/
- # mariadb-server
+ # mariadb-galera-server
install -m 0755 $(BUILDDIR)/scripts/mysqld_safe $(TMP)/usr/bin/mysqld_safe
- mkdir -p $(TMP)/usr/share/doc/mariadb-server-10.0/examples
+ mkdir -p $(TMP)/usr/share/doc/mariadb-galera-server-10.0/examples
# We have a sane my.cnf, cruft not needed (remove my-*.cnf and config-*.cnf)
- # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-server-10.0/examples/
+ # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-galera-server-10.0/examples/
rm -vf $(TMP)/usr/share/mysql/my-*.cnf \
$(TMP)/usr/share/mysql/config-*.cnf \
$(TMP)/usr/share/mysql/mi_test_all* \
$(TMP)/usr/share/mysql/mysql-log-rotate \
$(TMP)/usr/share/mysql/mysql.server \
$(TMP)/usr/share/mysql/binary-configure
- nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-server-10.0/mysqld.sym.gz
+ nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-galera-server-10.0/mysqld.sym.gz
install -m 0755 debian/additions/echo_stderr $(TMP)/usr/share/mysql/
install -m 0755 debian/additions/debian-start $(TMP)/etc/mysql/
install -m 0755 debian/additions/debian-start.inc.sh $(TMP)/usr/share/mysql/
- install -m 0644 $(builddir)/Docs/INFO_SRC $(TMP)/usr/share/doc/mariadb-server-10.0/INFO_SRC
- install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-server-10.0/INFO_BIN
+ install -m 0644 $(builddir)/Docs/INFO_SRC $(TMP)/usr/share/doc/mariadb-galera-server-10.0/INFO_SRC
+ install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-galera-server-10.0/INFO_BIN
# mariadb-test
mv $(TMP)/usr/mysql-test $(TMP)/usr/share/mysql
# lintian overrides
mkdir -p $(TMP)/usr/share/lintian/overrides/
- cp debian/mysql-common.lintian-overrides $(TMP)/usr/share/lintian/overrides/mysql-common
- cp debian/mariadb-server-10.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-server-10.0
- cp debian/mariadb-client-10.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-client-10.0
+ cp debian/mariadb-galera-server-10.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-galera-server-10.0
# For 5.0 -> 10.0 transition
d=$(TMP)/usr/share/mysql-common/internal-use-only/; \
mkdir -p $$d; \
- cp debian/mariadb-server-10.0.mysql.init $$d/_etc_init.d_mysql; \
- cp debian/mariadb-server-10.0.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \
+ cp debian/mariadb-galera-server-10.0.mysql.init $$d/_etc_init.d_mysql; \
+ cp debian/mariadb-galera-server-10.0.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \
cp debian/additions/debian-start $$d/_etc_mysql_debian-start;
# install AppArmor profile
install -D -m 644 debian/apparmor-profile $(TMP)/etc/apparmor.d/usr.sbin.mysqld
# install Apport hook
- install -D -m 644 debian/mariadb-server-10.0.py $(TMP)/usr/share/apport/package-hooks/source_mariadb-10.0.py
+ install -D -m 644 debian/mariadb-galera-server-10.0.py $(TMP)/usr/share/apport/package-hooks/source_mariadb-10.0.py
autorm=debian/autorm-file; \
rm -f $$autorm; \
diff --git a/debian/libmariadbclient-dev.README.Maintainer b/debian/libmariadbclient-dev.README.Maintainer
deleted file mode 100644
index f24cdcd519d..00000000000
--- a/debian/libmariadbclient-dev.README.Maintainer
+++ /dev/null
@@ -1,4 +0,0 @@
-The examples directory includes files that might be needed by some
-developers:
-- header files not installed by default
-- the example file udf_example.c
diff --git a/debian/libmariadbclient-dev.dirs b/debian/libmariadbclient-dev.dirs
deleted file mode 100644
index f6ad2870431..00000000000
--- a/debian/libmariadbclient-dev.dirs
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/include/
-usr/lib/
diff --git a/debian/libmariadbclient-dev.examples b/debian/libmariadbclient-dev.examples
deleted file mode 100644
index f1649c311c4..00000000000
--- a/debian/libmariadbclient-dev.examples
+++ /dev/null
@@ -1 +0,0 @@
-sql/udf_example.c
diff --git a/debian/libmariadbclient-dev.files b/debian/libmariadbclient-dev.files
deleted file mode 100644
index 8f56a3065d5..00000000000
--- a/debian/libmariadbclient-dev.files
+++ /dev/null
@@ -1,7 +0,0 @@
-usr/bin/mysql_config
-usr/include/mysql
-usr/lib/libmysqlclient.a
-usr/lib/libmysqlclient_r.a
-usr/lib/libmysqlservices.a
-usr/share/aclocal/mysql.m4
-usr/share/man/man1/mysql_config.1
diff --git a/debian/libmariadbclient-dev.links b/debian/libmariadbclient-dev.links
deleted file mode 100644
index 0076791dcfa..00000000000
--- a/debian/libmariadbclient-dev.links
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/lib/libmysqlclient.so.18 usr/lib/libmysqlclient.so
-usr/lib/libmysqlclient_r.so.18 usr/lib/libmysqlclient_r.so
diff --git a/debian/libmariadbclient18.dirs b/debian/libmariadbclient18.dirs
deleted file mode 100644
index 2964de6141b..00000000000
--- a/debian/libmariadbclient18.dirs
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/
diff --git a/debian/libmariadbclient18.files b/debian/libmariadbclient18.files
deleted file mode 100644
index 75020ecbd16..00000000000
--- a/debian/libmariadbclient18.files
+++ /dev/null
@@ -1,3 +0,0 @@
-usr/lib/libmysqlclient*.so.*
-usr/lib/mysql/plugin/mysql_clear_password.so
-usr/lib/mysql/plugin/dialog.so
diff --git a/debian/libmariadbclient18.postinst b/debian/libmariadbclient18.postinst
deleted file mode 100644
index 29d3b86f978..00000000000
--- a/debian/libmariadbclient18.postinst
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash -e
-
-# dh_installdeb will replace this with shell code automatically
-# generated by other debhelper scripts.
-
-#DEBHELPER#
-
-exit 0
-
-# vim: ts=4
-
-
diff --git a/debian/libmariadbd-dev.files b/debian/libmariadbd-dev.files
deleted file mode 100644
index 26cb8d0a606..00000000000
--- a/debian/libmariadbd-dev.files
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/lib/mysql/*.a
-usr/lib/mysql/*.la
diff --git a/debian/mariadb-client-10.0.README.Debian b/debian/mariadb-client-10.0.README.Debian
deleted file mode 100644
index b245638f9c9..00000000000
--- a/debian/mariadb-client-10.0.README.Debian
+++ /dev/null
@@ -1,4 +0,0 @@
-FAQ:
-
-Q: My <tab> completition is gone, why?
-A: You have "no-auto-rehash" in the "[mysql]" section of /etc/mysql/my.cnf!
diff --git a/debian/mariadb-client-10.0.dirs b/debian/mariadb-client-10.0.dirs
deleted file mode 100644
index ceda5922c5d..00000000000
--- a/debian/mariadb-client-10.0.dirs
+++ /dev/null
@@ -1,3 +0,0 @@
-usr/bin/
-usr/share/man/man1/
-usr/share/perl5/
diff --git a/debian/mariadb-client-10.0.docs b/debian/mariadb-client-10.0.docs
deleted file mode 100644
index 21446855f51..00000000000
--- a/debian/mariadb-client-10.0.docs
+++ /dev/null
@@ -1,2 +0,0 @@
-debian/additions/innotop/changelog.innotop
-README
diff --git a/debian/mariadb-client-10.0.files b/debian/mariadb-client-10.0.files
deleted file mode 100644
index a8a009517e6..00000000000
--- a/debian/mariadb-client-10.0.files
+++ /dev/null
@@ -1,28 +0,0 @@
-usr/bin/innochecksum
-usr/bin/innotop
-usr/bin/mysqlaccess
-usr/bin/mysqladmin
-usr/bin/mysqlbug
-usr/bin/mysqldump
-usr/bin/mysqldumpslow
-usr/bin/mysql_find_rows
-usr/bin/mysql_fix_extensions
-usr/bin/mysqlimport
-usr/bin/mysqlreport
-usr/bin/mysqlshow
-usr/bin/mysqlslap
-usr/bin/mysql_waitpid
-usr/share/lintian/overrides/mariadb-client-10.0
-usr/share/man/man1/innotop.1
-usr/share/man/man1/mysqlaccess.1
-usr/share/man/man1/mysqladmin.1
-usr/share/man/man1/mysqlbug.1
-usr/share/man/man1/mysqldump.1
-usr/share/man/man1/mysqldumpslow.1
-usr/share/man/man1/mysql_find_rows.1
-usr/share/man/man1/mysql_fix_extensions.1
-usr/share/man/man1/mysqlimport.1
-usr/share/man/man1/mysqlreport.1
-usr/share/man/man1/mysqlshow.1
-usr/share/man/man1/mysqlslap.1
-usr/share/man/man1/mysql_waitpid.1
diff --git a/debian/mariadb-client-10.0.links b/debian/mariadb-client-10.0.links
deleted file mode 100644
index 0b86e87f2e9..00000000000
--- a/debian/mariadb-client-10.0.links
+++ /dev/null
@@ -1,6 +0,0 @@
-usr/bin/mysqlcheck usr/bin/mysqlrepair
-usr/bin/mysqlcheck usr/bin/mysqlanalyze
-usr/bin/mysqlcheck usr/bin/mysqloptimize
-usr/share/man/man1/mysqlcheck.1.gz usr/share/man/man1/mysqlrepair.1.gz
-usr/share/man/man1/mysqlcheck.1.gz usr/share/man/man1/mysqlanalyze.1.gz
-usr/share/man/man1/mysqlcheck.1.gz usr/share/man/man1/mysqloptimize.1.gz
diff --git a/debian/mariadb-client-10.0.lintian-overrides b/debian/mariadb-client-10.0.lintian-overrides
deleted file mode 100644
index d4dc1a70b1e..00000000000
--- a/debian/mariadb-client-10.0.lintian-overrides
+++ /dev/null
@@ -1,3 +0,0 @@
-mariadb-client-5.3: package-has-a-duplicate-relation
-mariadb-client-5.3: wrong-name-for-upstream-changelog usr/share/doc/mariadb-client-5.3/changelog.innotop.gz
-mariadb-client-5.3: pkg-not-in-package-test innotop
diff --git a/debian/mariadb-client-10.0.menu b/debian/mariadb-client-10.0.menu
deleted file mode 100644
index 1378555c423..00000000000
--- a/debian/mariadb-client-10.0.menu
+++ /dev/null
@@ -1,3 +0,0 @@
-# According to /usr/share/menu/ policy 1.4, not /usr/share/doc/debian-policy/
-?package(innotop):needs="text" section="Applications/Data Management"\
- title="innotop" command="/usr/bin/innotop"
diff --git a/debian/mariadb-client-core-10.0.files b/debian/mariadb-client-core-10.0.files
deleted file mode 100644
index a2781309439..00000000000
--- a/debian/mariadb-client-core-10.0.files
+++ /dev/null
@@ -1,4 +0,0 @@
-usr/bin/mysql
-usr/bin/mysqlcheck
-usr/share/man/man1/mysql.1
-usr/share/man/man1/mysqlcheck.1
diff --git a/debian/mariadb-common.files b/debian/mariadb-common.files
deleted file mode 100644
index f37e46c45fe..00000000000
--- a/debian/mariadb-common.files
+++ /dev/null
@@ -1 +0,0 @@
-etc/mysql/conf.d/mariadb.cnf
diff --git a/debian/mariadb-common.postrm b/debian/mariadb-common.postrm
deleted file mode 100644
index 027592f816e..00000000000
--- a/debian/mariadb-common.postrm
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash -e
-
-if [ "$1" = "purge" ]; then
- rmdir /etc/mysql/conf.d 2>/dev/null || true
- rmdir /etc/mysql 2>/dev/null || true
-fi
-
-#DEBHELPER#
diff --git a/debian/mariadb-connect-engine-10.0.files b/debian/mariadb-connect-engine-10.0.files
deleted file mode 100644
index 0b042607c36..00000000000
--- a/debian/mariadb-connect-engine-10.0.files
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/lib/mysql/plugin/ha_connect.so
-etc/mysql/conf.d/connect.cnf
diff --git a/debian/mariadb-server-10.0.NEWS b/debian/mariadb-galera-server-10.0.NEWS
index a3042dc2918..a3042dc2918 100644
--- a/debian/mariadb-server-10.0.NEWS
+++ b/debian/mariadb-galera-server-10.0.NEWS
diff --git a/debian/mariadb-server-10.0.config b/debian/mariadb-galera-server-10.0.config
index 162017caf71..162017caf71 100644
--- a/debian/mariadb-server-10.0.config
+++ b/debian/mariadb-galera-server-10.0.config
diff --git a/debian/mariadb-galera-server-10.0.lintian-overrides b/debian/mariadb-galera-server-10.0.lintian-overrides
new file mode 100644
index 00000000000..0b2eb6a6496
--- /dev/null
+++ b/debian/mariadb-galera-server-10.0.lintian-overrides
@@ -0,0 +1,5 @@
+mariadb-galera-server-10.0: command-with-path-in-maintainer-script postinst
+mariadb-galera-server-10.0: possible-bashism-in-maintainer-script postinst:81 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}'
+mariadb-galera-server-10.0: possible-bashism-in-maintainer-script preinst:33 '${cmd/ */}'
+mariadb-galera-server-10.0: statically-linked-binary ./usr/bin/mysql_tzinfo_to_sql
+mariadb-galera-server-10.0: statically-linked-binary ./usr/sbin/mysqld
diff --git a/debian/mariadb-server-10.0.logcheck.ignore.paranoid b/debian/mariadb-galera-server-10.0.logcheck.ignore.paranoid
index 00cc5c3e29d..00cc5c3e29d 100644
--- a/debian/mariadb-server-10.0.logcheck.ignore.paranoid
+++ b/debian/mariadb-galera-server-10.0.logcheck.ignore.paranoid
diff --git a/debian/mariadb-server-10.0.logcheck.ignore.server b/debian/mariadb-galera-server-10.0.logcheck.ignore.server
index 37f25cb01ea..37f25cb01ea 100644
--- a/debian/mariadb-server-10.0.logcheck.ignore.server
+++ b/debian/mariadb-galera-server-10.0.logcheck.ignore.server
diff --git a/debian/mariadb-server-10.0.logcheck.ignore.workstation b/debian/mariadb-galera-server-10.0.logcheck.ignore.workstation
index 37f25cb01ea..37f25cb01ea 100644
--- a/debian/mariadb-server-10.0.logcheck.ignore.workstation
+++ b/debian/mariadb-galera-server-10.0.logcheck.ignore.workstation
diff --git a/debian/mariadb-server-10.0.mysql-server.logrotate b/debian/mariadb-galera-server-10.0.mysql-server.logrotate
index dbe2a7e7dfe..dbe2a7e7dfe 100644
--- a/debian/mariadb-server-10.0.mysql-server.logrotate
+++ b/debian/mariadb-galera-server-10.0.mysql-server.logrotate
diff --git a/debian/mariadb-server-10.0.mysql.init b/debian/mariadb-galera-server-10.0.mysql.init
index 46911aa57a1..a59013f8047 100644
--- a/debian/mariadb-server-10.0.mysql.init
+++ b/debian/mariadb-galera-server-10.0.mysql.init
@@ -17,6 +17,9 @@ set -e
set -u
${DEBIAN_SCRIPT_DEBUG:+ set -v -x}
+# Prevent Debian's init scripts from calling systemctl
+_SYSTEMCTL_SKIP_REDIRECT=true
+
test -x /usr/sbin/mysqld || exit 0
. /lib/lsb/init-functions
@@ -179,8 +182,15 @@ case "${1:-''}" in
fi
;;
+ 'bootstrap')
+ # Bootstrap the cluster, start the first node
+ # that initiates the cluster
+ log_daemon_msg "Bootstrapping the cluster" "mysqld"
+ $SELF start "${@:2}" --wsrep-new-cluster
+ ;;
+
*)
- echo "Usage: $SELF start|stop|restart|reload|force-reload|status"
+ echo "Usage: $SELF start|stop|restart|reload|force-reload|status|bootstrap"
exit 1
;;
esac
diff --git a/debian/mariadb-server-10.0.preinst b/debian/mariadb-galera-server-10.0.preinst
index 7ad46c6ee52..7ad46c6ee52 100644
--- a/debian/mariadb-server-10.0.preinst
+++ b/debian/mariadb-galera-server-10.0.preinst
diff --git a/debian/mariadb-server-10.0.prerm b/debian/mariadb-galera-server-10.0.prerm
index 03e9ea37420..03e9ea37420 100644
--- a/debian/mariadb-server-10.0.prerm
+++ b/debian/mariadb-galera-server-10.0.prerm
diff --git a/debian/mariadb-server-10.0.templates b/debian/mariadb-galera-server-10.0.templates
index 13943da534a..13943da534a 100644
--- a/debian/mariadb-server-10.0.templates
+++ b/debian/mariadb-galera-server-10.0.templates
diff --git a/debian/mariadb-test-10.0.dirs b/debian/mariadb-galera-test-10.0.dirs
index 65dbbc81c2a..b40bd89463d 100644
--- a/debian/mariadb-test-10.0.dirs
+++ b/debian/mariadb-galera-test-10.0.dirs
@@ -84,6 +84,12 @@ usr/share/mysql/mysql-test/suite/oqgraph
usr/share/mysql/mysql-test/suite/oqgraph/t
usr/share/mysql/mysql-test/suite/oqgraph/r
usr/share/mysql/mysql-test/suite/oqgraph/include
+usr/share/mysql/mysql-test/suite/wsrep
+usr/share/mysql/mysql-test/suite/wsrep/t
+usr/share/mysql/mysql-test/suite/wsrep/r
+usr/share/mysql/mysql-test/suite/galera
+usr/share/mysql/mysql-test/suite/galera/t
+usr/share/mysql/mysql-test/suite/galera/r
usr/share/mysql/mysql-test/std_data
usr/share/mysql/mysql-test/std_data/ndb_backup50
usr/share/mysql/mysql-test/std_data/parts
diff --git a/debian/mariadb-test-10.0.files b/debian/mariadb-galera-test-10.0.files
index 767f040b45a..0d5fb2ba8dd 100644
--- a/debian/mariadb-test-10.0.files
+++ b/debian/mariadb-galera-test-10.0.files
@@ -11,11 +11,7 @@ usr/lib/mysql/plugin/daemon_example.ini
usr/lib/mysql/plugin/libdaemon_example.so
usr/lib/mysql/plugin/adt_null.so
usr/bin/mysql_client_test
-usr/bin/mysql_client_test_embedded
-usr/bin/mysqltest_embedded
usr/share/man/man1/mysql_client_test.1
-usr/share/man/man1/mysql_client_test_embedded.1
usr/bin/mysqltest
usr/share/man/man1/mysqltest.1
-usr/share/man/man1/mysqltest_embedded.1
usr/share/mysql/mysql-test
diff --git a/debian/mariadb-test-10.0.links b/debian/mariadb-galera-test-10.0.links
index 082680fe5ed..082680fe5ed 100644
--- a/debian/mariadb-test-10.0.links
+++ b/debian/mariadb-galera-test-10.0.links
diff --git a/debian/mariadb-oqgraph-engine-10.0.files b/debian/mariadb-oqgraph-engine-10.0.files
deleted file mode 100644
index f67b0cd9d13..00000000000
--- a/debian/mariadb-oqgraph-engine-10.0.files
+++ /dev/null
@@ -1 +0,0 @@
-usr/lib/mysql/plugin/ha_oqgraph.so
diff --git a/debian/mariadb-server-10.0.lintian-overrides b/debian/mariadb-server-10.0.lintian-overrides
deleted file mode 100644
index ea67ed9de2b..00000000000
--- a/debian/mariadb-server-10.0.lintian-overrides
+++ /dev/null
@@ -1,5 +0,0 @@
-mariadb-server-10.0: command-with-path-in-maintainer-script postinst
-mariadb-server-10.0: possible-bashism-in-maintainer-script postinst:81 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}'
-mariadb-server-10.0: possible-bashism-in-maintainer-script preinst:33 '${cmd/ */}'
-mariadb-server-10.0: statically-linked-binary ./usr/bin/mysql_tzinfo_to_sql
-mariadb-server-10.0: statically-linked-binary ./usr/sbin/mysqld
diff --git a/debian/mariadb-server-core-10.0.files b/debian/mariadb-server-core-10.0.files
deleted file mode 100644
index 5c60ca5ec67..00000000000
--- a/debian/mariadb-server-core-10.0.files
+++ /dev/null
@@ -1,26 +0,0 @@
-usr/sbin/mysqld
-usr/share/man/man8/mysqld.8
-usr/share/mysql/charsets
-usr/share/mysql/czech
-usr/share/mysql/danish
-usr/share/mysql/dutch
-usr/share/mysql/english
-usr/share/mysql/estonian
-usr/share/mysql/french
-usr/share/mysql/german
-usr/share/mysql/greek
-usr/share/mysql/hungarian
-usr/share/mysql/italian
-usr/share/mysql/japanese
-usr/share/mysql/korean
-usr/share/mysql/norwegian
-usr/share/mysql/norwegian-ny
-usr/share/mysql/polish
-usr/share/mysql/portuguese
-usr/share/mysql/romanian
-usr/share/mysql/russian
-usr/share/mysql/serbian
-usr/share/mysql/slovak
-usr/share/mysql/spanish
-usr/share/mysql/swedish
-usr/share/mysql/ukrainian
diff --git a/debian/mysql-common.dirs b/debian/mysql-common.dirs
deleted file mode 100644
index a5a88ede9c1..00000000000
--- a/debian/mysql-common.dirs
+++ /dev/null
@@ -1 +0,0 @@
-etc/mysql/conf.d/
diff --git a/debian/mysql-common.files b/debian/mysql-common.files
deleted file mode 100644
index d167569e892..00000000000
--- a/debian/mysql-common.files
+++ /dev/null
@@ -1,3 +0,0 @@
-etc/mysql/my.cnf
-usr/share/mysql-common/internal-use-only
-usr/share/lintian/overrides/mysql-common
diff --git a/debian/mysql-common.lintian-overrides b/debian/mysql-common.lintian-overrides
deleted file mode 100644
index c6c60ccdc71..00000000000
--- a/debian/mysql-common.lintian-overrides
+++ /dev/null
@@ -1,2 +0,0 @@
-script-not-executable ./usr/share/mysql-common/internal-use-only/_etc_init.d_mysql
-script-not-executable ./usr/share/mysql-common/internal-use-only/_etc_mysql_debian-start
diff --git a/debian/mysql-common.postrm b/debian/mysql-common.postrm
deleted file mode 100644
index 0d3f8aed83d..00000000000
--- a/debian/mysql-common.postrm
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash -e
-
-if [ "$1" = "purge" ]; then
- rmdir /etc/mysql 2>/dev/null || true
-fi
-
-#DEBHELPER#
diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in
index 40b6d906195..804bf154b9b 100644
--- a/debian/po/POTFILES.in
+++ b/debian/po/POTFILES.in
@@ -1 +1 @@
-[type: gettext/rfc822deb] mariadb-server-10.0.templates
+[type: gettext/rfc822deb] mariadb-galera-server-10.0.templates
diff --git a/debian/po/ar.po b/debian/po/ar.po
index 1507fcc92ab..aeb18dcc9fd 100644
--- a/debian/po/ar.po
+++ b/debian/po/ar.po
@@ -27,19 +27,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "هل Ùعلاً تريد التثبيط؟"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "هناك مل٠مسمى /var/lib/mysql/debian-*.flag موجود على هذا النظام."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -52,7 +52,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -62,13 +62,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "ملاحظة هامة لمستخدمي NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -76,7 +76,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -88,13 +88,13 @@ msgstr "عليك أيضاً أن تقوم بالتأكد من صلاحيات Ù…Ø
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "إزالة جميع قواعد بيانات MariaDB؟"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -102,7 +102,7 @@ msgstr "الدليل /var/lib/mysql الذي يحتوي قواعد بيانات
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -113,13 +113,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "تشغيل خادم MariaDB عند الإقلاع؟"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -129,13 +129,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص بـMariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -145,7 +145,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -153,7 +153,7 @@ msgstr "إن ترك الحقل Ùارغاً، Ùلن يتم تغيير كلمة
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MariaDB \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -161,13 +161,13 @@ msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص ب
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "تعذر تعيين كلمة مرور للمستخدم \"root\" الخاص بـMariaDB."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -179,7 +179,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "You should check the account's password after tha package installation."
@@ -188,7 +188,7 @@ msgstr "يجب عليك التحقق من كلمة مرور الحساب عقب
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -202,25 +202,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/ca.po b/debian/po/ca.po
index 7ca3129f3c5..8814257569f 100644
--- a/debian/po/ca.po
+++ b/debian/po/ca.po
@@ -17,19 +17,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -37,7 +37,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -45,7 +45,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid "Important note for NIS/YP users!"
msgid "Important note for NIS/YP users"
@@ -53,7 +53,7 @@ msgstr "Nota important pels usuaris de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -61,7 +61,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -69,13 +69,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -83,7 +83,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -92,7 +92,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid "Should MySQL start on boot?"
msgid "Start the MariaDB server on boot?"
@@ -100,7 +100,7 @@ msgstr "Voleu que el MariaDB s'iniciï a l'arrencada ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
@@ -112,13 +112,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -126,25 +126,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -153,13 +153,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -167,25 +167,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/cs.po b/debian/po/cs.po
index 453bf5fb7fa..c1ce4ccc17e 100644
--- a/debian/po/cs.po
+++ b/debian/po/cs.po
@@ -26,19 +26,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Opravdu pokraÄovat v degradaci?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "V systému existuje soubor /var/lib/mysql/debian-*.flag."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -51,7 +51,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -61,13 +61,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Důležitá poznámka pro uživatele NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -75,7 +75,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -88,13 +88,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Odstranit všechny MariaDB databáze?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -104,7 +104,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -116,13 +116,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Spustit MariaDB server při startu systému?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -132,13 +132,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nové heslo MariaDB uživatele \"root\":"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -148,7 +148,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -156,7 +156,7 @@ msgstr "Ponecháte-li pole prázdné, heslo se nezmění."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -164,13 +164,13 @@ msgstr "Nové heslo MariaDB uživatele \"root\":"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Nelze nastavit heslo MariaDB uživatele \"root\""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -182,7 +182,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "You should check the account's password after tha package installation."
@@ -191,7 +191,7 @@ msgstr "Po instalaci balíku byste měli heslo ověřit."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -204,25 +204,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/da.po b/debian/po/da.po
index e6836118840..bcc50345cd3 100644
--- a/debian/po/da.po
+++ b/debian/po/da.po
@@ -27,20 +27,20 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Ønsker du virkelig at fortsætte nedgraderingen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
"Der er en fil med navnet /var/lib/mysql/debian-*.flag på dette system."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -54,7 +54,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -64,13 +64,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Vigtig oplysning til NIS/YP-brugere"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -78,7 +78,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -91,13 +91,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Fjern alle MariaDB-databaser?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -107,7 +107,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -119,13 +119,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Start MariaDB-serveren under systemopstart?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -135,13 +135,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Ny adgangskode for MariaDB's \"root\"-bruger:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -151,7 +151,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -159,7 +159,7 @@ msgstr "Hvis du lader dette felt stå tomt, vil adgangskoden ikke blive ændret."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -167,13 +167,13 @@ msgstr "Ny adgangskode for MariaDB's \"root\"-bruger:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Kunne ikke sætte adgangskoden for MariaDB's \"root\"-bruger"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -186,13 +186,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr "Du bør tjekke kontoens adgangskode efter pakkeinstallationen."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -206,25 +206,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/de.po b/debian/po/de.po
index 3a36bf7221f..f8d4dc7a895 100644
--- a/debian/po/de.po
+++ b/debian/po/de.po
@@ -29,13 +29,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Möchten Sie wirklich eine ältere Version einspielen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
"Auf diesem System existiert eine Datei mit dem Namen /var/lib/mysql/debian-*."
@@ -43,7 +43,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -53,7 +53,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -63,13 +63,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Wichtige Anmerkung für NIS/YP-Benutzer!"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -79,7 +79,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -89,13 +89,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Alle MariaDB-Datenbanken entfernen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -105,7 +105,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -117,13 +117,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Soll der MariaDB-Server automatisch beim Booten starten?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -133,13 +133,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Neues Passwort für den MariaDB »root«-Benutzer:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -149,25 +149,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "Wenn dieses Feld freigelassen wird, wird das Passwort nicht geändert."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Wiederholen Sie das Passwort für den MariaDB-»root«-Benutzer:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Konnte für den MariaDB-»root«-Benutzer kein Passwort setzen"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -180,7 +180,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"Sie sollten das Passwort des administrativen Benutzers nach der "
@@ -188,7 +188,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.1/README.Debian file for "
@@ -202,13 +202,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "Passwort-Eingabefehler"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
"Die beiden von Ihnen eingegebenen Passwörter sind nicht identisch. Bitte "
@@ -216,13 +216,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB-Cluster scheint gerade benutzt zu werden"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/es.po b/debian/po/es.po
index f4e729b5f90..e88bcf1aa87 100644
--- a/debian/po/es.po
+++ b/debian/po/es.po
@@ -52,20 +52,20 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "¿Desea realmente continuar con la desactualización?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
"Existe un archivo con el nombre /var/lib/mysql/debian-*.flag en este sistema."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -79,7 +79,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -89,13 +89,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante para los usuarios de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -103,7 +103,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -117,13 +117,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "¿Desea eliminar todas las bases de datos MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -133,7 +133,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -145,13 +145,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "¿Debería ejecutarse el servidor MariaDB al iniciarse el sistema?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -161,13 +161,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nueva contraseña para el usuario «root» de MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -177,7 +177,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -185,7 +185,7 @@ msgstr "No se modificará la contraseña si deja el espacio en blanco."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -193,13 +193,13 @@ msgstr "Nueva contraseña para el usuario «root» de MariaDB:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "No se pudo fijar la contraseña para el usuario «root» de MariaDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -212,7 +212,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"Debería comprobar la contraseña de la cuenta después de la instalación del "
@@ -220,7 +220,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -234,25 +234,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/eu.po b/debian/po/eu.po
index e5643f1ce65..a62bf4c3d5c 100644
--- a/debian/po/eu.po
+++ b/debian/po/eu.po
@@ -20,19 +20,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Benetan bertsio zaharragora itzuli nahi duzu?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "Sisteman badago /var/lib/mysql/debian-*.flag izeneko fitxategi bat."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -46,7 +46,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -56,13 +56,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "NIS/YP erabiltzaileentzat ohar garrantzitsua"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -70,7 +70,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -84,13 +84,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Ezabatu MariaDB datubase guztiak?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -99,7 +99,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -111,13 +111,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Abioan MariaDB zerbitzaria abiarazi?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -127,13 +127,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "MariaDB \"root\" erabiltzailearen pasahitz berria:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -143,7 +143,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -151,19 +151,19 @@ msgstr "Eremua hau zurian utziaz gero ez da pasahitza aldatuko."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Errepikatu MariaDB \"root\" erabiltzailearen pasahitza:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Ezin da MariaDB \"root\" erabiltzailearen pasahitza ezarri"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -175,14 +175,14 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"Kontuaren pasahitza egiaztatu beharko zenuke paketea instalatu aurretik."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
@@ -196,25 +196,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "Pasahitz sarrera errorea"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "Idatzi dituzun bi pasahitzak ez dira berdina. Mesedez saiatu berriz."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "Dirudienez NDB Cluster-a erabilia dago"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
#, fuzzy
#| msgid ""
#| "MySQL-5.1 has orphaned NDB Cluster support. Please migrate to the new "
diff --git a/debian/po/fr.po b/debian/po/fr.po
index da74e64a193..f2f87a915dd 100644
--- a/debian/po/fr.po
+++ b/debian/po/fr.po
@@ -22,19 +22,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Faut-il vraiment revenir à la version précédente ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "Un fichier /var/lib/mysql/debian-*.flag est présent sur ce système."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -44,7 +44,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -52,13 +52,13 @@ msgstr "Il n'est pas garanti que cette version puisse en utiliser les données."
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Note importante pour les utilisateurs NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -68,7 +68,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -78,13 +78,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Faut-il supprimer toutes les bases de données MariaDB ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -94,7 +94,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -105,13 +105,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Faut-il lancer MariaDB au démarrage ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -121,13 +121,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nouveau mot de passe du superutilisateur de MariaDB :"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -137,26 +137,26 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "Si ce champ est laissé vide, le mot de passe ne sera pas changé."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Confirmation du mot de passe du superutilisateur de MariaDB :"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
"Impossible de changer le mot de passe de l'utilisateur « root » de MariaDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -168,7 +168,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"Vous devriez vérifier le mot de passe de ce compte après l'installation du "
@@ -176,7 +176,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
@@ -190,13 +190,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "Erreur de saisie du mot de passe"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
"Le mot de passe et sa confirmation ne sont pas identiques. Veuillez "
@@ -204,13 +204,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "Abandon de la gestion de NDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/gl.po b/debian/po/gl.po
index 30e58547e78..c3d399a3642 100644
--- a/debian/po/gl.po
+++ b/debian/po/gl.po
@@ -17,19 +17,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "¿Quere pasar a unha versión anterior?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "Neste sistema hai un ficheiro chamado /var/lib/mysql/debian-*.flag."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -43,7 +43,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -53,13 +53,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante para os usuarios de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -67,7 +67,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -81,13 +81,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "¿Eliminar tódalas bases de datos de MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -97,7 +97,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -109,13 +109,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "¿Iniciar o servidor MariaDB co ordenador?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -125,13 +125,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Novo contrasinal para o usuario \"root\" de MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -141,7 +141,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -149,7 +149,7 @@ msgstr "Se deixa o campo en branco, non se ha cambiar o contrasinal."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -157,13 +157,13 @@ msgstr "Novo contrasinal para o usuario \"root\" de MariaDB:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Non se puido establecer o contrasinal do usuario \"root\" de MariaDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -175,7 +175,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "You should check the account's password after tha package installation."
@@ -184,7 +184,7 @@ msgstr "Debería comprobar o contrasinal da conta trala instalación do paquete.
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -198,25 +198,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/it.po b/debian/po/it.po
index bd39afe5398..0feaa77a45f 100644
--- a/debian/po/it.po
+++ b/debian/po/it.po
@@ -2,7 +2,7 @@
# Copyright (C) 2009 Software in the Public Interest
# This file is distributed under the same license as the mysql-dfsg-5.1 package.
# Luca Monducci <luca.mo@tiscali.it>, 2006 - 2009.
-#
+#
msgid ""
msgstr ""
"Project-Id-Version: mysql-dfsg-5.1 5.1.37 italian debconf templates\n"
@@ -18,20 +18,20 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Procedere realmente con l'abbassamento di versione?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
"Su questo sistema esiste un file con nome /var/lib/mysql/debian-*.flag."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -41,7 +41,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -51,13 +51,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante per gli utenti NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -67,7 +67,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -77,13 +77,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Eliminare tutti i database MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -93,7 +93,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -105,13 +105,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Lanciare il server MariaDB all'avvio?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -121,13 +121,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nuova password per l'utente «root» di MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -137,25 +137,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "Se questo campo è lasciato vuoto, la password non viene cambiata."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Ripetere la password per l'utente «root» di MariaDB:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Impossibile impostare la password per l'utente «root» di MariaDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -168,18 +168,15 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"Al termine dell'installazione si deve verificare la password dell'account."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
-#| msgid ""
-#| "Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
-#| "more information."
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -189,25 +186,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "Errore di inserimento della password"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "Le due password inserite sono diverse. Riprovare."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "È in uso un cluster NDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/ja.po b/debian/po/ja.po
index 4cc190425f4..692c2e3686c 100644
--- a/debian/po/ja.po
+++ b/debian/po/ja.po
@@ -27,13 +27,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "本当ã«ãƒ€ã‚¦ãƒ³ã‚°ãƒ¬ãƒ¼ãƒ‰ã‚’実行ã—ã¾ã™ã‹?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
"ã“ã®ã‚·ã‚¹ãƒ†ãƒ ã«ã¯ /var/lib/mysql/debian-*.flag ã¨ã„ã†åå‰ã®ãƒ•ã‚¡ã‚¤ãƒ«ãŒå­˜åœ¨ã—ã¦"
@@ -41,7 +41,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -51,7 +51,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -61,13 +61,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "NIS/YP ユーザã¸ã®é‡è¦ãªæ³¨æ„"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -77,7 +77,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -85,13 +85,13 @@ msgstr "/var/lib/mysql ã®æ‰€æœ‰è€…権é™ã‚’ãƒã‚§ãƒƒã‚¯ã™ã‚‹å¿…è¦ã‚‚ã‚ã‚Šã¾
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "ã™ã¹ã¦ã® MariaDB データベースを削除ã—ã¾ã™ã‹?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -101,7 +101,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -113,13 +113,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "MariaDB をシステム起動時ã«é–‹å§‹ã—ã¾ã™ã‹?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -129,13 +129,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "MariaDB ã® \"root\" ユーザã«å¯¾ã™ã‚‹æ–°ã—ã„パスワード:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -145,25 +145,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "ã“ã®å€¤ã‚’空ã®ã¾ã¾ã«ã—ã¦ãŠã„ãŸå ´åˆã¯ã€ãƒ‘スワードã¯å¤‰æ›´ã•ã‚Œã¾ã›ã‚“。"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "MariaDB ã® \"root\" ユーザã«å¯¾ã™ã‚‹æ–°ã—ã„パスワード:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "MariaDB ã® \"root\" ユーザã®ãƒ‘スワードを設定ã§ãã¾ã›ã‚“"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -175,14 +175,14 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"パッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«å¾Œã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ãƒ‘スワードを確èªã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
@@ -195,25 +195,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "パスワード入力エラー"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "入力ã•ã‚ŒãŸäºŒã¤ã®ãƒ‘スワードãŒä¸€è‡´ã—ã¾ã›ã‚“。å†å…¥åŠ›ã—ã¦ãã ã•ã„。"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB クラスタãŒåˆ©ç”¨ã•ã‚Œã¦ã„るよã†ã§ã™"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/nb.po b/debian/po/nb.po
index ed02ca1d48e..e8509bea43b 100644
--- a/debian/po/nb.po
+++ b/debian/po/nb.po
@@ -19,7 +19,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid "Do you really want to downgrade?"
msgid "Really proceed with downgrade?"
@@ -27,13 +27,13 @@ msgstr "Er du sikker på at du vil nedgradere?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates "
@@ -50,7 +50,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -58,7 +58,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid "Important note for NIS/YP users!"
msgid "Important note for NIS/YP users"
@@ -66,7 +66,7 @@ msgstr "Viktig merknad for NIS/YP-brukere!"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -74,7 +74,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -82,13 +82,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -96,7 +96,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
#, fuzzy
#| msgid ""
#| "The script is about to remove the data directory /var/lib/mysql. If it is "
@@ -113,7 +113,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid "Should MySQL start on boot?"
msgid "Start the MariaDB server on boot?"
@@ -121,7 +121,7 @@ msgstr "Skal MariaDB startes ved maskinoppstart?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid ""
#| "The MySQL can start automatically on boot time or only if you manually "
@@ -135,7 +135,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "New password for MySQL \"root\" user:"
msgid "New password for the MariaDB \"root\" user:"
@@ -143,7 +143,7 @@ msgstr "Nytt passord for MariaDBs «root»-bruker:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid ""
#| "It is highly recommended that you set a password for the MySQL "
@@ -157,13 +157,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -171,7 +171,7 @@ msgstr "Nytt passord for MariaDBs «root»-bruker:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid "Unable to set password for MySQL \"root\" user"
msgid "Unable to set password for the MariaDB \"root\" user"
@@ -179,7 +179,7 @@ msgstr "Klarer ikke angi passord for MariaDBs «root»-bruker"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "It seems an error occurred while setting the password for the MySQL "
@@ -198,13 +198,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -212,25 +212,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/nl.po b/debian/po/nl.po
index a3694f6eea0..accf69555ef 100644
--- a/debian/po/nl.po
+++ b/debian/po/nl.po
@@ -18,7 +18,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid "Do you really want to downgrade?"
msgid "Really proceed with downgrade?"
@@ -26,13 +26,13 @@ msgstr "Wilt u echt een oude versie herstellen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates "
@@ -50,7 +50,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -58,7 +58,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid "Important note for NIS/YP users!"
msgid "Important note for NIS/YP users"
@@ -66,7 +66,7 @@ msgstr "Belangrijke opmerking voor gebruikers van NIS/YP!"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -74,7 +74,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -82,13 +82,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -96,7 +96,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
#, fuzzy
#| msgid ""
#| "The script is about to remove the data directory /var/lib/mysql. If it is "
@@ -114,7 +114,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid "Should MySQL start on boot?"
msgid "Start the MariaDB server on boot?"
@@ -122,7 +122,7 @@ msgstr "Moet MariaDB starten als de computer start?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid ""
#| "The MySQL can start automatically on boot time or only if you manually "
@@ -136,7 +136,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "New password for MySQL \"root\" user:"
msgid "New password for the MariaDB \"root\" user:"
@@ -144,7 +144,7 @@ msgstr "Nieuw wachtwoord voor de MariaDB \"root\"-gebruiker:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid ""
#| "It is highly recommended that you set a password for the MySQL "
@@ -158,13 +158,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -172,7 +172,7 @@ msgstr "Nieuw wachtwoord voor de MariaDB \"root\"-gebruiker:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid "Unable to set password for MySQL \"root\" user"
msgid "Unable to set password for the MariaDB \"root\" user"
@@ -180,7 +180,7 @@ msgstr "Kan het wachtwoord voor de MariaDB \"root\"-gebruiker niet instellen"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "It seems an error occurred while setting the password for the MySQL "
@@ -199,13 +199,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -213,25 +213,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/pt.po b/debian/po/pt.po
index 4f2e646dcc7..7be7dde415b 100644
--- a/debian/po/pt.po
+++ b/debian/po/pt.po
@@ -18,19 +18,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Deseja mesmo fazer downgrade?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "Existe um ficheiro chamado /var/lib/mysql/debian-*.flag neste sistema."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -44,7 +44,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -54,13 +54,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante para utilizadores de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -68,7 +68,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -81,13 +81,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Remover todas as bases de dados MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -97,7 +97,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -109,13 +109,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Iniciar o servidor MariaDB no arranque?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -125,13 +125,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nova palavra-passe para o utilizador \"root\" do MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -141,7 +141,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -150,7 +150,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -158,7 +158,7 @@ msgstr "Nova palavra-passe para o utilizador \"root\" do MariaDB:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
"Não foi possível definir a palavra-passe para o utilizador \"root\" do "
@@ -166,7 +166,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -179,7 +179,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "You should check the account's password after tha package installation."
@@ -189,7 +189,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -203,25 +203,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po
index 7cfa5a05190..dd8fb9c1f15 100644
--- a/debian/po/pt_BR.po
+++ b/debian/po/pt_BR.po
@@ -21,19 +21,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Realmente proceder com o rebaixamento de versão?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "Um arquivo de nome /var/lib/mysql/debian-*.flag existe no sistema."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "Such file is an indication that a mariadb-server package with a higher "
@@ -47,7 +47,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -57,13 +57,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Aviso importante para usuários NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -71,7 +71,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid ""
#| "You should also check the permissions and the owner of the /var/lib/mysql "
@@ -84,13 +84,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Remover todas as bases de dados do MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -100,7 +100,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -112,13 +112,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Iniciar o servidor MariaDB junto a inicialização da máquina?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -128,13 +128,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nova senha para o usuário \"root\" do MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -144,7 +144,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "If that field is left blank, the password will not be changed."
msgid "If this field is left blank, the password will not be changed."
@@ -152,7 +152,7 @@ msgstr "Caso este campo seja deixado em branco, a senha não sera mudada."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for the MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -160,13 +160,13 @@ msgstr "Nova senha para o usuário \"root\" do MariaDB:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Impossível definir senha para o usuário \"root\" do MariaDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -179,7 +179,7 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "You should check the account's password after tha package installation."
@@ -188,7 +188,7 @@ msgstr "Você deverá checar a senha dessa conta após a instalação deste paco
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
@@ -202,25 +202,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/ro.po b/debian/po/ro.po
index a0c69e7161f..ec71d628021 100644
--- a/debian/po/ro.po
+++ b/debian/po/ro.po
@@ -19,7 +19,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid "Do you really want to downgrade?"
msgid "Really proceed with downgrade?"
@@ -27,13 +27,13 @@ msgstr "Sunteţi sigur că doriţi să instalaţi o versiune mai veche?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
#, fuzzy
#| msgid ""
#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates "
@@ -50,7 +50,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -58,7 +58,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid "Important note for NIS/YP users!"
msgid "Important note for NIS/YP users"
@@ -66,7 +66,7 @@ msgstr "Notă importantă pentru utilizatorii NIS/YP!"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -74,7 +74,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -82,13 +82,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -96,7 +96,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
#, fuzzy
#| msgid ""
#| "The script is about to remove the data directory /var/lib/mysql. If it is "
@@ -113,7 +113,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid "Should MySQL start on boot?"
msgid "Start the MariaDB server on boot?"
@@ -121,7 +121,7 @@ msgstr "Doriţi ca MariaDB să pornească la initializarea sistemului?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid ""
#| "The MySQL can start automatically on boot time or only if you manually "
@@ -135,7 +135,7 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid "New password for MySQL \"root\" user:"
msgid "New password for the MariaDB \"root\" user:"
@@ -143,7 +143,7 @@ msgstr "Noua parolă pentru utilizatorul „root†al MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
#, fuzzy
#| msgid ""
#| "It is highly recommended that you set a password for the MySQL "
@@ -157,13 +157,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
#, fuzzy
#| msgid "New password for MySQL \"root\" user:"
msgid "Repeat password for the MariaDB \"root\" user:"
@@ -171,7 +171,7 @@ msgstr "Noua parolă pentru utilizatorul „root†al MariaDB:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid "Unable to set password for MySQL \"root\" user"
msgid "Unable to set password for the MariaDB \"root\" user"
@@ -179,7 +179,7 @@ msgstr "Nu s-a putut stabili parola pentru utilizatorul „root†al MariaDB"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "It seems an error occurred while setting the password for the MySQL "
@@ -198,13 +198,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -212,25 +212,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/ru.po b/debian/po/ru.po
index e1e73ee2748..d555c6b086d 100644
--- a/debian/po/ru.po
+++ b/debian/po/ru.po
@@ -32,19 +32,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "ДейÑтвительно уÑтановить более Ñтарую верÑию?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "Ð’ ÑиÑтеме найден файл /var/lib/mysql/debian-*.flag."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -54,7 +54,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -64,13 +64,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Важное замечание Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹ NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -80,7 +80,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -88,13 +88,13 @@ msgstr "Также проверьте права доÑтупа и владелÑ
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Удалить вÑе базы данных MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -103,7 +103,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -115,13 +115,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "ЗапуÑкать MariaDB при загрузке ÑиÑтемы?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -131,13 +131,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Ðовый пароль Ð´Ð»Ñ MariaDB Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"root\":"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -147,25 +147,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "ЕÑли оÑтавить поле пуÑтым, то пароль изменён не будет."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Повторите ввод Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð´Ð»Ñ MariaDB Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"root\":"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Ðевозможно задать пароль MariaDB пользователю \"root\""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -177,13 +177,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr "Проверьте пароль учётной запиÑи поÑле уÑтановки пакета."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
@@ -196,25 +196,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "Ошибка ввода паролÑ"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "Два введённых Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½Ðµ одинаковы. Повторите ввод."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB Cluster уже иÑпользуетÑÑ"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/sv.po b/debian/po/sv.po
index 788349fa504..fe21df1e229 100644
--- a/debian/po/sv.po
+++ b/debian/po/sv.po
@@ -1,7 +1,7 @@
# Translation of mysql-dfsg-5.1 debconf template to Swedish
# Copyright (C) 2009 Martin Bagge <brother@bsnet.se>
# This file is distributed under the same license as the mysql-dfsg-5.1 package.
-#
+#
# Andreas Henriksson <andreas@fatal.se>, 2007
# Martin Bagge <brother@bsnet.se>, 2009
msgid ""
@@ -21,19 +21,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Vill du verkligen genomföra nedgraderingen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr "En fil med namnet /var/lib/mysql/debian-*.flag hittades i systemet."
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -43,7 +43,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -53,13 +53,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Viktig information för NIS/YP-användare"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -69,7 +69,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -79,13 +79,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Ta bort alla MariaDB-databaser?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -95,7 +95,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -107,13 +107,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Ska MariaDB startas vid systemets uppstart?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -123,13 +123,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nytt lösenord för MariaDBs \"root\"-användare:"
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -139,25 +139,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "Om detta fält lämnas tom kommer lösenordet inte att ändras."
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Repetera lösenordet för MariaDBs \"root\"-användare:"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Kunde inte sätta lösenord för MariaDBs \"root\"-användare"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -170,17 +170,14 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr "Du bör kontrollera kontots lösenord efter installationen av paketet."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
#, fuzzy
-#| msgid ""
-#| "Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
-#| "more information."
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -190,25 +187,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr "Fel vid inmatning av lösenord"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "De två lösenorden du angav stämde inte överrens. Prova igen."
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB-kluster används inte"
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/templates.pot b/debian/po/templates.pot
index b046b068ff9..c67429d7706 100644
--- a/debian/po/templates.pot
+++ b/debian/po/templates.pot
@@ -19,19 +19,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -39,7 +39,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -47,13 +47,13 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid "Important note for NIS/YP users"
msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -61,7 +61,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -69,13 +69,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -83,7 +83,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -92,13 +92,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
"with the '/etc/init.d/mysql start' command."
@@ -106,13 +106,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -120,25 +120,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -147,13 +147,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -161,25 +161,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/debian/po/tr.po b/debian/po/tr.po
index a648bf38698..789ff9f8e2b 100644
--- a/debian/po/tr.po
+++ b/debian/po/tr.po
@@ -18,19 +18,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "Really proceed with downgrade?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"Such a file is an indication that a mariadb-server package with a higher "
"version has been installed previously."
@@ -38,7 +38,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:2001
+#: ../mariadb-galera-server-10.0.templates:2001
msgid ""
"There is no guarantee that the version you're currently installing will be "
"able to use the current databases."
@@ -46,7 +46,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
#, fuzzy
#| msgid "Important note for NIS/YP users!"
msgid "Important note for NIS/YP users"
@@ -54,7 +54,7 @@ msgstr "NIS/YP kullanıcıları için önemli not!"
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
"local system with:"
@@ -62,7 +62,7 @@ msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-10.0.templates:3001
+#: ../mariadb-galera-server-10.0.templates:3001
msgid ""
"You should also check the permissions and ownership of the /var/lib/mysql "
"directory:"
@@ -70,13 +70,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"The /var/lib/mysql directory which contains the MariaDB databases is about "
"to be removed."
@@ -84,7 +84,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:4001
+#: ../mariadb-galera-server-10.0.templates:4001
msgid ""
"If you're removing the MariaDB package in order to later install a more "
"recent version or if a different mariadb-server package is already using it, "
@@ -93,7 +93,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
#| msgid "Should MySQL start on boot?"
msgid "Start the MariaDB server on boot?"
@@ -101,7 +101,7 @@ msgstr "MariaDB açılış sırasında başlatılsın mı?"
#. Type: boolean
#. Description
-#: ../mariadb-server-10.0.templates:5001
+#: ../mariadb-galera-server-10.0.templates:5001
#, fuzzy
msgid ""
"The MariaDB server can be launched automatically at boot time or manually "
@@ -113,13 +113,13 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid ""
"While not mandatory, it is highly recommended that you set a password for "
"the MariaDB administrative \"root\" user."
@@ -127,25 +127,25 @@ msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:6001
+#: ../mariadb-galera-server-10.0.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-10.0.templates:7001
+#: ../mariadb-galera-server-10.0.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"An error occurred while setting the password for the MariaDB administrative "
"user. This may have happened because the account already has a password, or "
@@ -154,13 +154,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:8001
+#: ../mariadb-galera-server-10.0.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-10.0/README.Debian file for "
"more information."
@@ -168,25 +168,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:9001
+#: ../mariadb-galera-server-10.0.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-10.0.templates:10001
+#: ../mariadb-galera-server-10.0.templates:10001
msgid ""
"MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the new "
"mysql-cluster package and remove all lines starting with \"ndb\" from all "
diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c
index 7695f669b1f..cb883a60f85 100644
--- a/extra/my_print_defaults.c
+++ b/extra/my_print_defaults.c
@@ -98,6 +98,11 @@ static struct my_option my_long_options[] =
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
+void cleanup_and_exit(int exit_code)
+{
+ my_end(0);
+ exit(exit_code);
+}
static void version()
{
@@ -116,7 +121,7 @@ static void usage()
my_print_default_files(config_file);
my_print_variables(my_long_options);
printf("\nExample usage:\n%s --defaults-file=example.cnf client client-server mysql\n", my_progname);
- exit(0);
+ cleanup_and_exit(0);
}
@@ -129,7 +134,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_defaults_file_used= 1;
break;
case 'n':
- exit(0);
+ cleanup_and_exit(0);
case 'I':
case '?':
usage();
@@ -179,7 +184,7 @@ int main(int argc, char **argv)
/* Check out the args */
if (get_options(&argc,&argv))
- exit(1);
+ cleanup_and_exit(1);
nargs= argc + 1;
if (opt_mysqld)
diff --git a/include/my_global.h b/include/my_global.h
index 816c9dd87c6..057c613d64c 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -598,6 +598,19 @@ typedef SOCKET_SIZE_TYPE size_socket;
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+#ifdef __GLIBC__
+#define STR_O_CLOEXEC "e"
+#else
+#define STR_O_CLOEXEC ""
+#endif
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#else
+#define HAVE_SOCK_CLOEXEC
+#endif
/* additional file share flags for win32 */
#ifdef __WIN__
diff --git a/include/mysql/psi/mysql_socket.h b/include/mysql/psi/mysql_socket.h
index 1573fe77a9a..70700a733d8 100644
--- a/include/mysql/psi/mysql_socket.h
+++ b/include/mysql/psi/mysql_socket.h
@@ -553,7 +553,7 @@ inline_mysql_socket_socket
int domain, int type, int protocol)
{
MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET;
- mysql_socket.fd= socket(domain, type, protocol);
+ mysql_socket.fd= socket(domain, type | SOCK_CLOEXEC, protocol);
#ifdef HAVE_PSI_SOCKET_INTERFACE
if (likely(mysql_socket.fd != INVALID_SOCKET))
@@ -562,6 +562,12 @@ inline_mysql_socket_socket
(key, (const my_socket*)&mysql_socket.fd, NULL, 0);
}
#endif
+
+ /* SOCK_CLOEXEC isn't always a number - can't preprocessor compare */
+#if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) && !defined(HAVE_SOCK_CLOEXEC)
+ (void) fcntl(mysql_socket.fd, F_SETFD, FD_CLOEXEC);
+#endif
+
return mysql_socket;
}
@@ -1013,6 +1019,8 @@ inline_mysql_socket_accept
#endif
MYSQL_SOCKET socket_listen, struct sockaddr *addr, socklen_t *addr_len)
{
+ int flags;
+
MYSQL_SOCKET socket_accept= MYSQL_INVALID_SOCKET;
socklen_t addr_length= (addr_len != NULL) ? *addr_len : 0;
@@ -1026,7 +1034,17 @@ inline_mysql_socket_accept
(&state, socket_listen.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line);
/* Instrumented code */
+#ifdef HAVE_ACCEPT4
+ socket_accept.fd= accept4(socket_listen.fd, addr, &addr_length,
+ SOCK_CLOEXEC);
+#else
socket_accept.fd= accept(socket_listen.fd, addr, &addr_length);
+ flags= fcntl(socket_accept.fd, F_GETFD);
+ if (flags != -1) {
+ flags |= FD_CLOEXEC;
+ fcntl(socket_accept.fd, F_SETFD, flags);
+ }
+#endif
/* Instrumentation end */
if (locker != NULL)
@@ -1036,7 +1054,17 @@ inline_mysql_socket_accept
#endif
{
/* Non instrumented code */
+#ifdef HAVE_ACCEPT4
+ socket_accept.fd= accept4(socket_listen.fd, addr, &addr_length,
+ SOCK_CLOEXEC);
+#else
socket_accept.fd= accept(socket_listen.fd, addr, &addr_length);
+ flags= fcntl(socket_accept.fd, F_GETFD);
+ if (flags != -1) {
+ flags |= FD_CLOEXEC;
+ fcntl(socket_accept.fd, F_SETFD, flags);
+ }
+#endif
}
#ifdef HAVE_PSI_SOCKET_INTERFACE
diff --git a/include/mysqld_default_groups.h b/include/mysqld_default_groups.h
index a2e94ddd854..30dfdae1338 100644
--- a/include/mysqld_default_groups.h
+++ b/include/mysqld_default_groups.h
@@ -5,4 +5,7 @@ const char *load_default_groups[]= {
"mysqld", "server", MYSQL_BASE_VERSION,
"mariadb", MARIADB_BASE_VERSION,
"client-server",
+#ifdef WITH_WSREP
+"galera",
+#endif
0, 0};
diff --git a/include/thr_lock.h b/include/thr_lock.h
index 3f7a5ca988f..f05db666da9 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>
@@ -95,6 +104,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/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test
index ce5dde97894..831c6c886d5 100644
--- a/mysql-test/extra/binlog_tests/binlog.test
+++ b/mysql-test/extra/binlog_tests/binlog.test
@@ -372,7 +372,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;
@@ -387,7 +388,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
@@ -401,7 +403,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/assert_grep.inc b/mysql-test/include/assert_grep.inc
new file mode 100644
index 00000000000..a980a6d73b1
--- /dev/null
+++ b/mysql-test/include/assert_grep.inc
@@ -0,0 +1,154 @@
+# ==== Purpose ====
+#
+# Grep a file for a pattern, produce a single string out of the
+# matching lines, and assert that the string matches a given regular
+# expression.
+#
+# ==== Usage ====
+#
+# --let $assert_text= TEXT
+# --let $assert_file= FILE
+# --let $assert_select= REGEX
+# [--let $assert_match= REGEX | --let $assert_count= NUMBER]
+# [--let $assert_only_after= REGEX]
+# --source include/assert_grep.inc
+#
+# Parameters:
+#
+# $assert_text
+# Text that describes what is being checked. This text is written to
+# the query log so it should not contain non-deterministic elements.
+#
+# $assert_file
+# File to search.
+#
+# $assert_select
+# All lines matching this text will be checked.
+#
+# $assert_match
+# The script will find all lines that match $assert_select,
+# concatenate them to a long string, and assert that it matches
+# $assert_match.
+#
+# $assert_count
+# Instead of asserting that the selected lines match
+# $assert_match, assert that there were exactly $assert_count
+# matching lines.
+#
+# $assert_only_after
+# Reset all the lines matched and the counter when finding this pattern.
+# It is useful for searching things in the mysqld.err log file just
+# after the last server restart for example (discarding the log content
+# of previous server executions).
+
+
+if (!$assert_text)
+{
+ --die !!!ERROR IN TEST: you must set $assert_text
+}
+if (!$assert_file)
+{
+ --die !!!ERROR IN TEST: you must set $assert_file
+}
+if (!$assert_select)
+{
+ --die !!!ERROR IN TEST: you must set $assert_select
+}
+if ($assert_match == '')
+{
+ if ($assert_count == '')
+ {
+ --die !!!ERROR IN TEST: you must set either $assert_match or $assert_count
+ }
+}
+if ($assert_match != '')
+{
+ if ($assert_count != '')
+ {
+ --echo assert_text='$assert_text' assert_count='$assert_count'
+ --die !!!ERROR IN TEST: you must set only one of $assert_match or $assert_count
+ }
+}
+
+
+--let $include_filename= assert_grep.inc [$assert_text]
+--source include/begin_include_file.inc
+
+
+--let _AG_ASSERT_TEXT= $assert_text
+--let _AG_ASSERT_FILE= $assert_file
+--let _AG_ASSERT_SELECT= $assert_select
+--let _AG_ASSERT_MATCH= $assert_match
+--let _AG_ASSERT_COUNT= $assert_count
+--let _AG_OUT= `SELECT CONCAT('$MYSQLTEST_VARDIR/tmp/_ag_', UUID())`
+--let _AG_ASSERT_ONLY_AFTER= $assert_only_after
+
+
+--perl
+ use strict;
+ use warnings;
+ my $file= $ENV{'_AG_ASSERT_FILE'};
+ my $assert_select= $ENV{'_AG_ASSERT_SELECT'};
+ my $assert_match= $ENV{'_AG_ASSERT_MATCH'};
+ my $assert_count= $ENV{'_AG_ASSERT_COUNT'};
+ my $assert_only_after= $ENV{'_AG_ASSERT_ONLY_AFTER'};
+ my $out= $ENV{'_AG_OUT'};
+
+ my $result= '';
+ my $count= 0;
+ open(FILE, "$file") or die("Error $? opening $file: $!\n");
+ while (<FILE>) {
+ my $line = $_;
+ if ($assert_only_after && $line =~ /$assert_only_after/) {
+ $result = "";
+ $count = 0;
+ }
+ if ($line =~ /$assert_select/) {
+ if ($assert_count ne '') {
+ $count++;
+ }
+ else {
+ $result .= $line;
+ }
+ }
+ }
+ close(FILE) or die("Error $? closing $file: $!");
+ open OUT, "> $out" or die("Error $? opening $out: $!");
+ if ($assert_count ne '' && ($count != $assert_count)) {
+ print OUT ($count) or die("Error $? writing $out: $!");
+ }
+ elsif ($assert_count eq '' && $result !~ /$assert_match/) {
+ print OUT ($result) or die("Error $? writing $out: $!");
+ }
+ else {
+ print OUT ("assert_grep.inc ok");
+ }
+ close OUT or die("Error $? closing $out: $!");
+EOF
+
+
+--let $_ag_outcome= `SELECT LOAD_FILE('$_AG_OUT')`
+if ($_ag_outcome != 'assert_grep.inc ok')
+{
+ --source include/show_rpl_debug_info.inc
+ --echo include/assert_grep.inc failed!
+ --echo assert_text: '$assert_text'
+ --echo assert_file: '$assert_file'
+ --echo assert_select: '$assert_select'
+ --echo assert_match: '$assert_match'
+ --echo assert_count: '$assert_count'
+ --echo assert_only_after: '$assert_only_after'
+ if ($assert_match != '')
+ {
+ --echo matching lines: '$_ag_outcome'
+ }
+ if ($assert_count != '')
+ {
+ --echo number of matching lines: $_ag_outcome
+ }
+ --die assert_grep.inc failed.
+}
+
+
+--let $include_filename= include/assert_grep.inc [$assert_text]
+--source include/end_include_file.inc
diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test
index 3a9ec419bb1..c91d45d7d59 100644
--- a/mysql-test/include/check-testcase.test
+++ b/mysql-test/include/check-testcase.test
@@ -1,3 +1,5 @@
+--source include/wait_until_ready.inc
+
# ==== Purpose ====
#
# This test is executed twice for each test case. Before every
diff --git a/mysql-test/include/check-warnings.test b/mysql-test/include/check-warnings.test
index 9ecf7de419a..b2f73c32e35 100644
--- a/mysql-test/include/check-warnings.test
+++ b/mysql-test/include/check-warnings.test
@@ -11,6 +11,10 @@
# Don't write these queries to binlog
set SQL_LOG_BIN=0;
+# Do not replicate updates to other galera nodes
+--error 0,1193
+set WSREP_ON=0;
+
# Turn off any debug crashes, allow the variable to be
# non existent in release builds
--error 0,1193
diff --git a/mysql-test/include/diff_servers.inc b/mysql-test/include/diff_servers.inc
new file mode 100644
index 00000000000..5ec7efc38b9
--- /dev/null
+++ b/mysql-test/include/diff_servers.inc
@@ -0,0 +1,67 @@
+# ==== Purpose ====
+#
+# Check that two or more servers have identical databases; fail if not.
+#
+# ==== Usage ====
+#
+# --let $diff_servers= 1 2
+# [--let $databases= db1 db2 ...]
+# [--let $rpl_debug= 1]
+# --source include/diff_servers.inc
+
+# pretty-print header
+--let $_ds_info= servers=$diff_servers
+if ($databases != '')
+{
+ --let $_ds_info= $_ds_info databases=$databases
+}
+--let $include_filename= diff_servers.inc [$_ds_info]
+--source include/begin_include_file.inc
+
+# get databases
+--let $_ds_databases= $diff_database
+if ($_ds_databases == '')
+{
+ --let $_ds_databases= `SELECT GROUP_CONCAT(SCHEMA_NAME SEPARATOR ' ') FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'mtr', 'mysql', 'performance_schema')`
+}
+
+# generate command line
+--let $_ds_arg= --defaults-group-suffix=.
+--let $_ds_number_pos= `SELECT LOCATE('$_ds_arg', '$MYSQL_DUMP') + LENGTH('$_ds_arg')`
+--let $_ds_pre_command= `SELECT SUBSTR('$MYSQL_DUMP', 1, $_ds_number_pos - 1)`
+--let $_ds_post_command= `SELECT SUBSTR('$MYSQL_DUMP', $_ds_number_pos + 1)`
+--let $_ds_post_command= $_ds_post_command --compact --order-by-primary --skip-extended-insert --no-create-info --databases $_ds_databases
+--let $_ds_prev_outfile=
+
+# iterate over servers
+--let $_ds_servers= $diff_servers
+while ($_ds_servers != '')
+{
+ --let $_ds_server_number= `SELECT SUBSTRING_INDEX('$_ds_servers', ' ', 1)`
+ --let $_ds_servers= `SELECT TRIM(SUBSTRING('$_ds_servers', 1 + LENGTH('_$ds_server_number')))`
+ --let $_ds_outfile= $MYSQLTEST_VARDIR/tmp/diff_servers_$_ds_server_number
+
+ if ($rpl_debug)
+ {
+ --echo generating dump from server '$_ds_server_number' using command '$_ds_pre_command$_ds_server_number $_ds_post_command > $_ds_outfile'
+ --echo remaining servers: '$_ds_servers'
+ }
+ --exec $_ds_pre_command$_ds_server_number $_ds_post_command > $_ds_outfile
+
+ if ($_ds_prev_outfile != '')
+ {
+ if ($rpl_debug)
+ {
+ --echo diffing files '$_ds_prev_outfile' and '$_ds_outfile'
+ }
+ --diff_files $_ds_prev_outfile $_ds_outfile
+
+ --remove_file $_ds_prev_outfile
+ }
+ --let $_ds_prev_outfile= $_ds_outfile
+}
+
+--remove_file $_ds_prev_outfile
+
+--let $include_filename= diff_servers.inc [servers=$_ds_info]
+--source include/end_include_file.inc
diff --git a/mysql-test/include/galera_clear_sync_point.inc b/mysql-test/include/galera_clear_sync_point.inc
new file mode 100644
index 00000000000..589522a55b0
--- /dev/null
+++ b/mysql-test/include/galera_clear_sync_point.inc
@@ -0,0 +1 @@
+SET GLOBAL wsrep_provider_options = 'dbug=';
diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/include/galera_cluster.inc
new file mode 100644
index 00000000000..c1834c3c26f
--- /dev/null
+++ b/mysql-test/include/galera_cluster.inc
@@ -0,0 +1,12 @@
+# galera_cluster.inc
+# ==================
+#
+# Description
+# -----------
+# Configure galera cluster with 2 nodes.
+#
+
+--let $galera_cluster_size = 2
+--source include/galera_init.inc
+
+--source include/have_innodb.inc
diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/include/galera_connect.inc
new file mode 100644
index 00000000000..bfd9b188667
--- /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 00000000000..6043b582647
--- /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 00000000000..0fb5479844e
--- /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 00000000000..7c79d6fc138
--- /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_set_sync_point.inc b/mysql-test/include/galera_set_sync_point.inc
new file mode 100644
index 00000000000..5fe4e8c38c0
--- /dev/null
+++ b/mysql-test/include/galera_set_sync_point.inc
@@ -0,0 +1 @@
+--eval SET GLOBAL wsrep_provider_options = 'dbug=d,$galera_sync_point'
diff --git a/mysql-test/include/galera_signal_sync_point.inc b/mysql-test/include/galera_signal_sync_point.inc
new file mode 100644
index 00000000000..eaa5cdd43f5
--- /dev/null
+++ b/mysql-test/include/galera_signal_sync_point.inc
@@ -0,0 +1 @@
+--eval SET GLOBAL wsrep_provider_options = 'signal=$galera_sync_point'
diff --git a/mysql-test/include/galera_wait_ready.inc b/mysql-test/include/galera_wait_ready.inc
new file mode 100644
index 00000000000..e20f01fad90
--- /dev/null
+++ b/mysql-test/include/galera_wait_ready.inc
@@ -0,0 +1,2 @@
+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/galera_wait_sync_point.inc b/mysql-test/include/galera_wait_sync_point.inc
new file mode 100644
index 00000000000..cf3a4980186
--- /dev/null
+++ b/mysql-test/include/galera_wait_sync_point.inc
@@ -0,0 +1,6 @@
+--let $wait_timeout = 10
+--let $wsrep_on_orig = `SELECT @@wsrep_on`
+SET SESSION wsrep_on = 0;
+--let $wait_condition = SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters' AND VARIABLE_VALUE = '$galera_sync_point'
+--source include/wait_condition.inc
+--eval SET SESSION wsrep_on = $wsrep_on_orig
diff --git a/mysql-test/include/have_innodb_disallow_writes.inc b/mysql-test/include/have_innodb_disallow_writes.inc
new file mode 100644
index 00000000000..83b516b7a34
--- /dev/null
+++ b/mysql-test/include/have_innodb_disallow_writes.inc
@@ -0,0 +1,6 @@
+--source include/have_innodb.inc
+
+if (`SELECT COUNT(*) = 0 from INFORMATION_SCHEMA.GLOBAL_VARIABLES
+ WHERE VARIABLE_NAME = 'INNODB_DISALLOW_WRITES'`) {
+ --skip Test requires 'innodb_disallow_writes'
+}
diff --git a/mysql-test/include/have_wsrep.inc b/mysql-test/include/have_wsrep.inc
new file mode 100644
index 00000000000..52220edf481
--- /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 00000000000..4b322f769c7
--- /dev/null
+++ b/mysql-test/include/have_wsrep_enabled.inc
@@ -0,0 +1,9 @@
+# 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_on.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 00000000000..818abdd43b0
--- /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)
+}
+
diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql
index e34e32ad1a6..6e3908aa841 100644
--- a/mysql-test/include/mtr_check.sql
+++ b/mysql-test/include/mtr_check.sql
@@ -34,12 +34,18 @@ BEGIN
AND variable_name != 'INNODB_USE_NATIVE_AIO'
AND variable_name not like 'GTID%POS'
AND variable_name != 'GTID_BINLOG_STATE'
+ AND variable_name != '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
+ -- and the wsrep_schema schema that may be created by Galera
+ SELECT * FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mtr_wsrep_notify', 'wsrep_schema');
+
-- The test database should not contain any tables
SELECT table_name AS tables_in_test FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema='test';
diff --git a/mysql-test/include/mysqlhotcopy.inc b/mysql-test/include/mysqlhotcopy.inc
index f775d782b28..2fc14d599d9 100644
--- a/mysql-test/include/mysqlhotcopy.inc
+++ b/mysql-test/include/mysqlhotcopy.inc
@@ -109,7 +109,7 @@ DROP DATABASE hotcopy_save;
--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
--list_files $MYSQLD_DATADIR/hotcopy_save
--replace_result $MASTER_MYSOCK MASTER_MYSOCK
---error 1
+--error 1,9,11,110,2304,255
--exec $MYSQLHOTCOPY --quiet -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save
--replace_result $MASTER_MYSOCK MASTER_MYSOCK
--exec $MYSQLHOTCOPY --quiet --allowold -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save
diff --git a/mysql-test/include/not_wsrep.inc b/mysql-test/include/not_wsrep.inc
new file mode 100644
index 00000000000..3314b5c8717
--- /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/restart_mysqld.inc b/mysql-test/include/restart_mysqld.inc
index 940e081c431..a0447280ff5 100644
--- a/mysql-test/include/restart_mysqld.inc
+++ b/mysql-test/include/restart_mysqld.inc
@@ -50,6 +50,9 @@ if (!$restart_parameters)
# Call script that will poll the server waiting for it to be back online again
--source include/wait_until_connected_again.inc
+# Wait for wsrep
+--source include/wait_wsrep_ready.inc
+
# Turn off reconnect again
--disable_reconnect
diff --git a/mysql-test/include/start_mysqld.inc b/mysql-test/include/start_mysqld.inc
index e31f26aad8c..04dff714d49 100644
--- a/mysql-test/include/start_mysqld.inc
+++ b/mysql-test/include/start_mysqld.inc
@@ -16,6 +16,9 @@ if (!$restart_parameters)
# Call script that will poll the server waiting for it to be back online again
--source include/wait_until_connected_again.inc
+# Wait for wsrep
+--source include/wait_wsrep_ready.inc
+
# Turn off reconnect again
--disable_reconnect
diff --git a/mysql-test/include/wait_condition.inc b/mysql-test/include/wait_condition.inc
index ac61b76db32..5fbde6950c8 100644
--- a/mysql-test/include/wait_condition.inc
+++ b/mysql-test/include/wait_condition.inc
@@ -39,6 +39,7 @@ let $wait_timeout= 0;
let $wait_condition_reps= 0;
while ($wait_counter)
{
+ --error 0,ER_NO_SUCH_TABLE,ER_LOCK_WAIT_TIMEOUT,ER_UNKNOWN_COM_ERROR
let $success= `$wait_condition`;
inc $wait_condition_reps;
if ($success)
diff --git a/mysql-test/include/wait_until_ready.inc b/mysql-test/include/wait_until_ready.inc
new file mode 100644
index 00000000000..e7a6940975a
--- /dev/null
+++ b/mysql-test/include/wait_until_ready.inc
@@ -0,0 +1,34 @@
+# If wsrep patch is enabled, wait for a minute until node is ready.
+# Note: include/wait_for_status_var.inc cannot be used here, as server rejects
+# all commands except SHOW & SET until its ready. (see wsrep_ready status
+# variable)
+
+--disable_result_log
+--disable_query_log
+--enable_reconnect
+
+let $counter= 600;
+
+# Check if wsrep_ready status variable exists.
+if (`SHOW STATUS LIKE 'wsrep_ready'`)
+{
+ let $wsrep_ready= query_get_value("SHOW STATUS LIKE 'wsrep_ready'", Value, 1);
+
+ while ($wsrep_ready == 'OFF')
+ {
+ if (!$counter)
+ {
+ echo ===============================================;
+ echo Node still not ready after a minute, giving up!;
+ echo ===============================================;
+ die;
+ }
+ dec $counter;
+ sleep 0.1;
+ let $wsrep_ready= query_get_value("SHOW STATUS LIKE 'wsrep_ready'", Value, 1);
+ }
+}
+
+--disable_reconnect
+--enable_query_log
+--enable_result_log
diff --git a/mysql-test/include/wait_wsrep_ready.inc b/mysql-test/include/wait_wsrep_ready.inc
new file mode 100644
index 00000000000..0e666afa33d
--- /dev/null
+++ b/mysql-test/include/wait_wsrep_ready.inc
@@ -0,0 +1,15 @@
+#
+# If the wsrep plugin is loaded, wait until the wsrep provider becomes
+# ready for use.
+#
+
+--disable_query_log
+--disable_result_log
+
+if (`SELECT COUNT(*)=1 FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'wsrep' AND PLUGIN_STATUS='ACTIVE'`)
+{
+ --source include/galera_wait_ready.inc
+}
+
+--enable_query_log
+--enable_result_log
diff --git a/mysql-test/include/write_var_to_file.inc b/mysql-test/include/write_var_to_file.inc
index 08de195ccbb..4c54e719ebd 100644
--- a/mysql-test/include/write_var_to_file.inc
+++ b/mysql-test/include/write_var_to_file.inc
@@ -51,7 +51,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/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm
index 38c52b705f6..5ec7553674c 100644
--- a/mysql-test/lib/mtr_cases.pm
+++ b/mysql-test/lib/mtr_cases.pm
@@ -320,7 +320,7 @@ sub parse_disabled {
chomp;
next if /^\s*#/ or /^\s*$/;
mtr_error("Syntax error in $filename line $.")
- unless /^\s*(?:([-0-9A-Za-z_\/]+)\.)?([-0-9A-Za-z_\*]+)\s*:\s*(.*?)\s*$/;
+ unless /^\s*(?:([-0-9A-Za-z_\/]+)\.)?([-0-9A-Za-z_#\*]+)\s*:\s*(.*?)\s*$/;
mtr_error("Wrong suite name in $filename line $.: suitename = $suitename but the file says $1")
if defined $1 and defined $suitename and $1 ne $suitename;
my ($sname, $casename, $text)= (($1 || $suitename || ''), $2, $3);
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index f6d8cda592d..d5758abb03e 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -137,6 +137,8 @@ my $opt_start_dirty;
my $opt_start_exit;
my $start_only;
+our @global_suppressions;
+
END {
if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ )
{
@@ -188,6 +190,8 @@ my @DEFAULT_SUITES= qw(
sys_vars-
unit-
vcol-
+ wsrep-
+ galera-
);
my $opt_suites;
@@ -359,6 +363,7 @@ my $opt_max_test_fail= env_or_val(MTR_MAX_TEST_FAIL => 10);
my $opt_core_on_failure= 0;
my $opt_parallel= $ENV{MTR_PARALLEL} || 1;
+my $opt_port_group_size = $ENV{MTR_PORT_GROUP_SIZE} || 20;
# lock file to stop tests
my $opt_stop_file= $ENV{MTR_STOP_FILE};
@@ -1135,6 +1140,7 @@ sub command_line_setup {
# Specify ports
'build-thread|mtr-build-thread=i' => \$opt_build_thread,
'port-base|mtr-port-base=i' => \$opt_port_base,
+ 'port-group-size=s' => \$opt_port_group_size,
# Test case authoring
'record' => \$opt_record,
@@ -1827,16 +1833,16 @@ sub set_build_thread_ports($) {
$ENV{MTR_BUILD_THREAD}= $build_thread;
# Calculate baseport
- $baseport= $build_thread * 20 + 10000;
- if ( $baseport < 5001 or $baseport + 19 >= 32767 )
+ $baseport= $build_thread * $opt_port_group_size + 10000;
+ if ( $baseport < 5001 or $baseport + $opt_port_group_size >= 32767 )
{
mtr_error("MTR_BUILD_THREAD number results in a port",
"outside 5001 - 32767",
- "($baseport - $baseport + 19)");
+ "($baseport - $baseport + $opt_port_group_size)");
}
mtr_report("Using MTR_BUILD_THREAD $build_thread,",
- "with reserved ports $baseport..".($baseport+19));
+ "with reserved ports $baseport..".($baseport+($opt_port_group_size-1)));
}
@@ -3184,7 +3190,6 @@ sub ndbcluster_start ($) {
return 0;
}
-
sub mysql_server_start($) {
my ($mysqld, $tinfo) = @_;
@@ -3389,8 +3394,8 @@ sub kill_leftovers ($) {
sub check_ports_free ($)
{
my $bthread= shift;
- my $portbase = $bthread * 10 + 10000;
- for ($portbase..$portbase+9){
+ my $portbase = $bthread * $opt_port_group_size + 10000;
+ for ($portbase..$portbase+($opt_port_group_size-1)){
if (mtr_ping_port($_)){
mtr_report(" - 'localhost:$_' was not free");
return 0; # One port was not free
@@ -4812,6 +4817,7 @@ sub extract_warning_lines ($$) {
# Perl code.
my @antipatterns =
(
+ @global_suppressions,
qr/error .*connecting to master/,
qr/Plugin 'ndbcluster' will be forced to shutdown/,
qr/InnoDB: Error: in ALTER TABLE `test`.`t[12]`/,
@@ -6525,6 +6531,8 @@ Options that specify ports
build-thread=# Can be set in environment variable MTR_BUILD_THREAD.
Set MTR_BUILD_THREAD="auto" to automatically aquire
a build thread id that is unique to current host
+ port-group-size=N Reserve groups of TCP ports of size N for each MTR thread
+
Options for test case authoring
diff --git a/mysql-test/r/have_wsrep_on.require b/mysql-test/r/have_wsrep_on.require
new file mode 100644
index 00000000000..af32ac7dca7
--- /dev/null
+++ b/mysql-test/r/have_wsrep_on.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 cb53a0b8f67..d383dbe6feb 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1584,50 +1584,10 @@ id select_type table type possible_keys key key_len ref rows Extra
explain select count(*) from information_schema.views;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE views ALL NULL NULL NULL NULL NULL Open_frm_only; Scanned all databases
-set global init_connect="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 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 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 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 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;";
-select * from information_schema.global_variables where variable_name='init_connect';
-VARIABLE_NAME VARIABLE_VALUE
-INIT_CONNECT 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 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 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 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 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
+set global init_connect=repeat("drop table if exists t1;", 100);
+select length(@@global.init_connect), length(variable_value) from information_schema.global_variables where variable_name='init_connect';
+length(@@global.init_connect) length(variable_value)
+2400 2048
Warnings:
Warning 1265 Data truncated for column 'VARIABLE_VALUE' at row 1
set global init_connect="";
diff --git a/mysql-test/r/innodb_load_xa_with_wsrep.result b/mysql-test/r/innodb_load_xa_with_wsrep.result
new file mode 100644
index 00000000000..5c4f3e85b5c
--- /dev/null
+++ b/mysql-test/r/innodb_load_xa_with_wsrep.result
@@ -0,0 +1,21 @@
+install plugin innodb soname 'ha_innodb';
+select engine,support,transactions,xa from information_schema.engines where engine='innodb';
+engine support transactions xa
+InnoDB YES YES YES
+create table t1 (a int) engine=innodb;
+start transaction;
+insert t1 values (1);
+insert t1 values (2);
+commit;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 # Gtid # # GTID #-#-#
+mysqld-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb
+mysqld-bin.000001 # Gtid # # BEGIN GTID #-#-#
+mysqld-bin.000001 # Query # # use `test`; insert t1 values (1)
+mysqld-bin.000001 # Query # # use `test`; insert t1 values (2)
+mysqld-bin.000001 # Xid # # COMMIT /* XID */
+drop table t1;
+uninstall plugin innodb;
+Warnings:
+Warning 1620 Plugin is busy and will be uninstalled on shutdown
diff --git a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result
index f127e756987..a04eb4cca2b 100644
--- a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result
+++ b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result
@@ -1,6 +1,7 @@
#
# MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above
#
+SET SESSION wsrep_replicate_myisam=ON;
# Verbose run
TRUNCATE TABLE time_zone;
TRUNCATE TABLE time_zone_name;
diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result
index 3abde78fb31..3c1e1287c0c 100644
--- a/mysql-test/r/mysqld--help.result
+++ b/mysql-test/r/mysqld--help.result
@@ -1058,6 +1058,99 @@ The following specify which files/extra groups are read (specified before remain
-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-dirty-reads Allow reads even when the node is not in the primary
+ component.
+ --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-new-cluster Bootstrap a cluster. It works by overriding the current
+ value of wsrep_cluster_address. It is recommended not to
+ add this option to the config file as this will trigger
+ bootstrap on every server start.
+ --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-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 checks
+ --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 and BEGIN/START TRANSACTION); 2 -
+ UPDATE and DELETE; 4 - INSERT and REPLACE; 8 - SHOW
Variables (--variable-name=value)
allow-suspicious-udfs FALSE
@@ -1162,7 +1255,6 @@ log-slow-rate-limit 1
log-slow-slave-statements FALSE
log-slow-verbosity
log-tc tc.log
-log-tc-size 24576
log-warnings 1
long-query-time 10
low-priority-updates FALSE
@@ -1356,6 +1448,45 @@ use-stat-tables NEVER
userstat FALSE
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-dbug-option
+wsrep-debug FALSE
+wsrep-desync FALSE
+wsrep-dirty-reads FALSE
+wsrep-drupal-282555-workaround FALSE
+wsrep-forced-binlog-format NONE
+wsrep-load-data-splitting TRUE
+wsrep-log-conflicts FALSE
+wsrep-max-ws-rows 0
+wsrep-max-ws-size 2147483647
+wsrep-mysql-replication-bundle 0
+wsrep-new-cluster FALSE
+wsrep-node-address
+wsrep-node-incoming-address AUTO
+wsrep-notify-cmd
+wsrep-on TRUE
+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 00000000000..7c8e74af144
--- /dev/null
+++ b/mysql-test/r/not_wsrep.require
@@ -0,0 +1,2 @@
+HAVE_WSREP
+0
diff --git a/mysql-test/r/read_only_innodb.result b/mysql-test/r/read_only_innodb.result
index 2af72d30851..1e041395d3c 100644
--- a/mysql-test/r/read_only_innodb.result
+++ b/mysql-test/r/read_only_innodb.result
@@ -221,14 +221,6 @@ a a
5 10
DROP TABLE temp1, temp2;
-# MDEV-14185 CREATE TEMPORARY TABLE AS SELECT causes error 1290 with read_only and InnoDB.
-
-CREATE TEMPORARY TABLE temp1 ENGINE=INNODB AS SELECT a FROM t1;
-SELECT * FROM temp1;
-a
-1
-DROP TABLE temp1;
-
# Disconnect and cleanup
SET GLOBAL READ_ONLY = OFF;
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 5669e0bcbde..c481b1e8903 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/binlog-header.log b/mysql-test/std_data/binlog-header.log
new file mode 100644
index 00000000000..c415a57e616
--- /dev/null
+++ b/mysql-test/std_data/binlog-header.log
Binary files differ
diff --git a/mysql-test/std_data/galera-cert.pem b/mysql-test/std_data/galera-cert.pem
new file mode 100644
index 00000000000..2996b330cc0
--- /dev/null
+++ b/mysql-test/std_data/galera-cert.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkGgAwIBAgIJAIlW4JmZGnU4MA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNV
+BAYTAkZJMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
+Q29tcGFueSBMdGQwIBcNMTQxMDI0MDc1MTU1WhgPMzAxNDAyMjQwNzUxNTVaMEIx
+CzAJBgNVBAYTAkZJMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl
+ZmF1bHQgQ29tcGFueSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDDzU6xLZDD5rZENsOpTpTmqS8YisBaefU3ZeN7VJepZZ/7unM/1YLGJtuRh2Qa
+MyTkvyjzf7bSFsDt9L5lfQwBBblVeWkrCvGnQmHDQQYB7JrSmFDPz9W9Mxf9Q2BW
+B3lcoKXXJgMnWw0WGrt0lEdFp9gWbq8H9hwJdjpyyk4ZTIuucSOD4JUP3QFEhYU5
+kdcIbDRVw81J4eAZ6EdvbjDN05S7qWjW7rJTnCHAHEd18hcsMGwjpwhjEaSdhMrM
+mhOeL8kuQV0fI8v2xfYBliIn9xBZGOVzySPzwFmQceORlW6F3V5w6mwFkmuXqXWX
+Qo98swTu7mb89qVYmR71d3L3AgMBAAGjUDBOMB0GA1UdDgQWBBRdWet/kGNTyvXK
+wuBdP/eSldOgWjAfBgNVHSMEGDAWgBRdWet/kGNTyvXKwuBdP/eSldOgWjAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCcJpP+DR4AJxVelNTSZa+V38c+
+jgrMD2Ku2eU8NQlsjgMfNEU5Md/g7FpP8aCFzVf0kAAT7DxZmSE3uWXQbMXyVJmy
+bF+qXinf71QzdWULm6sASoshC6wbHnXL9ZjWQ3gh1nqVgo3MmLQYrb3eJfKaaLoc
+wpjhYxVxGFOx1ITN3jED64lUfoLHvR6NFbESYKAuAAzSNqX4HOQ3uGk2THM8JocZ
+oH2+38d81Kd4HQ7DDDKS/isG0+rR60Ti1cMgu7OT7p1dZCwT/KQuI5eGjE9lubkc
+yAJjaod4rVLdBri3XVvtySfS2+/75qUgv2TF7d/s7mxMq4DDt29yeKSUhZCs
+-----END CERTIFICATE-----
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAJWyvKjE+s7OP4Lj1jXKGlJGWT4Vd5YaxPljihTsRe1aXkWAgsuwISXk
+/TQ8Rx5Zmze7rtwtU0PoYxvuam9FMXYqhw2dVe4qRdeSX78DSiL/YBkQzaxlfWVy
+RE9+9dzHbCtRVDlN7K1kA+mGWH4/r7NAu4Qm/003V0NTtMwQSqebAgEC
+-----END DH PARAMETERS-----
+
diff --git a/mysql-test/std_data/galera-key.pem b/mysql-test/std_data/galera-key.pem
new file mode 100644
index 00000000000..c88c613cacf
--- /dev/null
+++ b/mysql-test/std_data/galera-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDDzU6xLZDD5rZE
+NsOpTpTmqS8YisBaefU3ZeN7VJepZZ/7unM/1YLGJtuRh2QaMyTkvyjzf7bSFsDt
+9L5lfQwBBblVeWkrCvGnQmHDQQYB7JrSmFDPz9W9Mxf9Q2BWB3lcoKXXJgMnWw0W
+Grt0lEdFp9gWbq8H9hwJdjpyyk4ZTIuucSOD4JUP3QFEhYU5kdcIbDRVw81J4eAZ
+6EdvbjDN05S7qWjW7rJTnCHAHEd18hcsMGwjpwhjEaSdhMrMmhOeL8kuQV0fI8v2
+xfYBliIn9xBZGOVzySPzwFmQceORlW6F3V5w6mwFkmuXqXWXQo98swTu7mb89qVY
+mR71d3L3AgMBAAECggEBAIMT0UdZSp1quL/nrYqNGa9kuSuDz4uCM3+3jNcGZVU4
+vCYHxpmINLi0UK8W5ROJA3zC4AZKjDgOlW93NXK5iKyyiUTIN3hiJi4jiVDuGbh2
+DZtH7mmAKAU1zCx2y2osLLmurfbe8qOJF7ShhrZfgWsHFujFhhUdU92dsTkhZ7EU
+2NF8ScxCo4PbOJoHC3j0ApfwCMxUMAKZF5+08EeKYqK7OAXI79HeIvEbHn3cUDGm
+bvg6ykwlz2UUO4sg+xdCmn1Bt36HF/4e973Y5fkE/vd9mryHIlu9t7GJgWyUiPr8
+BGEoAWDSpPOMd/b9ivtxh9Gd+LW/uitMuBIfrRPgz9kCgYEA+JqeeD2xqF2IzZyq
+i1UqgKe3su2U2zhkgbu1h/1M/reNIZGylF0wFs3P+kNIB2NavmHjXcgSjdJzqRL9
+XEWfFJRmeARo9RTEQEVd8zp1Eo8ISeiksGgvbL4rrNIRR5V5MZytfISRiGCWN6jx
+ulJ6EieQk5EcvknGlWpJY/bBsQ0CgYEAyaCLqrR38gVl2Z0t6YlhW/HWAwGt+lf4
+apN1AS4uykx7wRW2B0y9QUDfsrYeVlbbeRPP4UzPmJez+J2cweoIIeFFyo3KP2L7
+79E3EVYywjXhPg52F7OjFA4Bp970XclIC5Al7kDufSgwZmWdceSx4Jjc5ixyQEC8
+Ad0ThgP6yxMCgYAvC4OFmZcvF1Q2JLmZWGqMojB/KbqLqaZLbqwxqduSMEYC3kF/
+FgttpVEAOQ8+ZqzbbkbKjnwEXpkIm9FaTsqF6HdjquH5zw48Y2QeDSfudSbKZb4U
+rAKdf3dgYvhmJYEjxFSIRcYMmsqSieQEsGrtWJNheYqI8AkmaVCuHBoXWQKBgQCj
+daelNffD2wJuQNI28axfiRjSiSsNuQHpDTCfS1ydnxH5QGu5UUphO4HfdWv03SfC
+6f/vDIGEmQBLvyOVxfDf3qzhAMCFUO8kxj1ZrcMq1dmMoNa2cmj0WkKXYNZFrmfd
+D/jgRf3Ss6FBcoIJErnudp8nb8MUOibxb9RjIpjQxwKBgEliKaGN+/QkPTNJ4vXz
+609CIilxpE+YVTzlv3YeZP5HqsJTJPS2ARIUr/Pjpbl3LHfYNeeGDCwgkJIK0JJH
+iA1M51q6t3zG2y9gKmC15FF0jShoZkRgqBxqrSHAnrCo5t2C48ElxJ3FEU8T75sz
+dlGTbkmR0Wm43Kh++dWICJ3g
+-----END PRIVATE KEY-----
diff --git a/mysql-test/std_data/galera-upgrade-ca-cert.pem b/mysql-test/std_data/galera-upgrade-ca-cert.pem
new file mode 100644
index 00000000000..13d27e84bb3
--- /dev/null
+++ b/mysql-test/std_data/galera-upgrade-ca-cert.pem
@@ -0,0 +1,40 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkGgAwIBAgIJAIlW4JmZGnU4MA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNV
+BAYTAkZJMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
+Q29tcGFueSBMdGQwIBcNMTQxMDI0MDc1MTU1WhgPMzAxNDAyMjQwNzUxNTVaMEIx
+CzAJBgNVBAYTAkZJMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl
+ZmF1bHQgQ29tcGFueSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDDzU6xLZDD5rZENsOpTpTmqS8YisBaefU3ZeN7VJepZZ/7unM/1YLGJtuRh2Qa
+MyTkvyjzf7bSFsDt9L5lfQwBBblVeWkrCvGnQmHDQQYB7JrSmFDPz9W9Mxf9Q2BW
+B3lcoKXXJgMnWw0WGrt0lEdFp9gWbq8H9hwJdjpyyk4ZTIuucSOD4JUP3QFEhYU5
+kdcIbDRVw81J4eAZ6EdvbjDN05S7qWjW7rJTnCHAHEd18hcsMGwjpwhjEaSdhMrM
+mhOeL8kuQV0fI8v2xfYBliIn9xBZGOVzySPzwFmQceORlW6F3V5w6mwFkmuXqXWX
+Qo98swTu7mb89qVYmR71d3L3AgMBAAGjUDBOMB0GA1UdDgQWBBRdWet/kGNTyvXK
+wuBdP/eSldOgWjAfBgNVHSMEGDAWgBRdWet/kGNTyvXKwuBdP/eSldOgWjAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCcJpP+DR4AJxVelNTSZa+V38c+
+jgrMD2Ku2eU8NQlsjgMfNEU5Md/g7FpP8aCFzVf0kAAT7DxZmSE3uWXQbMXyVJmy
+bF+qXinf71QzdWULm6sASoshC6wbHnXL9ZjWQ3gh1nqVgo3MmLQYrb3eJfKaaLoc
+wpjhYxVxGFOx1ITN3jED64lUfoLHvR6NFbESYKAuAAzSNqX4HOQ3uGk2THM8JocZ
+oH2+38d81Kd4HQ7DDDKS/isG0+rR60Ti1cMgu7OT7p1dZCwT/KQuI5eGjE9lubkc
+yAJjaod4rVLdBri3XVvtySfS2+/75qUgv2TF7d/s7mxMq4DDt29yeKSUhZCs
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDVzCCAj+gAwIBAgIJALBO5bqmtlYkMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNV
+BAYTAkZJMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
+Q29tcGFueSBMdGQwHhcNMTUwNjI2MDcxMjQ1WhcNMjUwNTA0MDcxMjQ1WjBCMQsw
+CQYDVQQGEwJGSTEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh
+dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+1DlcztIzSngGeTUFibj9GZ4ZO78ASpgYySZv/DRIVn/3hbF41ZRD/6uJlb5rf1R7
+fpFsurbXNDDxeap7b/Gz2XSQy96Dbm0SbsFSZttV/R2WtlT1Wf5n9ix6RLqhKSbg
+nPyL2fsDaxtZh2uywGJEXhwXFtdx3deIo/tYivDfl5Tcsv0NnZY8Vg0boBRP+FEn
+ReJOdSa5LLn+QJN2Xa+wutbLHe0hI6huKUXU2YUeBfgyk1nWol5241ZUDCgDsoaW
+8r2YeJNHmNInd3wERbqFgFHsR4N1+Atcyrfn/uQSj9zrTPO/Pp51KpjWf/gjxjXP
+biu5De50qZ4+U4no20EIOwIDAQABo1AwTjAdBgNVHQ4EFgQU3kSPGchrOoQJ5gq1
+mmV2HEra6GswHwYDVR0jBBgwFoAU3kSPGchrOoQJ5gq1mmV2HEra6GswDAYDVR0T
+BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAfoBD64FJ9fAR19+vwueFGmpWNIqF
+PzN7QmEpCMduV3DXuxYO73q2ikXgrVO5HWFz9IjNvzXbSRmWNzJGaZ3QYZ+Xx1JJ
+8MrAOUr6djWuyD659f64dh/2jMxiQNoEHrknXm9HSqR5oJVwndFyr/zvSkYSRexE
+KFciIprb9LOba9G3ZMBYBdqK+f3Ky16BMjaD6XfaTx+xjHk/8peSueXIQl+v2biz
+zSfpEUa0dKCIxckrzD4JknDHFimTsrzlRftcg8t8piOXwZomFcnVunyGs2bJ/Npj
+25c2e6sx7XSc5bUgPGuQcSGflZPLg9zWyJ69sVYUNAz+gqfvWfOOJuzPNg==
+-----END CERTIFICATE-----
diff --git a/mysql-test/std_data/galera-upgrade-server-cert.pem b/mysql-test/std_data/galera-upgrade-server-cert.pem
new file mode 100644
index 00000000000..3af8b1ae7dd
--- /dev/null
+++ b/mysql-test/std_data/galera-upgrade-server-cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVzCCAj+gAwIBAgIJALBO5bqmtlYkMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNV
+BAYTAkZJMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg
+Q29tcGFueSBMdGQwHhcNMTUwNjI2MDcxMjQ1WhcNMjUwNTA0MDcxMjQ1WjBCMQsw
+CQYDVQQGEwJGSTEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh
+dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+1DlcztIzSngGeTUFibj9GZ4ZO78ASpgYySZv/DRIVn/3hbF41ZRD/6uJlb5rf1R7
+fpFsurbXNDDxeap7b/Gz2XSQy96Dbm0SbsFSZttV/R2WtlT1Wf5n9ix6RLqhKSbg
+nPyL2fsDaxtZh2uywGJEXhwXFtdx3deIo/tYivDfl5Tcsv0NnZY8Vg0boBRP+FEn
+ReJOdSa5LLn+QJN2Xa+wutbLHe0hI6huKUXU2YUeBfgyk1nWol5241ZUDCgDsoaW
+8r2YeJNHmNInd3wERbqFgFHsR4N1+Atcyrfn/uQSj9zrTPO/Pp51KpjWf/gjxjXP
+biu5De50qZ4+U4no20EIOwIDAQABo1AwTjAdBgNVHQ4EFgQU3kSPGchrOoQJ5gq1
+mmV2HEra6GswHwYDVR0jBBgwFoAU3kSPGchrOoQJ5gq1mmV2HEra6GswDAYDVR0T
+BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAfoBD64FJ9fAR19+vwueFGmpWNIqF
+PzN7QmEpCMduV3DXuxYO73q2ikXgrVO5HWFz9IjNvzXbSRmWNzJGaZ3QYZ+Xx1JJ
+8MrAOUr6djWuyD659f64dh/2jMxiQNoEHrknXm9HSqR5oJVwndFyr/zvSkYSRexE
+KFciIprb9LOba9G3ZMBYBdqK+f3Ky16BMjaD6XfaTx+xjHk/8peSueXIQl+v2biz
+zSfpEUa0dKCIxckrzD4JknDHFimTsrzlRftcg8t8piOXwZomFcnVunyGs2bJ/Npj
+25c2e6sx7XSc5bUgPGuQcSGflZPLg9zWyJ69sVYUNAz+gqfvWfOOJuzPNg==
+-----END CERTIFICATE-----
diff --git a/mysql-test/std_data/galera-upgrade-server-key.pem b/mysql-test/std_data/galera-upgrade-server-key.pem
new file mode 100644
index 00000000000..d243c9e0381
--- /dev/null
+++ b/mysql-test/std_data/galera-upgrade-server-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDUOVzO0jNKeAZ5
+NQWJuP0Znhk7vwBKmBjJJm/8NEhWf/eFsXjVlEP/q4mVvmt/VHt+kWy6ttc0MPF5
+qntv8bPZdJDL3oNubRJuwVJm21X9HZa2VPVZ/mf2LHpEuqEpJuCc/IvZ+wNrG1mH
+a7LAYkReHBcW13Hd14ij+1iK8N+XlNyy/Q2dljxWDRugFE/4USdF4k51Jrksuf5A
+k3Zdr7C61ssd7SEjqG4pRdTZhR4F+DKTWdaiXnbjVlQMKAOyhpbyvZh4k0eY0id3
+fARFuoWAUexHg3X4C1zKt+f+5BKP3OtM878+nnUqmNZ/+CPGNc9uK7kN7nSpnj5T
+iejbQQg7AgMBAAECggEBAJ4m7VG3db+uOGzFJY5fzEX1+qn6ibYNKJNmUJfrQmkr
+zgLUoc7QQehbJhnwoN1v0OQebZ+rOC7NtnZLpNdkkPmhk3JKLTnykIT3DnhWRftt
+vG2+XGUnYMQkmy1ywz0Omt6CmZnlJMQByrNPgBM8Z+SWHGLKRTHkOBCz82T/YjDr
+wqug1Yv6W0wMNM/cikgoBldVG7hABCJuShjffIbUgVysK3dEPNywNAC78neoGECm
+evPZOaIkWEr86SpAlwA6Yh+zTQZ03CXATcGonJdWJ015DvlKRv6QyRR0Q/Y1ONwb
+f115kll15MJBEspFdSyhlMcVJlwO8WMaZ2qIzlQZmdECgYEA//P469QzX00L/urK
+7IRvtSVu5CP/A/Wui90U4KoP7XgXIeExnEtzLVs1K7vjuzdpTyq+68XuC40gPcJW
+RvoX229m6gRV8nC53UiV71jM8IvkyEqFYT/gfZC9KQCMSRJLtVnDMpZ3gMxAY6/5
+p20o616Au8DKFFetQV0aD4Hj1/MCgYEA1ENV1WkgvN6yItB77E9kN/vbKLRh0hrg
+9xj0SmMXGYyDM9NpjbgbgJIZo3ukkBtp3kEY8P9JQZRcd1EcnnSrwTB7ChdInWkR
+m/LpIZBEMqNQbeu4QSzZYYS6z4tcGGx43aHqzzNBZdnQnqhYL1CvlLwhkgX6oQCo
+woXqyfMNKJkCgYEA63gD1NGPwWkcVBSlQxpDup8JeZE0Fux6++kUP+u0Y39LqLuH
+7IXtHBkAvY9JXv8HPvHQWw/og2/97VNQFFQYhqPiRgBfIX9bPpx8c4l6YQISI8GL
+G4CsglgZ7hK2/LJ8PAascWnD3xYJVqyaPNFMB90VCaW/Qx+2IKAKTaHtfskCgYBu
+1f5C4pMqrCpeTXj4Cvis1wE4PwB5QnnH7SrakOVl/N4huLn8O2948lEa8Zwbd4UP
+ffR1Gwh4iuzBjQQhpZBt30/QFBphv5RnVy7uzLMfsfF0hEqBFdcoubMGXqGnSzTN
+nhfLO9thQJxTzFnH0xzr0FTDOAYH/h0g/eZ8r0JmuQKBgQDjhXM+hJ3Pkwua+Fnl
+nZfY5MeSzkJki/9iwVo8rSDwmZS9Nsc83oZnddM7c2x63t+zYOAcMxsVCiByMDzo
+5IB781HWRBGcU8TnW1b0bAnZimjKp/qsZ/Szr38rvImqG8TjzbcSD7w0SpyRQ/Ot
+A7SZFkWYfem8/q/VImjU/CNbOQ==
+-----END PRIVATE KEY-----
diff --git a/mysql-test/std_data/wsrep_notify.sh b/mysql-test/std_data/wsrep_notify.sh
new file mode 100755
index 00000000000..7036f603c84
--- /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 eb82ac4cc4b..cabb5672c8d 100644
--- a/mysql-test/suite/binlog/r/binlog_row_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result
@@ -806,9 +806,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;
@@ -824,9 +826,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
@@ -842,8 +846,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_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
index 824bf3ed2a0..3a6af15e88a 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
@@ -618,9 +618,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;
@@ -636,9 +638,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
@@ -654,8 +658,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/funcs_1/r/is_columns_is.result b/mysql-test/suite/funcs_1/r/is_columns_is.result
index 8f2f81a4616..f0d1f196193 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_is.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_is.result
@@ -151,9 +151,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 INDEX_STATISTICS INDEX_NAME 3 NO varchar 192 576 NULL NULL NULL utf8 utf8_general_ci varchar(192) select
def information_schema INDEX_STATISTICS ROWS_READ 4 0 NO bigint NULL NULL 19 0 NULL NULL NULL bigint(21) select
def information_schema INDEX_STATISTICS TABLE_NAME 2 NO varchar 192 576 NULL NULL NULL utf8 utf8_general_ci varchar(192) select
@@ -304,9 +304,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
@@ -638,9 +638,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 INDEX_STATISTICS TABLE_SCHEMA varchar 192 576 utf8 utf8_general_ci varchar(192)
3.0000 information_schema INDEX_STATISTICS TABLE_NAME varchar 192 576 utf8 utf8_general_ci varchar(192)
3.0000 information_schema INDEX_STATISTICS INDEX_NAME varchar 192 576 utf8 utf8_general_ci varchar(192)
@@ -791,9 +791,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/disabled.def b/mysql-test/suite/galera/disabled.def
new file mode 100644
index 00000000000..fad1e69d4d7
--- /dev/null
+++ b/mysql-test/suite/galera/disabled.def
@@ -0,0 +1,53 @@
+##############################################################################
+#
+# List the test cases that are to be disabled temporarily.
+#
+# Separate the test case name and the comment with ':'.
+#
+# <testcasename> : MDEV-<xxxx> <comment>
+#
+# Do not use any TAB characters for whitespace.
+#
+##############################################################################
+
+MW-336 : MDEV-13549 Galera test failures
+galera_gra_log : MDEV-13549 Galera test failures
+galera_flush_local : MDEV-13549 Galera test failures
+galera_flush : MDEV-13549 Galera test failures
+MW-329 : MDEV-13549 Galera test failures
+galera_account_management : MariaDB 10.0 does not support ALTER USER
+galera_binlog_row_image : MariaDB 10.0 does not support binlog_row_image
+galera_binlog_rows_query_log_events: MariaDB does not support binlog_rows_query_log_events
+GAL-419 : MDEV-13549 Galera test failures
+galera_toi_ddl_fk_insert : MDEV-13549 Galera test failures
+galera_var_notify_cmd : MDEV-13549 Galera test failures
+galera_var_slave_threads : MDEV-13549 Galera test failures
+mysql-wsrep#90 : MDEV-13549 Galera test failures
+galera_as_master_gtid : Requires MySQL GTID
+galera_as_master_gtid_change_master : Requires MySQL GTID
+galera_as_slave_replication_bundle : MDEV-13549 Galera test failures
+galera_as_slave_preordered : wsrep-preordered feature not merged to MariaDB
+galera_gcs_fragment : MDEV-13549 Galera test failures
+galera_gcache_recover : MDEV-13549 Galera test failures
+galera_gcache_recover_full_gcache : MDEV-13549 Galera test failures
+galera_gcache_recover_manytrx : MDEV-13549 Galera test failures
+galera_ist_mysqldump : MDEV-13549 Galera test failures
+mysql-wsrep#31 : MDEV-13549 Galera test failures
+galera_migrate : MariaDB 10.0 does not support START SLAVE USER
+galera_concurrent_ctas : MDEV-13549 Galera test failures
+galera_bf_abort_for_update : MDEV-13549 Galera test failures
+galera_wsrep_desync_wsrep_on : MDEV-13549 Galera test failures
+galera_ssl_upgrade : MDEV-13549 Galera test failures
+mysql-wsrep#33 : MDEV-13549 Galera test failures
+galera_var_auto_inc_control_on : MDEV-13549 Galera test failures
+MW-44 : MDEV-13549 Galera test failures
+galera_var_retry_autocommit : MDEV-13549 Galera test failures
+pxc-421 : MDEV-13549 Galera test failures
+lp1376747-2 : MDEV-13549 Galera test failures
+lp1376747 : MDEV-13549 Galera test failures
+galera_toi_ddl_nonconflicting : MDEV-13549 Galera test failures
+galera_parallel_simple : MDEV-13549 Galera test failures
+galera_admin : MDEV-13549 Galera test failures
+MW-416 : MDEV-13549 Galera test failures
+galera_wan : MDEV-13549 Galera test failures
+MW-388 : MDEV-13549 Galera test failures
diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf
new file mode 100644
index 00000000000..3d510d74429
--- /dev/null
+++ b/mysql-test/suite/galera/galera_2nodes.cnf
@@ -0,0 +1,43 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+binlog-format=row
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+wsrep_cluster_address='gcomm://'
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;gcache.size=10M'
+
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;gcache.size=10M;evs.suspect_timeout=PT10S'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
+
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+
+
+[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
+
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 00000000000..78b0ac84273
--- /dev/null
+++ b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
@@ -0,0 +1,69 @@
+#
+# This file creates a setup with a 2-node Galera cluster (master) and one
+# standalone MariaDB server, to be used as a slave.
+#
+
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+binlog-format=row
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+server-id=1
+log-bin=mysqld-bin
+log_slave_updates
+
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M'
+wsrep_cluster_address=gcomm://
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+wsrep_node_address=127.0.0.1
+wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+server-id=2
+log-bin=mysqld-bin
+log_slave_updates
+
+wsrep_provider=@ENV.WSREP_PROVIDER
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M'
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_node_address=127.0.0.1
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+
+[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 00000000000..cf1eccb1ba9
--- /dev/null
+++ b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
@@ -0,0 +1,73 @@
+#
+# This .cnf file creates a setup with 1 standard MariaDB server, followed by a 2-node Galera cluster
+#
+
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+binlog-format=row
+
+[mysqld.1]
+log-bin
+server-id=1
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+log-bin
+log-slave-updates
+
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+server-id=2
+
+[mysqld.3]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+log-bin
+log-slave-updates
+
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+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_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_3nodes_as_slave.cnf b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
new file mode 100644
index 00000000000..ac1ca34e242
--- /dev/null
+++ b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
@@ -0,0 +1,97 @@
+#
+# This .cnf file creates a setup with 1 standard MariaDB server, followed by a 3-node Galera cluster
+#
+
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+log-bin
+binlog-format=row
+
+[mysqld.1]
+server-id=1
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+log-slave-updates
+
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.install_timeout = PT15S;evs.max_install_timeouts=1;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+server-id=2
+
+[mysqld.3]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+log-slave-updates
+
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+server-id=3
+
+[mysqld.4]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+log-slave-updates
+
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
+wsrep_provider_options='base_port=@mysqld.4.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port'
+
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+server-id=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_2= @mysqld.2.#galera_port
+NODE_GALERAPORT_3= @mysqld.3.#galera_port
+NODE_GALERAPORT_4= @mysqld.4.#galera_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/galera_4nodes.cnf b/mysql-test/suite/galera/galera_4nodes.cnf
new file mode 100644
index 00000000000..a0ef1dc092b
--- /dev/null
+++ b/mysql-test/suite/galera/galera_4nodes.cnf
@@ -0,0 +1,73 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+binlog-format=row
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+
+
+[mysqld.3]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+
+
+[mysqld.4]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.4.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port'
+
+[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/auto_increment_offset_restore.inc b/mysql-test/suite/galera/include/auto_increment_offset_restore.inc
new file mode 100644
index 00000000000..1248ed100ca
--- /dev/null
+++ b/mysql-test/suite/galera/include/auto_increment_offset_restore.inc
@@ -0,0 +1,41 @@
+# See auto_increment_offset_restore.inc for details.
+
+if (!$node_1)
+{
+ --die ERROR IN TEST: $node_1 must be set before sourcing auto_increment_offset_save.inc
+}
+
+if (!$node_2)
+{
+ --die ERROR IN TEST: $node_2 must be set before sourcing auto_increment_offset_save.inc
+}
+
+if (!$auto_increment_offset_node_1)
+{
+ --die ERROR IN TEST: $auto_increment_offset_node_1 must be set before sourcing auto_increment_offset_save.inc
+}
+
+if (!$auto_increment_offset_node_2)
+{
+ --die ERROR IN TEST: $auto_increment_offset_node_2 must be set before sourcing auto_increment_offset_save.inc
+}
+
+# Restore original auto_increment_offset values.
+--disable_query_log
+--connection $node_1
+--eval SET @@global.auto_increment_offset = $auto_increment_offset_node_1;
+--connection $node_2
+--eval SET @@global.auto_increment_offset = $auto_increment_offset_node_2;
+
+if ($node_3)
+{
+--connection $node_3
+--eval SET @@global.auto_increment_offset = $auto_increment_offset_node_3;
+}
+
+if ($node_4)
+{
+--connection $node_4
+--eval SET @@global.auto_increment_offset = $auto_increment_offset_node_4;
+}
+--enable_query_log
diff --git a/mysql-test/suite/galera/include/auto_increment_offset_save.inc b/mysql-test/suite/galera/include/auto_increment_offset_save.inc
new file mode 100644
index 00000000000..216c689ec8c
--- /dev/null
+++ b/mysql-test/suite/galera/include/auto_increment_offset_save.inc
@@ -0,0 +1,45 @@
+# This file can be used to save the @@global.auto_increment_offset value at
+# the beginning of any test that intends to restart any of the participating
+# nodes. This is required as the node may get auto-assigned a different
+# auto_increment_offset value on restart, which could cause MTR's internal
+# post-check to fail. auto_increment_offset_restore.inc can be used at the
+# end of the test to restore these saved values.
+
+# Parameters
+# ----------
+# $node_1
+# Connection handle for 1st node
+# $node_2
+# Connection handle for 2nd node
+# $node_3 (optional)
+# Connection handle for 3rd node
+# $node_4 (optional)
+# Connection handle for 4th node
+
+if (!$node_1)
+{
+ --die ERROR IN TEST: $node_1 must be set before sourcing auto_increment_offset_save.inc
+}
+
+if (!$node_2)
+{
+ --die ERROR IN TEST: $node_2 must be set before sourcing auto_increment_offset_save.inc
+}
+
+--connection $node_1
+let $auto_increment_offset_node_1 = `SELECT @@global.auto_increment_offset`;
+--connection $node_2
+let $auto_increment_offset_node_2 = `SELECT @@global.auto_increment_offset`;
+
+if ($node_3)
+{
+ --connection $node_3
+ let $auto_increment_offset_node_3 = `SELECT @@global.auto_increment_offset`;
+}
+
+if ($node_4)
+{
+ --connection $node_4
+ let $auto_increment_offset_node_4 = `SELECT @@global.auto_increment_offset`;
+}
+
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 00000000000..7c0156052d8
--- /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 00000000000..761a1a89fd3
--- /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/wait_until_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 00000000000..02937ec8ea3
--- /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_resume.inc b/mysql-test/suite/galera/include/galera_resume.inc
new file mode 100644
index 00000000000..232cb46479e
--- /dev/null
+++ b/mysql-test/suite/galera/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/suite/galera/include/galera_sst_restore.inc b/mysql-test/suite/galera/include/galera_sst_restore.inc
new file mode 100644
index 00000000000..a08b148c31a
--- /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 00000000000..5f87d23dcc1
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_sst_set_mysqldump.inc
@@ -0,0 +1,23 @@
+#
+# 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';
+
+--let $wsrep_sst_auth_orig = `SELECT @@wsrep_sst_auth`
+SET GLOBAL wsrep_sst_auth = 'sst:';
+
+--connection node_2
+--source include/wait_until_connected_again.inc
+--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 00000000000..81ba54aa6f5
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_st_clean_slave.inc
@@ -0,0 +1,113 @@
+--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
+--source include/wait_until_ready.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 00000000000..c8869746bd1
--- /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 00000000000..bae37755c65
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_st_kill_slave.inc
@@ -0,0 +1,108 @@
+--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
+--source include/wait_until_ready.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 00000000000..b8dd0fda987
--- /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_dbug`
+SET GLOBAL debug_dbug = '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
+--source include/wait_until_ready.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;
+
+SET GLOBAL debug_dbug = $debug_orig;
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 00000000000..1a65ef1bd94
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_st_shutdown_slave.inc
@@ -0,0 +1,105 @@
+--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
+--source include/wait_until_ready.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 00000000000..edc7eb31e0e
--- /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 00000000000..090ffe5f5df
--- /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 --innodb --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/include/kill_galera.inc b/mysql-test/suite/galera/include/kill_galera.inc
new file mode 100644
index 00000000000..c61bad8e19d
--- /dev/null
+++ b/mysql-test/suite/galera/include/kill_galera.inc
@@ -0,0 +1,21 @@
+--echo Killing server ...
+
+# Write file to make mysql-test-run.pl expect the crash, but don't start it
+--source include/wait_until_connected_again.inc
+--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/suite/galera/include/shutdown_mysqld.inc b/mysql-test/suite/galera/include/shutdown_mysqld.inc
new file mode 100644
index 00000000000..54bba1318e7
--- /dev/null
+++ b/mysql-test/suite/galera/include/shutdown_mysqld.inc
@@ -0,0 +1,18 @@
+# This is the first half of include/restart_mysqld.inc.
+if ($rpl_inited)
+{
+ if (!$allow_rpl_inited)
+ {
+ --die ERROR IN TEST: When using the replication test framework (master-slave.inc, rpl_init.inc etc), use rpl_restart_server.inc instead of restart_mysqld.inc. If you know what you are doing and you really have to use restart_mysqld.inc, set allow_rpl_inited=1 before you source restart_mysqld.inc
+ }
+}
+
+# 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
+
+# Send shutdown to the connected server
+--shutdown_server
+--source include/wait_until_disconnected.inc
+
diff --git a/mysql-test/suite/galera/include/start_mysqld.inc b/mysql-test/suite/galera/include/start_mysqld.inc
new file mode 100644
index 00000000000..4ee3d17810c
--- /dev/null
+++ b/mysql-test/suite/galera/include/start_mysqld.inc
@@ -0,0 +1,22 @@
+# 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
+
+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
+
+# Call script that will poll the server waiting for it to be back online again
+--source include/wait_until_connected_again.inc
+
+# Turn off reconnect again
+--disable_reconnect
diff --git a/mysql-test/suite/galera/my.cnf b/mysql-test/suite/galera/my.cnf
new file mode 100644
index 00000000000..ca163a540d9
--- /dev/null
+++ b/mysql-test/suite/galera/my.cnf
@@ -0,0 +1 @@
+!include galera_2nodes.cnf
diff --git a/mysql-test/suite/galera/r/GAL-382.result b/mysql-test/suite/galera/r/GAL-382.result
new file mode 100644
index 00000000000..0c7365f3005
--- /dev/null
+++ b/mysql-test/suite/galera/r/GAL-382.result
@@ -0,0 +1,6 @@
+create table t1 (i int, j int, k int, primary key pk(i)) engine=innodb;
+insert into t1 values (1, 1, 1), (2, 2, 2), (3, 3, 3);
+create table t2 (i int, j int, k int, primary key pk(i, j, k), index idx(i, k, j)) engine=innodb;
+replace into t2 (i, j, k) select /*!99997 */ i, k, j from t1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera/r/GAL-401.result b/mysql-test/suite/galera/r/GAL-401.result
new file mode 100644
index 00000000000..03509cb0e29
--- /dev/null
+++ b/mysql-test/suite/galera/r/GAL-401.result
@@ -0,0 +1,23 @@
+SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
+SET @@global.wsrep_desync = 1;
+SET SESSION wsrep_dirty_reads=1;
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+SET wsrep_dirty_reads=0;
+SHOW STATUS LIKE 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 0
+SET @@global.wsrep_desync = 0;
+SET SESSION wsrep_sync_wait=15;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) NOT NULL,
+ `f2` char(1) DEFAULT NULL,
+ PRIMARY KEY (`f1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CALL mtr.add_suppression("WSREP: Protocol violation. JOIN message sender (.*) is not in state transfer \\(SYNCED\\). Message ignored.");
+SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=false';
diff --git a/mysql-test/suite/galera/r/GAL-419.result b/mysql-test/suite/galera/r/GAL-419.result
new file mode 100644
index 00000000000..410c91b4f98
--- /dev/null
+++ b/mysql-test/suite/galera/r/GAL-419.result
@@ -0,0 +1,4 @@
+SET SESSION wsrep_sync_wait = 0;
+Killing server ...
+SET SESSION wsrep_sync_wait = 0;
+Killing server ...
diff --git a/mysql-test/suite/galera/r/GAL-480.result b/mysql-test/suite/galera/r/GAL-480.result
new file mode 100644
index 00000000000..b762e07423e
--- /dev/null
+++ b/mysql-test/suite/galera/r/GAL-480.result
@@ -0,0 +1,39 @@
+CREATE TABLE t1 (f1 CHAR(10), f0 integer) ENGINE=InnoDB;
+FLUSH TABLE t1 FOR EXPORT;
+UNLOCK TABLES;
+ALTER TABLE t1 DROP COLUMN f1;
+SET SESSION wsrep_osu_method='RSU';
+ALTER TABLE t1 ADD COLUMN f1 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f1;
+ALTER TABLE t1 ADD COLUMN f2 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f2;
+ALTER TABLE t1 ADD COLUMN f3 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f3;
+ALTER TABLE t1 ADD COLUMN f4 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f4;
+ALTER TABLE t1 ADD COLUMN f5 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f5;
+ALTER TABLE t1 ADD COLUMN f6 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f6;
+ALTER TABLE t1 ADD COLUMN f7 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f7;
+ALTER TABLE t1 ADD COLUMN f8 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f8;
+ALTER TABLE t1 ADD COLUMN f9 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f9;
+ALTER TABLE t1 ADD COLUMN f10 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f10;
+ALTER TABLE t1 ADD COLUMN f11 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f11;
+ALTER TABLE t1 ADD COLUMN f12 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f12;
+ALTER TABLE t1 ADD COLUMN f13 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f13;
+ALTER TABLE t1 ADD COLUMN f14 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f14;
+ALTER TABLE t1 ADD COLUMN f15 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f15;
+ALTER TABLE t1 ADD COLUMN f16 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f16;
+SET SESSION wsrep_osu_method='TOI';
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-252.result b/mysql-test/suite/galera/r/MW-252.result
new file mode 100644
index 00000000000..c422edcb82a
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-252.result
@@ -0,0 +1,7 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+FLUSH TABLES WITH READ LOCK;
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+UNLOCK TABLES;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-258.result b/mysql-test/suite/galera/r/MW-258.result
new file mode 100644
index 00000000000..1b4d4ae0de8
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-258.result
@@ -0,0 +1,34 @@
+CREATE TABLE t1 (f1 INTEGER);
+LOCK TABLE t1 WRITE;
+value prior to RSU:
+SHOW STATUS LIKE 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 0
+SHOW VARIABLES LIKE 'wsrep_desync';
+Variable_name Value
+wsrep_desync OFF
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_osu_method = RSU;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_osu_method = RSU;
+ALTER TABLE t1 ADD COLUMN f3 INTEGER;;
+value during RSU:
+SHOW STATUS LIKE 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 2
+SHOW VARIABLES LIKE 'wsrep_desync';
+Variable_name Value
+wsrep_desync OFF
+UNLOCK TABLES;
+value after RSU:
+SHOW STATUS LIKE 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 0
+SHOW VARIABLES LIKE 'wsrep_desync';
+Variable_name Value
+wsrep_desync OFF
+SET GLOBAL wsrep_desync=0;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-259.result b/mysql-test/suite/galera/r/MW-259.result
new file mode 100644
index 00000000000..df76e959de5
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-259.result
@@ -0,0 +1,12 @@
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+SET GLOBAL wsrep_desync=0;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+SET wsrep_OSU_method=RSU;
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET GLOBAL wsrep_desync=1;;
+SET DEBUG_SYNC= 'now SIGNAL continue';
+DROP TABLE t1;
+SET GLOBAL wsrep_desync=0;
+SET DEBUG_SYNC= 'RESET';
diff --git a/mysql-test/suite/galera/r/MW-284.result b/mysql-test/suite/galera/r/MW-284.result
new file mode 100644
index 00000000000..3ff131674ea
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-284.result
@@ -0,0 +1,14 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+SET SESSION wsrep_on = OFF;
+SET SESSION wsrep_on = ON;
+START SLAVE;
+include/wait_for_slave_param.inc [Slave_IO_Running]
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+include/wait_for_slave_to_start.inc
+INSERT INTO t1 VALUES (1);
+DROP TABLE t1;
+STOP SLAVE;
+RESET SLAVE ALL;
+CALL mtr.add_suppression('failed registering on master');
+CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
diff --git a/mysql-test/suite/galera/r/MW-285.result b/mysql-test/suite/galera/r/MW-285.result
new file mode 100644
index 00000000000..8c5a21fcbee
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-285.result
@@ -0,0 +1,19 @@
+CREATE TABLE parent1 ( id INT PRIMARY KEY, KEY (id) ) ENGINE=InnoDB;
+CREATE TABLE parent2 ( id INT PRIMARY KEY, KEY (id) ) ENGINE=InnoDB;
+CREATE TABLE child (
+id INT PRIMARY KEY,
+parent1_id INT,
+parent2_id INT,
+FOREIGN KEY (parent1_id) REFERENCES parent1(id),
+FOREIGN KEY (parent1_id) REFERENCES parent2(id)
+) ENGINE=InnoDB;
+INSERT INTO parent1 VALUES (1);
+INSERT INTO parent2 VALUES (1);
+INSERT INTO child VALUES (1,1,1);
+INSERT INTO child VALUES (2,1,1);
+SET foreign_key_checks=OFF;
+DROP TABLE parent1;
+UPDATE child SET parent1_id=2 WHERE id=1;
+DROP TABLE child;
+DROP TABLE parent2;
+SET foreign_key_checks=ON;
diff --git a/mysql-test/suite/galera/r/MW-286.result b/mysql-test/suite/galera/r/MW-286.result
new file mode 100644
index 00000000000..adc996c1cbe
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-286.result
@@ -0,0 +1,13 @@
+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_desync = TRUE;
+SET wsrep_on = FALSE;
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+ERROR 70100: Query execution was interrupted
+SET wsrep_on = TRUE;
+SET GLOBAL wsrep_desync = FALSE;
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera/r/MW-292.result b/mysql-test/suite/galera/r/MW-292.result
new file mode 100644
index 00000000000..f038f880efa
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-292.result
@@ -0,0 +1,30 @@
+CREATE TABLE rand_table (f1 FLOAT);
+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,commit_monitor_enter_sync';
+COMMIT;;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
+SELECT TIMEDIFF(SYSDATE(), NOW()) < 2;
+TIMEDIFF(SYSDATE(), NOW()) < 2
+1
+INSERT INTO rand_table VALUES (RAND()),(RAND()),(RAND()),(RAND()),(RAND());
+INSERT INTO rand_table VALUES (RAND()),(RAND()),(RAND()),(RAND()),(RAND());
+SELECT COUNT(DISTINCT f1) = 10 FROM rand_table;
+COUNT(DISTINCT f1) = 10
+1
+wsrep_local_replays
+1
+DROP TABLE t1;
+DROP TABLE rand_table;
diff --git a/mysql-test/suite/galera/r/MW-309.result b/mysql-test/suite/galera/r/MW-309.result
new file mode 100644
index 00000000000..3dd49a041ee
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-309.result
@@ -0,0 +1,22 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+SET GLOBAL wsrep_max_ws_rows = 2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 GROUP BY f1;
+f1
+1
+SELECT * FROM t1 GROUP BY f1;
+f1
+1
+SELECT * FROM t1 GROUP BY f1;
+f1
+1
+SHOW STATUS LIKE '%wsrep%';
+SET GLOBAL wsrep_max_ws_rows = 0;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-313.result b/mysql-test/suite/galera/r/MW-313.result
new file mode 100644
index 00000000000..dc605ffc370
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-313.result
@@ -0,0 +1,32 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+SET GLOBAL wsrep_max_ws_rows = 2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 GROUP BY f1;
+f1
+1
+SELECT * FROM t1 GROUP BY f1;
+f1
+1
+SELECT * FROM t1 GROUP BY f1;
+f1
+1
+SHOW STATUS LIKE '%wsrep%';
+INSERT INTO t1 SELECT * FROM t1;
+ERROR HY000: wsrep_max_ws_rows exceeded
+START TRANSACTION;
+INSERT INTO t1 (f1) VALUES (1);
+INSERT INTO t1 (f1) VALUES (2),(3),(4);
+ERROR HY000: wsrep_max_ws_rows exceeded
+ROLLBACK;
+START TRANSACTION;
+DELETE FROM t1;
+ERROR HY000: wsrep_max_ws_rows exceeded
+DROP TABLE t1;
+SET GLOBAL wsrep_max_ws_rows = 0;
diff --git a/mysql-test/suite/galera/r/MW-328A.result b/mysql-test/suite/galera/r/MW-328A.result
new file mode 100644
index 00000000000..daed2469f11
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-328A.result
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+CALL proc_update();;
+SET SESSION wsrep_retry_autocommit = 0;
+have_successes
+1
+have_deadlocks
+1
+Got one of the listed errors
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-test/suite/galera/r/MW-328B.result b/mysql-test/suite/galera/r/MW-328B.result
new file mode 100644
index 00000000000..780988938f6
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-328B.result
@@ -0,0 +1,17 @@
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+CALL proc_update();;
+SET SESSION wsrep_retry_autocommit = 0;
+Got one of the listed errors
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-test/suite/galera/r/MW-328C.result b/mysql-test/suite/galera/r/MW-328C.result
new file mode 100644
index 00000000000..5cd74f05171
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-328C.result
@@ -0,0 +1,17 @@
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+CALL proc_update();;
+SET SESSION wsrep_retry_autocommit = 10000;
+Got one of the listed errors
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-test/suite/galera/r/MW-328D.result b/mysql-test/suite/galera/r/MW-328D.result
new file mode 100644
index 00000000000..f6d055def93
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-328D.result
@@ -0,0 +1,15 @@
+CREATE TABLE t1 (i INT) ENGINE = InnoDB;
+INSERT INTO t1 (i) VALUES(1);
+CREATE TABLE t2 (i INT) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 WHERE i = 1 LOCK IN SHARE MODE;
+i
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT IGNORE INTO t2 SELECT * FROM t1 WHERE i = 1 FOR UPDATE;;
+DELETE FROM t1 WHERE i = 1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera/r/MW-328E.result b/mysql-test/suite/galera/r/MW-328E.result
new file mode 100644
index 00000000000..5829559fa4d
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-328E.result
@@ -0,0 +1,15 @@
+create table t1 (i int primary key, j int) engine=innodb;
+create table t2 (i int primary key, j int) engine=innodb;
+insert into t1 values (1,0);
+insert into t2 values (2,0);
+set autocommit=off;
+start transaction;
+update t1 set j=1 where i=1;
+set autocommit=off;
+start transaction;
+begin;
+update t2 set j=1 where i=2;
+insert into t1 select * from t2;;
+insert into t2 select * from t1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera/r/MW-329.result b/mysql-test/suite/galera/r/MW-329.result
new file mode 100644
index 00000000000..a79ba598d69
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-329.result
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (f1 INTEGER, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1),(65535);
+FLUSH STATUS;
+SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+VARIABLE_VALUE = 0
+1
+CREATE PROCEDURE proc_insert ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f1) VALUES (FLOOR( 1 + RAND( ) * 65535 ));
+END WHILE;
+END|
+CALL proc_insert();;
+SELECT VARIABLE_VALUE > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+VARIABLE_VALUE > 0
+1
+DROP PROCEDURE proc_insert;
+DROP TABLE t1;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-test/suite/galera/r/MW-336.result b/mysql-test/suite/galera/r/MW-336.result
new file mode 100644
index 00000000000..9bdb61c1a9c
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-336.result
@@ -0,0 +1,42 @@
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+SET GLOBAL wsrep_slave_threads = 10;
+SET GLOBAL wsrep_slave_threads = 1;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_slave_threads = 10;
+SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+COUNT(*) = 11
+1
+SET GLOBAL wsrep_slave_threads = 20;
+SELECT COUNT(*) = 21 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+COUNT(*) = 21
+1
+SET GLOBAL wsrep_slave_threads = 1;
+INSERT INTO t1 VALUES (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);
+SET GLOBAL wsrep_slave_threads = 10;
+SET GLOBAL wsrep_slave_threads = 0;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_slave_threads value: '0'
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+INSERT INTO t1 VALUES (16);
+INSERT INTO t1 VALUES (17);
+INSERT INTO t1 VALUES (18);
+INSERT INTO t1 VALUES (19);
+INSERT INTO t1 VALUES (20);
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+COUNT(*) = 2
+1
+SET GLOBAL wsrep_slave_threads = 1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-357.result b/mysql-test/suite/galera/r/MW-357.result
new file mode 100644
index 00000000000..d249d5997f7
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-357.result
@@ -0,0 +1,6 @@
+SET GLOBAL wsrep_slave_threads = 0;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_slave_threads value: '0'
+CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
+INSERT INTO t1 VALUES (1);
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-369.result b/mysql-test/suite/galera/r/MW-369.result
new file mode 100644
index 00000000000..516904d1b2a
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-369.result
@@ -0,0 +1,155 @@
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+DELETE FROM p WHERE f1 = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+INSERT INTO c VALUES (1, 1);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+1 0
+2 0
+SELECT * FROM c;
+f1 p_id
+1 1
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE p SET f2 = 1 WHERE f1 = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+UPDATE c SET f2 = 1 WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SELECT * FROM p;
+f1 f2
+1 1
+2 0
+SELECT * FROM c;
+f1 p_id f2
+1 1 1
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE p SET f2 = 1 WHERE f1 = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+DELETE FROM c WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SELECT * FROM p;
+f1 f2
+1 1
+2 0
+SELECT * FROM c;
+f1 p_id
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER UNIQUE KEY) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f2)) ;
+INSERT INTO p VALUES (1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE p SET f2 = 1 WHERE f1 = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+INSERT INTO c VALUES (1, 0);;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+1 0
+SELECT * FROM c;
+f1 p_id
+1 0
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)
+ON DELETE CASCADE) ;
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+DELETE FROM p WHERE f1 = 1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+UPDATE c SET f2 = 1 WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+1 0
+2 0
+SELECT * FROM c;
+f1 p_id f2
+1 1 1
+DROP TABLE c;
+DROP TABLE p;
diff --git a/mysql-test/suite/galera/r/MW-388.result b/mysql-test/suite/galera/r/MW-388.result
new file mode 100644
index 00000000000..17d347a11fb
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-388.result
@@ -0,0 +1,46 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB;
+CREATE PROCEDURE insert_proc ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+BEGIN
+GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;
+END;
+INSERT INTO t1 VALUES (1, 'node 1'),(2, 'node 1');
+INSERT INTO t1 VALUES (3, 'node 1');
+END|
+SET GLOBAL wsrep_slave_threads = 2;
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+INSERT INTO t1 VALUES (1, 'node 2');;
+SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION DEBUG_SYNC = 'wsrep_after_replication SIGNAL wsrep_after_replication_reached WAIT_FOR wsrep_after_replication_continue';
+CALL insert_proc ();;
+SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_replication_reached";
+SET GLOBAL DEBUG = "";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL wsrep_after_replication_continue";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+SELECT @errno = 1213;
+@errno = 1213
+1
+SELECT * FROM t1;
+f1 f2
+1 node 2
+3 node 1
+SELECT * FROM t1;
+f1 f2
+1 node 2
+3 node 1
+SET GLOBAL wsrep_slave_threads = DEFAULT;
+DROP TABLE t1;
+DROP PROCEDURE insert_proc;
+SET GLOBAL debug = NULL;
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET debug_sync='RESET';
+SELECT @@debug_sync;
+@@debug_sync
+ON - current signal: ''
diff --git a/mysql-test/suite/galera/r/MW-402.result b/mysql-test/suite/galera/r/MW-402.result
new file mode 100644
index 00000000000..fdcf6e324b5
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-402.result
@@ -0,0 +1,192 @@
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON DELETE CASCADE);
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE c SET f2=1 where f1=1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+DELETE FROM p WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+2 0
+SELECT * FROM c;
+f1 p_id f2
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE);
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE c SET f2=2 where f1=1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+UPDATE p set f1=11 WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+2 0
+11 0
+SELECT * FROM c;
+f1 p_id f2
+1 11 0
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE);
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE c SET p_id=2 where f1=1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+UPDATE p set f1=11 WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+2 0
+11 0
+SELECT * FROM c;
+f1 p_id f2
+1 11 0
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE p set f1=21 WHERE f1 = 11;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+UPDATE c SET p_id=2 where f1=1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p;
+f1 f2
+2 0
+11 0
+SELECT * FROM c;
+f1 p_id f2
+1 2 0
+DROP TABLE c;
+DROP TABLE p;
+CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ON DELETE CASCADE,
+CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1));
+INSERT INTO p1 VALUES (1, 0);
+INSERT INTO p2 VALUES (1, 0);
+INSERT INTO c VALUES (1, 1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE p2 SET f2=2 where f1=1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+DELETE FROM p1 WHERE f1 = 1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SELECT * FROM p1;
+f1 f2
+SELECT * FROM p2;
+f1 f2
+1 2
+SELECT * FROM c;
+f1 p1_id p2_id f2
+DROP TABLE c;
+DROP TABLE p1;
+DROP TABLE p2;
+CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ON DELETE CASCADE,
+CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
+ON DELETE CASCADE);
+INSERT INTO p1 VALUES (1, 0);
+INSERT INTO p2 VALUES (1, 0);
+INSERT INTO c VALUES (1, 1, 1, 0);
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+DELETE FROM p2 WHERE f1=1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+DELETE FROM p1 WHERE f1=1;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM p1;
+f1 f2
+SELECT * FROM p2;
+f1 f2
+1 0
+SELECT * FROM c;
+f1 p1_id p2_id f2
+DROP TABLE c;
+DROP TABLE p1;
+DROP TABLE p2;
diff --git a/mysql-test/suite/galera/r/MW-416.result b/mysql-test/suite/galera/r/MW-416.result
new file mode 100644
index 00000000000..05399b213a8
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-416.result
@@ -0,0 +1,114 @@
+CREATE USER 'userMW416'@'localhost';
+GRANT SELECT, INSERT, UPDATE ON test.* TO 'userMW416'@'localhost';
+SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
+Variable_name Value
+wsrep_replicated 2
+ALTER DATABASE db CHARACTER SET = utf8;
+ERROR 42000: Access denied for user 'userMW416'@'localhost' to database 'db'
+ALTER EVENT ev1 RENAME TO ev2;
+ERROR 42000: Access denied for user 'userMW416'@'localhost' to database 'test'
+ALTER FUNCTION fun1 COMMENT 'foo';
+ERROR 42000: alter routine command denied to user 'userMW416'@'localhost' for routine 'test.fun1'
+ALTER LOGFILE GROUP lfg ADD UNDOFILE 'file' ENGINE=InnoDB;
+Got one of the listed errors
+ALTER PROCEDURE proc1 COMMENT 'foo';
+Got one of the listed errors
+ALTER SERVER srv OPTIONS (USER 'sally');
+Got one of the listed errors
+ALTER TABLE tbl DROP COLUMN col;
+Got one of the listed errors
+ALTER TABLESPACE tblspc DROP DATAFILE 'file' ENGINE=innodb;
+Got one of the listed errors
+ALTER VIEW vw AS SELECT 1;
+Got one of the listed errors
+CREATE DATABASE db;
+Got one of the listed errors
+CREATE EVENT ev1 ON SCHEDULE AT CURRENT_TIMESTAMP DO SELECT 1;
+Got one of the listed errors
+CREATE FUNCTION fun1() RETURNS int RETURN(1);
+Got one of the listed errors
+CREATE FUNCTION fun1 RETURNS STRING SONAME 'funlib.so';
+Got one of the listed errors
+CREATE PROCEDURE proc1() BEGIN END;
+Got one of the listed errors
+CREATE INDEX idx ON tbl(id);
+Got one of the listed errors
+CREATE LOGFILE GROUP lfg ADD UNDOFILE 'undofile' ENGINE innodb;
+Got one of the listed errors
+CREATE SERVER srv FOREIGN DATA WRAPPER 'fdw' OPTIONS (USER 'user');
+Got one of the listed errors
+CREATE TABLE t (i int);
+Got one of the listed errors
+CREATE TABLESPACE tblspc ADD DATAFILE 'file' ENGINE=innodb;
+Got one of the listed errors
+CREATE TRIGGER trg BEFORE UPDATE ON t FOR EACH ROW BEGIN END;
+Got one of the listed errors
+CREATE VIEW vw AS SELECT 1;
+Got one of the listed errors
+DROP DATABASE db;
+Got one of the listed errors
+DROP EVENT ev;
+Got one of the listed errors
+DROP FUNCTION fun1;
+Got one of the listed errors
+DROP INDEX idx ON t0;
+Got one of the listed errors
+DROP LOGFILE GROUP lfg;
+Got one of the listed errors
+DROP PROCEDURE proc1;
+Got one of the listed errors
+DROP SERVEr srv;
+Got one of the listed errors
+DROP TABLE t0;
+Got one of the listed errors
+DROP TABLESPACE tblspc;
+Got one of the listed errors
+DROP TRIGGER trg;
+Got one of the listed errors
+DROP VIEW vw;
+Got one of the listed errors
+RENAME TABLE t0 TO t1;
+Got one of the listed errors
+TRUNCATE TABLE t0;
+Got one of the listed errors
+ALTER USER myuser PASSWORD EXPIRE;
+Got one of the listed errors
+CREATE USER myuser IDENTIFIED BY 'pass';
+Got one of the listed errors
+DROP USER myuser;
+Got one of the listed errors
+GRANT ALL ON *.* TO 'myuser';
+Got one of the listed errors
+RENAME USER myuser TO mariauser;
+Got one of the listed errors
+REVOKE SELECT ON test FROM myuser;
+Got one of the listed errors
+REVOKE ALL, GRANT OPTION FROM myuser;
+Got one of the listed errors
+REVOKE PROXY ON myuser FROM myuser;
+Got one of the listed errors
+ANALYZE TABLE db.tbl;
+Got one of the listed errors
+CHECK TABLE db.tbl;
+Got one of the listed errors
+CHECKSUM TABLE db.tbl;
+Got one of the listed errors
+OPTIMIZE TABLE db.tbl;
+Got one of the listed errors
+REPAIR TABLE db.tbl;
+Got one of the listed errors
+INSTALL PLUGIN plg SONAME 'plg.so';
+Got one of the listed errors
+UNINSTALL PLUGIN plg;
+Got one of the listed errors
+DROP USER 'userMW416'@'localhost';
+SHOW DATABASES;
+Database
+information_schema
+mtr
+mysql
+performance_schema
+test
+SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
+Variable_name Value
+wsrep_replicated 3
diff --git a/mysql-test/suite/galera/r/MW-44.result b/mysql-test/suite/galera/r/MW-44.result
new file mode 100644
index 00000000000..28a6f1ac8dd
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-44.result
@@ -0,0 +1,14 @@
+TRUNCATE TABLE mysql.general_log;
+TRUNCATE TABLE mysql.general_log;
+SET SESSION wsrep_osu_method=TOI;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_osu_method=RSU;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+SET SESSION wsrep_osu_method=TOI;
+SELECT COUNT(*) = 2 FROM mysql.general_log WHERE argument LIKE 'CREATE%' OR argument LIKE 'ALTER%';
+COUNT(*) = 2
+1
+SELECT COUNT(*) = 0 FROM mysql.general_log WHERE argument NOT LIKE 'SELECT%';
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-86-wait1.result b/mysql-test/suite/galera/r/MW-86-wait1.result
new file mode 100644
index 00000000000..a38255eff8f
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-86-wait1.result
@@ -0,0 +1,48 @@
+SELECT @@debug_sync;
+@@debug_sync
+ON - current signal: ''
+SET SESSION wsrep_sync_wait = 1;
+SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+CREATE TABLE t_wait1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t_wait1 VALUES (1);
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SHOW BINARY LOGS;
+SHOW BINLOG EVENTS;
+SHOW COLUMNS FROM t1;
+SHOW CREATE EVENT e1;
+SHOW CREATE FUNCTION f1;
+SHOW CREATE PROCEDURE p1;
+SHOW CREATE TABLE t1;
+SHOW CREATE TRIGGER tr1;
+SHOW CREATE VIEW v1;
+SHOW DATABASES;
+SHOW ENGINE InnoDB STATUS;
+SHOW FUNCTION CODE f1;
+SHOW FUNCTION STATUS;
+SHOW GRANTS FOR 'root'@'localhost';
+SHOW INDEX FROM t1;
+SHOW OPEN TABLES;
+SHOW PROCEDURE CODE p1;
+SHOW PROCEDURE STATUS;
+SHOW PRIVILEGES;
+SHOW STATUS LIKE 'wsrep_cluster_size';
+SHOW TABLE STATUS;
+SHOW TABLES;
+SHOW TRIGGERS;
+SHOW GLOBAL VARIABLES LIKE 'foo_bar';
+SHOW WARNINGS;
+SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET SESSION debug_sync = "now SIGNAL signal.wsrep_apply_cb";
+SET SESSION wsrep_sync_wait = default;
+DROP TABLE t_wait1;
+SET GLOBAL debug = NULL;
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET debug_sync='RESET';
+SELECT @@debug_sync;
+@@debug_sync
+ON - current signal: ''
diff --git a/mysql-test/suite/galera/r/MW-86-wait8.result b/mysql-test/suite/galera/r/MW-86-wait8.result
new file mode 100644
index 00000000000..04c93e9a9f2
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-86-wait8.result
@@ -0,0 +1,50 @@
+SELECT @@debug_sync;
+@@debug_sync
+ON - current signal: ''
+SET SESSION wsrep_sync_wait = 8;
+SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+CREATE TABLE t_wait8 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t_wait8 VALUES (1);
+SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT0.1S";
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SHOW BINARY LOGS;
+SHOW BINLOG EVENTS;
+SHOW COLUMNS FROM t1;
+SHOW CREATE DATABASE db1;
+SHOW CREATE EVENT e1;
+SHOW CREATE FUNCTION f1;
+SHOW CREATE PROCEDURE p1;
+SHOW CREATE TABLE t1;
+SHOW CREATE TRIGGER tr1;
+SHOW CREATE VIEW v1;
+SHOW DATABASES;
+SHOW ENGINE InnoDB STATUS;
+SHOW FUNCTION CODE f1;
+SHOW FUNCTION STATUS;
+SHOW GRANTS FOR 'root'@'localhost';
+SHOW INDEX FROM t1;
+SHOW OPEN TABLES;
+SHOW PROCEDURE CODE p1;
+SHOW PROCEDURE STATUS;
+SHOW PRIVILEGES;
+SHOW STATUS LIKE 'wsrep_cluster_size';
+SHOW TABLE STATUS;
+SHOW TABLES;
+SHOW TRIGGERS;
+SHOW GLOBAL VARIABLES LIKE 'foo_bar';
+SHOW WARNINGS;
+SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+SET SESSION wsrep_sync_wait = default;
+DROP TABLE t_wait8;
+SET GLOBAL debug = NULL;
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET debug_sync='RESET';
+SELECT @@debug_sync;
+@@debug_sync
+ON - current signal: ''
diff --git a/mysql-test/suite/galera/r/basic.result b/mysql-test/suite/galera/r/basic.result
new file mode 100644
index 00000000000..d4efe348b61
--- /dev/null
+++ b/mysql-test/suite/galera/r/basic.result
@@ -0,0 +1,30 @@
+USE test;
+CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+SELECT * FROM t1;
+c1
+1
+2
+3
+4
+5
+
+# On node_1
+SELECT * FROM test.t1;
+c1
+1
+2
+3
+4
+5
+
+# On node_2
+SELECT * FROM test.t1;
+c1
+1
+2
+3
+4
+5
+DROP TABLE t1;
+# End of test
diff --git a/mysql-test/suite/galera/r/binlog_checksum.result b/mysql-test/suite/galera/r/binlog_checksum.result
new file mode 100644
index 00000000000..5c1981fc17f
--- /dev/null
+++ b/mysql-test/suite/galera/r/binlog_checksum.result
@@ -0,0 +1,36 @@
+# On node_1
+SET @binlog_checksum_saved= @@GLOBAL.BINLOG_CHECKSUM;
+SET @@GLOBAL.BINLOG_CHECKSUM=CRC32;
+# On node_2
+SET @binlog_checksum_saved= @@GLOBAL.BINLOG_CHECKSUM;
+SET @@GLOBAL.BINLOG_CHECKSUM=CRC32;
+USE test;
+CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+SELECT * FROM t1;
+c1
+1
+2
+3
+4
+5
+SELECT * FROM test.t1;
+c1
+1
+2
+3
+4
+5
+
+# On node_2
+SELECT * FROM test.t1;
+c1
+1
+2
+3
+4
+5
+DROP TABLE t1;
+SET @@GLOBAL.BINLOG_CHECKSUM = @binlog_checksum_saved;
+SET @@GLOBAL.BINLOG_CHECKSUM = @binlog_checksum_saved;
+# End of test
diff --git a/mysql-test/suite/galera/r/create.result b/mysql-test/suite/galera/r/create.result
new file mode 100644
index 00000000000..d32a0378eb6
--- /dev/null
+++ b/mysql-test/suite/galera/r/create.result
@@ -0,0 +1,59 @@
+#
+# MDEV-6924 : Server crashed on CREATE TABLE ... SELECT
+#
+SET @wsrep_forced_binlog_format_saved=@@GLOBAL.wsrep_forced_binlog_format;
+SET @@GLOBAL.wsrep_forced_binlog_format=STATEMENT;
+SHOW VARIABLES LIKE '%log%bin%';
+Variable_name Value
+log_bin OFF
+log_bin_trust_function_creators ON
+sql_log_bin ON
+USE test;
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+CREATE TEMPORARY TABLE `t1_temp` AS SELECT * FROM `t1` WHERE i = 1;
+SELECT * FROM t1;
+i
+1
+SELECT * FROM t1_temp;
+i
+1
+DROP TABLE t1;
+SET @@GLOBAL.wsrep_forced_binlog_format=@wsrep_forced_binlog_format_saved;
+#
+# MDEV-7673: CREATE TABLE SELECT fails on Galera cluster
+#
+CREATE TABLE t1 (i INT) ENGINE=INNODB DEFAULT CHARSET=utf8 SELECT 1 as i;
+SELECT * FROM t1;
+i
+1
+SELECT * FROM t1;
+i
+1
+DROP TABLE t1;
+#
+# MDEV-8166 : Adding index on new table from select crashes Galera
+# cluster
+#
+CREATE TABLE t1(i int(11) NOT NULL DEFAULT '0') ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO t1(i) VALUES (1), (2), (3);
+CREATE TABLE t2 (i INT) SELECT i FROM t1;
+ALTER TABLE t2 ADD INDEX idx(i);
+SELECT * FROM t2;
+i
+1
+2
+3
+SELECT * FROM t2;
+i
+1
+2
+3
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `i` int(11) DEFAULT NULL,
+ KEY `idx` (`i`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1, t2;
+# End of tests
diff --git a/mysql-test/suite/galera/r/ev51914.result b/mysql-test/suite/galera/r/ev51914.result
new file mode 100644
index 00000000000..4b9f7ace0da
--- /dev/null
+++ b/mysql-test/suite/galera/r/ev51914.result
@@ -0,0 +1,162 @@
+SAVEPOINT in a stored function should be forbidden
+CREATE FUNCTION f1 () RETURNS INT BEGIN
+SAVEPOINT s;
+RETURN 1;
+END|
+SELECT f1();
+f1()
+1
+DROP FUNCTION f1;
+ROLLBACK TO SAVEPOINT in a stored function should be forbidden
+CREATE FUNCTION f2 () RETURNS INT BEGIN
+ROLLBACK TO SAVEPOINT s;
+RETURN 1;
+END|
+BEGIN;
+SAVEPOINT s;
+SELECT f2();
+ERROR 42000: SAVEPOINT s does not exist
+COMMIT;
+DROP FUNCTION f2;
+BEGIN;
+SAVEPOINT S;
+ROLLBACK TO SAVEPOINT S;
+COMMIT;
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+INSERT INTO t1 values (110), (111), (112), (113), (114);
+Direct SAVEPOINT in a trigger should be forbidden
+CREATE TRIGGER i1_t1 BEFORE INSERT ON t1 FOR EACH ROW SAVEPOINT s;
+INSERT INTO t1 VALUES (1);
+DROP TRIGGER i1_t1;
+CREATE TRIGGER i2_t1 AFTER INSERT ON t1 FOR EACH ROW SAVEPOINT s;
+INSERT INTO t1 VALUES (2);
+DROP TRIGGER i2_t1;
+INSERT INTO t1 VALUES (3);
+CREATE TRIGGER u1_t1 BEFORE UPDATE ON t1 FOR EACH ROW SAVEPOINT s;
+UPDATE t1 SET a=4 WHERE a=3;
+DROP TRIGGER u1_t1;
+CREATE TRIGGER u2_t1 AFTER UPDATE ON t1 FOR EACH ROW SAVEPOINT s;
+UPDATE t1 SET a=4 WHERE a=3;
+DROP TRIGGER u2_t1;
+CREATE TRIGGER d1_t1 BEFORE DELETE ON t1 FOR EACH ROW SAVEPOINT s;
+DELETE FROM t1;
+DROP TRIGGER d1_t1;
+CREATE TRIGGER d1_t1 AFTER DELETE ON t1 FOR EACH ROW SAVEPOINT s;
+DELETE FROM t1;
+DROP TRIGGER d1_t1;
+SAVEPOINT in a compound statement in a trigger should be forbidden
+CREATE TRIGGER i3_t1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
+SAVEPOINT s;
+END|
+INSERT INTO t1 VALUES (5);
+DROP TRIGGER i3_t1;
+SAVEPOINT in a PS call in a trigger should be forbidden
+CREATE TRIGGER i4_t1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
+PREPARE set_savepoint FROM "SAVEPOINT s";
+EXECUTE set_savepoint;
+DEALLOCATE PREPARE set_savepoint;
+END|
+ERROR 0A000: Dynamic SQL is not allowed in stored function or trigger
+SAVEPOINT in SP called from a trigger should be forbidden
+CREATE PROCEDURE p1() BEGIN
+SAVEPOINT s;
+END|
+CREATE TRIGGER i5_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p1;
+INSERT INTO t1 VALUES (6);
+DROP TRIGGER i5_t1;
+SAVEPOINT in a SP called from a PS called from a trigger be forbidden
+PREPARE call_p1 FROM "CALL p1";
+CREATE TRIGGER i6_t1 BEFORE INSERT ON t1 FOR EACH ROW EXECUTE call_p1;
+ERROR 0A000: Dynamic SQL is not allowed in stored function or trigger
+SAVEPOINT in a function called from a trigger should be forbidden
+CREATE FUNCTION f1 () RETURNS INT BEGIN
+SAVEPOINT s;
+RETURN 1;
+END|
+CREATE TRIGGER i7_t1 BEFORE INSERT ON t1 FOR EACH ROW SET @foo = f1();
+INSERT INTO t1 VALUES (7);
+DROP TRIGGER i7_t1;
+SAVEPOINT in a SP called from a SP called from a trigger should be forbidden
+CREATE PROCEDURE p2() BEGIN
+CALL p1();
+END|
+CREATE TRIGGER i8_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p2;
+INSERT INTO t1 VALUES (8);
+DROP TRIGGER i8_t1;
+SAVEPOINT in a SP called from a trigger called from a SP should be forbidden
+CREATE TRIGGER i9_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p1;
+CREATE PROCEDURE p3() BEGIN
+INSERT INTO t1 VALUES (9);
+END|
+CALL p3();
+DROP TRIGGER i9_t1;
+ROLLBACK TO SAVEPOINT in trigger as a trivial statement should be forbidden
+CREATE TRIGGER i4_t1 BEFORE INSERT ON t1 FOR EACH ROW ROLLBACK TO SAVEPOINT s;
+BEGIN;
+SAVEPOINT s;
+INSERT INTO t1 VALUES (5);
+ERROR 42000: SAVEPOINT s does not exist
+COMMIT;
+DROP TRIGGER i4_t1;
+ROLLBACK TO SAVEPOINT in a trigger in a SP call should be forbidden
+CREATE PROCEDURE p4() BEGIN
+ROLLBACK TO SAVEPOINT s;
+END|
+CREATE TRIGGER i5_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p4;
+BEGIN;
+SAVEPOINT s;
+INSERT INTO t1 VALUES (6);
+ERROR 42000: SAVEPOINT s does not exist
+COMMIT;
+DROP TRIGGER i5_t1;
+SAVEPOINT in a SP next to a trigger should work
+CREATE TRIGGER i6_t1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a = NEW.a + 1;
+CREATE PROCEDURE p5() BEGIN
+SAVEPOINT s;
+INSERT INTO t1 VALUES (10);
+ROLLBACK TO SAVEPOINT s;
+END|
+BEGIN;
+CALL p5();
+COMMIT;
+DROP TRIGGER i6_t1;
+create trigger t1 before insert on t1 for each row
+begin
+insert into t2 values (NULL);
+end|
+INSERT INTO t1 VALUES (201), (202), (203);
+SELECT * FROM t1;
+a
+5
+6
+7
+8
+9
+201
+202
+203
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+3
+SELECT * FROM t1;
+a
+5
+6
+7
+8
+9
+201
+202
+203
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+3
+DEALLOCATE PREPARE call_p1;
+DROP TABLE t1, t2;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP FUNCTION f1;
diff --git a/mysql-test/suite/galera/r/fk.result b/mysql-test/suite/galera/r/fk.result
new file mode 100644
index 00000000000..d6a3a25b01a
--- /dev/null
+++ b/mysql-test/suite/galera/r/fk.result
@@ -0,0 +1,96 @@
+USE test;
+
+# On node_1
+CREATE TABLE networks (
+`tenant_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+`id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+`status` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
+`admin_state_up` tinyint(1) DEFAULT NULL,
+`shared` tinyint(1) DEFAULT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+CREATE TABLE ports (
+`tenant_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+`id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+`network_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+`mac_address` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
+`admin_state_up` tinyint(1) NOT NULL,
+`status` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
+`device_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+`device_owner` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+PRIMARY KEY (`id`),
+KEY `network_id` (`network_id`),
+CONSTRAINT `ports_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES networks (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+CREATE TABLE subnets (
+`tenant_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+`id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+`network_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL,
+`ip_version` int(11) NOT NULL,
+`cidr` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
+`gateway_ip` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
+`enable_dhcp` tinyint(1) DEFAULT NULL,
+`shared` tinyint(1) DEFAULT NULL,
+`ipv6_ra_mode` enum('slaac','dhcpv6-stateful','dhcpv6-stateless') COLLATE utf8_unicode_ci DEFAULT NULL,
+`ipv6_address_mode` enum('slaac','dhcpv6-stateful','dhcpv6-stateless') COLLATE utf8_unicode_ci DEFAULT NULL,
+PRIMARY KEY (`id`),
+KEY `network_id` (`network_id`),
+CONSTRAINT `subnets_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES networks (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+CREATE TABLE `ipallocations` (
+`port_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL,
+`ip_address` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
+`subnet_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+`network_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+PRIMARY KEY (`ip_address`,`subnet_id`,`network_id`),
+KEY `port_id` (`port_id`),
+KEY `subnet_id` (`subnet_id`),
+KEY `network_id` (`network_id`),
+CONSTRAINT `ipallocations_ibfk_1` FOREIGN KEY (`port_id`) REFERENCES `ports` (`id`) ON DELETE CASCADE,
+CONSTRAINT `ipallocations_ibfk_2` FOREIGN KEY (`subnet_id`) REFERENCES `subnets` (`id`) ON DELETE CASCADE,
+CONSTRAINT `ipallocations_ibfk_3` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+INSERT INTO networks VALUES ('f37aa3fe-ab99-4d0f-a566-6cd3169d7516','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','MyNet','ACTIVE',0,0);
+INSERT INTO ports VALUES ('','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','fa:16:3e:e3:cc:bb',1,'DOWN','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','network:router_gateway');
+INSERT INTO subnets VALUES ('f37aa3fe-ab99-4d0f-a566-6cd3169d7516','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','ext-subnet','f37aa3fe-ab99-4d0f-a566-6cd3169d7516',4,'10.25.0.0/24','10.25.0.4',0,1,NULL,NULL);
+INSERT INTO ipallocations VALUES ('f37aa3fe-ab99-4d0f-a566-6cd3169d7516','10.25.0.17','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','f37aa3fe-ab99-4d0f-a566-6cd3169d7516');
+select * from ports where ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516';
+tenant_id id name network_id mac_address admin_state_up status device_id device_owner
+ f37aa3fe-ab99-4d0f-a566-6cd3169d7516 f37aa3fe-ab99-4d0f-a566-6cd3169d7516 fa:16:3e:e3:cc:bb 1 DOWN f37aa3fe-ab99-4d0f-a566-6cd3169d7516 network:router_gateway
+select * from ports where ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516';
+tenant_id id name network_id mac_address admin_state_up status device_id device_owner
+ f37aa3fe-ab99-4d0f-a566-6cd3169d7516 f37aa3fe-ab99-4d0f-a566-6cd3169d7516 fa:16:3e:e3:cc:bb 1 DOWN f37aa3fe-ab99-4d0f-a566-6cd3169d7516 network:router_gateway
+DELETE FROM ports WHERE ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516';
+select * from networks;
+tenant_id id name status admin_state_up shared
+f37aa3fe-ab99-4d0f-a566-6cd3169d7516 f37aa3fe-ab99-4d0f-a566-6cd3169d7516 MyNet ACTIVE 0 0
+select * from ports;
+tenant_id id name network_id mac_address admin_state_up status device_id device_owner
+select * from subnets;
+tenant_id id name network_id ip_version cidr gateway_ip enable_dhcp shared ipv6_ra_mode ipv6_address_mode
+f37aa3fe-ab99-4d0f-a566-6cd3169d7516 f37aa3fe-ab99-4d0f-a566-6cd3169d7516 ext-subnet f37aa3fe-ab99-4d0f-a566-6cd3169d7516 4 10.25.0.0/24 10.25.0.4 0 1 NULL NULL
+select * from ipallocations;
+port_id ip_address subnet_id network_id
+select * from ports;
+tenant_id id name network_id mac_address admin_state_up status device_id device_owner
+
+# On node_2
+select * from networks;
+tenant_id id name status admin_state_up shared
+f37aa3fe-ab99-4d0f-a566-6cd3169d7516 f37aa3fe-ab99-4d0f-a566-6cd3169d7516 MyNet ACTIVE 0 0
+select * from ports;
+tenant_id id name network_id mac_address admin_state_up status device_id device_owner
+select * from subnets;
+tenant_id id name network_id ip_version cidr gateway_ip enable_dhcp shared ipv6_ra_mode ipv6_address_mode
+f37aa3fe-ab99-4d0f-a566-6cd3169d7516 f37aa3fe-ab99-4d0f-a566-6cd3169d7516 ext-subnet f37aa3fe-ab99-4d0f-a566-6cd3169d7516 4 10.25.0.0/24 10.25.0.4 0 1 NULL NULL
+select * from ipallocations;
+port_id ip_address subnet_id network_id
+select * from ports;
+tenant_id id name network_id mac_address admin_state_up status device_id device_owner
+drop table ipallocations;
+drop table subnets;
+drop table ports;
+drop table networks;
diff --git a/mysql-test/suite/galera/r/galera#414.result b/mysql-test/suite/galera/r/galera#414.result
new file mode 100644
index 00000000000..5bb22587241
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera#414.result
@@ -0,0 +1,7 @@
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = OFF;
+SET SESSION wsrep_on = ON;
+CALL mtr.add_suppression("Failed to set packet size");
+set GLOBAL auto_increment_offset = 1;
+CALL mtr.add_suppression("Failed to set packet size");
+set GLOBAL auto_increment_offset = 2;
diff --git a/mysql-test/suite/galera/r/galera#500.result b/mysql-test/suite/galera/r/galera#500.result
new file mode 100644
index 00000000000..6a07d0359a4
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera#500.result
@@ -0,0 +1,10 @@
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options="gmcast.isolate=2";
+SET SESSION wsrep_sync_wait = 0;
+SHOW STATUS LIKE 'wsrep_cluster_status';
+Variable_name Value
+wsrep_cluster_status non-Primary
+SET SESSION wsrep_sync_wait = default;
+SET GLOBAL wsrep_provider_options="pc.bootstrap=1";
+SET SESSION wsrep_on=0;
+CALL mtr.add_suppression("WSREP: exception from gcomm, backend must be restarted: Gcomm backend termination was requested by setting gmcast.isolate=2.");
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 00000000000..4fa33a63064
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_account_management.result
@@ -0,0 +1,47 @@
+CREATE USER user1, user2 IDENTIFIED BY 'password';
+SELECT COUNT(*) = 2 FROM mysql.user WHERE user IN ('user1', 'user2');
+COUNT(*) = 2
+1
+ALTER USER user1 PASSWORD EXPIRE;
+SELECT password_expired = 'Y' FROM mysql.user WHERE user = 'user1';
+password_expired = 'Y'
+1
+SELECT password_expired = 'Y' FROM mysql.user WHERE user = 'user1';
+password_expired = 'Y'
+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_admin.result b/mysql-test/suite/galera/r/galera_admin.result
new file mode 100644
index 00000000000..e58b0a5e310
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_admin.result
@@ -0,0 +1,43 @@
+DROP TABLE IF EXISTS t1, t2;
+DROP TABLE IF EXISTS x1, x2;
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
+SET GLOBAL wsrep_replicate_myisam = TRUE;
+CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE x2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
+INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+# ANALYZE test
+ANALYZE TABLE t1, t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+# OPTIMIZE test
+OPTIMIZE TABLE t1, t2;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t2 optimize status OK
+# REPAIR test
+REPAIR TABLE x1, x2;
+Table Op Msg_type Msg_text
+test.x1 repair status OK
+test.x2 repair status OK
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+SELECT COUNT(*) = 10 FROM x1;
+COUNT(*) = 10
+1
+SELECT COUNT(*) = 10000 FROM t2;
+COUNT(*) = 10000
+1
+SELECT COUNT(*) = 10 FROM x2;
+COUNT(*) = 10
+1
+DROP TABLE t1, t2;
+DROP TABLE x1, x2;
+SET GLOBAL wsrep_replicate_myisam = FALSE;
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 00000000000..2b30ac5814d
--- /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 00000000000..280cb58208c
--- /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 00000000000..401ab46d868
--- /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_applier_ftwrl_table.result b/mysql-test/suite/galera/r/galera_applier_ftwrl_table.result
new file mode 100644
index 00000000000..1b2a3b937bb
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_applier_ftwrl_table.result
@@ -0,0 +1,15 @@
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+FLUSH TABLE t1 WITH READ LOCK;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+UNLOCK TABLES;
+SET SESSION wsrep_sync_wait = 15;
+SELECT COUNT(*) = 2 FROM t1;
+COUNT(*) = 2
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result b/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result
new file mode 100644
index 00000000000..c30f78896e5
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result
@@ -0,0 +1,26 @@
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION lock_wait_timeout = 60;
+SET SESSION innodb_lock_wait_timeout=60;
+SET SESSION wait_timeout=60;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+FLUSH TABLE t1 WITH READ LOCK;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+SELECT 1 FROM DUAL;
+1
+1
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock';
+COUNT(*) = 1
+1
+UNLOCK TABLES;
+SET SESSION wsrep_sync_wait = 15;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) NOT NULL,
+ `f2` int(11) DEFAULT NULL,
+ PRIMARY KEY (`f1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock';
+COUNT(*) = 0
+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 00000000000..bd7d63ad1ab
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_master.result
@@ -0,0 +1,8 @@
+START SLAVE;
+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;
+CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
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 00000000000..8dfe462d495
--- /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 00000000000..80fbccf58e2
--- /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 00000000000..2d7d689aa36
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave.result
@@ -0,0 +1,15 @@
+START SLAVE;
+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;
+RESET MASTER;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_autoinc.result b/mysql-test/suite/galera/r/galera_as_slave_autoinc.result
new file mode 100644
index 00000000000..3c5319a6126
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_autoinc.result
@@ -0,0 +1,80 @@
+START SLAVE;
+SET SESSION binlog_format='STATEMENT';
+CREATE TABLE t1 (
+i int(11) NOT NULL AUTO_INCREMENT,
+c char(32) DEFAULT 'dummy_text',
+PRIMARY KEY (i)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+insert into t1(i) values(null);
+select * from t1;
+i c
+1 dummy_text
+insert into t1(i) values(null), (null), (null);
+select * from t1;
+i c
+1 dummy_text
+2 dummy_text
+3 dummy_text
+4 dummy_text
+SET SESSION auto_increment_increment=7;
+insert into t1(i) values(null), (null), (null);
+SET SESSION auto_increment_offset=5;
+insert into t1(i) values(null), (null), (null);
+select * from t1;
+i c
+1 dummy_text
+2 dummy_text
+3 dummy_text
+4 dummy_text
+8 dummy_text
+15 dummy_text
+22 dummy_text
+33 dummy_text
+40 dummy_text
+47 dummy_text
+show variables like 'binlog_format';
+Variable_name Value
+binlog_format STATEMENT
+show variables like 'auto_increment_increment';
+Variable_name Value
+auto_increment_increment 7
+select * from t1;
+i c
+1 dummy_text
+2 dummy_text
+3 dummy_text
+4 dummy_text
+8 dummy_text
+15 dummy_text
+22 dummy_text
+33 dummy_text
+40 dummy_text
+47 dummy_text
+show variables like 'binlog_format';
+Variable_name Value
+binlog_format ROW
+show variables like 'auto_increment_increment';
+Variable_name Value
+auto_increment_increment 2
+select * from t1;
+i c
+1 dummy_text
+2 dummy_text
+3 dummy_text
+4 dummy_text
+8 dummy_text
+15 dummy_text
+22 dummy_text
+33 dummy_text
+40 dummy_text
+47 dummy_text
+show variables like 'binlog_format';
+Variable_name Value
+binlog_format ROW
+show variables like 'auto_increment_increment';
+Variable_name Value
+auto_increment_increment 2
+DROP TABLE t1;
+STOP SLAVE;
+RESET SLAVE ALL;
+RESET MASTER;
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 00000000000..fbac7b1b6b5
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_gtid.result
@@ -0,0 +1,16 @@
+START SLAVE;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES(1);
+SELECT LENGTH(@@global.gtid_binlog_state) > 1;
+LENGTH(@@global.gtid_binlog_state) > 1
+1
+gtid_binlog_state_equal
+1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+gtid_binlog_state_equal
+1
+DROP TABLE t1;
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_nonprim.result b/mysql-test/suite/galera/r/galera_as_slave_nonprim.result
new file mode 100644
index 00000000000..365ea31f292
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_nonprim.result
@@ -0,0 +1,18 @@
+START SLAVE;
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+expected_error
+1
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+START SLAVE;
+DROP TABLE t1;
+STOP SLAVE;
+RESET SLAVE ALL;
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown command' on query");
+CALL mtr.add_suppression("Slave: Unknown command Error_code: 1047");
+CALL mtr.add_suppression("Transport endpoint is not connected");
+CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed, 'Deadlock found when trying to get lock; try restarting transaction', Error_code: 1213");
+CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+RESET MASTER;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_preordered.result b/mysql-test/suite/galera/r/galera_as_slave_preordered.result
new file mode 100644
index 00000000000..27a08e73491
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_preordered.result
@@ -0,0 +1,19 @@
+START SLAVE USER='root';
+Warnings:
+Note 1759 Sending passwords in plain text without SSL/TLS is extremely insecure.
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
+SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
+COUNT(DISTINCT f1) = 2 * 100 * 10 * 10
+1
+SELECT COUNT(*) = 2 * 100 * 10 * 10 FROM t1;
+COUNT(*) = 2 * 100 * 10 * 10
+1
+SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
+COUNT(DISTINCT f1) = 2 * 100 * 10 * 10
+1
+DROP TABLE t1;
+DROP TABLE ten;
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_replication_bundle.result b/mysql-test/suite/galera/r/galera_as_slave_replication_bundle.result
new file mode 100644
index 00000000000..a86bfd20e2f
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_replication_bundle.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);
+INSERT INTO t1 VALUES(3);
+INSERT INTO t1 VALUES(4);
+INSERT INTO t1 VALUES(5);
+SELECT COUNT(*) = 4 FROM t1;
+COUNT(*) = 4
+1
+DROP TABLE t1;
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/r/galera_autoinc_sst_xtrabackup.result b/mysql-test/suite/galera/r/galera_autoinc_sst_xtrabackup.result
new file mode 100644
index 00000000000..228d7c6f041
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_autoinc_sst_xtrabackup.result
@@ -0,0 +1,36 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+CREATE PROCEDURE p1 ()
+BEGIN
+DECLARE x INT DEFAULT 1;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+WHILE 1 DO
+INSERT INTO t1 VALUES (DEFAULT);
+COMMIT;
+END WHILE;
+END|
+CALL p1();;
+CALL p1();;
+Killing server ...
+INSERT INTO t1 VALUES (DEFAULT);
+INSERT INTO t1 VALUES (DEFAULT);
+Got one of the listed errors
+Got one of the listed errors
+count_equal
+1
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0");
+SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE
+2
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE
+2
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CALL mtr.add_suppression("gcs_caused\\(\\) returned -1 \\(Operation not permitted\\)");
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0");
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 00000000000..cc750f05050
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_abort.result
@@ -0,0 +1,10 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(6)) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1,'node_2');
+INSERT INTO t1 VALUES (1,'node_1');
+INSERT INTO t1 VALUES (2, 'node_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_flush_for_export.result b/mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result
new file mode 100644
index 00000000000..3c5c07ae396
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result
@@ -0,0 +1,15 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+FLUSH TABLES t1 FOR EXPORT;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_sync_wait = 0;
+UNLOCK TABLES;
+COMMIT;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_sync_wait = 15;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+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 00000000000..3978a3df193
--- /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 00000000000..e3819172510
--- /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 00000000000..2e44a773b23
--- /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 00000000000..7510e48ee83
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result
@@ -0,0 +1,12 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+LOCK TABLE t1 WRITE;
+INSERT INTO t1 VALUES (2);
+UNLOCK TABLES;
+COMMIT;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+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 00000000000..8e85a5feda2
--- /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 00000000000..9726cf2a440
--- /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 00000000000..a6ab62350b1
--- /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 00000000000..4156c0c70a7
--- /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 00000000000..984a943fcbe
--- /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 00000000000..a1f0fb455f3
--- /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 00000000000..80ae3d0de2c
--- /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_concurrent_ctas.result b/mysql-test/suite/galera/r/galera_concurrent_ctas.result
new file mode 100644
index 00000000000..8b0a4c07ac2
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_concurrent_ctas.result
@@ -0,0 +1 @@
+# End of test
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 00000000000..a35d7661a51
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_create_function.result
@@ -0,0 +1,58 @@
+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 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
+SELECT 1 FROM DUAL;
+1
+1
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 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 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 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 00000000000..0806749ebc8
--- /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 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 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 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 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 00000000000..b335101fa62
--- /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 00000000000..7e656081871
--- /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_ddl_multiline.result b/mysql-test/suite/galera/r/galera_ddl_multiline.result
new file mode 100644
index 00000000000..602f18326e8
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ddl_multiline.result
@@ -0,0 +1,80 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `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
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB; CREATE TABLE t4 (f1 INTEGER) ENGINE=InnoDB;;
+SHOW CREATE TABLE t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t4;
+Table Create Table
+t4 CREATE TABLE `t4` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t4;
+Table Create Table
+t4 CREATE TABLE `t4` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t5 (f1 INTEGER) ENGINE=InnoDB;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SHOW CREATE TABLE t5;
+Table Create Table
+t5 CREATE TABLE `t5` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SHOW CREATE TABLE t5;
+Table Create Table
+t5 CREATE TABLE `t5` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE TABLE t6 (f1 INTEGER) ENGINE=InnoDB; INSERT INTO t2 VALUES (1);;
+SELECT COUNT(*) = 1 FROM t2;
+COUNT(*) = 1
+1
+SHOW CREATE TABLE t6;
+Table Create Table
+t6 CREATE TABLE `t6` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SELECT COUNT(*) = 1 FROM t2;
+COUNT(*) = 1
+1
+SHOW CREATE TABLE t6;
+Table Create Table
+t6 CREATE TABLE `t6` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1, t2, t3, t4, t5, t6;
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 00000000000..e7a776e9047
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_defaults.result
@@ -0,0 +1,119 @@
+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_DIRTY_READS OFF
+WSREP_DRUPAL_282555_WORKAROUND OFF
+WSREP_FORCED_BINLOG_FORMAT NONE
+WSREP_LOAD_DATA_SPLITTING ON
+WSREP_LOG_CONFLICTS OFF
+WSREP_MAX_WS_ROWS 0
+WSREP_MAX_WS_SIZE 2147483647
+WSREP_MYSQL_REPLICATION_BUNDLE 0
+WSREP_NOTIFY_CMD
+WSREP_ON ON
+WSREP_OSU_METHOD TOI
+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 15
+<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 = PT10S; 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.recover = no; gcache.size = 10M; gcomm.thread_prio = ; 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>; 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 = PT30S; pc.weight = 1; protonet.backend = asio; protonet.version = 0; repl.causal_read_timeout = PT90S; repl.commit_order = 3; repl.key_format = FLAT8; repl.max_ws_size = 2147483647; repl.proto_max = 8; socket.checksum = 2; socket.recv_buf_size = 212992;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_STATUS
+WHERE VARIABLE_NAME LIKE 'wsrep_%'
+AND VARIABLE_NAME != 'wsrep_debug_sync_waiters';
+COUNT(*)
+58
+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_DESYNC_COUNT
+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
+WSREP_THREAD_COUNT
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 00000000000..72bee18eab6
--- /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_desync_overlapped.result b/mysql-test/suite/galera/r/galera_desync_overlapped.result
new file mode 100644
index 00000000000..a1e7d59a661
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_desync_overlapped.result
@@ -0,0 +1,45 @@
+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 (f1)) Engine=InnoDB;
+CREATE TABLE t2 (f1 INTEGER, PRIMARY KEY (f1)) Engine=InnoDB;
+SET GLOBAL wsrep_desync = 1;
+show status like 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 1
+SET DEBUG_SYNC='before_execute_sql_command SIGNAL alter1 WAIT_FOR alter2';
+INSERT INTO t1 (f1) SELECT 0000 + (100 * a1.f1) + (10 * a2.f1) + a3.f1 FROM ten AS a1, ten AS a2, ten AS a3;
+SET GLOBAL wsrep_desync = 1;
+Warnings:
+Warning 1231 'wsrep_desync' is already ON.
+show status like 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 1
+SET DEBUG_SYNC='now WAIT_FOR alter1';
+SET DEBUG_SYNC='before_execute_sql_command SIGNAL alter2';
+INSERT INTO t2 (f1) SELECT 0000 + (100 * a1.f1) + (10 * a2.f1) + a3.f1 FROM ten AS a1, ten AS a2, ten AS a3;
+SET DEBUG_SYNC='RESET';
+SET GLOBAL wsrep_desync = 0;
+show status like 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 0
+SET GLOBAL wsrep_desync = 0;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+show status like 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 0
+show status like 'wsrep_desync_count';
+Variable_name Value
+wsrep_desync_count 0
+SET GLOBAL wsrep_desync = 0;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1000
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+1000
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera/r/galera_drop_multi.result b/mysql-test/suite/galera/r/galera_drop_multi.result
new file mode 100644
index 00000000000..d82ae3bec1a
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_drop_multi.result
@@ -0,0 +1,20 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TEMPORARY TABLE t4 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t5 (f1 INTEGER);
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+DROP TABLE t1, t2, t3, t4;
+INSERT INTO t5 VALUES (1);
+COMMIT;
+SHOW CREATE TABLE t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+SHOW CREATE TABLE t2;
+ERROR 42S02: Table 'test.t2' doesn't exist
+SHOW CREATE TABLE t3;
+ERROR 42S02: Table 'test.t3' doesn't exist
+SHOW CREATE TABLE t4;
+ERROR 42S02: Table 'test.t4' doesn't exist
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test.t2,test.t4'' on query\. Default database: 'test'\. Query: 'DROP TABLE t1, t2, t3, t4', Error_code: 1051");
+DROP TABLE t5;
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 00000000000..e853c5c9943
--- /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 00000000000..09d8406d5d0
--- /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 00000000000..89f4301a0b4
--- /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 00000000000..2ab2ad31a13
--- /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 00000000000..ae6c4823a54
--- /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 00000000000..07cdb1b09a2
--- /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 00000000000..a86b87a83ef
--- /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 00000000000..e77128d3b04
--- /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 00000000000..e4f92863d92
--- /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 00000000000..25c37046e88
--- /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 00000000000..f7fb9d04040
--- /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_flush.result b/mysql-test/suite/galera/r/galera_flush.result
new file mode 100644
index 00000000000..620ad1ccb67
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_flush.result
@@ -0,0 +1,88 @@
+DROP TABLE IF EXISTS t1, t2;
+FLUSH DES_KEY_FILE;
+wsrep_last_committed_diff
+1
+FLUSH HOSTS;
+wsrep_last_committed_diff
+1
+SET GLOBAL wsrep_replicate_myisam = TRUE;
+INSERT INTO mysql.user VALUES('localhost','user1',PASSWORD('pass1'), 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'mysql_native_password','','N','N');
+FLUSH PRIVILEGES;
+DELETE FROM mysql.user WHERE user = 'user1';
+SET GLOBAL wsrep_replicate_myisam = FALSE;
+FLUSH PRIVILEGES;
+FLUSH QUERY CACHE;
+wsrep_last_committed_diff
+1
+FLUSH STATUS;
+wsrep_last_committed_diff
+1
+FLUSH USER_RESOURCES;
+wsrep_last_committed_diff
+1
+FLUSH TABLES;
+wsrep_last_committed_diff
+1
+CREATE TABLE t2 (f1 INTEGER);
+FLUSH TABLES t2;
+wsrep_last_committed_diff
+1
+FLUSH ERROR LOGS;
+wsrep_last_committed_diff
+1
+FLUSH SLOW LOGS;
+wsrep_last_committed_diff
+1
+FLUSH GENERAL LOGS;
+wsrep_last_committed_diff
+1
+FLUSH ENGINE LOGS;
+wsrep_last_committed_diff
+1
+FLUSH RELAY LOGS;
+wsrep_last_committed_diff
+1
+SET @userstat_old= @@userstat;
+SET GLOBAL userstat=ON;
+FLUSH CLIENT_STATISTICS;
+FLUSH INDEX_STATISTICS;
+FLUSH TABLE_STATISTICS;
+FLUSH USER_STATISTICS;
+wsrep_last_committed_diff
+1
+SET @old_thread_statistics= @@global.thread_statistics;
+SET GLOBAL thread_statistics= ON;
+FLUSH THREAD_STATISTICS;
+wsrep_last_committed_diff
+1
+FLUSH CHANGED_PAGE_BITMAPS;
+wsrep_last_committed_diff
+1
+CREATE TABLE t1 (f1 INTEGER);
+FLUSH LOGS;
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+wsrep_last_committed_diff
+1
+LOCK TABLES t1 WRITE;
+FLUSH TABLES t1;
+UNLOCK TABLES;
+wsrep_last_committed_diff
+1
+LOCK TABLES t1 READ;
+FLUSH TABLES t1;
+ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
+UNLOCK TABLES;
+wsrep_last_committed_diff
+1
+FLUSH TABLES t1;
+wsrep_last_committed_diff
+1
+DROP TABLE t1;
+DROP TABLE t2;
+SET GLOBAL userstat= @userstat_old;
+SET GLOBAL thread_statistics= @old_thread_statistics;
diff --git a/mysql-test/suite/galera/r/galera_flush_local.result b/mysql-test/suite/galera/r/galera_flush_local.result
new file mode 100644
index 00000000000..3fdd541b513
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_flush_local.result
@@ -0,0 +1,145 @@
+DROP TABLE IF EXISTS t1, t2, x1, x2;
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
+CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE x2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
+INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+FLUSH LOCAL DES_KEY_FILE;
+FLUSH LOCAL HOSTS;
+FLUSH LOCAL QUERY CACHE;
+FLUSH LOCAL STATUS;
+FLUSH LOCAL PRIVILEGES;
+FLUSH LOCAL USER_RESOURCES;
+FLUSH LOCAL TABLES;
+FLUSH LOCAL TABLES t2;
+FLUSH LOCAL ERROR LOGS;
+FLUSH LOCAL SLOW LOGS;
+FLUSH LOCAL GENERAL LOGS;
+FLUSH LOCAL ENGINE LOGS;
+FLUSH LOCAL RELAY LOGS;
+FLUSH LOCAL CLIENT_STATISTICS;
+FLUSH LOCAL INDEX_STATISTICS;
+FLUSH LOCAL TABLE_STATISTICS;
+FLUSH LOCAL USER_STATISTICS;
+FLUSH LOCAL LOGS;
+FLUSH LOCAL BINARY LOGS;
+FLUSH LOCAL TABLES WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH LOCAL TABLES t1 WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH LOCAL TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+LOCK TABLES t1 WRITE;
+FLUSH LOCAL TABLES t1;
+UNLOCK TABLES;
+LOCK TABLES t1 READ;
+FLUSH LOCAL TABLES t1;
+ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
+UNLOCK TABLES;
+FLUSH LOCAL TABLES t1;
+ANALYZE LOCAL TABLE t1, t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+OPTIMIZE LOCAL TABLE t1, t2;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t2 optimize status OK
+REPAIR LOCAL TABLE x1, x2;
+Table Op Msg_type Msg_text
+test.x1 repair status OK
+test.x2 repair status OK
+wsrep_last_committed_diff
+1
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+SELECT COUNT(*) = 10 FROM x1;
+COUNT(*) = 10
+1
+SELECT COUNT(*) = 10000 FROM t2;
+COUNT(*) = 10000
+1
+SELECT COUNT(*) = 10 FROM x2;
+COUNT(*) = 10
+1
+DROP TABLE t1, t2, x1, x2;
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
+CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE x2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
+INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+set wsrep_on=0;
+FLUSH DES_KEY_FILE;
+FLUSH HOSTS;
+FLUSH QUERY CACHE;
+FLUSH STATUS;
+FLUSH PRIVILEGES;
+FLUSH USER_RESOURCES;
+FLUSH TABLES;
+FLUSH TABLES t2;
+FLUSH ERROR LOGS;
+FLUSH SLOW LOGS;
+FLUSH GENERAL LOGS;
+FLUSH ENGINE LOGS;
+FLUSH RELAY LOGS;
+FLUSH CLIENT_STATISTICS;
+FLUSH INDEX_STATISTICS;
+FLUSH TABLE_STATISTICS;
+FLUSH USER_STATISTICS;
+FLUSH LOGS;
+FLUSH BINARY LOGS;
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+LOCK TABLES t1 WRITE;
+FLUSH TABLES t1;
+UNLOCK TABLES;
+LOCK TABLES t1 READ;
+FLUSH TABLES t1;
+ERROR HY000: Table 't1' was locked with a READ lock and can't be updated
+UNLOCK TABLES;
+FLUSH TABLES t1;
+ANALYZE TABLE t1, t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+OPTIMIZE TABLE t1, t2;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t2 optimize status OK
+REPAIR TABLE x1, x2;
+Table Op Msg_type Msg_text
+test.x1 repair status OK
+test.x2 repair status OK
+wsrep_last_committed_diff
+1
+wsrep_last_committed_diff2
+1
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+SELECT COUNT(*) = 10 FROM x1;
+COUNT(*) = 10
+1
+SELECT COUNT(*) = 10000 FROM t2;
+COUNT(*) = 10000
+1
+SELECT COUNT(*) = 10 FROM x2;
+COUNT(*) = 10
+1
+set wsrep_on=1;
+DROP TABLE t1, t2, x1, x2;
diff --git a/mysql-test/suite/galera/r/galera_forced_binlog_format.result b/mysql-test/suite/galera/r/galera_forced_binlog_format.result
new file mode 100644
index 00000000000..a793f7f6d8b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_forced_binlog_format.result
@@ -0,0 +1,43 @@
+RESET MASTER;
+SET SESSION binlog_format = 'STATEMENT';
+Warnings:
+Warning 1105 MariaDB Galera does not support binlog format: STATEMENT
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET SESSION binlog_format = 'MIXED';
+Warnings:
+Warning 1105 MariaDB Galera does not support binlog format: MIXED
+INSERT INTO t1 VALUES (2);
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 248;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 <Pos> Gtid_list 1 <End_log_pos> []
+mysqld-bin.000001 <Pos> Binlog_checkpoint 1 <End_log_pos> mysqld-bin.000001
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> GTID 0-1-1
+mysqld-bin.000001 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-3
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+DROP TABLE t1;
+#
+# MDEV-9401: wsrep_forced_binlog_format with binlog causes crash
+#
+SET SESSION binlog_format = 'ROW';
+CREATE DATABASE testdb_9401;
+USE testdb_9401;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+CREATE USER dummy@localhost;
+GRANT ALL PRIVILEGES ON testdb_9401.t1 TO dummy@localhost;
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+Grants for dummy@localhost
+GRANT USAGE ON *.* TO 'dummy'@'localhost'
+GRANT ALL PRIVILEGES ON `testdb_9401`.`t1` TO 'dummy'@'localhost'
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE testdb_9401;
+# End of tests
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 00000000000..c216b52650b
--- /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_ftwrl_drain.result b/mysql-test/suite/galera/r/galera_ftwrl_drain.result
new file mode 100644
index 00000000000..d704699925b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ftwrl_drain.result
@@ -0,0 +1,26 @@
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+FLUSH TABLES WITH READ LOCK;;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION lock_wait_timeout = 1;
+SET SESSION innodb_lock_wait_timeout=1;
+SET SESSION wait_timeout=1;
+INSERT INTO t2 VALUES (2);
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+UNLOCK TABLES;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+INSERT INTO t1 VALUES (3);
+SELECT COUNT(*) = 2 FROM t1;
+COUNT(*) = 2
+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 00000000000..84ae0a116a1
--- /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;
+SELECT COUNT(f2) = 1000 FROM t1 WHERE MATCH(f2) AGAINST ('foobarbaz');
+COUNT(f2) = 1000
+1
+UPDATE t1 SET f2 = 'abcdefjhk';
+SELECT COUNT(f2) = 1000 FROM t1 WHERE MATCH(f2) AGAINST ('abcdefjhk');
+COUNT(f2) = 1000
+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_gcache_recover.result b/mysql-test/suite/galera/r/galera_gcache_recover.result
new file mode 100644
index 00000000000..127bcba39d8
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_gcache_recover.result
@@ -0,0 +1,18 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_sync_wait = 0;
+Killing server ...
+INSERT INTO t1 VALUES (2);
+Killing server ...
+Performing --wsrep-recover ...
+Using --wsrep-start-position when starting mysqld ...
+INSERT INTO t1 VALUES (3);
+Performing --wsrep-recover ...
+Using --wsrep-start-position when starting mysqld ...
+include/diff_servers.inc [servers=1 2]
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+include/assert_grep.inc [async IST sender starting to serve]
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+include/assert_grep.inc [Recovering GCache ring buffer: found gapless sequence]
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result b/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result
new file mode 100644
index 00000000000..30ee5772411
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result
@@ -0,0 +1,19 @@
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 LONGBLOB) ENGINE=InnoDB;
+SET SESSION wsrep_sync_wait = 0;
+Killing server ...
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+Killing server ...
+Performing --wsrep-recover ...
+Using --wsrep-start-position when starting mysqld ...
+Performing --wsrep-recover ...
+Using --wsrep-start-position when starting mysqld ...
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1;
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+include/assert_grep.inc [IST first seqno 2 not found from cache, falling back to SST]
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
diff --git a/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result b/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result
new file mode 100644
index 00000000000..868b39bfbd6
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_gcache_recover_manytrx.result
@@ -0,0 +1,107 @@
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 LONGBLOB) ENGINE=InnoDB;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+CREATE PROCEDURE insert_simple ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f1, f2) VALUES (DEFAULT,'abcdef');
+END WHILE;
+END|
+CREATE PROCEDURE insert_multi ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f1) VALUES (DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT);
+END WHILE;
+END|
+CREATE PROCEDURE insert_transaction ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+SET AUTOCOMMIT = OFF;
+WHILE 1 DO
+START TRANSACTION;
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+INSERT INTO t1 (f1) VALUES (DEFAULT);
+COMMIT;
+END WHILE;
+END|
+CREATE PROCEDURE update_simple ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = CONCAT(f2,f2);
+END WHILE;
+END|
+CREATE PROCEDURE insert_1k ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024));
+END WHILE;
+END|
+CREATE PROCEDURE insert_1m ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024));
+END WHILE;
+END|
+CREATE PROCEDURE insert_10m ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+END WHILE;
+END|
+CALL insert_simple();;
+CALL insert_multi();;
+CALL insert_transaction ();;
+CALL update_simple ();;
+CALL insert_1k ();;
+CALL insert_1m ();;
+CALL insert_10m ();;
+SET SESSION wsrep_sync_wait = 0;
+Killing server ...
+Killing server ...
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+ERROR HY000: Lost connection to MySQL server during query
+Performing --wsrep-recover ...
+Using --wsrep-start-position when starting mysqld ...
+Performing --wsrep-recover ...
+Using --wsrep-start-position when starting mysqld ...
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1;
+DROP TABLE ten;
+DROP PROCEDURE insert_simple;
+DROP PROCEDURE insert_multi;
+DROP PROCEDURE insert_transaction;
+DROP PROCEDURE update_simple;
+DROP PROCEDURE insert_1k;
+DROP PROCEDURE insert_1m;
+CALL mtr.add_suppression("conflict state 7 after post commit");
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+include/assert_grep.inc [async IST sender starting to serve]
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+include/assert_grep.inc [Recovering GCache ring buffer: found gapless sequence]
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 00000000000..9463b5f8eef
--- /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);
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1';
+LOCK TABLE t1 WRITE;
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+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_fragment.result b/mysql-test/suite/galera/r/galera_gcs_fragment.result
new file mode 100644
index 00000000000..0c9c1819f60
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_gcs_fragment.result
@@ -0,0 +1,24 @@
+CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 TEXT);
+SET GLOBAL wsrep_cluster_address='';
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,gcs_core_after_frag_send';
+SET SESSION wsrep_retry_autocommit=0;
+INSERT INTO t1 VALUES (1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+INSERT INTO t1 VALUES (2, "bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+SET GLOBAL wsrep_provider_options = 'signal=gcs_core_after_frag_send';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+INSERT INTO t1 VALUES (3, "cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+SELECT * FROM t1;
+f1 f2
+2 bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+3 cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+SELECT * FROM t1;
+f1 f2
+2 bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+3 cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+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 00000000000..606cb549def
--- /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_gra_log.result b/mysql-test/suite/galera/r/galera_gra_log.result
new file mode 100644
index 00000000000..9f5cbdd75fc
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_gra_log.result
@@ -0,0 +1,41 @@
+SET SESSION wsrep_on=OFF;
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t1 (f1 INTEGER);
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+DELIMITER /*!*/;
+# at 4
+<ISO TIMESTAMP> server id 2 end_log_pos 120 Start: binlog v 4, server v 5.6.24-debug-log created 150804 11:37:14 at startup
+# Warning: this binlog is either in use or was not closed properly.
+ROLLBACK/*!*/;
+BINLOG '
+unnAVQ8CAAAAdAAAAHgAAAABAAQANS42LjI0LWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAC6ecBVEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAKNu
+Jfk=
+'/*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 91 Query thread_id=<QUERY_THREAD_ID> exec_time=0 error_code=0
+use `test`/*!*/;
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+SET @@session.pseudo_thread_id=<PSEUDO_THREAD_ID>/*!*/;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
+SET @@session.sql_mode=1073741824/*!*/;
+SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
+/*!\C latin1 *//*!*/;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
+SET @@session.lc_time_names=0/*!*/;
+SET @@session.collation_database=DEFAULT/*!*/;
+CREATE TABLE t1 (f1 INTEGER)
+/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
+SET SESSION wsrep_on=ON;
+CALL mtr.add_suppression("Slave SQL: Error 'Table 't1' already exists' on query");
+DROP TABLE t1;
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 00000000000..546c29cb49a
--- /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_binlog_state_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 00000000000..b98a308efb5
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_insert_ignore.result
@@ -0,0 +1,52 @@
+SET GLOBAL wsrep_sync_wait = 15;
+SET GLOBAL wsrep_sync_wait = 15;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT IGNORE INTO t1 VALUES (1), (2);
+Warnings:
+Warning 1062 Duplicate entry '1' for key 'PRIMARY'
+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;
+Warnings:
+Warning 1062 Duplicate entry '2' for key 'PRIMARY'
+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 00000000000..33717781f2c
--- /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 00000000000..5421b234ee1
--- /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 00000000000..9a5b4e8a76f
--- /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';
+SET GLOBAL wsrep_sst_auth = '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_progress.result b/mysql-test/suite/galera/r/galera_ist_progress.result
new file mode 100644
index 00000000000..9fc7febbea5
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ist_progress.result
@@ -0,0 +1,19 @@
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 1';
+SET SESSION wsrep_on = OFF;
+SET SESSION wsrep_on = ON;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (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);
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0';
+include/assert_grep.inc [Receiving IST: 11 writesets, seqnos]
+include/assert_grep.inc [Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete]
+include/assert_grep.inc [Receiving IST\.\.\.100\.0% \(11/11 events\) complete]
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_ist_recv_bind.result b/mysql-test/suite/galera/r/galera_ist_recv_bind.result
new file mode 100644
index 00000000000..de4e07fbe41
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ist_recv_bind.result
@@ -0,0 +1,13 @@
+SELECT @@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%';
+@@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%'
+1
+SELECT @@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%';
+@@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%'
+1
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 1';
+SET SESSION wsrep_on = OFF;
+SET SESSION wsrep_on = ON;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0';
+DROP TABLE t1;
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 00000000000..ca6848fb925
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
@@ -0,0 +1,32 @@
+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;
+Loading wsrep_provider ...
+SET SESSION wsrep_on=OFF;
+SET SESSION wsrep_on=ON;
+UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
+UPDATE t1 SET f2 = 'e' WHERE f1 > 4;
+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
+DROP TABLE t1;
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 00000000000..0b25a299b24
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ist_rsync.result
@@ -0,0 +1,358 @@
+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_dbug = '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;
+SET GLOBAL debug_dbug = $debug_orig;
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 00000000000..175e7443a4d
--- /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_applier.result b/mysql-test/suite/galera/r/galera_kill_applier.result
new file mode 100644
index 00000000000..fe4911639ed
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_kill_applier.result
@@ -0,0 +1,4 @@
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
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 00000000000..b83226bbd42
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_kill_ddl.result
@@ -0,0 +1,8 @@
+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
+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 00000000000..a37056ad9b0
--- /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 00000000000..db3c75e2886
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_kill_nochanges.result
@@ -0,0 +1,10 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+Killing server ...
+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 00000000000..8409740a035
--- /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 00000000000..16e9037a4de
--- /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 00000000000..7243ff21722
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_log_bin.result
@@ -0,0 +1,59 @@
+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 'mysqld-bin.000002' LIMIT 4,18;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000002 353 Gtid 1 391 GTID 0-1-1
+mysqld-bin.000002 391 Query 1 504 use `test`; CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB
+mysqld-bin.000002 504 Gtid 1 542 BEGIN GTID 0-1-2
+mysqld-bin.000002 542 Table_map 1 583 table_id: # (test.t1)
+mysqld-bin.000002 583 Write_rows_v1 1 617 table_id: # flags: STMT_END_F
+mysqld-bin.000002 617 Xid 1 644 COMMIT /* xid=# */
+mysqld-bin.000002 644 Gtid 1 682 GTID 0-1-3
+mysqld-bin.000002 682 Query 1 783 use `test`; CREATE TABLE t2 (id INT) ENGINE=InnoDB
+mysqld-bin.000002 783 Gtid 1 821 BEGIN GTID 0-1-4
+mysqld-bin.000002 821 Table_map 1 862 table_id: # (test.t2)
+mysqld-bin.000002 862 Write_rows_v1 1 896 table_id: # flags: STMT_END_F
+mysqld-bin.000002 896 Xid 1 923 COMMIT /* xid=# */
+mysqld-bin.000002 923 Gtid 1 961 BEGIN GTID 0-1-5
+mysqld-bin.000002 961 Table_map 1 1002 table_id: # (test.t2)
+mysqld-bin.000002 1002 Write_rows_v1 1 1036 table_id: # flags: STMT_END_F
+mysqld-bin.000002 1036 Xid 1 1063 COMMIT /* xid=# */
+mysqld-bin.000002 1063 Gtid 1 1101 GTID 0-1-6
+mysqld-bin.000002 1101 Query 1 1200 use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000003' LIMIT 3,19;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000003 313 Gtid 1 351 GTID 0-1-1
+mysqld-bin.000003 351 Query 1 464 use `test`; CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB
+mysqld-bin.000003 464 Gtid 1 502 BEGIN GTID 0-1-2
+mysqld-bin.000003 502 Table_map 1 543 table_id: # (test.t1)
+mysqld-bin.000003 543 Write_rows_v1 1 577 table_id: # flags: STMT_END_F
+mysqld-bin.000003 577 Xid 1 604 COMMIT /* xid=# */
+mysqld-bin.000003 604 Gtid 1 642 GTID 0-1-3
+mysqld-bin.000003 642 Query 1 743 use `test`; CREATE TABLE t2 (id INT) ENGINE=InnoDB
+mysqld-bin.000003 743 Gtid 1 781 BEGIN GTID 0-1-4
+mysqld-bin.000003 781 Table_map 1 822 table_id: # (test.t2)
+mysqld-bin.000003 822 Write_rows_v1 1 856 table_id: # flags: STMT_END_F
+mysqld-bin.000003 856 Xid 1 883 COMMIT /* xid=# */
+mysqld-bin.000003 883 Gtid 1 921 BEGIN GTID 0-1-5
+mysqld-bin.000003 921 Table_map 1 962 table_id: # (test.t2)
+mysqld-bin.000003 962 Write_rows_v1 1 996 table_id: # flags: STMT_END_F
+mysqld-bin.000003 996 Xid 1 1023 COMMIT /* xid=# */
+mysqld-bin.000003 1023 Gtid 1 1061 GTID 0-1-6
+mysqld-bin.000003 1061 Query 1 1160 use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER
+DROP TABLE t1;
+DROP TABLE t2;
+RESET MASTER;
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 00000000000..cdb5ee49f3e
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_log_output_csv.result
@@ -0,0 +1,18 @@
+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 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 00000000000..6fa574e47c2
--- /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 00000000000..ab6eec550a1
--- /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 00000000000..e650dd6f5de
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_many_rows.result
@@ -0,0 +1,32 @@
+SET SESSION innodb_lock_wait_timeout=600;
+SET SESSION lock_wait_timeout=600;
+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;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_sync_wait = 15;
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT1H';
+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
+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 00000000000..7a4f364730c
--- /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 00000000000..37474797d74
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_many_tables_pk.result
@@ -0,0 +1,21 @@
+SELECT COUNT(*) = 100 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME LIKE 't%';
+COUNT(*) = 100
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+COMMIT;
+CREATE TABLE sum_table (f1 INTEGER);
+SELECT SUM(f1) = 100 FROM sum_table;
+SUM(f1) = 100
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t100 SET f1 = 3;
+COMMIT;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+include/diff_servers.inc [servers=1 2]
+DROP SCHEMA test;
+CREATE SCHEMA test;
diff --git a/mysql-test/suite/galera/r/galera_mdl_race.result b/mysql-test/suite/galera/r/galera_mdl_race.result
new file mode 100644
index 00000000000..535f20de7f1
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_mdl_race.result
@@ -0,0 +1,38 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+CREATE TABLE t2 (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;
+LOCK TABLE t2 WRITE;
+SET GLOBAL DEBUG = "d,sync.wsrep_before_mdl_wait";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SELECT * FROM t2;;
+SET GLOBAL DEBUG = "d,sync.wsrep_after_BF_victim_lock";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+UPDATE t1 SET f2 = 'c' WHERE f1 = 1;
+SET GLOBAL DEBUG = "";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_after_BF_victim_lock";
+UNLOCK TABLES;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+DROP TABLE t1;
+DROP TABLE t2;
+SET DEBUG_SYNC = "RESET";
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 00000000000..aab3ffbd6b6
--- /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';
+SET GLOBAL wsrep_sst_auth = 'sst:';
+GRANT ALL PRIVILEGES ON *.* TO '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 00000000000..a04eb484caf
--- /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 00000000000..3f8d93bae76
--- /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 00000000000..284f92b414c
--- /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 00000000000..5723dac42fd
--- /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 00000000000..7491b715ed2
--- /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 00000000000..abca81e15b0
--- /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 00000000000..68d049a2146
--- /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 00000000000..27768dc441a
--- /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 = 15;;
+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 00000000000..1f163f4366c
--- /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 00000000000..05ce328228a
--- /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 00000000000..3b10815c63d
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_parallel_simple.result
@@ -0,0 +1,28 @@
+CREATE TABLE t1 (id INT) ENGINE=InnoDB;
+CREATE TABLE t2 (id INT) ENGINE=InnoDB;
+SET GLOBAL wsrep_slave_threads = 2;
+LOCK TABLE t1 WRITE;
+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);
+SET SESSION wsrep_sync_wait = 0;
+UNLOCK TABLES;
+SET SESSION wsrep_sync_wait = 15;
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+0
+SELECT COUNT(*) = 10 FROM t2;
+COUNT(*) = 10
+0
+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 00000000000..5fcccfe2d59
--- /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 00000000000..a3075994657
--- /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 00000000000..441926e949c
--- /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_prepared_statement.result b/mysql-test/suite/galera/r/galera_prepared_statement.result
new file mode 100644
index 00000000000..de5ac9c760a
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_prepared_statement.result
@@ -0,0 +1,33 @@
+CREATE TABLE t1 (f1 CHAR(5)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 CHAR(5)) ENGINE=InnoDB;
+CREATE TABLE t3 (f1 CHAR(5)) ENGINE=InnoDB;
+CREATE TABLE t4 (f1 CHAR(5)) ENGINE=InnoDB;
+SET SESSION sql_mode='STRICT_ALL_TABLES';
+PREPARE st1 FROM 'INSERT INTO t1 VALUES ("abc")';
+PREPARE st2 FROM 'INSERT INTO t2 VALUES ("abc")';
+PREPARE st3 FROM 'INSERT INTO t3 VALUES ("abc")';
+PREPARE st4 FROM 'INSERT INTO t4 VALUES ("abc")';
+EXECUTE st1;
+EXECUTE st2;
+EXECUTE st3;
+EXECUTE st4;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t3;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t4;
+COUNT(*) = 1
+1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+ALTER TABLE t1 DROP COLUMN f1;
+EXECUTE st1;
+ERROR 22007: Incorrect integer value: 'abc' for column 'f2' at row 1
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
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 00000000000..502d8a58e9c
--- /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_query_cache_sync_wait.result b/mysql-test/suite/galera/r/galera_query_cache_sync_wait.result
new file mode 100644
index 00000000000..5fe382048fb
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_query_cache_sync_wait.result
@@ -0,0 +1,53 @@
+CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT1S";
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SELECT MAX(id) FROM t1;
+MAX(id)
+1
+INSERT INTO t1 VALUES (2);
+SELECT MAX(id) FROM t1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+SET GLOBAL DEBUG = "";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+FLUSH QUERY CACHE;
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "RESET";
+INSERT INTO t1 VALUES (3);
+SELECT MAX(id) FROM t1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+SET GLOBAL DEBUG = "";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+INSERT INTO t1 VALUES (4);
+SELECT MAX(id) FROM t1;
+MAX(id)
+4
+FLUSH STATUS;
+SELECT MAX(id) FROM t1;
+MAX(id)
+4
+SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
+VARIABLE_VALUE = 1
+1
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+INSERT INTO t1 VALUES (5);
+SELECT MAX(id) FROM t1 ;
+SET GLOBAL DEBUG = "";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+MAX(id)
+5
+SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
+VARIABLE_VALUE = 1
+1
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 00000000000..82736c5f4ba
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_read_only.result
@@ -0,0 +1,18 @@
+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
+CREATE USER foo@localhost;
+# Open connection to node 2 using 'foo' user.
+
+# Connect with foo_node_2
+INSERT INTO t1 VALUES (2);
+ERROR HY000: The MariaDB server is running with the --read-only option so it cannot execute this statement
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SET GLOBAL read_only=FALSE;
+DROP TABLE t1;
+DROP USER foo@localhost;
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 00000000000..4acf0143f8b
--- /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 00000000000..70c09bda3f9
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result
@@ -0,0 +1,12 @@
+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 "Input/output error" during COMMIT
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+CALL mtr.add_suppression("Maximum writeset size exceeded by");
+CALL mtr.add_suppression("transaction size limit");
+CALL mtr.add_suppression("transaction size exceeded");
+CALL mtr.add_suppression("rbr write fail");
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 00000000000..accace97826
--- /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_restart_on_unknown_option.result b/mysql-test/suite/galera/r/galera_restart_on_unknown_option.result
new file mode 100644
index 00000000000..a21b1edf3e7
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_restart_on_unknown_option.result
@@ -0,0 +1,40 @@
+CALL mtr.add_suppression("Aborting");
+CALL mtr.add_suppression("unknown option '--galera-unknown-option'");
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+INSERT INTO t1 VALUES (1, 'a'), (2, 'a'), (3, 'a');
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 a
+Shutting down server ...
+UPDATE t1 SET f2 = 'b' WHERE f1 > 1;
+UPDATE t1 SET f2 = 'c' WHERE f1 > 2;
+SELECT * FROM t1;
+f1 f2
+1 a
+2 b
+3 c
+Starting server ...
+Starting server ...
+SELECT * FROM t1;
+f1 f2
+1 a
+2 b
+3 c
+Shutting down server ...
+UPDATE t1 SET f2 = 'd' WHERE f1 > 1;
+UPDATE t1 SET f2 = 'd' WHERE f1 > 2;
+SELECT * FROM t1;
+f1 f2
+1 a
+2 d
+3 d
+Starting server ...
+Starting server ...
+SELECT * FROM t1;
+f1 f2
+1 a
+2 d
+3 d
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_roles.result b/mysql-test/suite/galera/r/galera_roles.result
new file mode 100644
index 00000000000..d8c13758797
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_roles.result
@@ -0,0 +1,195 @@
+#
+# Testing CREATE/GRANT role
+#
+
+# On node_1
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (a int, b int);
+CREATE TABLE test1.t2 (a int, b int);
+INSERT INTO test1.t1 values (1,2),(3,4);
+INSERT INTO test1.t2 values (5,6),(7,8);
+CREATE PROCEDURE test1.pr1() SELECT "pr1";
+CREATE USER foo@localhost;
+CREATE ROLE role1;
+GRANT role1 TO foo@localhost;
+GRANT RELOAD ON *.* TO role1;
+GRANT SELECT ON mysql.* TO role1;
+GRANT EXECUTE ON PROCEDURE test1.pr1 TO role1;
+GRANT SELECT ON test1.t1 TO role1;
+GRANT SELECT (a) ON test1.t2 TO role1;
+# Open connections to the 2 nodes using 'foo' user.
+
+# Connect with foo_node_1
+SHOW GRANTS;
+Grants for foo@localhost
+GRANT role1 TO 'foo'@'localhost'
+GRANT USAGE ON *.* TO 'foo'@'localhost'
+FLUSH TABLES;
+ERROR 42000: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation
+SELECT * FROM mysql.roles_mapping;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'roles_mapping'
+SHOW TABLES FROM test1;
+ERROR 42000: Access denied for user 'foo'@'localhost' to database 'test1'
+SET ROLE role1;
+FLUSH TABLES;
+SELECT * FROM mysql.roles_mapping;
+Host User Role Admin_option
+localhost foo role1 N
+localhost root role1 Y
+SHOW TABLES FROM test1;
+Tables_in_test1
+t1
+t2
+SELECT * FROM test1.t1;
+a b
+1 2
+3 4
+SELECT * FROM test1.t2;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't2'
+SELECT a FROM test1.t2;
+a
+5
+7
+CALL test1.pr1();
+pr1
+pr1
+
+# Connect with foo_node_2
+SHOW GRANTS;
+Grants for foo@localhost
+GRANT role1 TO 'foo'@'localhost'
+GRANT USAGE ON *.* TO 'foo'@'localhost'
+FLUSH TABLES;
+ERROR 42000: Access denied; you need (at least one of) the RELOAD privilege(s) for this operation
+SELECT * FROM mysql.roles_mapping;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'roles_mapping'
+SHOW TABLES FROM test1;
+ERROR 42000: Access denied for user 'foo'@'localhost' to database 'test1'
+SET ROLE role1;
+FLUSH TABLES;
+SELECT * FROM mysql.roles_mapping;
+Host User Role Admin_option
+localhost foo role1 N
+localhost root role1 Y
+SHOW TABLES FROM test1;
+Tables_in_test1
+t1
+t2
+SELECT * FROM test1.t1;
+a b
+1 2
+3 4
+SELECT * FROM test1.t2;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't2'
+SELECT a FROM test1.t2;
+a
+5
+7
+CALL test1.pr1();
+pr1
+pr1
+#
+# Testing REVOKE role
+#
+#
+# Connect with node_1
+REVOKE EXECUTE ON PROCEDURE test1.pr1 FROM role1;
+
+# Connect with foo_node_1
+CALL test1.pr1();
+ERROR 42000: execute command denied to user 'foo'@'localhost' for routine 'test1.pr1'
+
+# Connect with foo_node_2
+CALL test1.pr1();
+ERROR 42000: execute command denied to user 'foo'@'localhost' for routine 'test1.pr1'
+#
+# Testing DROP role
+#
+
+# Connect with node_1
+DROP ROLE role1;
+
+# Connect with foo_node_1
+FLUSH TABLES;
+SELECT * FROM mysql.roles_mapping;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'roles_mapping'
+SELECT * FROM test1.t1;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1'
+SELECT a FROM test1.t2;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't2'
+SHOW GRANTS;
+Grants for foo@localhost
+GRANT USAGE ON *.* TO 'foo'@'localhost'
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
+ROLE_NAME
+NULL
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
+ROLE_NAME
+NULL
+SELECT CURRENT_ROLE();
+CURRENT_ROLE()
+role1
+
+# Connect with foo_node_2
+FLUSH TABLES;
+SELECT * FROM mysql.roles_mapping;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 'roles_mapping'
+SELECT * FROM test1.t1;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't1'
+SELECT a FROM test1.t2;
+ERROR 42000: SELECT command denied to user 'foo'@'localhost' for table 't2'
+SHOW GRANTS;
+Grants for foo@localhost
+GRANT USAGE ON *.* TO 'foo'@'localhost'
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
+ROLE_NAME
+NULL
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
+ROLE_NAME
+NULL
+SELECT CURRENT_ROLE();
+CURRENT_ROLE()
+role1
+# Connect with node_1
+DROP USER foo@localhost;
+DROP DATABASE test1;
+#
+# MDEV-10566: Create role statement replicated inconsistently in Galera Cluster
+#
+
+# On node_1
+CREATE USER foo@localhost;
+CREATE ROLE role1;
+CREATE ROLE role2 WITH ADMIN CURRENT_USER;
+CREATE ROLE role3 WITH ADMIN foo@localhost;
+CREATE ROLE role4 WITH ADMIN role1;
+SELECT * FROM mysql.roles_mapping;
+Host User Role Admin_option
+ role1 role4 Y
+localhost foo role3 Y
+localhost root role1 Y
+localhost root role2 Y
+SELECT * FROM INFORMATION_SCHEMA.APPLICABLE_ROLES;
+GRANTEE ROLE_NAME IS_GRANTABLE
+role1 role4 YES
+root@localhost role1 YES
+root@localhost role2 YES
+
+# On node_2
+SELECT * FROM mysql.roles_mapping;
+Host User Role Admin_option
+ role1 role4 Y
+localhost foo role3 Y
+localhost root role1 Y
+localhost root role2 Y
+SELECT * FROM INFORMATION_SCHEMA.APPLICABLE_ROLES;
+GRANTEE ROLE_NAME IS_GRANTABLE
+role1 role4 YES
+root@localhost role1 YES
+root@localhost role2 YES
+DROP ROLE role1;
+DROP ROLE role2;
+DROP ROLE role3;
+DROP ROLE role4;
+DROP USER foo@localhost;
+# End of test
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 00000000000..3fd24af9ad7
--- /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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+SET SESSION 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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+SET SESSION 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 00000000000..039fb68d244
--- /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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 DROP PRIMARY KEY;
+SET SESSION 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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 DROP PRIMARY KEY;
+SET SESSION 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 00000000000..bfe41390d1d
--- /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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+SET SESSION 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 00000000000..4c2780a2933
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_rsu_simple.result
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+SET SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+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_rsu_wsrep_desync.result b/mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result
new file mode 100644
index 00000000000..08980389392
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result
@@ -0,0 +1,41 @@
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+SET GLOBAL wsrep_desync=1;
+SET wsrep_OSU_method=RSU;
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET GLOBAL wsrep_desync=0;
+SET DEBUG_SYNC= 'now SIGNAL continue';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) DEFAULT NULL,
+ `f2` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW VARIABLES LIKE 'wsrep_desync';
+Variable_name Value
+wsrep_desync OFF
+SET wsrep_OSU_method=TOI;
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+SET GLOBAL wsrep_desync=0;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+SET wsrep_OSU_method=RSU;
+SET DEBUG_SYNC = 'alter_table_before_create_table_no_lock WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET GLOBAL wsrep_desync=1;;
+SET DEBUG_SYNC= 'now SIGNAL continue';
+SET GLOBAL wsrep_desync=0;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) DEFAULT NULL,
+ `f2` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SET wsrep_OSU_method=TOI;
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
+CALL mtr.add_suppression("Protocol violation");
+CALL mtr.add_suppression("desync failed");
+CALL mtr.add_suppression("Protocol violation");
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 00000000000..0bf6cc7c9d3
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sbr.result
@@ -0,0 +1,14 @@
+SET SESSION binlog_format = 'STATEMENT';
+Warnings:
+Warning 1105 MariaDB Galera does not support binlog format: STATEMENT
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET SESSION binlog_format = 'MIXED';
+Warnings:
+Warning 1105 MariaDB Galera does not support 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 00000000000..0bf6cc7c9d3
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sbr_binlog.result
@@ -0,0 +1,14 @@
+SET SESSION binlog_format = 'STATEMENT';
+Warnings:
+Warning 1105 MariaDB Galera does not support binlog format: STATEMENT
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET SESSION binlog_format = 'MIXED';
+Warnings:
+Warning 1105 MariaDB Galera does not support 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_serializable.result b/mysql-test/suite/galera/r/galera_serializable.result
new file mode 100644
index 00000000000..90fe628e505
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_serializable.result
@@ -0,0 +1,27 @@
+CREATE TABLE t1 (id INT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+START TRANSACTION;
+SELECT * FROM t1;
+id f2
+INSERT INTO t1 VALUES (1,1);
+SELECT * FROM t1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+DELETE FROM t1;
+INSERT INTO t1 VALUES (1,1);
+START TRANSACTION;
+SELECT * FROM t1;
+id f2
+1 1
+UPDATE t1 SET f2 = 2;
+UPDATE t1 SET f2 = 3;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+DELETE FROM t1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1,1);
+INSERT INTO t1 VALUES (1,2);
+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_split_brain.result b/mysql-test/suite/galera/r/galera_split_brain.result
new file mode 100644
index 00000000000..6473f95735b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_split_brain.result
@@ -0,0 +1,4 @@
+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
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 00000000000..89ab8d5e55b
--- /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 00000000000..569c3c607d5
--- /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_ssl_compression.result b/mysql-test/suite/galera/r/galera_ssl_compression.result
new file mode 100644
index 00000000000..f25b614d139
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ssl_compression.result
@@ -0,0 +1,22 @@
+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 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
+SET GLOBAL wsrep_provider_options = "socket.ssl_compression=No";
+ERROR HY000: Incorrect arguments to SET
+CREATE TABLE t1 (f1 VARCHAR(333) PRIMARY KEY, f2 BLOB) Engine=InnoDB;
+INSERT INTO t1 VALUES (REPEAT('a', 333), REPEAT('b', 65535));
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = REPEAT('a', 333) AND f2 = REPEAT('b', 65535);
+COUNT(*) = 1
+1
+DROP TABLE t1;
+CALL mtr.add_suppression("Unknown parameter 'socket\.ssl_compression'");
+CALL mtr.add_suppression("Set options returned 7");
diff --git a/mysql-test/suite/galera/r/galera_ssl_upgrade.result b/mysql-test/suite/galera/r/galera_ssl_upgrade.result
new file mode 100644
index 00000000000..b24671d120d
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_ssl_upgrade.result
@@ -0,0 +1,15 @@
+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 VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
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 00000000000..e35c4055f45
--- /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';
+SET GLOBAL wsrep_sst_auth = '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_mysqldump_with_key.result b/mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result
new file mode 100644
index 00000000000..7d30b356aa9
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_mysqldump_with_key.result
@@ -0,0 +1,108 @@
+Setting SST method to mysqldump ...
+GRANT ALL PRIVILEGES ON *.* TO 'sst';
+SET GLOBAL wsrep_sst_auth = 'sst:';
+SET GLOBAL wsrep_sst_method = 'mysqldump';
+CREATE USER sslsst;
+GRANT ALL PRIVILEGES ON *.* TO sslsst;
+GRANT USAGE ON *.* TO sslsst REQUIRE SSL;
+SET GLOBAL wsrep_sst_auth = 'sslsst:';
+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;
+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");
+DROP USER sslsst;
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
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 00000000000..df2d9190a4b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_rsync.result
@@ -0,0 +1,359 @@
+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_dbug = '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;
+SET GLOBAL debug_dbug = $debug_orig;
diff --git a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2-options.result b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2-options.result
new file mode 100644
index 00000000000..990e0a29506
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2-options.result
@@ -0,0 +1,3 @@
+SELECT 1;
+1
+1
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 00000000000..df2d9190a4b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2.result
@@ -0,0 +1,359 @@
+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_dbug = '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;
+SET GLOBAL debug_dbug = $debug_orig;
diff --git a/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_encrypt_with_key.result b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_encrypt_with_key.result
new file mode 100644
index 00000000000..990e0a29506
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_xtrabackup-v2_encrypt_with_key.result
@@ -0,0 +1,3 @@
+SELECT 1;
+1
+1
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 00000000000..d7cf671cb10
--- /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_index.result b/mysql-test/suite/galera/r/galera_status_local_index.result
new file mode 100644
index 00000000000..4e886ac8921
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_status_local_index.result
@@ -0,0 +1,13 @@
+CREATE TABLE wsrep_local_indexes (wsrep_local_index INTEGER);
+INSERT INTO wsrep_local_indexes VALUES ((SELECT variable_value FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_local_index'));
+INSERT INTO wsrep_local_indexes VALUES ((SELECT variable_value FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_local_index'));
+SELECT COUNT(*) = 2 FROM wsrep_local_indexes;
+COUNT(*) = 2
+1
+SELECT COUNT(DISTINCT wsrep_local_index) = 2 FROM wsrep_local_indexes;
+COUNT(DISTINCT wsrep_local_index) = 2
+1
+SELECT COUNT(*) = 0 FROM wsrep_local_indexes WHERE wsrep_local_index NOT IN (0, 1);
+COUNT(*) = 0
+1
+DROP TABLE wsrep_local_indexes;
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 00000000000..65713f1975c
--- /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 00000000000..357a0d4f78e
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_suspend_slave.result
@@ -0,0 +1,13 @@
+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 ...
+SET SESSION wsrep_sync_wait = 1;
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_sync_wait = 1;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SET SESSION wsrep_sync_wait = 15;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_sync_wait_show.result b/mysql-test/suite/galera/r/galera_sync_wait_show.result
new file mode 100644
index 00000000000..2eac93ad665
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sync_wait_show.result
@@ -0,0 +1,39 @@
+SET SESSION wsrep_sync_wait = 8;
+CREATE DATABASE db1;
+SHOW CREATE DATABASE db1;
+Database Create Database
+db1 CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET latin1 */
+DROP DATABASE db1;
+CREATE PROCEDURE p1 () SELECT 1 FROM DUAL;
+SHOW CREATE PROCEDURE p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
+SELECT 1 FROM DUAL latin1 latin1_swedish_ci latin1_swedish_ci
+DROP PROCEDURE p1;
+CREATE PROCEDURE p1 () SELECT 1 FROM DUAL;
+SHOW PROCEDURE CODE p1;
+Pos Instruction
+0 stmt 0 "SELECT 1 FROM DUAL"
+DROP PROCEDURE p1;
+CREATE FUNCTION f1 () RETURNS INTEGER RETURN 123;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11)
+RETURN 123 latin1 latin1_swedish_ci latin1_swedish_ci
+DROP FUNCTION f1;
+CREATE FUNCTION f1 () RETURNS INTEGER RETURN 123;
+SHOW FUNCTION CODE f1;
+Pos Instruction
+0 freturn 3 123
+DROP FUNCTION f1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.f1 = 'a';
+SHOW CREATE TRIGGER tr1;
+Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation
+tr1 CREATE DEFINER=`root`@`localhost` TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.f1 = 'a' latin1 latin1_swedish_ci latin1_swedish_ci
+DROP TABLE t1;
+CREATE EVENT event1 ON SCHEDULE AT '2038-01-01 23:59:59' DO SELECT 1;
+SHOW CREATE EVENT event1;
+Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
+event1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `event1` ON SCHEDULE AT '2038-01-01 23:59:59' ON COMPLETION NOT PRESERVE DISABLE ON SLAVE DO SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci
+DROP EVENT event1;
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 00000000000..f91415323ec
--- /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 00000000000..656e20bcc46
--- /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 00000000000..81781fbeae7
--- /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_fk_update.result b/mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result
new file mode 100644
index 00000000000..8366cfd27c8
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result
@@ -0,0 +1,23 @@
+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,
+KEY (id)
+) ENGINE=InnoDB;
+CREATE TABLE child (
+id INT PRIMARY KEY AUTO_INCREMENT,
+parent_id INT
+) ENGINE=InnoDB;
+INSERT INTO parent VALUES (1);
+INSERT INTO child (parent_id) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(id) ON UPDATE CASCADE;;
+UPDATE parent SET id = 2 WHERE id = 1;;
+SELECT COUNT(*) = 10000 FROM child WHERE parent_id = 2;
+COUNT(*) = 10000
+1
+SELECT COUNT(*) = 10000 FROM child WHERE parent_id = 2;
+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 00000000000..d72a80b5a23
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_locking.result
@@ -0,0 +1,41 @@
+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
+SET DEBUG_SYNC= 'RESET';
+SET DEBUG_SYNC= 'RESET';
+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 00000000000..41e693c2b19
--- /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 00000000000..9dfa433d49f
--- /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_drop_database.result b/mysql-test/suite/galera/r/galera_toi_drop_database.result
new file mode 100644
index 00000000000..d652a5154be
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_toi_drop_database.result
@@ -0,0 +1,24 @@
+CREATE DATABASE database1;
+USE database1;
+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;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_retry_autocommit = 0;
+INSERT INTO t1 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;;
+USE database1;
+SET SESSION wsrep_retry_autocommit = 0;
+INSERT INTO t2 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;;
+DROP DATABASE database1;;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'database1';
+COUNT(*) = 0
+1
+USE database1;
+ERROR 42000: Unknown database 'database1'
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'database1';
+COUNT(*) = 0
+1
+USE database1;
+ERROR 42000: Unknown database 'database1'
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 00000000000..594717c96ff
--- /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 00000000000..eac50e8853c
--- /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 00000000000..36c38860688
--- /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_toi_truncate.result b/mysql-test/suite/galera/r/galera_toi_truncate.result
new file mode 100644
index 00000000000..f52316f3cbc
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_toi_truncate.result
@@ -0,0 +1,15 @@
+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;
+SET SESSION wsrep_retry_autocommit = 0;
+INSERT INTO t1 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;;
+TRUNCATE TABLE t1;;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+DROP TABLE ten;
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 00000000000..3cd1076a285
--- /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 00000000000..eec9ba03ef5
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_transaction_replay.result
@@ -0,0 +1,59 @@
+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,commit_monitor_enter_sync';
+COMMIT;;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=commit_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;
+CREATE TABLE t1 (i int primary key, j int) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1, 0), (3, 0);
+SELECT * FROM t1;
+i j
+1 0
+3 0
+PREPARE stmt1 FROM "UPDATE t1 SET j = 1 where i > 0";
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
+EXECUTE stmt1;;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+INSERT INTO t1 VALUES(2,2);
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
+SELECT * FROM t1;
+i j
+1 1
+2 2
+3 1
+SELECT * FROM t1;
+i j
+1 1
+2 2
+3 1
+DEALLOCATE PREPARE stmt1;
+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 00000000000..eeeb6721d12
--- /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 00000000000..0bdc4e3632a
--- /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 00000000000..9aee4616ec5
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_unicode_identifiers.result
@@ -0,0 +1,46 @@
+SET GLOBAL wsrep_sync_wait = 15;
+SET GLOBAL wsrep_sync_wait = 15;
+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 (1, 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 00000000000..d59615b2542
--- /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 00000000000..c26eb1c29f6
--- /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 00000000000..a6ab62350b1
--- /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_OSU_method.result b/mysql-test/suite/galera/r/galera_var_OSU_method.result
new file mode 100644
index 00000000000..9a07873e1b9
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_OSU_method.result
@@ -0,0 +1,16 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+SET SESSION wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET GLOBAL wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+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
+SET SESSION wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC= 'RESET';
+SET DEBUG_SYNC= 'RESET';
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_var_OSU_method2.result b/mysql-test/suite/galera/r/galera_var_OSU_method2.result
new file mode 100644
index 00000000000..08f2e6aa0d8
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_OSU_method2.result
@@ -0,0 +1,19 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+SET SESSION wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+INSERT INTO t1 VALUES (1,2);
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+INSERT INTO t1 VALUES (3,4);
+SET GLOBAL wsrep_OSU_method = "TOI";
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
+SET DEBUG_SYNC= 'RESET';
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 00000000000..92b69fbbaa7
--- /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 00000000000..c1bb065975b
--- /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 @@global.auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1;
+@@global.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 @@global.auto_increment_offset = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_index') + 1;
+@@global.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 00000000000..35dabb7654f
--- /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 00000000000..17b5a7bca37
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result
@@ -0,0 +1,39 @@
+SET GLOBAL wsrep_cluster_address = 'foo://';
+SET SESSION wsrep_sync_wait=0;
+SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
+ERROR 08S01: WSREP has not yet prepared node for application use
+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
+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("gcs connect failed: Connection timed out");
+CALL mtr.add_suppression("WSREP: wsrep::connect\\(foo://\\) failed: 7");
+# End of test
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 00000000000..f286ae72308
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_desync_on.result
@@ -0,0 +1,31 @@
+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
+CALL mtr.add_suppression("Protocol violation");
+DROP TABLE t1;
+CALL mtr.add_suppression("Protocol violation");
diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
new file mode 100644
index 00000000000..405d86b3027
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
@@ -0,0 +1,45 @@
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+SELECT * FROM t1;
+i
+1
+SET @@global.wsrep_cluster_address = '';
+SET @@session.wsrep_dirty_reads=OFF;
+SET SESSION wsrep_sync_wait=0;
+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
+SELECT * FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SELECT 1 FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET @@session.wsrep_dirty_reads=ON;
+SELECT * FROM t1;
+i
+1
+SELECT 1 FROM t1;
+1
+1
+SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
+i variable_name variable_value
+1 WSREP_DIRTY_READS ON
+SET @@session.wsrep_dirty_reads=OFF;
+SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SELECT 1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+USE information_schema;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SELECT * FROM information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads";
+ERROR 08S01: WSREP has not yet prepared node for application use
+SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history;
+ERROR 08S01: WSREP has not yet prepared node for application use
+USE test;
+SELECT * FROM t1;
+i
+1
+DROP TABLE t1;
+# End of test
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 00000000000..342212a5241
--- /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 00000000000..912e45a14b1
--- /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 00000000000..db145fd1561
--- /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_log_bin.result b/mysql-test/suite/galera/r/galera_var_log_bin.result
new file mode 100644
index 00000000000..a6ab62350b1
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_log_bin.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_max_ws_rows.result b/mysql-test/suite/galera/r/galera_var_max_ws_rows.result
new file mode 100644
index 00000000000..6e239c70a3e
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_max_ws_rows.result
@@ -0,0 +1,115 @@
+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;
+SET GLOBAL wsrep_max_ws_rows = 4;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (3);
+INSERT INTO t1 (f2) VALUES (4);
+INSERT INTO t1 (f2) VALUES (5);
+ERROR HY000: wsrep_max_ws_rows exceeded
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (3);
+INSERT INTO t1 (f2) VALUES (4);
+UPDATE t1 SET f2 = 10 WHERE f2 = 4;
+ERROR HY000: wsrep_max_ws_rows exceeded
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (3);
+INSERT INTO t1 (f2) VALUES (4);
+DELETE FROM t1 WHERE f2 = 1;
+ERROR HY000: wsrep_max_ws_rows exceeded
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SET GLOBAL wsrep_max_ws_rows = 5;
+INSERT INTO t1 (f2) VALUES (1),(2),(3),(4),(5);
+SET GLOBAL wsrep_max_ws_rows = 4;
+UPDATE t1 SET f2 = f2 + 10;
+ERROR HY000: wsrep_max_ws_rows exceeded
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+DELETE FROM t1 WHERE f2 < 10;
+ERROR HY000: wsrep_max_ws_rows exceeded
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+INSERT INTO t1 (f2) SELECT * FROM ten;
+ERROR HY000: wsrep_max_ws_rows exceeded
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+INSERT INTO t1 (f2) VALUES (10),(20),(30),(40),(50);
+ERROR HY000: wsrep_max_ws_rows exceeded
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SET GLOBAL wsrep_max_ws_rows = 10;
+DELETE FROM t1 WHERE f2 < 10;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SET GLOBAL wsrep_max_ws_rows = 100;
+SELECT COUNT(*) = 100 FROM t1;
+COUNT(*) = 100
+1
+DELETE FROM t1 WHERE f2 < 101;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SET GLOBAL wsrep_max_ws_rows = 9999;
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+ERROR HY000: wsrep_max_ws_rows exceeded
+SET GLOBAL wsrep_max_ws_rows = 10000;
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+SET GLOBAL wsrep_max_ws_rows = 9999;
+UPDATE t1 SET f2 = 2 WHERE f2 = 1;
+ERROR HY000: wsrep_max_ws_rows exceeded
+SET GLOBAL wsrep_max_ws_rows = 10000;
+UPDATE t1 SET f2 = 2 WHERE f2 = 1;
+SET GLOBAL wsrep_max_ws_rows = 9999;
+DELETE FROM t1 WHERE f2 = 2;
+ERROR HY000: wsrep_max_ws_rows exceeded
+SET GLOBAL wsrep_max_ws_rows = 10000;
+DELETE FROM t1 WHERE f2 = 2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT = ON;
+SET GLOBAL wsrep_max_ws_rows = 1;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+ERROR HY000: wsrep_max_ws_rows exceeded
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+SET AUTOCOMMIT = OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+ERROR HY000: wsrep_max_ws_rows exceeded
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+ERROR HY000: wsrep_max_ws_rows exceeded
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+ERROR HY000: wsrep_max_ws_rows exceeded
+DROP TABLE t1;
+DROP TABLE ten;
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 00000000000..0940b5f12c0
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_max_ws_size.result
@@ -0,0 +1,17 @@
+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 "Input/output error" during COMMIT
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=10000';
+SELECT @@wsrep_max_ws_size = 10000;
+@@wsrep_max_ws_size = 10000
+1
+SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=20000';
+SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=10000';
+SET GLOBAL wsrep_max_ws_size = 20000;
+provider_options_match
+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 00000000000..f2a951c26b0
--- /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_node_address.result b/mysql-test/suite/galera/r/galera_var_node_address.result
new file mode 100644
index 00000000000..cf36e964f93
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_node_address.result
@@ -0,0 +1,11 @@
+call mtr.add_suppression("WSREP: Stray state UUID msg: .* current group state WAIT_STATE_UUID .*");
+call mtr.add_suppression("WSREP: Protocol violation. JOIN message sender .* is not in state transfer (.*). Message ignored.");
+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);
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+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 00000000000..e9e4605e1bc
--- /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 00000000000..c8b79071d10
--- /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 00000000000..73a0576048b
--- /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_retry_autocommit.result b/mysql-test/suite/galera/r/galera_var_retry_autocommit.result
new file mode 100644
index 00000000000..f4d17ad9a41
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_retry_autocommit.result
@@ -0,0 +1,32 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.f2 = SLEEP(5);
+SET SESSION wsrep_retry_autocommit = 0;
+INSERT INTO t1 (f1) VALUES (1),(2);;
+TRUNCATE TABLE t1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SET SESSION wsrep_retry_autocommit = 1;
+INSERT INTO t1 (f1) VALUES (3),(4);;
+TRUNCATE TABLE t1;
+SELECT * FROM test.t1;
+f1 f2
+3 0
+4 0
+CREATE PROCEDURE repeated_truncate ()
+BEGIN
+DECLARE i INT;
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET i = 0;
+WHILE i <= 1000 DO
+TRUNCATE TABLE t1;
+SET i = i + 1;
+END WHILE;
+END|
+CALL repeated_truncate();
+SET SESSION wsrep_retry_autocommit = 1;
+INSERT INTO t1 (f1) VALUES (5),(6);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SET SESSION wsrep_retry_autocommit = 1024;
+INSERT INTO t1 (f1) VALUES (7),(8);;
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1;
+DROP PROCEDURE repeated_truncate;
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 00000000000..603dfaeacc7
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_slave_threads.result
@@ -0,0 +1,114 @@
+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;
+#
+# lp:1372840 - Changing wsrep_slave_threads causes future connections to hang
+#
+CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY) ENGINE=INNODB;
+SET GLOBAL wsrep_slave_threads = 4;
+SET GLOBAL wsrep_slave_threads = 1;
+DROP TABLE t1;
+# End of tests
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 00000000000..f573c251bdd
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_sync_wait.result
@@ -0,0 +1,18 @@
+CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
+SET GLOBAL wsrep_sync_wait = 1;
+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 = 15;
+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 00000000000..8b1c4ebf83b
--- /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 00000000000..6be32b291e5
--- /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_wan_restart_ist.result b/mysql-test/suite/galera/r/galera_wan_restart_ist.result
new file mode 100644
index 00000000000..e58bff34e54
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_wan_restart_ist.result
@@ -0,0 +1,53 @@
+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);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (13);
+Shutting down server ...
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (131);
+INSERT INTO t1 VALUES (22);
+Shutting down server ...
+INSERT INTO t1 VALUES (21);
+INSERT INTO t1 VALUES (23);
+INSERT INTO t1 VALUES (24);
+INSERT INTO t1 VALUES (221);
+INSERT INTO t1 VALUES (34);
+Shutting down server ...
+INSERT INTO t1 VALUES (31);
+INSERT INTO t1 VALUES (32);
+INSERT INTO t1 VALUES (33);
+INSERT INTO t1 VALUES (341);
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+1
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 4
+1
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+1
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 4
+1
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+1
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 4
+1
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+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");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+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");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
diff --git a/mysql-test/suite/galera/r/galera_wan_restart_sst.result b/mysql-test/suite/galera/r/galera_wan_restart_sst.result
new file mode 100644
index 00000000000..15de0fab342
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_wan_restart_sst.result
@@ -0,0 +1,54 @@
+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);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (13);
+Killing server ...
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (131);
+INSERT INTO t1 VALUES (22);
+Killing server ...
+INSERT INTO t1 VALUES (21);
+INSERT INTO t1 VALUES (23);
+INSERT INTO t1 VALUES (24);
+INSERT INTO t1 VALUES (221);
+INSERT INTO t1 VALUES (34);
+Killing server ...
+INSERT INTO t1 VALUES (31);
+INSERT INTO t1 VALUES (32);
+INSERT INTO t1 VALUES (33);
+INSERT INTO t1 VALUES (341);
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+1
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 4
+1
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+1
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 4
+1
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+1
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 4
+1
+SELECT COUNT(*) = 19 FROM t1;
+COUNT(*) = 19
+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");
+CALL mtr.add_suppression("WSREP: gcs_caused\\(\\) returned -1 \\(Operation not permitted\\)");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+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");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
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 00000000000..06fc27ae7ed
--- /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_log_conficts.result b/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result
new file mode 100644
index 00000000000..b535c6477b7
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result
@@ -0,0 +1,18 @@
+CREATE TABLE t1 (
+f1 VARCHAR(255) PRIMARY KEY
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES ('abc');
+SELECT f1 = 'abc' FROM t1;
+f1 = 'abc'
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'klm';
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'xyz';
+COMMIT;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+include/assert_grep.inc [cluster conflict due to high priority abort for threads]
+DROP TABLE t1;
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 00000000000..e3f2fa4046f
--- /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_options_syntax.result b/mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result
new file mode 100644
index 00000000000..f19dc40205b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result
@@ -0,0 +1,5 @@
+call mtr.add_suppression("WSREP\: Unknown parameter 'gmcasts\.segment'");
+call mtr.add_suppression("WSREP\: Set options returned 7");
+SET GLOBAL wsrep_provider_options="gmcasts.segment=1";
+ERROR HY000: Incorrect arguments to SET
+Unhandled exceptions: 0
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 00000000000..89110b48def
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result
@@ -0,0 +1,14 @@
+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);
+SET SESSION wsrep_sync_wait = 0;
+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 00000000000..2e6119bd1ba
--- /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/grant.result b/mysql-test/suite/galera/r/grant.result
new file mode 100644
index 00000000000..8d257e7e8e2
--- /dev/null
+++ b/mysql-test/suite/galera/r/grant.result
@@ -0,0 +1,17 @@
+#
+# MDEV#6266: Changing password fails on galera cluster
+#
+
+# On node_1
+GRANT SELECT ON *.* TO 'user_6266'@'localhost' IDENTIFIED BY 'pass';
+
+# Now, try changing password for 'user_6266'. This command should also
+# execute successfully on the other node.
+SET PASSWORD FOR 'user_6266'@'localhost' = PASSWORD('newpass');
+
+# On node_2
+SELECT user FROM mysql.user WHERE user='user_6266';
+user
+user_6266
+DROP USER 'user_6266'@'localhost';
+# End of test
diff --git a/mysql-test/suite/galera/r/lp1276424.result b/mysql-test/suite/galera/r/lp1276424.result
new file mode 100644
index 00000000000..5f09ec9ea8b
--- /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 00000000000..c085059e014
--- /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/lp1376747-2.result b/mysql-test/suite/galera/r/lp1376747-2.result
new file mode 100644
index 00000000000..3b8aee61ed2
--- /dev/null
+++ b/mysql-test/suite/galera/r/lp1376747-2.result
@@ -0,0 +1,19 @@
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+FLUSH TABLES t1 FOR EXPORT;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+INSERT INTO t1 VALUES (2,3);
+UNLOCK TABLES;
+### t1 should have column f2
+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
+SELECT * from t1;
+id f2
+1 NULL
+2 3
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/lp1376747-3.result b/mysql-test/suite/galera/r/lp1376747-3.result
new file mode 100644
index 00000000000..fc982c94244
--- /dev/null
+++ b/mysql-test/suite/galera/r/lp1376747-3.result
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+FLUSH TABLE WITH READ LOCK;
+### This shouldn't block.
+FLUSH TABLES t1 FOR EXPORT;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+UNLOCK TABLES;
+### t1 should have column f2
+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
+INSERT INTO t1 VALUES (2,3);
+SELECT * from t1;
+id f2
+1 NULL
+2 3
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/lp1376747-4.result b/mysql-test/suite/galera/r/lp1376747-4.result
new file mode 100644
index 00000000000..b0ae2b7fc92
--- /dev/null
+++ b/mysql-test/suite/galera/r/lp1376747-4.result
@@ -0,0 +1,36 @@
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET session wsrep_sync_wait=0;
+SET session wsrep_causal_reads=OFF;
+FLUSH TABLE WITH READ LOCK;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+INSERT INTO t1 VALUES (2,3);
+SET session wsrep_sync_wait=0;
+SET session wsrep_causal_reads=OFF;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+FLUSH TABLES t1 WITH READ LOCK;;
+UNLOCK TABLES;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+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
+SELECT * from t1;
+id f2
+1 NULL
+2 3
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/lp1376747.result b/mysql-test/suite/galera/r/lp1376747.result
new file mode 100644
index 00000000000..4617d5952bb
--- /dev/null
+++ b/mysql-test/suite/galera/r/lp1376747.result
@@ -0,0 +1,19 @@
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+FLUSH TABLES t1 WITH READ LOCK;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+INSERT INTO t1 VALUES (2,3);
+UNLOCK TABLES;
+### t1 should have column f2
+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
+SELECT * from t1;
+id f2
+1 NULL
+2 3
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/lp1438990.result b/mysql-test/suite/galera/r/lp1438990.result
new file mode 100644
index 00000000000..b53bc186953
--- /dev/null
+++ b/mysql-test/suite/galera/r/lp1438990.result
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t3 (f1 INTEGER PRIMARY KEY);
+CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1);
+CREATE PROCEDURE p1 (IN x INT)
+BEGIN
+DECLARE EXIT HANDLER FOR SQLEXCEPTION
+BEGIN
+ROLLBACK TO event_logging;
+INSERT t3 VALUES (x);
+END;
+SAVEPOINT event_logging;
+INSERT INTO t2 VALUES (x);
+RELEASE SAVEPOINT event_logging;
+END|
+INSERT INTO t2 VALUES (1);
+INSERT INTO t1 VALUES (1);
+DROP PROCEDURE p1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
diff --git a/mysql-test/suite/galera/r/lp959512.result b/mysql-test/suite/galera/r/lp959512.result
new file mode 100644
index 00000000000..55adfa360b0
--- /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/r/mdev_9290.result b/mysql-test/suite/galera/r/mdev_9290.result
new file mode 100644
index 00000000000..cb2f0813333
--- /dev/null
+++ b/mysql-test/suite/galera/r/mdev_9290.result
@@ -0,0 +1,14 @@
+#
+# MDEV-9290 : InnoDB: Assertion failure in file trx0sys.cc line 353
+# InnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno
+#
+CREATE TABLE t1 (i INT) ENGINE=InnoDB;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+COMMIT;
+SELECT * FROM t1;
+i
+1
+2
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#110.result b/mysql-test/suite/galera/r/mysql-wsrep#110.result
new file mode 100644
index 00000000000..551c3666fb4
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#110.result
@@ -0,0 +1,38 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t3 (f1 INTEGER PRIMARY KEY);
+CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1);
+CREATE PROCEDURE p1 (IN x INT)
+BEGIN
+DECLARE EXIT HANDLER FOR SQLEXCEPTION
+BEGIN
+ROLLBACK TO event_logging;
+INSERT t3 VALUES (x);
+END;
+SAVEPOINT event_logging;
+INSERT INTO t2 VALUES (x);
+END|
+INSERT INTO t2 VALUES (1);
+INSERT INTO t1 VALUES (1);
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t3;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t3;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#198.result b/mysql-test/suite/galera/r/mysql-wsrep#198.result
new file mode 100644
index 00000000000..a278c492372
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#198.result
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
+SELECT 1 FROM DUAL;
+1
+1
+LOCK TABLE t2 WRITE;
+OPTIMIZE TABLE t1,t2;;
+REPAIR TABLE t1,t2;;
+SET SESSION wsrep_sync_wait = 0;
+INSERT INTO t2 VALUES (1);
+UNLOCK TABLES;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t2 optimize status OK
+Table Op Msg_type Msg_text
+test.t1 repair note The storage engine for the table doesn't support repair
+test.t2 repair note The storage engine for the table doesn't support repair
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#201.result b/mysql-test/suite/galera/r/mysql-wsrep#201.result
new file mode 100644
index 00000000000..34d184d8ec1
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#201.result
@@ -0,0 +1,3 @@
+CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (DEFAULT);
+SET GLOBAL query_cache_size=1355776;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#237.result b/mysql-test/suite/galera/r/mysql-wsrep#237.result
new file mode 100644
index 00000000000..1889a8feca0
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#237.result
@@ -0,0 +1,11 @@
+CREATE TABLE t (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+SET DEBUG_SYNC = 'wsrep_before_replication WAIT_FOR continue';
+INSERT INTO t values (1);;
+SET SESSION wsrep_sync_wait = 0;
+FLUSH TABLES;
+SELECT SLEEP(1);
+SLEEP(1)
+0
+SET DEBUG_SYNC= 'now SIGNAL continue';
+DROP TABLE t;
+SET DEBUG_SYNC= 'RESET';
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#247.result b/mysql-test/suite/galera/r/mysql-wsrep#247.result
new file mode 100644
index 00000000000..1b00f511f03
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#247.result
@@ -0,0 +1,11 @@
+SET GLOBAL wsrep_desync=1;
+SET wsrep_OSU_method=RSU;
+CREATE TABLE t1 (i int primary key);
+SHOW VARIABLES LIKE 'wsrep_desync';
+Variable_name Value
+wsrep_desync ON
+SET GLOBAL wsrep_desync=0;
+DROP TABLE t1;
+SHOW VARIABLES LIKE 'wsrep_desync';
+Variable_name Value
+wsrep_desync OFF
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#31.result b/mysql-test/suite/galera/r/mysql-wsrep#31.result
new file mode 100644
index 00000000000..a21bb3eccfd
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#31.result
@@ -0,0 +1,10 @@
+CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES('test');
+CREATE DATABASE db;
+Shutting down server 2 ...
+Recovering server 2 ...
+Performing --wsrep-recover ...
+Restarting server ...
+Using --wsrep-start-position when starting mysqld ...
+DROP TABLE t1;
+DROP DATABASE db;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#33.result b/mysql-test/suite/galera/r/mysql-wsrep#33.result
new file mode 100644
index 00000000000..62af519ad32
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#33.result
@@ -0,0 +1,103 @@
+Setting SST method to mysqldump ...
+GRANT ALL PRIVILEGES ON *.* TO 'sst';
+SET GLOBAL wsrep_sst_auth = '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;
+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");
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#90.result b/mysql-test/suite/galera/r/mysql-wsrep#90.result
new file mode 100644
index 00000000000..da57b9d0068
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#90.result
@@ -0,0 +1,31 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+SET GLOBAL wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+SET GLOBAL wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+INSERT INTO t1 VALUES (1,2);
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+COUNT(*) = 2
+1
+INSERT INTO t1 VALUES (3,4);
+DROP TABLE t1;
+SET GLOBAL WSREP_OSU_METHOD = TOI;
diff --git a/mysql-test/suite/galera/r/partition.result b/mysql-test/suite/galera/r/partition.result
new file mode 100644
index 00000000000..3907b4f08c9
--- /dev/null
+++ b/mysql-test/suite/galera/r/partition.result
@@ -0,0 +1,140 @@
+#
+# MDEV#4953 Galera: DELETE from a partitioned table is not replicated
+#
+USE test;
+CREATE TABLE t1 (pk INT PRIMARY KEY, i INT) ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+INSERT INTO t1 VALUES (1,100), (2,200);
+SELECT * FROM t1;
+pk i
+2 200
+1 100
+DELETE FROM t1;
+SELECT * FROM t1;
+pk i
+
+# On node_1
+SELECT * FROM t1;
+pk i
+
+# On node_2
+SELECT * FROM t1;
+pk i
+DROP TABLE t1;
+#
+# MDEV#7501 : alter table exchange partition is not replicated in
+# galera cluster
+#
+
+# On node_1
+CREATE TABLE test.t1 (
+i INT UNSIGNED NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (i)
+) ENGINE=INNODB
+PARTITION BY RANGE (i)
+(PARTITION p1 VALUES LESS THAN (10) ENGINE = INNODB,
+PARTITION p2 VALUES LESS THAN (20) ENGINE = INNODB,
+PARTITION pMax VALUES LESS THAN MAXVALUE ENGINE = INNODB);
+INSERT INTO test.t1 (i) VALUE (9),(19);
+CREATE TABLE test.p1 LIKE test.t1;
+ALTER TABLE test.p1 REMOVE PARTITIONING;
+ALTER TABLE test.t1 EXCHANGE PARTITION p1 WITH TABLE test.p1;
+SELECT * FROM test.t1;
+i
+19
+SELECT * FROM test.p1;
+i
+9
+
+# On node_2
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`i`)
+) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (i)
+(PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB,
+ PARTITION p2 VALUES LESS THAN (20) ENGINE = InnoDB,
+ PARTITION pMax VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
+SHOW CREATE TABLE p1;
+Table Create Table
+p1 CREATE TABLE `p1` (
+ `i` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`i`)
+) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1
+SELECT * FROM test.t1;
+i
+19
+SELECT * FROM test.p1;
+i
+9
+
+# On node_1
+ALTER TABLE t1 TRUNCATE PARTITION p2;
+SELECT * FROM test.t1;
+i
+
+# On node_2
+SELECT * FROM test.t1;
+i
+
+# On node_1
+ALTER TABLE t1 DROP PARTITION p2;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`i`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (i)
+(PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB,
+ PARTITION pMax VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
+
+# On node_2
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`i`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (i)
+(PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB,
+ PARTITION pMax VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
+DROP TABLE t1, p1;
+#
+# MDEV-5146: Bulk loads into partitioned table not working
+#
+# Case 1: wsrep_load_data_splitting = ON & LOAD DATA with 20002
+# entries.
+SET GLOBAL wsrep_load_data_splitting = ON;
+CREATE TABLE t1 (pk INT PRIMARY KEY)
+ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+SELECT COUNT(*) = 20002 FROM t1;
+COUNT(*) = 20002
+1
+wsrep_last_committed_diff
+1
+DROP TABLE t1;
+# Case 2: wsrep_load_data_splitting = ON & LOAD DATA with 101 entries.
+SET GLOBAL wsrep_load_data_splitting = ON;
+CREATE TABLE t1 (pk INT PRIMARY KEY)
+ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+SELECT COUNT(*) = 101 FROM t1;
+COUNT(*) = 101
+1
+wsrep_last_committed_diff
+1
+DROP TABLE t1;
+# Case 3: wsrep_load_data_splitting = OFF & LOAD DATA with 20002
+# entries.
+SET GLOBAL wsrep_load_data_splitting = OFF;
+CREATE TABLE t1 (pk INT PRIMARY KEY)
+ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+SELECT COUNT(*) = 20002 FROM t1;
+COUNT(*) = 20002
+1
+wsrep_last_committed_diff
+1
+DROP TABLE t1;
+SET GLOBAL wsrep_load_data_splitting = 1;;
+# End of test
diff --git a/mysql-test/suite/galera/r/pxc-421.result b/mysql-test/suite/galera/r/pxc-421.result
new file mode 100644
index 00000000000..f5c0fabcd6e
--- /dev/null
+++ b/mysql-test/suite/galera/r/pxc-421.result
@@ -0,0 +1,38 @@
+set GLOBAL wsrep_slave_threads=26;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 (f1) SELECT * from t1 as x1;
+set GLOBAL wsrep_slave_threads=16;
+SET GLOBAL wsrep_provider='none';
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+set SESSION wsrep_sync_wait=0;
+INSERT INTO t1 VALUES (4);
+set GLOBAL wsrep_slave_threads=5;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+set GLOBAL wsrep_slave_threads=12;
+SELECT COUNT(*) = 4 FROM t1;
+COUNT(*) = 4
+1
+INSERT INTO t1 VALUES (100), (101), (102);
+set GLOBAL wsrep_slave_threads=5;
+INSERT INTO t1 (f1) SELECT * from t1 as x1;
+show global variables like 'wsrep_slave_threads';
+Variable_name Value
+wsrep_slave_threads 5
+SET GLOBAL wsrep_slave_threads = 1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+16
+SET GLOBAL auto_increment_offset = 2;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+15
+show global variables like 'wsrep_slave_threads';
+Variable_name Value
+wsrep_slave_threads 12
+SET GLOBAL wsrep_slave_threads = 1;
+DROP TABLE t1;
+SET GLOBAL auto_increment_offset = 1;
diff --git a/mysql-test/suite/galera/r/query_cache.result b/mysql-test/suite/galera/r/query_cache.result
new file mode 100644
index 00000000000..4b1b950e5c3
--- /dev/null
+++ b/mysql-test/suite/galera/r/query_cache.result
@@ -0,0 +1,1645 @@
+
+# Execute FLUSH/RESET commands.
+# On node-1
+SET @query_cache_size_saved=@@GLOBAL.query_cache_size;
+SET @query_cache_type_saved=@@GLOBAL.query_cache_type;
+set GLOBAL query_cache_size=1355776;
+flush query cache;
+reset query cache;
+flush status;
+# On node-2
+SET @query_cache_size_saved=@@GLOBAL.query_cache_size;
+SET @query_cache_type_saved=@@GLOBAL.query_cache_type;
+set GLOBAL query_cache_size=1355776;
+flush query cache;
+reset query cache;
+flush status;
+# On node-1
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+select sql_no_cache * from t1;
+a
+1
+2
+3
+select length(now()) from t1;
+length(now())
+19
+19
+19
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-2
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+select sql_no_cache * from t1;
+a
+1
+2
+3
+select length(now()) from t1;
+length(now())
+19
+19
+19
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-1
+delete from t1 where a=1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-1
+select * from t1;
+a
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-2
+select * from t1;
+a
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-1
+update t1 set a=1 where a=3;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-1
+select * from t1;
+a
+2
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-2
+select * from t1;
+a
+2
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-1
+drop table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+# On node-2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+
+# On node-1
+create table t1 (a int not null) ENGINE=MyISAM;
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null) ENGINE=MyISAM;
+insert into t2 values (4),(5),(6);
+create table t3 (a int not null) engine=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
+select * from t3;
+a
+1
+2
+3
+4
+5
+6
+select * from t3;
+a
+1
+2
+3
+4
+5
+6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+insert into t2 values (7);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+insert into t3 values (8);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+select * from t3;
+a
+1
+2
+3
+8
+4
+5
+6
+7
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+update t2 set a=9 where a=7;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+select * from t1;
+a
+1
+2
+3
+8
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+update t3 set a=10 where a=1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+select * from t3;
+a
+10
+2
+3
+8
+4
+5
+6
+9
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+delete from t2 where a=9;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+select * from t1;
+a
+10
+2
+3
+8
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+delete from t3 where a=10;
+select * from t3;
+a
+2
+3
+8
+4
+5
+6
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+# On node-2
+select * from t3;
+a
+select * from t3;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+drop table t1, t2, t3;
+# On node-1
+set query_cache_type=demand;
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+select sql_cache * from t1 union select * from t1;
+a
+1
+2
+3
+set query_cache_type=2;
+select sql_cache * from t1 union select * from t1;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+set query_cache_type=on;
+# On node-2
+set query_cache_type=demand;
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 2
+select sql_cache * from t1 union select * from t1;
+a
+1
+2
+3
+set query_cache_type=2;
+select sql_cache * from t1 union select * from t1;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+set query_cache_type=on;
+# On node-1
+reset query cache;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+# On node-2
+reset query cache;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+# On node-1
+select sql_no_cache * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+# On node-2
+select sql_no_cache * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+drop table t1;
+# On node-1
+create table t1 (a text not null) engine=innodb;
+select CONNECTION_ID() from t1;
+CONNECTION_ID()
+select FOUND_ROWS();
+FOUND_ROWS()
+0
+select NOW() from t1;
+NOW()
+select CURDATE() from t1;
+CURDATE()
+select CURTIME() from t1;
+CURTIME()
+select DATABASE() from t1;
+DATABASE()
+select ENCRYPT("test") from t1;
+ENCRYPT("test")
+select LAST_INSERT_ID() from t1;
+LAST_INSERT_ID()
+select RAND() from t1;
+RAND()
+select UNIX_TIMESTAMP() from t1;
+UNIX_TIMESTAMP()
+select USER() from t1;
+USER()
+select CURRENT_USER() from t1;
+CURRENT_USER()
+select benchmark(1,1) from t1;
+benchmark(1,1)
+explain extended select benchmark(1,1) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00
+Warnings:
+Note 1003 select benchmark(1,1) AS `benchmark(1,1)` from `test`.`t1`
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+# On node-2
+select CONNECTION_ID() from t1;
+CONNECTION_ID()
+select FOUND_ROWS();
+FOUND_ROWS()
+0
+select NOW() from t1;
+NOW()
+select CURDATE() from t1;
+CURDATE()
+select CURTIME() from t1;
+CURTIME()
+select DATABASE() from t1;
+DATABASE()
+select ENCRYPT("test") from t1;
+ENCRYPT("test")
+select LAST_INSERT_ID() from t1;
+LAST_INSERT_ID()
+select RAND() from t1;
+RAND()
+select UNIX_TIMESTAMP() from t1;
+UNIX_TIMESTAMP()
+select USER() from t1;
+USER()
+select CURRENT_USER() from t1;
+CURRENT_USER()
+select benchmark(1,1) from t1;
+benchmark(1,1)
+explain extended select benchmark(1,1) from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1 100.00
+Warnings:
+Note 1003 select benchmark(1,1) AS `benchmark(1,1)` from `test`.`t1`
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+drop table t1;
+# On node-1
+create database mysqltest;
+create table mysqltest.t1 (i int not null auto_increment, a int, primary key
+(i)) engine=innodb;
+insert into mysqltest.t1 values (1, 1);
+select * from mysqltest.t1 where i is null;
+i a
+create table t1(a int) engine=innodb;
+select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+select * from mysqltest.t1;
+i a
+1 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+# On node-2
+select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+select * from mysqltest.t1;
+i a
+1 1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+drop database mysqltest;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+drop table t1;
+# On node-1
+create table t1 (a char(1) not null collate koi8r_general_ci) engine=innodb;
+insert into t1 values(_koi8r"á");
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+set CHARACTER SET koi8r;
+select * from t1;
+a
+set CHARACTER SET cp1251_koi8;
+select * from t1;
+a
+set CHARACTER SET DEFAULT;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 4
+# On node-2
+set CHARACTER SET koi8r;
+select * from t1;
+a
+set CHARACTER SET cp1251_koi8;
+select * from t1;
+a
+set CHARACTER SET DEFAULT;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 3
+drop table t1;
+# On node-1
+create database if not exists mysqltest;
+create table mysqltest.t1 (i int not null) engine=innodb;
+create table t1 (i int not null) engine=innodb;
+insert into mysqltest.t1 (i) values (1);
+insert into t1 (i) values (2);
+select * from t1;
+i
+2
+use mysqltest;
+select * from t1;
+i
+1
+select * from t1;
+i
+1
+use test;
+select * from t1;
+i
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+# On node-2
+select * from t1;
+i
+2
+use mysqltest;
+select * from t1;
+i
+1
+select * from t1;
+i
+1
+use test;
+select * from t1;
+i
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 5
+drop database mysqltest;
+drop table t1;
+# On node-1
+create table t1 (i int not null) engine=innodb;
+insert into t1 (i) values (1),(2),(3),(4);
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+i
+1
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+select * from t1 where i=1;
+i
+1
+select FOUND_ROWS();
+FOUND_ROWS()
+1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+i
+1
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+select * from t1 where i=1;
+i
+1
+select FOUND_ROWS();
+FOUND_ROWS()
+1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+# On node-2
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+i
+1
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 5
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+select * from t1 where i=1;
+i
+1
+select FOUND_ROWS();
+FOUND_ROWS()
+1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 5
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+i
+1
+2
+select FOUND_ROWS();
+FOUND_ROWS()
+4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+select * from t1 where i=1;
+i
+1
+select FOUND_ROWS();
+FOUND_ROWS()
+1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 7
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+drop table t1;
+# On node-2
+flush query cache;
+reset query cache;
+# On node-1
+flush query cache;
+reset query cache;
+create table t1 (a int not null) ENGINE=MYISAM;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 9
+insert delayed into t1 values (4);
+select a from t1;
+a
+1
+2
+3
+4
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 9
+# On node-2
+select * from t1;
+a
+select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+insert delayed into t1 values (4);
+select a from t1;
+a
+4
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+drop table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 8
+# On node-1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 9
+# On node-2
+show global variables like "query_cache_min_res_unit";
+Variable_name Value
+query_cache_min_res_unit 4096
+set GLOBAL query_cache_min_res_unit=1001;
+Warnings:
+Warning 1292 Truncated incorrect query_cache_min_res_unit value: '1001'
+show global variables like "query_cache_min_res_unit";
+Variable_name Value
+query_cache_min_res_unit 1000
+# On node-1
+show global variables like "query_cache_min_res_unit";
+Variable_name Value
+query_cache_min_res_unit 4096
+set GLOBAL query_cache_min_res_unit=1001;
+Warnings:
+Warning 1292 Truncated incorrect query_cache_min_res_unit value: '1001'
+show global variables like "query_cache_min_res_unit";
+Variable_name Value
+query_cache_min_res_unit 1000
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null) engine=innodb;
+insert into t2 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+select * from t2;
+a
+1
+2
+3
+select * from t2;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+# On node-2
+select * from t1;
+a
+1
+2
+3
+select * from t1;
+a
+1
+2
+3
+select * from t2;
+a
+1
+2
+3
+select * from t2;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 10
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+drop table t1;
+select a from t2;
+a
+1
+2
+3
+select a from t2;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+set GLOBAL query_cache_min_res_unit=default;
+show global variables like "query_cache_min_res_unit";
+Variable_name Value
+query_cache_min_res_unit 4096
+# On node-1
+select a from t2;
+a
+1
+2
+3
+select a from t2;
+a
+1
+2
+3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+drop table t2;
+set GLOBAL query_cache_min_res_unit=default;
+show global variables like "query_cache_min_res_unit";
+Variable_name Value
+query_cache_min_res_unit 4096
+# On node-1
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1);
+select "aaa" from t1;
+aaa
+aaa
+select "AAA" from t1;
+AAA
+AAA
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+# On node-2
+select "aaa" from t1;
+aaa
+aaa
+select "AAA" from t1;
+AAA
+AAA
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+drop table t1;
+# On node-1
+create table t1 (a int) engine=innodb;
+set GLOBAL query_cache_size=1000;
+Warnings:
+Warning 1292 Truncated incorrect query_cache_size value: '1000'
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=1024;
+Warnings:
+Warning 1282 Query cache failed to set size 1024; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=10240;
+Warnings:
+Warning 1282 Query cache failed to set size 10240; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=20480;
+Warnings:
+Warning 1282 Query cache failed to set size 20480; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=40960;
+Warnings:
+Warning 1282 Query cache failed to set size 40960; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=51200;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 51200
+select * from t1;
+a
+set GLOBAL query_cache_size=61440;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 61440
+select * from t1;
+a
+set GLOBAL query_cache_size=81920;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 81920
+select * from t1;
+a
+set GLOBAL query_cache_size=102400;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 102400
+select * from t1;
+a
+# On node-2
+set GLOBAL query_cache_size=1000;
+Warnings:
+Warning 1292 Truncated incorrect query_cache_size value: '1000'
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=1024;
+Warnings:
+Warning 1282 Query cache failed to set size 1024; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=10240;
+Warnings:
+Warning 1282 Query cache failed to set size 10240; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=20480;
+Warnings:
+Warning 1282 Query cache failed to set size 20480; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=40960;
+Warnings:
+Warning 1282 Query cache failed to set size 40960; new query cache size is 0
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 0
+select * from t1;
+a
+set GLOBAL query_cache_size=51200;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 51200
+select * from t1;
+a
+set GLOBAL query_cache_size=61440;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 61440
+select * from t1;
+a
+set GLOBAL query_cache_size=81920;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 81920
+select * from t1;
+a
+set GLOBAL query_cache_size=102400;
+show global variables like "query_cache_size";
+Variable_name Value
+query_cache_size 102400
+select * from t1;
+a
+drop table t1;
+# On node-1
+set GLOBAL query_cache_size=1048576;
+create table t1 (i int not null) engine=innodb;
+create table t2 (i int not null) engine=innodb;
+select * from t1;
+i
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+create temporary table t3 (i int not null);
+select * from t2;
+i
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+select * from t3;
+i
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+update t1 set i=(select distinct 1 from (select * from t2) a);
+drop table t3;
+# On node-2
+set GLOBAL query_cache_size=1048576;
+select * from t1;
+i
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+select * from t2;
+i
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+drop table t1, t2;
+# On node-1
+use mysql;
+select * from db;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+use test;
+select * from mysql.db;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+# On node-1
+create table t1(id int auto_increment primary key) engine=innodb;
+insert into t1 values (1), (2), (3);
+select * from t1;
+id
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+# On node-2
+select * from t1;
+id
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+# On node-1
+alter table t1 rename to t2;
+select * from t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+# On node-2
+select * from t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+drop table t2;
+# On node-1
+create table t1 (word char(20) not null) engine=innodb;
+select * from t1;
+word
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+load data infile 'MYSQLTEST_VARDIR/std_data/words.dat' into table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+select count(*) from t1;
+count(*)
+70
+# On node-2
+select count(*) from t1;
+count(*)
+70
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+load data infile 'MYSQLTEST_VARDIR/std_data/words.dat' into table t1;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+select count(*) from t1;
+count(*)
+140
+drop table t1;
+# On node-1
+create table t1 (a int) engine=innodb;
+insert into t1 values (1),(2),(3);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+select * from t1 into outfile "query_cache.out.file";
+select * from t1 into outfile "query_cache.out.file";
+ERROR HY000: File 'query_cache.out.file' already exists
+select * from t1 limit 1 into dumpfile "query_cache.dump.file";
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+drop table t1;
+# On node-1
+create table t1 (a int) engine=innodb;
+insert into t1 values (1),(2);
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+select * from t1;
+a
+1
+2
+SET SQL_SELECT_LIMIT=1;
+select * from t1;
+a
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+SET SQL_SELECT_LIMIT=DEFAULT;
+# On node-2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+select * from t1;
+a
+1
+2
+SET SQL_SELECT_LIMIT=1;
+select * from t1;
+a
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+SET SQL_SELECT_LIMIT=DEFAULT;
+drop table t1;
+# On node-1
+create table t1 (a int not null) engine=innodb;
+create table t2 (a int not null) engine=innodb;
+set query_cache_wlock_invalidate=1;
+create view v1 as select * from t1;
+select * from t1;
+a
+select * from t2;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+lock table t1 write, t2 read;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+unlock table;
+select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+lock table v1 write;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+unlock table;
+drop view v1;
+set query_cache_wlock_invalidate=default;
+# On node-2
+set query_cache_wlock_invalidate=1;
+create view v1 as select * from t1;
+select * from t1;
+a
+select * from t2;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+lock table t1 write, t2 read;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+unlock table;
+select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+lock table v1 write;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+unlock table;
+drop view v1;
+set query_cache_wlock_invalidate=default;
+drop table t1,t2;
+# On node-1
+create table t1 (id int primary key) engine=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+id
+1
+2
+3
+create temporary table t1 (a int not null auto_increment primary key);
+select * from t1;
+a
+drop table t1;
+drop table t1;
+# On node-1
+SET NAMES koi8r;
+CREATE TABLE t1 (a char(1) character set koi8r) engine=innodb;
+INSERT INTO t1 VALUES (_koi8r'á'),(_koi8r'Ã');
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+Warning 1265 Data truncated for column 'a' at row 2
+SELECT a,'Â','â'='Â' FROM t1;
+a  'â'='Â'
+à Â 0
+à Â 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+set collation_connection=koi8r_bin;
+SELECT a,'Â','â'='Â' FROM t1;
+a  'â'='Â'
+à Â 0
+à Â 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+set character_set_client=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+a ç? 'ç?'='ç?'
+Ã ç? 1
+Ã ç? 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+set character_set_results=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+a � 'â'='Â'
+ö Ã? 1
+ö Ã? 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+SET NAMES default;
+# On node-2
+SELECT a,'Â','â'='Â' FROM t1;
+a  'â'='Â'
+? Â 0
+? Â 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+set collation_connection=koi8r_bin;
+SELECT a,'Â','â'='Â' FROM t1;
+a ?? 'â'='Â'
+? ?? 1
+? ?? 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+set character_set_client=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+a ?? '??'='?‚'
+? ?? 1
+? ?? 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+set character_set_results=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+a � 'â'='Â'
+ö Ã? 1
+ö Ã? 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+drop table t1;
+# On node-1
+create table t1 (a int) engine=innodb;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 46
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+/**/ select * from t1;
+a
+/**/ select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 47
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 13
+# On node-2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 38
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 11
+/**/ select * from t1;
+a
+/**/ select * from t1;
+a
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 39
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 12
+drop table t1;
+# On node-1
+set session query_cache_type = 2;
+create table t1(a int) engine=innodb;
+select table_name from information_schema.tables
+where table_schema="test";
+table_name
+t1
+drop table t1;
+select table_name from information_schema.tables
+where table_schema="test";
+table_name
+set session query_cache_type = 1;
+set global query_cache_size=1024*1024;
+flush query cache;
+create table t1 ( a int ) engine=myisam;
+insert into t1 values (1);
+select a from t1;
+a
+1
+select a from t1;
+a
+1
+show status like 'qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 14
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+show status like 'qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 14
+# On node-2
+select a from t1;
+a
+select a from t1;
+a
+show status like 'qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 13
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+show status like 'qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 0
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 13
+drop table t1;
+# Restore original settings.
+# On node-1
+SET GLOBAL query_cache_size=@query_cache_size_saved;
+SET GLOBAL query_cache_type=@query_cache_type_saved;
+
+# On node-2
+SET GLOBAL query_cache_size=@query_cache_size_saved;
+SET GLOBAL query_cache_type=@query_cache_type_saved;
+# End of test
diff --git a/mysql-test/suite/galera/r/rename.result b/mysql-test/suite/galera/r/rename.result
new file mode 100644
index 00000000000..f13d3f13b24
--- /dev/null
+++ b/mysql-test/suite/galera/r/rename.result
@@ -0,0 +1,38 @@
+#
+# MDEV-8598 : Failed MySQL DDL commands and Galera replication
+#
+# On node 1
+USE test;
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUE(1);
+SELECT * FROM t1;
+i
+1
+# Create a new user 'foo' with limited privileges
+GRANT SELECT on test.* TO foo@localhost;
+# Open connection to the 1st node using 'test_user1' user.
+SELECT * FROM t1;
+i
+1
+# Following RENAME should not replicate to other node.
+RENAME TABLE t1 TO t2;
+ERROR 42000: DROP, ALTER command denied to user 'foo'@'localhost' for table 't1'
+# On node 2
+USE test;
+SELECT * FROM t1;
+i
+1
+# On node_1
+RENAME TABLE t1 TO t2;
+SHOW TABLES;
+Tables_in_test
+t2
+# On node 2
+USE test;
+SELECT * FROM t2;
+i
+1
+DROP USER foo@localhost;
+DROP TABLE t2;
+# End of tests
diff --git a/mysql-test/suite/galera/r/rpl_row_annotate.result b/mysql-test/suite/galera/r/rpl_row_annotate.result
new file mode 100644
index 00000000000..ff8d49702ac
--- /dev/null
+++ b/mysql-test/suite/galera/r/rpl_row_annotate.result
@@ -0,0 +1,66 @@
+# On node_2
+RESET MASTER;
+# On node_1
+RESET MASTER;
+CREATE TABLE t1(i INT)ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+DELETE FROM t1 WHERE i = 1;
+# On node_2
+INSERT INTO t1 VALUES(2);
+DELETE FROM t1 WHERE i = 2;
+# On node_1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM <start_pos>;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 # Gtid_list 1 # []
+mysqld-bin.000001 # Binlog_checkpoint 1 # mysqld-bin.000001
+mysqld-bin.000001 # Gtid 1 # GTID 0-1-1
+mysqld-bin.000001 # Query 1 # use `test`; CREATE TABLE t1(i INT)ENGINE=INNODB
+mysqld-bin.000001 # Gtid 1 # BEGIN GTID 0-1-2
+mysqld-bin.000001 # Annotate_rows 1 # INSERT INTO t1 VALUES(1)
+mysqld-bin.000001 # Table_map 1 # table_id: # (test.t1)
+mysqld-bin.000001 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Gtid 1 # BEGIN GTID 0-1-3
+mysqld-bin.000001 # Annotate_rows 1 # DELETE FROM t1 WHERE i = 1
+mysqld-bin.000001 # Table_map 1 # table_id: # (test.t1)
+mysqld-bin.000001 # Delete_rows_v1 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Gtid 2 # BEGIN GTID 0-2-4
+mysqld-bin.000001 # Annotate_rows 2 # INSERT INTO t1 VALUES(2)
+mysqld-bin.000001 # Table_map 2 # table_id: # (test.t1)
+mysqld-bin.000001 # Write_rows_v1 2 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
+mysqld-bin.000001 # Gtid 2 # BEGIN GTID 0-2-5
+mysqld-bin.000001 # Annotate_rows 2 # DELETE FROM t1 WHERE i = 2
+mysqld-bin.000001 # Table_map 2 # table_id: # (test.t1)
+mysqld-bin.000001 # Delete_rows_v1 2 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
+# On node_2
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM <start_pos>;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 # Gtid_list 2 # []
+mysqld-bin.000001 # Binlog_checkpoint 2 # mysqld-bin.000001
+mysqld-bin.000001 # Gtid 1 # GTID 0-1-1
+mysqld-bin.000001 # Query 1 # use `test`; CREATE TABLE t1(i INT)ENGINE=INNODB
+mysqld-bin.000001 # Gtid 1 # BEGIN GTID 0-1-2
+mysqld-bin.000001 # Annotate_rows 1 # INSERT INTO t1 VALUES(1)
+mysqld-bin.000001 # Table_map 1 # table_id: # (test.t1)
+mysqld-bin.000001 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Gtid 1 # BEGIN GTID 0-1-3
+mysqld-bin.000001 # Annotate_rows 1 # DELETE FROM t1 WHERE i = 1
+mysqld-bin.000001 # Table_map 1 # table_id: # (test.t1)
+mysqld-bin.000001 # Delete_rows_v1 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Gtid 2 # BEGIN GTID 0-2-4
+mysqld-bin.000001 # Annotate_rows 2 # INSERT INTO t1 VALUES(2)
+mysqld-bin.000001 # Table_map 2 # table_id: # (test.t1)
+mysqld-bin.000001 # Write_rows_v1 2 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
+mysqld-bin.000001 # Gtid 2 # BEGIN GTID 0-2-5
+mysqld-bin.000001 # Annotate_rows 2 # DELETE FROM t1 WHERE i = 2
+mysqld-bin.000001 # Table_map 2 # table_id: # (test.t1)
+mysqld-bin.000001 # Delete_rows_v1 2 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
+DROP TABLE t1;
+# End of test
diff --git a/mysql-test/suite/galera/r/unique_key.result b/mysql-test/suite/galera/r/unique_key.result
new file mode 100644
index 00000000000..ffb4f01c1f8
--- /dev/null
+++ b/mysql-test/suite/galera/r/unique_key.result
@@ -0,0 +1,47 @@
+#
+# MDEV#5552 Deadlock when inserting NULL column value in column with
+# UNIQUE index
+#
+USE test;
+
+# On node_1
+CREATE TABLE t1(c1 INT DEFAULT NULL, UNIQUE KEY c1(c1)) ENGINE=INNODB;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM test.t1;
+c1
+NULL
+NULL
+
+# On node_2
+SELECT * FROM test.t1;
+c1
+NULL
+NULL
+
+# On node_1
+INSERT INTO t1 VALUES (1);
+UPDATE t1 SET c1=NULL WHERE c1=1;
+SELECT * FROM test.t1;
+c1
+NULL
+NULL
+NULL
+
+# On node_2
+SELECT * FROM test.t1;
+c1
+NULL
+NULL
+NULL
+
+# On node_1
+DELETE FROM t1 WHERE c1<=>NULL;
+SELECT * FROM test.t1;
+c1
+
+# On node_2
+SELECT * FROM test.t1;
+c1
+DROP TABLE t1;
+# End of test
diff --git a/mysql-test/suite/galera/r/view.result b/mysql-test/suite/galera/r/view.result
new file mode 100644
index 00000000000..06d7bf072e8
--- /dev/null
+++ b/mysql-test/suite/galera/r/view.result
@@ -0,0 +1,52 @@
+#
+# MDEV-7222: Cluster Node Crash at CREATE DEFINER statement
+#
+USE test;
+CREATE DEFINER=CURRENT_USER VIEW v1 AS SELECT 1;
+DROP VIEW v1;
+#
+# MDEV-8464 : ALTER VIEW not replicated in some cases
+#
+# On node_1
+USE test;
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+CREATE DEFINER=CURRENT_USER VIEW v1 AS SELECT * FROM t1;
+CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM t1;
+CREATE ALGORITHM=TEMPTABLE VIEW v3 AS SELECT * FROM t1;
+CREATE ALGORITHM=UNDEFINED DEFINER=CURRENT_USER VIEW v4 AS SELECT * FROM t1;
+# On node_2
+USE test;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+SHOW CREATE VIEW v2;
+View Create View character_set_client collation_connection
+v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+SHOW CREATE VIEW v3;
+View Create View character_set_client collation_connection
+v3 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+SHOW CREATE VIEW v4;
+View Create View character_set_client collation_connection
+v4 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+# On node_1
+ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1;
+ALTER ALGORITHM=UNDEFINED VIEW v2 AS SELECT * FROM t1;
+ALTER DEFINER=CURRENT_USER VIEW v3 AS SELECT * FROM t1;
+ALTER ALGORITHM=TEMPTABLE DEFINER=CURRENT_USER VIEW v4 AS SELECT * FROM t1;
+# On node_2
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+SHOW CREATE VIEW v2;
+View Create View character_set_client collation_connection
+v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+SHOW CREATE VIEW v3;
+View Create View character_set_client collation_connection
+v3 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+SHOW CREATE VIEW v4;
+View Create View character_set_client collation_connection
+v4 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci
+# Cleanup
+DROP VIEW v1, v2, v3, v4;
+DROP TABLE t1;
+# End of tests
diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm
new file mode 100644
index 00000000000..d5de3628f75
--- /dev/null
+++ b/mysql-test/suite/galera/suite.pm
@@ -0,0 +1,86 @@
+package My::Suite::GALERA;
+use File::Basename;
+use My::Find;
+
+@ISA = qw(My::Suite);
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+return "WSREP is not compiled in" unless defined $::mysqld_variables{'wsrep-on'};
+
+my ($provider) = grep { -f $_ } $ENV{WSREP_PROVIDER},
+ "/usr/lib/galera/libgalera_smm.so",
+ "/usr/lib64/galera/libgalera_smm.so";
+
+return "No wsrep provider library" unless -f $provider;
+
+$ENV{WSREP_PROVIDER} = $provider;
+
+my ($spath) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir;
+return "No SST scripts" unless $spath;
+
+my ($cpath) = grep { -f "$_/mysql"; } "$::bindir/scripts", $::path_client_bindir;
+return "No scritps" unless $cpath;
+
+my ($epath) = grep { -f "$_/my_print_defaults"; } "$::bindir/extra", $::path_client_bindir;
+return "No my_print_defaults" unless $epath;
+
+push @::global_suppressions,
+ (
+ qr(WSREP: wsrep_sst_receive_address is set to '127.0.0.1),
+ qr(WSREP: Could not open saved state file for reading: .*),
+ qr(WSREP: Could not open state file for reading: .*),
+ qr(WSREP: Gap in state sequence. Need state transfer.),
+ qr(WSREP: Failed to prepare for incremental state transfer:),
+ qr(WSREP:.*down context.*),
+ qr(WSREP: Failed to send state UUID:),
+ qr(WSREP: last inactive check more than .* skipping check),
+ qr(WSREP: SQL statement was ineffective),
+ qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.),
+ qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|,
+ qr(WSREP: Quorum: No node with complete state),
+ qr(WSREP: Initial position was provided by configuration or SST, avoiding override),
+ qr|WSREP: discarding established \(time wait\) .*|,
+ qr(WSREP: There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside. Will use that one.),
+ qr(WSREP: evs::proto.*),
+ qr|WSREP: Ignoring possible split-brain \(allowed by configuration\) from view:.*|,
+ qr(WSREP: no nodes coming from prim view, prim not possible),
+ qr(WSREP: Member .* requested state transfer from .* but it is impossible to select State Transfer donor: Resource temporarily unavailable),
+ qr(WSREP: user message in state LEAVING),
+ qr(WSREP: .* sending install message failed: Transport endpoint is not connected),
+ qr(WSREP: .* sending install message failed: Resource temporarily unavailable),
+ qr(WSREP: Maximum writeset size exceeded by .*),
+ qr(WSREP: transaction size exceeded.*),
+ qr(WSREP: RBR event .*),
+ qr(WSREP: Ignoring error for TO isolated action: .*),
+ qr(WSREP: transaction size limit .*),
+ qr(WSREP: rbr write fail, .*),
+ qr(WSREP: .*Backend not supported: foo.*),
+ qr(WSREP: .*Failed to initialize backend using .*),
+ qr(WSREP: .*Failed to open channel 'my_wsrep_cluster' at .*),
+ qr(WSREP: gcs connect failed: Socket type not supported),
+ qr(WSREP: failed to open gcomm backend connection: 110: failed to reach primary view: 110 .*),
+ qr(WSREP: .*Failed to open backend connection: -110 .*),
+ qr(WSREP: .*Failed to open channel 'my_wsrep_cluster' at .*),
+ qr(WSREP: gcs connect failed: Connection timed out),
+ qr|WSREP: wsrep::connect\(\) failed: 7|,
+ qr|WSREP: wsrep::connect\(.*\) failed: 7|,
+ qr(WSREP: SYNC message from member .* in non-primary configuration. Ignored.),
+ qr(WSREP: Could not find peer:),
+ qr(WSREP: TO isolation failed for: .*),
+ qr|WSREP: gcs_caused\(\) returned .*|,
+ qr|WSREP: Protocol violation. JOIN message sender .* is not in state transfer \(SYNCED\). Message ignored.|,
+ qr|WSREP: Protocol violation. JOIN message sender .* is not in state transfer \(JOINED\). Message ignored.|,
+ qr|WSREP: Unsupported protocol downgrade: incremental data collection disabled. Expect abort.|,
+ qr(WSREP: Action message in non-primary configuration from member [0-9]*),
+ qr(WSREP: discarding established .*),
+ qr(WSREP: gcs\/src\/gcs_core.cpp:core_handle_uuid_msg\(\):.*),
+ );
+
+
+$ENV{PATH}="$epath:$ENV{PATH}";
+$ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath;
+$ENV{PATH}="$cpath:$ENV{PATH}" unless $cpath eq $spath;
+
+bless { };
+
diff --git a/mysql-test/suite/galera/t/GAL-382.test b/mysql-test/suite/galera/t/GAL-382.test
new file mode 100644
index 00000000000..05cc7346055
--- /dev/null
+++ b/mysql-test/suite/galera/t/GAL-382.test
@@ -0,0 +1,16 @@
+#
+# GAL-382 InnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno in trx0sys.cc line 356
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+create table t1 (i int, j int, k int, primary key pk(i)) engine=innodb;
+insert into t1 values (1, 1, 1), (2, 2, 2), (3, 3, 3);
+create table t2 (i int, j int, k int, primary key pk(i, j, k), index idx(i, k, j)) engine=innodb;
+replace into t2 (i, j, k) select /*!99997 */ i, k, j from t1;
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera/t/GAL-401.test b/mysql-test/suite/galera/t/GAL-401.test
new file mode 100644
index 00000000000..06ce37dc81f
--- /dev/null
+++ b/mysql-test/suite/galera/t/GAL-401.test
@@ -0,0 +1,56 @@
+# This tests proper desync counter cleanup when DONOR/DESYNC state is cleared.
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Make node 1 tolerate split-brain
+SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
+
+# Desync and disconnect node 2 from the PC:
+--connection node_2
+SET @@global.wsrep_desync = 1;
+SET SESSION wsrep_dirty_reads=1;
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+# Wait until node 2 disappears from the PC:
+--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
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+# Modify app state to force node 2 into PRIMARY upon reconnection.
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+
+# Reconnect node 2 to the PC:
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+SET wsrep_dirty_reads=0;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--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
+
+# Must return 0:
+SHOW STATUS LIKE 'wsrep_desync_count';
+
+# Resync node_2, should pass:
+SET @@global.wsrep_desync = 0;
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.inc
+
+SET SESSION wsrep_sync_wait=15;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+CALL mtr.add_suppression("WSREP: Protocol violation. JOIN message sender (.*) is not in state transfer \\(SYNCED\\). Message ignored.");
+
+--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
+SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=false';
diff --git a/mysql-test/suite/galera/t/GAL-419.test b/mysql-test/suite/galera/t/GAL-419.test
new file mode 100644
index 00000000000..e50b948bf35
--- /dev/null
+++ b/mysql-test/suite/galera/t/GAL-419.test
@@ -0,0 +1,35 @@
+#
+# GAL-419 safe_to_bootstrap: boostrap using wsrep_cluster_address=gcomm:// not prevented
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--source include/kill_galera.inc
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+--source include/kill_galera.inc
+
+--sleep 2
+
+# Node #1 has wsrep_cluster_address=gcomm:// in my.cnf, so should fail to bootstrap
+
+--error 1
+--exec $MYSQLD --defaults-group-suffix=.1 --defaults-file=$MYSQLTEST_VARDIR/my.cnf | grep 'This node is not safe to bootstrap the cluster'
+
+# Unless we remove grastate.dat
+
+--remove_file $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
+--connection node_1
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--connection node_2
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
diff --git a/mysql-test/suite/galera/t/GAL-480.test b/mysql-test/suite/galera/t/GAL-480.test
new file mode 100644
index 00000000000..142772fd8f9
--- /dev/null
+++ b/mysql-test/suite/galera/t/GAL-480.test
@@ -0,0 +1,47 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 CHAR(10), f0 integer) ENGINE=InnoDB;
+
+FLUSH TABLE t1 FOR EXPORT;
+UNLOCK TABLES;
+
+ALTER TABLE t1 DROP COLUMN f1;
+
+SET SESSION wsrep_osu_method='RSU';
+ALTER TABLE t1 ADD COLUMN f1 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f1;
+ALTER TABLE t1 ADD COLUMN f2 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f2;
+ALTER TABLE t1 ADD COLUMN f3 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f3;
+ALTER TABLE t1 ADD COLUMN f4 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f4;
+ALTER TABLE t1 ADD COLUMN f5 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f5;
+ALTER TABLE t1 ADD COLUMN f6 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f6;
+ALTER TABLE t1 ADD COLUMN f7 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f7;
+ALTER TABLE t1 ADD COLUMN f8 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f8;
+ALTER TABLE t1 ADD COLUMN f9 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f9;
+ALTER TABLE t1 ADD COLUMN f10 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f10;
+ALTER TABLE t1 ADD COLUMN f11 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f11;
+ALTER TABLE t1 ADD COLUMN f12 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f12;
+ALTER TABLE t1 ADD COLUMN f13 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f13;
+ALTER TABLE t1 ADD COLUMN f14 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f14;
+ALTER TABLE t1 ADD COLUMN f15 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f15;
+ALTER TABLE t1 ADD COLUMN f16 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f16;
+
+SET SESSION wsrep_osu_method='TOI';
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-252.test b/mysql-test/suite/galera/t/MW-252.test
new file mode 100644
index 00000000000..dfb82e8070a
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-252.test
@@ -0,0 +1,42 @@
+#
+# MW-252 - Check that FTWRL causes the node to become desynced
+# and not subject to flow control
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+FLUSH TABLES WITH READ LOCK;
+
+# Node #1 is now desynced
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Donor/Desynced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment'
+--source include/wait_condition.inc
+
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Node #2 can issue updates without flow control kicking in
+--connection node_2
+
+--let $count = 100
+--disable_query_log
+while ($count)
+{
+ INSERT INTO t1 VALUES (1);
+ --dec $count
+}
+--enable_query_log
+
+# Restore cluster
+--connection node_1
+UNLOCK TABLES;
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment'
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 100 FROM t1
+--source include/wait_condition.inc
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-258.test b/mysql-test/suite/galera/t/MW-258.test
new file mode 100644
index 00000000000..174dd2c02c6
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-258.test
@@ -0,0 +1,42 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+LOCK TABLE t1 WRITE;
+--echo value prior to RSU:
+SHOW STATUS LIKE 'wsrep_desync_count';
+SHOW VARIABLES LIKE 'wsrep_desync';
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_osu_method = RSU;
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1b
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_osu_method = RSU;
+--send ALTER TABLE t1 ADD COLUMN f3 INTEGER;
+
+--sleep 5
+--connection node_1
+--echo value during RSU:
+SHOW STATUS LIKE 'wsrep_desync_count';
+SHOW VARIABLES LIKE 'wsrep_desync';
+UNLOCK TABLES;
+
+--connection node_1a
+--reap
+--connection node_1b
+--reap
+
+--connection node_1
+--echo value after RSU:
+--sleep 3
+SHOW STATUS LIKE 'wsrep_desync_count';
+SHOW VARIABLES LIKE 'wsrep_desync';
+SET GLOBAL wsrep_desync=0;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-259.test b/mysql-test/suite/galera/t/MW-259.test
new file mode 100644
index 00000000000..ff9a30deed3
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-259.test
@@ -0,0 +1,42 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+
+SET GLOBAL wsrep_desync=0;
+SET wsrep_OSU_method=RSU;
+
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_1a
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_open_tables'
+--source include/wait_condition.inc
+
+# wsrep_desync=1 will block
+--send SET GLOBAL wsrep_desync=1;
+
+--connection node_1b
+--sleep 2
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'exit open_tables()' and INFO = 'SET GLOBAL wsrep_desync=1'
+--source include/wait_condition.inc
+
+SET DEBUG_SYNC= 'now SIGNAL continue';
+DROP TABLE t1;
+SET GLOBAL wsrep_desync=0;
+
+--connection node_1
+--reap
+
+--connection node_1a
+--reap
+
+# Cleanup
+SET DEBUG_SYNC= 'RESET';
+
diff --git a/mysql-test/suite/galera/t/MW-284.cnf b/mysql-test/suite/galera/t/MW-284.cnf
new file mode 100644
index 00000000000..52fd3093931
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-284.cnf
@@ -0,0 +1 @@
+!include ../galera_2nodes_as_master.cnf
diff --git a/mysql-test/suite/galera/t/MW-284.test b/mysql-test/suite/galera/t/MW-284.test
new file mode 100644
index 00000000000..f3ce1b0dc91
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-284.test
@@ -0,0 +1,58 @@
+#
+# MW-284 Slave I/O retry on ER_COM_UNKNOWN_ERROR
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.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, MASTER_USER='root', MASTER_CONNECT_RETRY=1;
+--enable_query_log
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+SET SESSION wsrep_on = OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'
+--source include/wait_condition.inc
+SET SESSION wsrep_on = ON;
+
+--connection node_3
+START SLAVE;
+--sleep 1
+--let $slave_param= Slave_IO_Running
+--let $slave_param_value= Connecting
+--source include/wait_for_slave_param.inc
+
+--connection node_1
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+# We expect the slave to reconnect and resume replication
+
+--connection node_3
+--source include/wait_for_slave_to_start.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+
+--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(*) > 0 FROM t1
+--source include/wait_condition.inc
+
+# Cleanup
+
+--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;
+
+CALL mtr.add_suppression('failed registering on master');
+CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
diff --git a/mysql-test/suite/galera/t/MW-285.test b/mysql-test/suite/galera/t/MW-285.test
new file mode 100644
index 00000000000..1c567f7b250
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-285.test
@@ -0,0 +1,31 @@
+#
+# Broken FK constraints cause assertions
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE parent1 ( id INT PRIMARY KEY, KEY (id) ) ENGINE=InnoDB;
+CREATE TABLE parent2 ( id INT PRIMARY KEY, KEY (id) ) ENGINE=InnoDB;
+
+CREATE TABLE child (
+ id INT PRIMARY KEY,
+ parent1_id INT,
+ parent2_id INT,
+ FOREIGN KEY (parent1_id) REFERENCES parent1(id),
+ FOREIGN KEY (parent1_id) REFERENCES parent2(id)
+) ENGINE=InnoDB;
+
+INSERT INTO parent1 VALUES (1);
+INSERT INTO parent2 VALUES (1);
+INSERT INTO child VALUES (1,1,1);
+INSERT INTO child VALUES (2,1,1);
+
+SET foreign_key_checks=OFF;
+DROP TABLE parent1;
+
+UPDATE child SET parent1_id=2 WHERE id=1;
+
+DROP TABLE child;
+DROP TABLE parent2;
+SET foreign_key_checks=ON;
diff --git a/mysql-test/suite/galera/t/MW-286.test b/mysql-test/suite/galera/t/MW-286.test
new file mode 100644
index 00000000000..1b2e322f078
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-286.test
@@ -0,0 +1,32 @@
+#
+# MW-286 Spurious deadlock error after error with wsrep_desync and wsrep_on
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.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_desync = TRUE;
+SET wsrep_on = FALSE;
+
+--error ER_QUERY_INTERRUPTED
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+
+SET wsrep_on = TRUE;
+SET GLOBAL wsrep_desync = FALSE;
+
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera/t/MW-292.test b/mysql-test/suite/galera/t/MW-292.test
new file mode 100644
index 00000000000..ecb1273759e
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-292.test
@@ -0,0 +1,79 @@
+#
+# MW-292 Reset timestamp after transaction replay
+#
+# We force transaction replay to happen and then we check that NOW() is not stuck in time.
+# As a bonus we also check that RAND() continues to return random values after replay
+#
+#
+
+--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 rand_table (f1 FLOAT);
+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
+--let $galera_sync_point = commit_monitor_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+--send COMMIT;
+
+# Wait until commit is blocked
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--source include/galera_wait_sync_point.inc
+
+# Issue a conflicting update on node #2
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+
+# Wait for both transactions to be blocked
+--connection node_1a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Update_rows_log_event::find_row%';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'init' AND INFO = 'COMMIT';
+--source include/wait_condition.inc
+
+# Unblock the commit
+--connection node_1a
+--source include/galera_clear_sync_point.inc
+--source include/galera_signal_sync_point.inc
+
+# Commit succeeds via replay
+--connection node_1
+--reap
+
+# Confirm that NOW() is not stuck in time relative to SYSDATE();
+--sleep 3
+SELECT TIMEDIFF(SYSDATE(), NOW()) < 2;
+
+INSERT INTO rand_table VALUES (RAND()),(RAND()),(RAND()),(RAND()),(RAND());
+INSERT INTO rand_table VALUES (RAND()),(RAND()),(RAND()),(RAND()),(RAND());
+
+SELECT COUNT(DISTINCT f1) = 10 FROM rand_table;
+
+# 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
+DROP TABLE t1;
+DROP TABLE rand_table;
diff --git a/mysql-test/suite/galera/t/MW-309.test b/mysql-test/suite/galera/t/MW-309.test
new file mode 100644
index 00000000000..351a508ecec
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-309.test
@@ -0,0 +1,32 @@
+#
+# MW-309 Regression: wsrep_max_ws_rows limit also applies to certain SELECT queries
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+
+SET GLOBAL wsrep_max_ws_rows = 2;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 GROUP BY f1;
+SELECT * FROM t1 GROUP BY f1;
+
+--error 0
+SELECT * FROM t1 GROUP BY f1;
+
+--disable_result_log
+--error 0
+SHOW STATUS LIKE '%wsrep%';
+--enable_result_log
+
+SET GLOBAL wsrep_max_ws_rows = 0;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-313-master.opt b/mysql-test/suite/galera/t/MW-313-master.opt
new file mode 100644
index 00000000000..8a755e98b00
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-313-master.opt
@@ -0,0 +1 @@
+--log-bin --log-slave-updates
diff --git a/mysql-test/suite/galera/t/MW-313.test b/mysql-test/suite/galera/t/MW-313.test
new file mode 100644
index 00000000000..92fd835c615
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-313.test
@@ -0,0 +1,51 @@
+#
+# MW-313 Enforce wsrep_max_ws_rows also when binlog is enabled
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_binlog_format_row.inc
+
+# No error expected for SELECT and SHOW
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+
+SET GLOBAL wsrep_max_ws_rows = 2;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 GROUP BY f1;
+SELECT * FROM t1 GROUP BY f1;
+
+--error 0
+SELECT * FROM t1 GROUP BY f1;
+
+--disable_result_log
+--error 0
+SHOW STATUS LIKE '%wsrep%';
+--enable_result_log
+
+# Error expected for DML
+
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 SELECT * FROM t1;
+
+START TRANSACTION;
+INSERT INTO t1 (f1) VALUES (1);
+
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f1) VALUES (2),(3),(4);
+
+ROLLBACK;
+START TRANSACTION;
+--error ER_ERROR_DURING_COMMIT
+DELETE FROM t1;
+
+DROP TABLE t1;
+SET GLOBAL wsrep_max_ws_rows = 0;
diff --git a/mysql-test/suite/galera/t/MW-328-footer.inc b/mysql-test/suite/galera/t/MW-328-footer.inc
new file mode 100644
index 00000000000..5b736df220f
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328-footer.inc
@@ -0,0 +1,18 @@
+#
+# Cleanup for MW-328 tests
+#
+
+--connection node_1
+--disable_query_log
+--eval KILL CONNECTION $sp_connection_id
+--enable_query_log
+
+--connection node_1X
+--error 2013,1317
+--reap
+
+--connection node_1
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-test/suite/galera/t/MW-328-header.inc b/mysql-test/suite/galera/t/MW-328-header.inc
new file mode 100644
index 00000000000..f0a6ccaccc6
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328-header.inc
@@ -0,0 +1,29 @@
+#
+# Initialization for MW-328 tests
+#
+
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+
+#
+# Have some random updates going on against t1
+#
+
+DELIMITER |;
+CREATE PROCEDURE proc_update ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+ END WHILE;
+END|
+
+DELIMITER ;|
+
+--connect node_1X, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1X
+--let $sp_connection_id = `SELECT CONNECTION_ID()`
+--send CALL proc_update();
diff --git a/mysql-test/suite/galera/t/MW-328A.test b/mysql-test/suite/galera/t/MW-328A.test
new file mode 100644
index 00000000000..4d6e1ea3625
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328A.test
@@ -0,0 +1,56 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Attempt to insert into t2 and check if insert actually inserted rows if
+# a success was reported.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+--let $successes = 0
+--let $deadlocks = 0
+
+SET SESSION wsrep_retry_autocommit = 0;
+
+--disable_query_log
+
+while ($count)
+{
+ TRUNCATE TABLE t2;
+
+ --error 0,1213
+ INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+ if ($mysql_errno != 1213) {
+ --inc $successes
+ if (`SELECT COUNT(*) = 0 FROM t2`) {
+ --die No rows arrived in table t2
+ }
+ }
+
+ if ($mysql_errno == 1213) {
+ --inc $deadlocks
+
+ }
+
+ --dec $count
+}
+
+--enable_query_log
+
+#
+# Check that the test produced both deadlocks and successes
+#
+
+--disable_query_log
+--eval SELECT $successes > 0 AS have_successes
+--eval SELECT $deadlocks > 0 AS have_deadlocks
+--enable_query_log
+
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-test/suite/galera/t/MW-328B.test b/mysql-test/suite/galera/t/MW-328B.test
new file mode 100644
index 00000000000..a7b4053ab0c
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328B.test
@@ -0,0 +1,36 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Make sure an unrelated SELECT following a BF-aborted query never
+# gets the deadlock error
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+
+SET SESSION wsrep_retry_autocommit = 0;
+
+--disable_query_log
+
+while ($count)
+{
+ --error 0,1213
+ INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+
+ --disable_result_log
+ --error 0
+ SELECT 1 FROM DUAL;
+ --enable_result_log
+
+ --dec $count
+}
+
+--enable_query_log
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-test/suite/galera/t/MW-328C.test b/mysql-test/suite/galera/t/MW-328C.test
new file mode 100644
index 00000000000..b681e743ab3
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328C.test
@@ -0,0 +1,36 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Make sure that a high value of wsrep_retry_autocommit
+# masks all deadlock errors
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+
+SET SESSION wsrep_retry_autocommit = 10000;
+
+--disable_query_log
+
+while ($count)
+{
+ --error 0
+ INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+
+ --disable_result_log
+ --error 0
+ SELECT 1 FROM DUAL;
+ --enable_result_log
+
+ --dec $count
+}
+
+--enable_query_log
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-test/suite/galera/t/MW-328D.test b/mysql-test/suite/galera/t/MW-328D.test
new file mode 100644
index 00000000000..d5cffdb8f47
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328D.test
@@ -0,0 +1,40 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Test that non-Galera deadlock error still behaves as expected
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (i INT) ENGINE = InnoDB;
+INSERT INTO t1 (i) VALUES(1);
+
+CREATE TABLE t2 (i INT) ENGINE = InnoDB;
+
+# Create a deadlock situation
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 WHERE i = 1 LOCK IN SHARE MODE;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+--send INSERT IGNORE INTO t2 SELECT * FROM t1 WHERE i = 1 FOR UPDATE;
+
+--connection node_1
+--sleep 2
+DELETE FROM t1 WHERE i = 1;
+COMMIT;
+
+# We expect that ER_LOCK_DEADLOCK will be delivered even though it was a INSERT INGORE statement
+--connection node_1a
+--error ER_LOCK_DEADLOCK
+--reap
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera/t/MW-328E.test b/mysql-test/suite/galera/t/MW-328E.test
new file mode 100644
index 00000000000..fd4b0bf9039
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-328E.test
@@ -0,0 +1,41 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Test that non-Galera deadlock error still behaves as expected (case #2)
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+create table t1 (i int primary key, j int) engine=innodb;
+create table t2 (i int primary key, j int) engine=innodb;
+
+insert into t1 values (1,0);
+insert into t2 values (2,0);
+
+set autocommit=off;
+start transaction;
+update t1 set j=1 where i=1;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+set autocommit=off;
+start transaction;
+begin;
+update t2 set j=1 where i=2;
+
+--connection node_1
+# Hang expected here
+--send insert into t1 select * from t2;
+
+--sleep 2
+--connection node_1a
+--error ER_LOCK_DEADLOCK
+insert into t2 select * from t1;
+
+--connection node_1
+--reap
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera/t/MW-329-master.opt b/mysql-test/suite/galera/t/MW-329-master.opt
new file mode 100644
index 00000000000..6565a6af3c4
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-329-master.opt
@@ -0,0 +1 @@
+--wsrep-retry-autocommit=0
diff --git a/mysql-test/suite/galera/t/MW-329.test b/mysql-test/suite/galera/t/MW-329.test
new file mode 100644
index 00000000000..d9f9a787442
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-329.test
@@ -0,0 +1,85 @@
+#
+# #MW-329 Fix incorrect affected rows count after replay
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+
+# We start with a populated table
+INSERT INTO t1 (f1) VALUES (1),(65535);
+
+# Clear the wsrep_local_replays counter
+
+FLUSH STATUS;
+SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+
+#
+# Run concurrent INSERTs
+#
+
+DELIMITER |;
+CREATE PROCEDURE proc_insert ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ INSERT INTO t1 (f1) VALUES (FLOOR( 1 + RAND( ) * 65535 ));
+ END WHILE;
+END|
+DELIMITER ;|
+
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1b
+--let $connection_id = `SELECT CONNECTION_ID()`
+--send CALL proc_insert();
+
+#
+# Run concurrent UPDATEs. We expect that each UPDATE will report that
+# some rows were matched and updated
+#
+
+--connection node_2
+--let $count = 10
+while ($count)
+{
+ --let $signature = `SELECT LEFT(MD5(RAND()), 10)`
+ --disable_query_log
+ --error 0,ER_LOCK_DEADLOCK
+ --eval UPDATE t1 SET f2 = '$signature'
+ --enable_query_log
+ --let $row_count = `SELECT ROW_COUNT()`
+ if (`SELECT @@error_count = 0`) {
+ if (`SELECT $row_count = 0`) {
+ --die ROW_COUNT() = 0
+ }
+ }
+ --dec $count
+}
+
+#
+# Confirm that some transaction replays occurred
+#
+
+SELECT VARIABLE_VALUE > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+
+#
+# Terminate the stored procedure
+#
+
+--connection node_1
+--disable_query_log
+--eval KILL CONNECTION $connection_id
+--enable_query_log
+
+--connection node_1b
+--error 0,2013,1317
+--reap
+
+--connection node_1
+DROP PROCEDURE proc_insert;
+DROP TABLE t1;
+
+# Due to MW-330, Multiple "conflict state 3 after post commit" warnings if table is dropped while SP is running
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-test/suite/galera/t/MW-336.test b/mysql-test/suite/galera/t/MW-336.test
new file mode 100644
index 00000000000..79d8951a822
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-336.test
@@ -0,0 +1,64 @@
+#
+# MW-336 Slave threads may leak if variable wsrep_slave_threads is set repeatedly
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+
+--connection node_1
+SET GLOBAL wsrep_slave_threads = 10;
+SET GLOBAL wsrep_slave_threads = 1;
+
+--connection node_2
+INSERT INTO t1 VALUES (1);
+
+--connection node_1
+--sleep 0.5
+SET GLOBAL wsrep_slave_threads = 10;
+--sleep 0.5
+SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+
+SET GLOBAL wsrep_slave_threads = 20;
+--sleep 0.5
+SELECT COUNT(*) = 21 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+
+
+SET GLOBAL wsrep_slave_threads = 1;
+
+--connection node_2
+INSERT INTO t1 VALUES (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);
+
+
+--connection node_1
+SET GLOBAL wsrep_slave_threads = 10;
+SET GLOBAL wsrep_slave_threads = 0;
+
+--connection node_2
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+INSERT INTO t1 VALUES (16);
+INSERT INTO t1 VALUES (17);
+INSERT INTO t1 VALUES (18);
+INSERT INTO t1 VALUES (19);
+INSERT INTO t1 VALUES (20);
+
+--connection node_1
+--sleep 0.5
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+
+SET GLOBAL wsrep_slave_threads = 1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-357.test b/mysql-test/suite/galera/t/MW-357.test
new file mode 100644
index 00000000000..d13cf058aeb
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-357.test
@@ -0,0 +1,13 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_2
+SET GLOBAL wsrep_slave_threads = 0;
+
+--connection node_1
+CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-369.inc b/mysql-test/suite/galera/t/MW-369.inc
new file mode 100644
index 00000000000..5fd9ef150ae
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-369.inc
@@ -0,0 +1,75 @@
+#
+# This file should be included from tests for MW-369 to run concurrent
+# transaction from node_1 with autocommit query from node_2.
+#
+# The parameters:
+# * $mw_369_parent_query - the parent query to be run inside transaction
+# * $mw_369_child_query - the child query
+#
+# The operations are the following:
+#
+# node_1:
+# START TRANSACTION;
+# $mw_369_parent_query
+# node_2
+# $mw_369_child_query - will be blocked on node_1 in apply monitor
+# node_1:
+# COMMIT; - will be blocked on node_1 in local monitor
+#
+# The $mw_369_child_query is always expected to succeed. The caller is
+# responsible for checking if the final COMMIT on connection node_1
+# succeeds.
+#
+
+--connection node_1
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+
+--eval $mw_369_parent_query
+
+#
+# Block the $mw_369_child_query from node_2
+#
+# --connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_set_sync_point.inc
+
+#
+# insert client row, which will make it impossible to replay the
+# delete on parent
+#
+--connection node_2
+--eval $mw_369_child_query
+
+#
+# Wait until $mw_369_child_query from node_2 reaches the sync point and
+# block the 'COMMIT' from node_1 before it certifies.
+#
+--connection node_1a
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+--let $galera_sync_point = local_monitor_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+--send COMMIT
+
+#
+# Wait until both sync points have been reached
+#
+--connection node_1a
+--let $galera_sync_point = apply_monitor_slave_enter_sync local_monitor_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# both threads are now parked in sync points, signal them to continue
+#
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+
+--let $galera_sync_point = local_monitor_enter_sync
+--source include/galera_signal_sync_point.inc
+--source include/galera_clear_sync_point.inc
diff --git a/mysql-test/suite/galera/t/MW-369.test b/mysql-test/suite/galera/t/MW-369.test
new file mode 100644
index 00000000000..720d6daf518
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-369.test
@@ -0,0 +1,246 @@
+#
+# Test A Outline:
+# ===============
+#
+# This test tests the scenario for MW-369 where a new child table
+# row referring to parent table row is inserted concurrently from
+# another node while the transaction which tries to delete a
+# referred row from the parent table is committing.
+#
+# The p table will originally have rows (1, 0), (2, 0).
+# The c table will be empty.
+#
+# A new row (1, 1) pointing to parent row (1, 0) is inserted from
+# connection node_2, the transaction which tries to remove the
+# parent row (1, 0) is run from connection node_1.
+#
+# Expected outcome:
+# ================
+#
+# The transaction on node_1 will fail. The parent table will contain
+# rows (1, 0), (2, 0) and the child table will contain row (1, 1).
+#
+
+--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 p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+
+--let $mw_369_parent_query = DELETE FROM p WHERE f1 = 1
+--let $mw_369_child_query = INSERT INTO c VALUES (1, 1)
+
+#
+# we must open connection node_1a here, MW-369.inc will use it later
+#
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+#
+# Test B Outline:
+# ===============
+#
+# This test tests the scenario for MW-369 where a existing
+# child table row is updated concurrently from another node
+# with a transaction which updates the parent table.
+#
+# The p table will originally have rows (1, 0), (2, 0).
+# The c table will originally have rows (1, 1, 0) which points
+# to parent table row (1, 0).
+#
+# Expected outcome:
+# ================
+#
+# Both updates should succeed since they are done to separate tables and
+# rows. The parent table will contain rows (1, 1), (2, 0). The child
+# table will contain row (1, 1, 1).
+#
+
+--connection node_1
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+ f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+
+--let mw_369_parent_query = UPDATE p SET f2 = 1 WHERE f1 = 1
+--let $mw_369_child_query = UPDATE c SET f2 = 1 WHERE f1 = 1
+--source MW-369.inc
+
+# Commit succeeds
+--connection node_1
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+#
+# Test C Outline:
+# ===============
+#
+# This test tests the scenario for MW-369 where a child table row is
+# deleted concurrently from the other node while a transaction updates
+# the parent table referred by the child table row.
+#
+# The p table will originally have rows (1, 0), (2, 0)
+# The c table will originally have row (1, 1) which points to parent
+# table row (1, 0).
+#
+# A row (1, 1) pointing to parent row (1, 0) is deleted from
+# connection node_2, the transaction which tries to update the
+# parent row (1, 0) is run from connection node_1.
+#
+# Expected Outcome:
+# ================
+# Both operations on node_1 and node_2 should succeed without conflicts.
+# The parent table should contain values (1, 1), (2, 0) and the child
+# table should be empty.
+
+--connection node_1
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1);
+
+--let $mw_369_parent_query = UPDATE p SET f2 = 1 WHERE f1 = 1
+--let $mw_369_child_query = DELETE FROM c WHERE f1 = 1
+--source MW-369.inc
+
+# Commit succeeds
+--connection node_1
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+
+#
+# Test D Outline:
+# ===============
+#
+# This test is similar to test A, where parent row is deleted while a child row
+# is inserted simultaneously on node 2. However, in this test case the FK
+# constraint's target column is a unique key, and parent row is not delete,
+# but this key value is changed so that insert on node 2 will cause FK
+# violation
+#
+# The p table will originally have rows (1, 0)
+# The c table will originally be empty
+#
+# in node_1, parent row is updated to value (1,1)
+# A row (1, 0) pointing to the old version of parent row (1, 0) is inserted
+# in connection node_2
+#
+# Expected Outcome:
+# ================
+# This is a true conflict and one transaciton must abort. In this case it is node_1
+# transaction, which was scheduled later.
+# Parent table should have row (1,0)
+# child table should have row (1,0)
+#
+
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER UNIQUE KEY) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f2)) ;
+
+INSERT INTO p VALUES (1, 0);
+
+--let $mw_369_parent_query = UPDATE p SET f2 = 1 WHERE f1 = 1
+--let $mw_369_child_query = INSERT INTO c VALUES (1, 0);
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+#
+# Test E Outline:
+# ===============
+#
+# This test is similar to test B, where parent row is deleted while a child row
+# is updated simultaneously on node 2. However, in this test case the FK
+# constraint has ON DELETE CASCADE option, and the delete on parent row will
+# cascade a delete on child row as well. This will cause true conflict with
+# connection node_2, which tries to update unrelated column on child table.
+#
+# The p table will originally have rows (1, 0), (2,0)
+# The c table will originally have row (1,1,0)
+#
+# in node_1, parent row (1,0) is deleted and cascaded delete will happen on
+# child table row (1,1,0).
+# in connection node_2 child table row is update to value (1,1,1)
+#
+# Expected Outcome:
+# ================
+# This is a true conflict and one transaciton must abort. In this case it is node_1
+# transaction, which was scheduled later.
+# Parent table should have rows (1,0), (2,0)
+# child table should have row (1,1,1)
+#
+
+
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)
+ ON DELETE CASCADE) ;
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+INSERT INTO c VALUES (1, 1, 0);
+
+--let $mw_369_parent_query = DELETE FROM p WHERE f1 = 1
+--let $mw_369_child_query = UPDATE c SET f2 = 1 WHERE f1 = 1
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
diff --git a/mysql-test/suite/galera/t/MW-388.test b/mysql-test/suite/galera/t/MW-388.test
new file mode 100644
index 00000000000..209695dca80
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-388.test
@@ -0,0 +1,76 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB;
+
+DELIMITER |;
+CREATE PROCEDURE insert_proc ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
+ BEGIN
+ GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;
+ END;
+ INSERT INTO t1 VALUES (1, 'node 1'),(2, 'node 1');
+ INSERT INTO t1 VALUES (3, 'node 1');
+END|
+DELIMITER ;|
+
+# We need two slave threads here to guarantee progress.
+# If we use only one thread the following could happen
+# in node_1:
+# We block the only slave thread in wsrep_apply_cb and we
+# issue an INSERT (by calling the stored procedure) that will
+# try to acquire galera's local monitor in pre_commit().
+# This usually works fine, except for when a commit cut event
+# sneaks in the slave queue and gets a local seqno smaller than
+# that of the INSERT. Because there is only one slave thread,
+# commit cut is not processed and therefore does not advance
+# local monitor, and our INSERT remains stuck there.
+SET GLOBAL wsrep_slave_threads = 2;
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+
+--connection node_2
+--send INSERT INTO t1 VALUES (1, 'node 2');
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION DEBUG_SYNC = 'wsrep_after_replication SIGNAL wsrep_after_replication_reached WAIT_FOR wsrep_after_replication_continue';
+--send CALL insert_proc ();
+
+--connection node_1a
+SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_replication_reached";
+
+
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL wsrep_after_replication_continue";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+--connection node_2
+--reap
+
+--connection node_1
+# We expect no errors here, because the handler in insert_proc() caught the deadlock error
+--reap
+SELECT @errno = 1213;
+SELECT * FROM t1;
+
+--connection node_2
+SELECT * FROM t1;
+
+--connection node_1
+SET GLOBAL wsrep_slave_threads = DEFAULT;
+DROP TABLE t1;
+DROP PROCEDURE insert_proc;
+
+SET GLOBAL debug = NULL;
+SET debug_sync='RESET';
+
+# Make sure no pending signals are leftover to surprise subsequent tests.
+SELECT @@debug_sync;
diff --git a/mysql-test/suite/galera/t/MW-402.test b/mysql-test/suite/galera/t/MW-402.test
new file mode 100644
index 00000000000..80f368b50c8
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-402.test
@@ -0,0 +1,228 @@
+--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
+
+#
+# we must open connection node_1a here, MW-369.inc will use it later
+#
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+#
+# cascading delete operation is replicated from node2
+# and this conflicts with an update for child table in node1
+#
+# As a result, the update should fail for certification error
+#
+--connection node_1
+
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON DELETE CASCADE);
+
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+
+INSERT INTO c VALUES (1, 1, 0);
+
+--let $mw_369_parent_query = UPDATE c SET f2=1 where f1=1
+--let $mw_369_child_query = DELETE FROM p WHERE f1 = 1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+#
+# cascading update operation is replicated from node2
+# and this conflicts with an update for child table in node1
+#
+# As a result, the update should fail for certification error
+#
+--connection node_1
+
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE);
+
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+
+INSERT INTO c VALUES (1, 1, 0);
+
+--let $mw_369_parent_query = UPDATE c SET f2=2 where f1=1
+--let $mw_369_child_query = UPDATE p set f1=11 WHERE f1 = 1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+#
+# ON UPDATE CASCADE tests
+# Here we update primary key of parent table to cause cascaded update
+# on child table
+#
+# cascading update operation is replicated from node2
+# and this conflicts with an update for child table in node1
+#
+# As a result, the update should fail for certification error
+#
+--connection node_1
+
+CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE);
+
+
+INSERT INTO p VALUES (1, 0);
+INSERT INTO p VALUES (2, 0);
+
+INSERT INTO c VALUES (1, 1, 0);
+
+--let $mw_369_parent_query = UPDATE c SET p_id=2 where f1=1
+--let $mw_369_child_query = UPDATE p set f1=11 WHERE f1 = 1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+# same as previous, but statements in different order
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+--let $mw_369_parent_query = UPDATE p set f1=21 WHERE f1 = 11
+--let $mw_369_child_query = UPDATE c SET p_id=2 where f1=1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit fails
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+
+--connection node_2
+SELECT * FROM p;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p;
+
+#
+# CASCADE DELETE tests with two parent tables
+# Here we cause cascaded operation on child table through
+# one parent table and have other operation on the other
+# parent table
+#
+# cascading update operation is replicated from node2
+# but this does not conflict with an update for the other parent table in node1
+#
+# As a result, the update on p2 should succeed
+#
+--connection node_1
+
+CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+ f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ ON DELETE CASCADE,
+ CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1));
+
+INSERT INTO p1 VALUES (1, 0);
+INSERT INTO p2 VALUES (1, 0);
+
+INSERT INTO c VALUES (1, 1, 1, 0);
+
+--let $mw_369_parent_query = UPDATE p2 SET f2=2 where f1=1
+--let $mw_369_child_query = DELETE FROM p1 WHERE f1 = 1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit succeeds
+--connection node_1
+--reap
+
+--connection node_2
+SELECT * FROM p1;
+SELECT * FROM p2;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p1;
+DROP TABLE p2;
+
+#
+# CASCADE DELETE tests with two parent tables
+# Here we cause cascaded operation on child table through
+# one parent table and issue other delete operation through the
+# other parent table. The cascade progresses to same child table row where
+# we should see the conflict to happen
+#
+# As a result, the update on p2 should fail
+#
+--connection node_1
+
+CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+ f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ ON DELETE CASCADE,
+ CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
+ ON DELETE CASCADE);
+
+INSERT INTO p1 VALUES (1, 0);
+INSERT INTO p2 VALUES (1, 0);
+
+INSERT INTO c VALUES (1, 1, 1, 0);
+
+--let $mw_369_parent_query = DELETE FROM p2 WHERE f1=1
+--let $mw_369_child_query = DELETE FROM p1 WHERE f1=1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit succeeds
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT * FROM p1;
+SELECT * FROM p2;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p1;
+DROP TABLE p2; \ No newline at end of file
diff --git a/mysql-test/suite/galera/t/MW-416.test b/mysql-test/suite/galera/t/MW-416.test
new file mode 100644
index 00000000000..df4fa35abc7
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-416.test
@@ -0,0 +1,134 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--source include/wait_until_ready.inc
+
+CREATE USER 'userMW416'@'localhost';
+GRANT SELECT, INSERT, UPDATE ON test.* TO 'userMW416'@'localhost';
+
+SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
+
+--connect userMW416, localhost, userMW416,, test, $NODE_MYPORT_1
+--connection userMW416
+
+# DDL
+
+--error 1044
+ALTER DATABASE db CHARACTER SET = utf8;
+--error 1044
+ALTER EVENT ev1 RENAME TO ev2;
+--error 1370
+ALTER FUNCTION fun1 COMMENT 'foo';
+#--error 1044,1227
+#ALTER INSTANCE ROTATE INNODB MASTER KEY;
+--error 1044,1227
+ALTER LOGFILE GROUP lfg ADD UNDOFILE 'file' ENGINE=InnoDB;
+--error 1044,1227,1370
+ALTER PROCEDURE proc1 COMMENT 'foo';
+--error 1044,1227,1370
+ALTER SERVER srv OPTIONS (USER 'sally');
+--error 1044,1142,1227,1370
+ALTER TABLE tbl DROP COLUMN col;
+--error 1044,1227,1370
+ALTER TABLESPACE tblspc DROP DATAFILE 'file' ENGINE=innodb;
+--error 1044,1142,1227,1370
+ALTER VIEW vw AS SELECT 1;
+
+--error 1044,1227,1370
+CREATE DATABASE db;
+--error 1044,1227,1370
+CREATE EVENT ev1 ON SCHEDULE AT CURRENT_TIMESTAMP DO SELECT 1;
+--error 1044,1227,1370
+CREATE FUNCTION fun1() RETURNS int RETURN(1);
+--error 1044,1227,1370
+CREATE FUNCTION fun1 RETURNS STRING SONAME 'funlib.so';
+--error 1044,1227,1370
+CREATE PROCEDURE proc1() BEGIN END;
+--error 1044,1142,1227,1370
+CREATE INDEX idx ON tbl(id);
+--error 1044,1142,1227,1370
+CREATE LOGFILE GROUP lfg ADD UNDOFILE 'undofile' ENGINE innodb;
+--error 1044,1142,1227,1370
+CREATE SERVER srv FOREIGN DATA WRAPPER 'fdw' OPTIONS (USER 'user');
+--error 1044,1142,1227,1370
+CREATE TABLE t (i int);
+--error 1044,1142,1227,1370
+CREATE TABLESPACE tblspc ADD DATAFILE 'file' ENGINE=innodb;
+--error 1044,1142,1227,1370
+CREATE TRIGGER trg BEFORE UPDATE ON t FOR EACH ROW BEGIN END;
+--error 1044,1142,1227,1370
+CREATE VIEW vw AS SELECT 1;
+
+
+
+--error 1044,1142,1227,1370
+DROP DATABASE db;
+--error 1044,1142,1227,1370
+DROP EVENT ev;
+--error 1044,1142,1227,1370
+DROP FUNCTION fun1;
+--error 1044,1142,1227,1370
+DROP INDEX idx ON t0;
+--error 1044,1142,1227,1370,1064
+DROP LOGFILE GROUP lfg;
+--error 1044,1142,1227,1370
+DROP PROCEDURE proc1;
+--error 1044,1142,1227,1370
+DROP SERVEr srv;
+--error 1044,1142,1227,1370
+DROP TABLE t0;
+--error 1044,1142,1227,1370,1064
+DROP TABLESPACE tblspc;
+--error 1044,1142,1227,1360,1370
+DROP TRIGGER trg;
+--error 1044,1142,1227,1370
+DROP VIEW vw;
+
+--error 1044,1142,1227,1370
+RENAME TABLE t0 TO t1;
+
+--error 1044,1142,1227,1370
+TRUNCATE TABLE t0;
+
+# DCL
+
+# account management
+--error 1044,1142,1227,1370,1064
+ALTER USER myuser PASSWORD EXPIRE;
+--error 1044,1142,1227,1370
+CREATE USER myuser IDENTIFIED BY 'pass';
+--error 1044,1142,1227,1370
+DROP USER myuser;
+--error 1044,1045,1142,1227,1370
+GRANT ALL ON *.* TO 'myuser';
+--error 1044,1142,1227,1370
+RENAME USER myuser TO mariauser;
+--error 1044,1142,1227,1370
+REVOKE SELECT ON test FROM myuser;
+--error 1044,1142,1227,1370,1698
+REVOKE ALL, GRANT OPTION FROM myuser;
+--error 1044,1142,1227,1370,1698
+REVOKE PROXY ON myuser FROM myuser;
+
+# table maintenance
+--error 1044,1142,1227,1370
+ANALYZE TABLE db.tbl;
+--error 1044,1142,1227,1370
+CHECK TABLE db.tbl;
+--error 1044,1142,1227,1370
+CHECKSUM TABLE db.tbl;
+--error 1044,1142,1227,1370
+OPTIMIZE TABLE db.tbl;
+--error 1044,1142,1227,1370
+REPAIR TABLE db.tbl;
+
+# plugin and user defined functions
+--error 1044,1142,1227,1370
+INSTALL PLUGIN plg SONAME 'plg.so';
+--error 1044,1142,1227,1370
+UNINSTALL PLUGIN plg;
+
+--connection node_1
+DROP USER 'userMW416'@'localhost';
+SHOW DATABASES;
+SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
diff --git a/mysql-test/suite/galera/t/MW-44-master.opt b/mysql-test/suite/galera/t/MW-44-master.opt
new file mode 100644
index 00000000000..a15aa0a99d9
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-44-master.opt
@@ -0,0 +1 @@
+--log-output=TABLE
diff --git a/mysql-test/suite/galera/t/MW-44.test b/mysql-test/suite/galera/t/MW-44.test
new file mode 100644
index 00000000000..55a3fd57f80
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-44.test
@@ -0,0 +1,25 @@
+#
+# MW-44: DDL is logged in the general_log on the slave
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+TRUNCATE TABLE mysql.general_log;
+
+--connection node_2
+TRUNCATE TABLE mysql.general_log;
+
+--connection node_1
+SET SESSION wsrep_osu_method=TOI;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_osu_method=RSU;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+SET SESSION wsrep_osu_method=TOI;
+
+SELECT COUNT(*) = 2 FROM mysql.general_log WHERE argument LIKE 'CREATE%' OR argument LIKE 'ALTER%';
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.general_log WHERE argument NOT LIKE 'SELECT%';
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-86-wait1-master.opt b/mysql-test/suite/galera/t/MW-86-wait1-master.opt
new file mode 100644
index 00000000000..8a755e98b00
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-86-wait1-master.opt
@@ -0,0 +1 @@
+--log-bin --log-slave-updates
diff --git a/mysql-test/suite/galera/t/MW-86-wait1.test b/mysql-test/suite/galera/t/MW-86-wait1.test
new file mode 100644
index 00000000000..6c0982ad8b3
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-86-wait1.test
@@ -0,0 +1,106 @@
+#
+# SHOW commands no longer obey wsrep_sync_wait = 1 (WSREP_SYNC_WAIT_BEFORE_READ)
+# (they do not wait for the background INSERT in the applier in node_2 to
+# complete)
+#
+--source include/galera_cluster.inc
+--source include/have_binlog_format_row.inc
+--source include/have_debug_sync.inc
+
+--connection node_2
+# Make sure no signals have been leftover from previous tests to surprise us.
+SELECT @@debug_sync;
+
+SET SESSION wsrep_sync_wait = 1;
+SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
+
+--connection node_1
+CREATE TABLE t_wait1 (f1 INTEGER) ENGINE=InnoDB;
+# This will complete in node_1 but will start a background apply in node_2
+# which will stop because of sync.wsrep_apply_cb we set above.
+INSERT INTO t_wait1 VALUES (1);
+
+--connection node_2
+
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+
+--disable_result_log
+
+SHOW BINARY LOGS;
+
+SHOW BINLOG EVENTS;
+
+--error ER_NO_SUCH_TABLE
+SHOW COLUMNS FROM t1;
+
+--error ER_EVENT_DOES_NOT_EXIST
+SHOW CREATE EVENT e1;
+
+--error ER_SP_DOES_NOT_EXIST
+SHOW CREATE FUNCTION f1;
+
+--error ER_SP_DOES_NOT_EXIST
+SHOW CREATE PROCEDURE p1;
+
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t1;
+
+--error ER_TRG_DOES_NOT_EXIST
+SHOW CREATE TRIGGER tr1;
+
+--error ER_NO_SUCH_TABLE
+SHOW CREATE VIEW v1;
+
+SHOW DATABASES;
+
+SHOW ENGINE InnoDB STATUS;
+
+--error ER_SP_DOES_NOT_EXIST
+SHOW FUNCTION CODE f1;
+
+SHOW FUNCTION STATUS;
+
+SHOW GRANTS FOR 'root'@'localhost';
+
+--error ER_NO_SUCH_TABLE
+SHOW INDEX FROM t1;
+
+SHOW OPEN TABLES;
+
+--error ER_SP_DOES_NOT_EXIST
+SHOW PROCEDURE CODE p1;
+
+SHOW PROCEDURE STATUS;
+
+SHOW PRIVILEGES;
+
+SHOW STATUS LIKE 'wsrep_cluster_size';
+
+SHOW TABLE STATUS;
+
+SHOW TABLES;
+
+SHOW TRIGGERS;
+
+SHOW GLOBAL VARIABLES LIKE 'foo_bar';
+
+--error 0
+SHOW WARNINGS;
+
+--enable_result_log
+
+# Unblock the background INSERT and remove the sync point.
+SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
+SET SESSION debug_sync = "now SIGNAL signal.wsrep_apply_cb";
+
+SET SESSION wsrep_sync_wait = default;
+
+# This will wait for the background INSERT to complete before we quit
+# from the test.
+DROP TABLE t_wait1;
+
+SET GLOBAL debug = NULL;
+SET debug_sync='RESET';
+
+# Make sure no pending signals are leftover to surprise subsequent tests.
+SELECT @@debug_sync;
diff --git a/mysql-test/suite/galera/t/MW-86-wait8-master.opt b/mysql-test/suite/galera/t/MW-86-wait8-master.opt
new file mode 100644
index 00000000000..8a755e98b00
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-86-wait8-master.opt
@@ -0,0 +1 @@
+--log-bin --log-slave-updates
diff --git a/mysql-test/suite/galera/t/MW-86-wait8.test b/mysql-test/suite/galera/t/MW-86-wait8.test
new file mode 100644
index 00000000000..65e612c5c8e
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-86-wait8.test
@@ -0,0 +1,128 @@
+#
+# SHOW commands now obey wsrep_sync_wait = 8 (WSREP_SYNC_WAIT_BEFORE_SHOW)
+#
+--source include/galera_cluster.inc
+--source include/have_binlog_format_row.inc
+--source include/have_debug_sync.inc
+
+--connection node_2
+# Make sure no signals have been leftover from previous tests to surprise us.
+SELECT @@debug_sync;
+
+SET SESSION wsrep_sync_wait = 8;
+SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
+
+--connection node_1
+CREATE TABLE t_wait8 (f1 INTEGER) ENGINE=InnoDB;
+# This will complete in node_1 but will start a background apply in node_2
+# which will stop because of sync.wsrep_apply_cb we set above.
+INSERT INTO t_wait8 VALUES (1);
+
+--connection node_2
+
+--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT0.1S";
+
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+
+--disable_result_log
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW BINARY LOGS;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW BINLOG EVENTS;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW COLUMNS FROM t1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE DATABASE db1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE EVENT e1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE FUNCTION f1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE PROCEDURE p1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE TABLE t1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE TRIGGER tr1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW CREATE VIEW v1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW DATABASES;
+
+--error 0
+SHOW ENGINE InnoDB STATUS;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW FUNCTION CODE f1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW FUNCTION STATUS;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW GRANTS FOR 'root'@'localhost';
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW INDEX FROM t1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW OPEN TABLES;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW PROCEDURE CODE p1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW PROCEDURE STATUS;
+
+--error 0
+SHOW PRIVILEGES;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW STATUS LIKE 'wsrep_cluster_size';
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW TABLE STATUS;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW TABLES;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW TRIGGERS;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW GLOBAL VARIABLES LIKE 'foo_bar';
+
+--error 0
+SHOW WARNINGS;
+
+--enable_result_log
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = "$wsrep_provider_options_orig"
+--enable_query_log
+
+# Unblock the background INSERT and remove the sync point.
+SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+SET SESSION wsrep_sync_wait = default;
+
+# This will wait for the background INSERT to complete before we quit
+# from the test.
+DROP TABLE t_wait8;
+
+SET GLOBAL debug = NULL;
+SET debug_sync='RESET';
+
+# Make sure no pending signals are leftover to surprise subsequent tests.
+SELECT @@debug_sync;
diff --git a/mysql-test/suite/galera/t/basic.test b/mysql-test/suite/galera/t/basic.test
new file mode 100644
index 00000000000..8fc6eee3b3b
--- /dev/null
+++ b/mysql-test/suite/galera/t/basic.test
@@ -0,0 +1,26 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+USE test;
+CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+SELECT * FROM t1;
+
+--echo
+--echo # On node_1
+--connection node_1
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM test.t1;
+
+--let $galera_diff_statement = SELECT * FROM t1
+--source include/galera_diff.inc
+
+# Cleanup
+DROP TABLE t1;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/binlog_checksum.test b/mysql-test/suite/galera/t/binlog_checksum.test
new file mode 100644
index 00000000000..5aab68a7746
--- /dev/null
+++ b/mysql-test/suite/galera/t/binlog_checksum.test
@@ -0,0 +1,36 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo # On node_1
+--connection node_1
+SET @binlog_checksum_saved= @@GLOBAL.BINLOG_CHECKSUM;
+SET @@GLOBAL.BINLOG_CHECKSUM=CRC32;
+
+--echo # On node_2
+--connection node_2
+SET @binlog_checksum_saved= @@GLOBAL.BINLOG_CHECKSUM;
+SET @@GLOBAL.BINLOG_CHECKSUM=CRC32;
+
+USE test;
+CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+SELECT * FROM t1;
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM test.t1;
+
+--let $galera_diff_statement = SELECT * FROM t1
+--source include/galera_diff.inc
+
+# Cleanup
+DROP TABLE t1;
+--connection node_1
+SET @@GLOBAL.BINLOG_CHECKSUM = @binlog_checksum_saved;
+--connection node_2
+SET @@GLOBAL.BINLOG_CHECKSUM = @binlog_checksum_saved;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/create.test b/mysql-test/suite/galera/t/create.test
new file mode 100644
index 00000000000..fb9b0935288
--- /dev/null
+++ b/mysql-test/suite/galera/t/create.test
@@ -0,0 +1,58 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-6924 : Server crashed on CREATE TABLE ... SELECT
+--echo #
+
+SET @wsrep_forced_binlog_format_saved=@@GLOBAL.wsrep_forced_binlog_format;
+SET @@GLOBAL.wsrep_forced_binlog_format=STATEMENT;
+
+# @@log_bin must be OFF
+SHOW VARIABLES LIKE '%log%bin%';
+
+USE test;
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+CREATE TEMPORARY TABLE `t1_temp` AS SELECT * FROM `t1` WHERE i = 1;
+SELECT * FROM t1;
+SELECT * FROM t1_temp;
+
+# Cleanup
+DROP TABLE t1;
+SET @@GLOBAL.wsrep_forced_binlog_format=@wsrep_forced_binlog_format_saved;
+
+--echo #
+--echo # MDEV-7673: CREATE TABLE SELECT fails on Galera cluster
+--echo #
+--connection node_1
+CREATE TABLE t1 (i INT) ENGINE=INNODB DEFAULT CHARSET=utf8 SELECT 1 as i;
+SELECT * FROM t1;
+
+--connection node_2
+SELECT * FROM t1;
+# Cleanup
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-8166 : Adding index on new table from select crashes Galera
+--echo # cluster
+--echo #
+--connection node_1
+CREATE TABLE t1(i int(11) NOT NULL DEFAULT '0') ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO t1(i) VALUES (1), (2), (3);
+
+CREATE TABLE t2 (i INT) SELECT i FROM t1;
+ALTER TABLE t2 ADD INDEX idx(i);
+
+SELECT * FROM t2;
+
+--connection node_2
+SELECT * FROM t2;
+SHOW CREATE TABLE t2;
+
+# Cleanup
+DROP TABLE t1, t2;
+
+--echo # End of tests
+
diff --git a/mysql-test/suite/galera/t/ev51914.test b/mysql-test/suite/galera/t/ev51914.test
new file mode 100644
index 00000000000..e5edacabe89
--- /dev/null
+++ b/mysql-test/suite/galera/t/ev51914.test
@@ -0,0 +1,214 @@
+# Disable SAVEPOINT and ROLLBACK TO SAVEPOINT in SP, SF, TR.
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+
+--connection node_1
+--echo SAVEPOINT in a stored function should be forbidden
+--delimiter |
+CREATE FUNCTION f1 () RETURNS INT BEGIN
+ SAVEPOINT s;
+ RETURN 1;
+END|
+--delimiter ;
+
+SELECT f1();
+
+DROP FUNCTION f1;
+
+--echo ROLLBACK TO SAVEPOINT in a stored function should be forbidden
+--delimiter |
+CREATE FUNCTION f2 () RETURNS INT BEGIN
+ ROLLBACK TO SAVEPOINT s;
+ RETURN 1;
+END|
+--delimiter ;
+
+BEGIN;
+SAVEPOINT s;
+--error ER_SP_DOES_NOT_EXIST
+SELECT f2();
+COMMIT;
+
+DROP FUNCTION f2;
+
+BEGIN;
+SAVEPOINT S;
+ROLLBACK TO SAVEPOINT S;
+COMMIT;
+
+
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (a INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+INSERT INTO t1 values (110), (111), (112), (113), (114);
+
+--echo Direct SAVEPOINT in a trigger should be forbidden
+--connection node_2
+CREATE TRIGGER i1_t1 BEFORE INSERT ON t1 FOR EACH ROW SAVEPOINT s;
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+DROP TRIGGER i1_t1;
+
+CREATE TRIGGER i2_t1 AFTER INSERT ON t1 FOR EACH ROW SAVEPOINT s;
+INSERT INTO t1 VALUES (2);
+DROP TRIGGER i2_t1;
+
+INSERT INTO t1 VALUES (3);
+CREATE TRIGGER u1_t1 BEFORE UPDATE ON t1 FOR EACH ROW SAVEPOINT s;
+UPDATE t1 SET a=4 WHERE a=3;
+DROP TRIGGER u1_t1;
+
+CREATE TRIGGER u2_t1 AFTER UPDATE ON t1 FOR EACH ROW SAVEPOINT s;
+UPDATE t1 SET a=4 WHERE a=3;
+DROP TRIGGER u2_t1;
+
+CREATE TRIGGER d1_t1 BEFORE DELETE ON t1 FOR EACH ROW SAVEPOINT s;
+DELETE FROM t1;
+DROP TRIGGER d1_t1;
+
+CREATE TRIGGER d1_t1 AFTER DELETE ON t1 FOR EACH ROW SAVEPOINT s;
+DELETE FROM t1;
+DROP TRIGGER d1_t1;
+
+--echo SAVEPOINT in a compound statement in a trigger should be forbidden
+--delimiter |
+CREATE TRIGGER i3_t1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
+ SAVEPOINT s;
+END|
+--delimiter ;
+INSERT INTO t1 VALUES (5);
+DROP TRIGGER i3_t1;
+
+--echo SAVEPOINT in a PS call in a trigger should be forbidden
+# echo handled by SAVEPOINT forbidden in PS
+--delimiter |
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+CREATE TRIGGER i4_t1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
+ PREPARE set_savepoint FROM "SAVEPOINT s";
+ EXECUTE set_savepoint;
+ DEALLOCATE PREPARE set_savepoint;
+END|
+--delimiter ;
+
+--connection node_2
+--echo SAVEPOINT in SP called from a trigger should be forbidden
+--delimiter |
+CREATE PROCEDURE p1() BEGIN
+ SAVEPOINT s;
+END|
+--delimiter ;
+--connection node_1
+CREATE TRIGGER i5_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p1;
+INSERT INTO t1 VALUES (6);
+DROP TRIGGER i5_t1;
+
+--echo SAVEPOINT in a SP called from a PS called from a trigger be forbidden
+# echo handled by SAVEPOINT forbidden in PS
+PREPARE call_p1 FROM "CALL p1";
+--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
+CREATE TRIGGER i6_t1 BEFORE INSERT ON t1 FOR EACH ROW EXECUTE call_p1;
+
+--echo SAVEPOINT in a function called from a trigger should be forbidden
+--delimiter |
+CREATE FUNCTION f1 () RETURNS INT BEGIN
+ SAVEPOINT s;
+ RETURN 1;
+END|
+--delimiter ;
+CREATE TRIGGER i7_t1 BEFORE INSERT ON t1 FOR EACH ROW SET @foo = f1();
+INSERT INTO t1 VALUES (7);
+DROP TRIGGER i7_t1;
+
+--echo SAVEPOINT in a SP called from a SP called from a trigger should be forbidden
+--delimiter |
+CREATE PROCEDURE p2() BEGIN
+ CALL p1();
+END|
+--delimiter ;
+CREATE TRIGGER i8_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p2;
+INSERT INTO t1 VALUES (8);
+DROP TRIGGER i8_t1;
+
+--echo SAVEPOINT in a SP called from a trigger called from a SP should be forbidden
+CREATE TRIGGER i9_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p1;
+--delimiter |
+CREATE PROCEDURE p3() BEGIN
+ INSERT INTO t1 VALUES (9);
+END|
+--delimiter ;
+CALL p3();
+DROP TRIGGER i9_t1;
+
+--echo ROLLBACK TO SAVEPOINT in trigger as a trivial statement should be forbidden
+# Trigger activation creates a new savepoint level, making the earlier levels
+# inaccessible. Thus forbidding SAVEPOINT should be enough as then there is
+# no valid savepoint to pass to ROLLBACK TO SAVEPOINT, but we forbid it once
+# more just in case.
+CREATE TRIGGER i4_t1 BEFORE INSERT ON t1 FOR EACH ROW ROLLBACK TO SAVEPOINT s;
+BEGIN;
+SAVEPOINT s;
+--error ER_SP_DOES_NOT_EXIST
+INSERT INTO t1 VALUES (5);
+COMMIT;
+DROP TRIGGER i4_t1;
+
+--echo ROLLBACK TO SAVEPOINT in a trigger in a SP call should be forbidden
+--delimiter |
+CREATE PROCEDURE p4() BEGIN
+ ROLLBACK TO SAVEPOINT s;
+END|
+--delimiter ;
+CREATE TRIGGER i5_t1 BEFORE INSERT ON t1 FOR EACH ROW CALL p4;
+BEGIN;
+SAVEPOINT s;
+--error ER_SP_DOES_NOT_EXIST
+INSERT INTO t1 VALUES (6);
+COMMIT;
+DROP TRIGGER i5_t1;
+
+--echo SAVEPOINT in a SP next to a trigger should work
+CREATE TRIGGER i6_t1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.a = NEW.a + 1;
+--delimiter |
+CREATE PROCEDURE p5() BEGIN
+ SAVEPOINT s;
+ INSERT INTO t1 VALUES (10);
+ ROLLBACK TO SAVEPOINT s;
+END|
+--delimiter ;
+BEGIN;
+CALL p5();
+COMMIT;
+DROP TRIGGER i6_t1;
+
+--connection node_2
+delimiter |;
+create trigger t1 before insert on t1 for each row
+begin
+ insert into t2 values (NULL);
+end|
+delimiter ;|
+
+--connection node_1
+INSERT INTO t1 VALUES (201), (202), (203);
+
+--connection node_1
+SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+
+--connection node_2
+SELECT * FROM t1;
+SELECT COUNT(*) FROM t2;
+
+--connection node_1
+DEALLOCATE PREPARE call_p1;
+
+--connection node_2
+DROP TABLE t1, t2;
+DROP PROCEDURE p1;
+DROP PROCEDURE p2;
+DROP PROCEDURE p3;
+DROP PROCEDURE p4;
+DROP PROCEDURE p5;
+DROP FUNCTION f1;
diff --git a/mysql-test/suite/galera/t/fk.test b/mysql-test/suite/galera/t/fk.test
new file mode 100644
index 00000000000..e0b7cf06ed0
--- /dev/null
+++ b/mysql-test/suite/galera/t/fk.test
@@ -0,0 +1,116 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# MDEV-6651: MariaDB galera cluster crashes in file row0mysql.cc line 684
+# DELETE FROM ports WHERE ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516'
+# where table ports have foreign keys
+#
+
+USE test;
+--echo
+--echo # On node_1
+--connection node_1
+
+ CREATE TABLE networks (
+ `tenant_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+ `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `status` varchar(16) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `admin_state_up` tinyint(1) DEFAULT NULL,
+ `shared` tinyint(1) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+ CREATE TABLE ports (
+ `tenant_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+ `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `network_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+ `mac_address` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
+ `admin_state_up` tinyint(1) NOT NULL,
+ `status` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
+ `device_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+ `device_owner` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `network_id` (`network_id`),
+ CONSTRAINT `ports_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES networks (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE subnets (
+ `tenant_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+ `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `network_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `ip_version` int(11) NOT NULL,
+ `cidr` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
+ `gateway_ip` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `enable_dhcp` tinyint(1) DEFAULT NULL,
+ `shared` tinyint(1) DEFAULT NULL,
+ `ipv6_ra_mode` enum('slaac','dhcpv6-stateful','dhcpv6-stateless') COLLATE utf8_unicode_ci DEFAULT NULL,
+ `ipv6_address_mode` enum('slaac','dhcpv6-stateful','dhcpv6-stateless') COLLATE utf8_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `network_id` (`network_id`),
+ CONSTRAINT `subnets_ibfk_1` FOREIGN KEY (`network_id`) REFERENCES networks (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+ CREATE TABLE `ipallocations` (
+ `port_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL,
+ `ip_address` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
+ `subnet_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+ `network_id` varchar(36) COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`ip_address`,`subnet_id`,`network_id`),
+ KEY `port_id` (`port_id`),
+ KEY `subnet_id` (`subnet_id`),
+ KEY `network_id` (`network_id`),
+ CONSTRAINT `ipallocations_ibfk_1` FOREIGN KEY (`port_id`) REFERENCES `ports` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `ipallocations_ibfk_2` FOREIGN KEY (`subnet_id`) REFERENCES `subnets` (`id`) ON DELETE CASCADE,
+ CONSTRAINT `ipallocations_ibfk_3` FOREIGN KEY (`network_id`) REFERENCES `networks` (`id`) ON DELETE CASCADE
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+INSERT INTO networks VALUES ('f37aa3fe-ab99-4d0f-a566-6cd3169d7516','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','MyNet','ACTIVE',0,0);
+
+INSERT INTO ports VALUES ('','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','fa:16:3e:e3:cc:bb',1,'DOWN','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','network:router_gateway');
+
+INSERT INTO subnets VALUES ('f37aa3fe-ab99-4d0f-a566-6cd3169d7516','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','ext-subnet','f37aa3fe-ab99-4d0f-a566-6cd3169d7516',4,'10.25.0.0/24','10.25.0.4',0,1,NULL,NULL);
+
+INSERT INTO ipallocations VALUES ('f37aa3fe-ab99-4d0f-a566-6cd3169d7516','10.25.0.17','f37aa3fe-ab99-4d0f-a566-6cd3169d7516','f37aa3fe-ab99-4d0f-a566-6cd3169d7516');
+
+select * from ports where ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516';
+
+--connection node_2
+
+select * from ports where ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516';
+
+--let $galera_diff_statement = SELECT * FROM ports
+--source include/galera_diff.inc
+
+--connection node_1
+
+DELETE FROM ports WHERE ports.id = 'f37aa3fe-ab99-4d0f-a566-6cd3169d7516';
+
+select * from networks;
+select * from ports;
+select * from subnets;
+select * from ipallocations;
+select * from ports;
+
+--echo
+--echo # On node_2
+--connection node_2
+select * from networks;
+select * from ports;
+select * from subnets;
+select * from ipallocations;
+select * from ports;
+
+--let $galera_diff_statement = SELECT * FROM ports
+--source include/galera_diff.inc
+
+--connection node_1
+drop table ipallocations;
+drop table subnets;
+drop table ports;
+drop table networks;
+
+--source include/galera_end.inc
diff --git a/mysql-test/suite/galera/t/galera#414.cnf b/mysql-test/suite/galera/t/galera#414.cnf
new file mode 100644
index 00000000000..fbd1c58754f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera#414.cnf
@@ -0,0 +1,8 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcs.max_packet_size=2'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcs.max_packet_size=2'
+
diff --git a/mysql-test/suite/galera/t/galera#414.test b/mysql-test/suite/galera/t/galera#414.test
new file mode 100644
index 00000000000..de10898df42
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera#414.test
@@ -0,0 +1,43 @@
+#
+# codership/galera#414 Shutdown crashes node if the node started with `gcs.max_packet_size=2`
+#
+
+--source include/big_test.inc
+--source include/have_innodb.inc
+--source include/galera_cluster.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+# We perform the shutdown/restart sequence in here. If there was a crash during shutdown, MTR will detect it
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+--connection node_2
+--source include/start_mysqld.inc
+
+--connection node_1
+SET SESSION wsrep_on = ON;
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--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
+
+--connection node_1
+CALL mtr.add_suppression("Failed to set packet size");
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
+--source include/wait_condition.inc
+CALL mtr.add_suppression("Failed to set packet size");
+
+--source include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera/t/galera#500.test b/mysql-test/suite/galera/t/galera#500.test
new file mode 100644
index 00000000000..3c8490b6907
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera#500.test
@@ -0,0 +1,38 @@
+#
+# The purpose of this test is to verify that if an exception is
+# thrown from gcomm background thread, the provider terminates properly
+# and wsrep_ready becomes 0.
+#
+
+--source include/have_innodb.inc
+--source include/galera_cluster.inc
+--source include/galera_have_debug_sync.inc
+
+# Force node_2 gcomm background thread to terminate via exception.
+--connection node_2
+--let $wsrep_cluster_address = `SELECT @@wsrep_cluster_address`
+# Setting gmcast.isolate=2 will force gcomm background thread to
+# throw exception.
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options="gmcast.isolate=2";
+
+# Wait until wsrep_ready becomes 0.
+--let $wait_condition = SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME ='wsrep_ready'
+--source include/wait_condition.inc
+
+# Wait until node_1 ends up in non-prim and rebootstrap the cluster.
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME ='wsrep_cluster_size'
+--source include/wait_condition.inc
+SHOW STATUS LIKE 'wsrep_cluster_status';
+SET SESSION wsrep_sync_wait = default;
+SET GLOBAL wsrep_provider_options="pc.bootstrap=1";
+
+# Restart node_2
+--connection node_2
+SET SESSION wsrep_on=0;
+--source include/restart_mysqld.inc
+
+--connection node_2
+CALL mtr.add_suppression("WSREP: exception from gcomm, backend must be restarted: Gcomm backend termination was requested by setting gmcast.isolate=2.");
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 00000000000..6dea0fcfa9e
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_account_management.test
@@ -0,0 +1,99 @@
+#
+# 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
+#
+
+--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_admin.test b/mysql-test/suite/galera/t/galera_admin.test
new file mode 100644
index 00000000000..e3c43256ad5
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_admin.test
@@ -0,0 +1,86 @@
+#
+# Test that various admin commands from sql_admin.cc
+# Currently, REPAIR, OPTIMIZE and ANALYZE are tested.
+# Jira: PXC-390
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+DROP TABLE IF EXISTS x1, x2;
+--enable_warnings
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
+SET GLOBAL wsrep_replicate_myisam = TRUE;
+CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE x2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
+INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+# Wait until all the data from t2 has been replicated
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 10 FROM x1;
+--source include/wait_condition.inc
+--let $wait_condition = SELECT COUNT(*) = 10 FROM x2;
+--source include/wait_condition.inc
+--let $wait_condition = SELECT COUNT(*) = 10 FROM t1;
+--source include/wait_condition.inc
+--let $wait_condition = SELECT COUNT(*) = 10000 FROM t2;
+--source include/wait_condition.inc
+
+
+--echo # ANALYZE test
+--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
+ANALYZE TABLE t1, t2;
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = $wsrep_last_committed_before + 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'
+--source include/wait_condition.inc
+
+
+
+--echo # OPTIMIZE test
+--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
+OPTIMIZE TABLE t1, t2;
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE >= $wsrep_last_committed_before + 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'
+--source include/wait_condition.inc
+
+
+
+--echo # REPAIR test
+--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
+REPAIR TABLE x1, x2;
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE >= $wsrep_last_committed_before + 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'
+--source include/wait_condition.inc
+
+
+
+--connection node_2
+SELECT COUNT(*) = 10 FROM t1;
+SELECT COUNT(*) = 10 FROM x1;
+SELECT COUNT(*) = 10000 FROM t2;
+SELECT COUNT(*) = 10 FROM x2;
+
+--connection node_1
+DROP TABLE t1, t2;
+DROP TABLE x1, x2;
+SET GLOBAL wsrep_replicate_myisam = FALSE;
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 00000000000..bc914a38776
--- /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 00000000000..6d41d276a17
--- /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 00000000000..1fcc9d4bda5
--- /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_applier_ftwrl_table.test b/mysql-test/suite/galera/t/galera_applier_ftwrl_table.test
new file mode 100644
index 00000000000..97819384a75
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_applier_ftwrl_table.test
@@ -0,0 +1,34 @@
+#
+# Test that applying plays well with FLUSH TABLE table_name WITH READ LOCK. The applier
+# thread should block until UNLOCK TABLEs.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+FLUSH TABLE t1 WITH READ LOCK;
+
+--connection node_2
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock'
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+UNLOCK TABLES;
+
+SET SESSION wsrep_sync_wait = 15;
+SELECT COUNT(*) = 2 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt b/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt
new file mode 100644
index 00000000000..d8ecaacaa4c
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt
@@ -0,0 +1 @@
+--lock_wait_timeout=5 --innodb_lock_wait_timeout=5 --wait_timeout=5
diff --git a/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter.test b/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter.test
new file mode 100644
index 00000000000..67f2108d263
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter.test
@@ -0,0 +1,37 @@
+#
+# Test that applying a DDL plays well with FLUSH TABLE table_name WITH READ LOCK. The applier
+# thread should block until UNLOCK TABLEs.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+
+# Those values are valid only for connection node_1. The global values from the -master.opt file apply to applier threads.
+SET SESSION lock_wait_timeout = 60;
+SET SESSION innodb_lock_wait_timeout=60;
+SET SESSION wait_timeout=60;
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+FLUSH TABLE t1 WITH READ LOCK;
+
+--connection node_2
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_1
+SELECT 1 FROM DUAL;
+# Sleep for longer than the global timeout ...
+--sleep 6
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock';
+
+UNLOCK TABLES;
+
+SET SESSION wsrep_sync_wait = 15;
+
+SHOW CREATE TABLE t1;
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock';
+
+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 00000000000..52fd3093931
--- /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 00000000000..b8f989d497b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_master.test
@@ -0,0 +1,41 @@
+#
+# 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/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_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE;
+
+--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;
+
+CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
+
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 00000000000..19517556331
--- /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 00000000000..9db104b7cab
--- /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 00000000000..19517556331
--- /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 00000000000..23606d7ac4c
--- /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 00000000000..9449ec9cf40
--- /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 00000000000..849b75eadd1
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave.test
@@ -0,0 +1,50 @@
+#
+# 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
+
+# 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_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE;
+
+--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;
+
+--connection node_1
+RESET MASTER;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_autoinc.cnf b/mysql-test/suite/galera/t/galera_as_slave_autoinc.cnf
new file mode 100644
index 00000000000..9449ec9cf40
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_autoinc.cnf
@@ -0,0 +1 @@
+!include ../galera_2nodes_as_slave.cnf
diff --git a/mysql-test/suite/galera/t/galera_as_slave_autoinc.test b/mysql-test/suite/galera/t/galera_as_slave_autoinc.test
new file mode 100644
index 00000000000..59483d0591c
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_autoinc.test
@@ -0,0 +1,83 @@
+#
+# 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
+
+# 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_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE;
+
+--connection node_1
+
+##
+## Verify the correct operation of the auto-increment when
+## the binlog format set to the 'STATEMENT' on the master node:
+##
+
+SET SESSION binlog_format='STATEMENT';
+
+CREATE TABLE t1 (
+ i int(11) NOT NULL AUTO_INCREMENT,
+ c char(32) DEFAULT 'dummy_text',
+ PRIMARY KEY (i)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+insert into t1(i) values(null);
+
+select * from t1;
+
+insert into t1(i) values(null), (null), (null);
+
+select * from t1;
+
+SET SESSION auto_increment_increment=7;
+insert into t1(i) values(null), (null), (null);
+
+SET SESSION auto_increment_offset=5;
+insert into t1(i) values(null), (null), (null);
+
+select * from t1;
+
+show variables like 'binlog_format';
+show variables like 'auto_increment_increment';
+
+--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(*) = 10 FROM t1;
+--source include/wait_condition.inc
+
+select * from t1;
+
+show variables like 'binlog_format';
+show variables like 'auto_increment_increment';
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
+select * from t1;
+
+show variables like 'binlog_format';
+show variables like 'auto_increment_increment';
+
+--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;
+
+--connection node_1
+RESET MASTER;
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 00000000000..01d2eb12630
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_gtid.cnf
@@ -0,0 +1,6 @@
+!include ../galera_2nodes_as_slave.cnf
+
+[mysqld]
+log-bin=mysqld-bin
+log-slave-updates
+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 00000000000..c2331a2ae05
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_gtid.test
@@ -0,0 +1,67 @@
+#
+# Test Galera as a slave to a MariaDB 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
+
+# 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_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES(1);
+
+SELECT LENGTH(@@global.gtid_binlog_state) > 1;
+--let $gtid_binlog_state_node1 = `SELECT @@global.gtid_binlog_state;`
+
+--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_binlog_state_node1' = @@global.gtid_binlog_state AS gtid_binlog_state_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_binlog_state_node1' = @@global.gtid_binlog_state AS gtid_binlog_state_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_as_slave_nonprim.cnf b/mysql-test/suite/galera/t/galera_as_slave_nonprim.cnf
new file mode 100644
index 00000000000..5a44e5664b5
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_nonprim.cnf
@@ -0,0 +1 @@
+!include ../galera_3nodes_as_slave.cnf
diff --git a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
new file mode 100644
index 00000000000..46a93458271
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
@@ -0,0 +1,96 @@
+#
+# Test the behavior of a Galera async slave if it goes non-prim. Async replication
+# should abort with an error but it should be possible to restart it.
+#
+# The galera/galera_2node_slave.cnf describes the setup of the nodes
+#
+
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+# Step #1. Establish replication
+#
+# 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, MASTER_USER='root';
+--enable_query_log
+START SLAVE;
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+--connection node_2
+--sleep 1
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+# Step #2. Force async slave to go non-primary
+
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+--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
+
+# Step #3. Force async replication to fail by creating a replication event while the slave is non-prim
+
+--connection node_1
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+
+--connection node_2
+--sleep 5
+
+--let $value = query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1)
+--connection node_3
+--disable_query_log
+--eval SELECT "$value" IN ("Error 'Unknown command' on query. Default database: 'test'. Query: 'BEGIN'", "Node has dropped from cluster") AS expected_error
+--enable_query_log
+
+# Step #4. Bring back the async slave and restart replication
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+
+--connection node_3
+--source include/wait_until_connected_again.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_2
+--source include/wait_until_ready.inc
+--source include/wait_until_connected_again.inc
+
+START SLAVE;
+
+# Confirm that the replication events have arrived
+
+--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+DROP TABLE t1;
+
+--sleep 2
+--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;
+
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown command' on query");
+CALL mtr.add_suppression("Slave: Unknown command Error_code: 1047");
+CALL mtr.add_suppression("Transport endpoint is not connected");
+CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed, 'Deadlock found when trying to get lock; try restarting transaction', Error_code: 1213");
+CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+
+
+--connection node_1
+RESET MASTER;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_preordered.cnf b/mysql-test/suite/galera/t/galera_as_slave_preordered.cnf
new file mode 100644
index 00000000000..d1a0fb15ff3
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_preordered.cnf
@@ -0,0 +1,3 @@
+!include ../galera_2nodes_as_slave.cnf
+[mysqld]
+wsrep-preordered=TRUE
diff --git a/mysql-test/suite/galera/t/galera_as_slave_preordered.test b/mysql-test/suite/galera/t/galera_as_slave_preordered.test
new file mode 100644
index 00000000000..6f221f83b3a
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_preordered.test
@@ -0,0 +1,84 @@
+#
+# Test Galera as a slave to a MySQL master with --wsrep-preordered=TRUE
+#
+# 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';
+
+#
+# Issue many large-ish transaction on the async master
+#
+
+--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 PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
+
+--disable_query_log
+--let $count = 100
+while ($count)
+{
+ --eval INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2;
+ --dec $count
+}
+--enable_query_log
+
+#
+# While the async transactions are being applied, issue another set of transactions
+# on the Galera node.
+#
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--let $count = 100
+--disable_query_log
+while ($count)
+{
+ --eval INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2;
+ --dec $count
+}
+--enable_query_log
+
+#
+# Confirm that all transactions successfully committed
+#
+
+--let $wait_condition = SELECT COUNT(*) = 2 * 100 * 10 * 10 FROM t1;
+--source include/wait_condition.inc
+
+SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+SELECT COUNT(*) = 2 * 100 * 10 * 10 FROM t1;
+SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
+
+#
+# Cleanup
+#
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE ten;
+
+--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_replication_bundle.cnf b/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.cnf
new file mode 100644
index 00000000000..d092d88bfaf
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.cnf
@@ -0,0 +1,4 @@
+!include ../galera_2nodes_as_slave.cnf
+
+[mysqld]
+wsrep-mysql-replication-bundle=2
diff --git a/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test b/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test
new file mode 100644
index 00000000000..460e040c010
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test
@@ -0,0 +1,48 @@
+#
+# Test the wsrep_replication_bundle variable. We expect that multiple async replication events
+# will be grouped together and thus a smaller number of wsrep_last_committed transactions will
+# be reported.
+#
+
+--source include/have_innodb.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_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 VALUES(2);
+INSERT INTO t1 VALUES(3);
+INSERT INTO t1 VALUES(4);
+INSERT INTO t1 VALUES(5);
+
+--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(*) = 4 FROM t1;
+--source include/wait_condition.inc
+
+# With wsrep_mysql_replication_bundle = 2, the last insert is not delivered
+# because there are not enough events remaining to complete an entire bundle
+SELECT COUNT(*) = 4 FROM t1;
+
+# Bundle is now complete, the last INSERT and the DROP are delivered
+--connection node_1
+DROP TABLE t1;
+
+--connection node_2
+--sleep 1
+--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_autoinc_sst_xtrabackup.cnf b/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.cnf
new file mode 100644
index 00000000000..b4bf5f02171
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.cnf
@@ -0,0 +1,12 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth="root:"
+
+[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_autoinc_sst_xtrabackup.test b/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test
new file mode 100644
index 00000000000..30ce9bc4ceb
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test
@@ -0,0 +1,95 @@
+#
+# Test that autoincrement works correctly while the cluster membership
+# is changing and SST takes place.
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+--let $connection_id = `SELECT CONNECTION_ID()`
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+
+# Issue an endless stream of autoincrement inserts
+
+DELIMITER |;
+CREATE PROCEDURE p1 ()
+BEGIN
+ DECLARE x INT DEFAULT 1;
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+
+ WHILE 1 DO
+ INSERT INTO t1 VALUES (DEFAULT);
+ COMMIT;
+ END WHILE;
+END|
+DELIMITER ;|
+
+--send CALL p1();
+--sleep 2
+
+--connection node_2
+--send CALL p1();
+--sleep 2
+
+# Kill and restart node #2
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+--source include/kill_galera.inc
+
+--sleep 10
+--source include/start_mysqld.inc
+--sleep 25
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (DEFAULT);
+
+# Terminate the stored procedure
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+--disable_query_log
+--eval KILL CONNECTION $connection_id
+--enable_query_log
+
+INSERT INTO t1 VALUES (DEFAULT);
+
+--connection node_1
+# CR_SERVER_LOST
+--error 2013,2006
+--reap
+
+--connection node_2
+# CR_SERVER_LOST
+--error 2013,2006
+--reap
+
+--sleep 10
+
+# Confirm that the count is correct and that the cluster is intact
+
+--connection node_1a
+--let $count = `SELECT COUNT(*) FROM t1`
+
+--connection node_2a
+--disable_query_log
+--eval SELECT COUNT(*) = $count AS count_equal FROM t1
+--enable_query_log
+
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0");
+
+SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+--connection node_1a
+SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+CALL mtr.add_suppression("gcs_caused\\(\\) returned -1 \\(Operation not permitted\\)");
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0");
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 00000000000..f3476fba490
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort.test
@@ -0,0 +1,34 @@
+--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, f2 CHAR(6)) ENGINE=InnoDB;
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+
+--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,'node_2');
+
+--connection node_1
+INSERT INTO t1 VALUES (1,'node_1');
+
+--connection node_2a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'node_1'
+--source include/wait_condition.inc
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (2, 'node_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_flush_for_export.test b/mysql-test/suite/galera/t/galera_bf_abort_flush_for_export.test
new file mode 100644
index 00000000000..fde783e2cef
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_flush_for_export.test
@@ -0,0 +1,39 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that a local FLUSH TABLES FOR EXPORT will NOT 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'`
+FLUSH TABLES t1 FOR EXPORT;
+
+--connection node_1
+INSERT INTO t1 VALUES (2);
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock'
+--source include/wait_condition.inc
+
+UNLOCK TABLES;
+
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock'
+--source include/wait_condition.inc
+
+COMMIT;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_sync_wait = 15;
+SELECT COUNT(*) = 1 FROM t1;
+
+--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 = 0 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 00000000000..24c29778e5d
--- /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 00000000000..44398e717d1
--- /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 00000000000..72fc1c5b583
--- /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 00000000000..4582f3f972d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_lock_table.test
@@ -0,0 +1,36 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that a local LOCK TABLE will NOT 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;
+
+--connection node_1
+INSERT INTO t1 VALUES (2);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock'
+--source include/wait_condition.inc
+
+UNLOCK TABLES;
+
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'Waiting for table metadata lock'
+--source include/wait_condition.inc
+
+COMMIT;
+SELECT COUNT(*) = 1 FROM t1;
+
+--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 = 0 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 00000000000..8d135dc7d42
--- /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 00000000000..6ce9072d412
--- /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 00000000000..c8e53f07fc2
--- /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 00000000000..48669305242
--- /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 00000000000..a36d21315a6
--- /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 00000000000..d0cc23446b2
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_binlog_event_max_size_max.test
@@ -0,0 +1,21 @@
+#
+# 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
+--source include/big_test.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 00000000000..22174756652
--- /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 00000000000..00b55339770
--- /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 00000000000..70262ec44ca
--- /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 00000000000..95bc85c4cab
--- /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_concurrent_ctas.test b/mysql-test/suite/galera/t/galera_concurrent_ctas.test
new file mode 100644
index 00000000000..8b9b461d0fd
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_concurrent_ctas.test
@@ -0,0 +1,57 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--write_file $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+DROP table t1;
+CREATE table t1 as SELECT SLEEP(0);
+CREATE table t2 as SELECT SLEEP(0);
+CREATE table t3 as SELECT SLEEP(0);
+CREATE table t4 as SELECT SLEEP(0);
+CREATE table t5 as SELECT SLEEP(0);
+CREATE table t6 as SELECT SLEEP(0);
+CREATE table t7 as SELECT SLEEP(0);
+CREATE table t8 as SELECT SLEEP(0);
+CREATE table t9 as SELECT SLEEP(0);
+DROP table t1;
+DROP table t2;
+DROP table t3;
+DROP table t4;
+DROP table t5;
+DROP table t6;
+DROP table t7;
+DROP table t8;
+DROP table t9;
+EOF
+
+let $run=10;
+
+while($run)
+{
+ --error 0,1
+ exec $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_1 test \
+ < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql & \
+ $MYSQL --user=root --host=127.0.0.1 --port=$NODE_MYPORT_2 test \
+ < $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql;
+ dec $run;
+}
+
+--remove_file $MYSQLTEST_VARDIR/tmp/galera_concurrent.sql
+
+--source include/galera_end.inc
+--echo # End of test
+
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 00000000000..0d7cec0114f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_create_function.test
@@ -0,0 +1,53 @@
+--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
+# Work around codership/mysql-wsrep#228 - SHOW CREATE FUNCTION not covered by wsrep_sync_wait
+SELECT 1 FROM DUAL;
+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 00000000000..30bc85fcea0
--- /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 00000000000..0e0e8b0ffcf
--- /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 00000000000..6708e30bf0f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_create_trigger.test
@@ -0,0 +1,43 @@
+--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_ddl_multiline.test b/mysql-test/suite/galera/t/galera_ddl_multiline.test
new file mode 100644
index 00000000000..c7155d066fa
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ddl_multiline.test
@@ -0,0 +1,54 @@
+#
+# Test that Galera works correctly with multiline statements, in particular involving DDLs
+#
+
+--source include/galera_cluster.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+
+SHOW CREATE TABLE t1;
+SHOW CREATE TABLE t2;
+
+--connection node_2
+SHOW CREATE TABLE t1;
+SHOW CREATE TABLE t2;
+
+--connection node_1
+--send CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB; CREATE TABLE t4 (f1 INTEGER) ENGINE=InnoDB;
+--reap
+
+SHOW CREATE TABLE t3;
+SHOW CREATE TABLE t4;
+
+--connection node_2
+SHOW CREATE TABLE t3;
+SHOW CREATE TABLE t4;
+
+--connection node_1
+INSERT INTO t1 VALUES (1); CREATE TABLE t5 (f1 INTEGER) ENGINE=InnoDB;
+
+SELECT COUNT(*) = 1 FROM t1;
+SHOW CREATE TABLE t5;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SHOW CREATE TABLE t5;
+
+--connection node_1
+--send CREATE TABLE t6 (f1 INTEGER) ENGINE=InnoDB; INSERT INTO t2 VALUES (1);
+--reap
+
+SELECT COUNT(*) = 1 FROM t2;
+SHOW CREATE TABLE t6;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t2;
+SHOW CREATE TABLE t6;
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+--connection node_1
+DROP TABLE t1, t2, t3, t4, t5, t6;
+
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 00000000000..cd718ae2bdb
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_defaults.test
@@ -0,0 +1,70 @@
+#
+# 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
+
+# Make sure that the test is operating on the right version of galera library.
+--disable_query_log
+--let $galera_version=3.20
+source ../wsrep/include/check_galera_version.inc;
+--enable_query_log
+
+# 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/gcs\.recv_q_hard_limit = .*?;/<GCS_RECV_Q_HARD_LIMIT>;/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 00000000000..4cbadbd3ba0
--- /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_desync_overlapped.test b/mysql-test/suite/galera/t/galera_desync_overlapped.test
new file mode 100644
index 00000000000..8b78e8cdeb7
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_desync_overlapped.test
@@ -0,0 +1,59 @@
+#
+# Test for overlapped transactions under manual desync.
+#
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+--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 (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+CREATE TABLE t1 (f1 INTEGER, PRIMARY KEY (f1)) Engine=InnoDB;
+CREATE TABLE t2 (f1 INTEGER, PRIMARY KEY (f1)) Engine=InnoDB;
+
+SET GLOBAL wsrep_desync = 1;
+show status like 'wsrep_desync_count';
+SET DEBUG_SYNC='before_execute_sql_command SIGNAL alter1 WAIT_FOR alter2';
+send INSERT INTO t1 (f1) SELECT 0000 + (100 * a1.f1) + (10 * a2.f1) + a3.f1 FROM ten AS a1, ten AS a2, ten AS a3;
+
+--connection node_1a
+
+SET GLOBAL wsrep_desync = 1;
+show status like 'wsrep_desync_count';
+SET DEBUG_SYNC='now WAIT_FOR alter1';
+SET DEBUG_SYNC='before_execute_sql_command SIGNAL alter2';
+send INSERT INTO t2 (f1) SELECT 0000 + (100 * a1.f1) + (10 * a2.f1) + a3.f1 FROM ten AS a1, ten AS a2, ten AS a3;
+
+--connection node_1
+reap;
+
+--connection node_1a
+reap;
+
+--connection node_1
+
+SET DEBUG_SYNC='RESET';
+
+SET GLOBAL wsrep_desync = 0;
+show status like 'wsrep_desync_count';
+SET GLOBAL wsrep_desync = 0;
+show status like 'wsrep_desync_count';
+
+--disable_query_log
+call mtr.add_suppression("Trying to make wsrep_desync = OFF on the node that is already synchronized.");
+--enable_query_log
+show status like 'wsrep_desync_count';
+SET GLOBAL wsrep_desync = 0;
+
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera/t/galera_drop_multi.test b/mysql-test/suite/galera/t/galera_drop_multi.test
new file mode 100644
index 00000000000..44b1b619b2b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_drop_multi.test
@@ -0,0 +1,41 @@
+#
+# Test that multi-table DROP TABLE statements are properly replicated
+# See http://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-20.html
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TEMPORARY TABLE t4 (f1 INTEGER) ENGINE=InnoDB;
+
+CREATE TABLE t5 (f1 INTEGER);
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+DROP TABLE t1, t2, t3, t4;
+
+INSERT INTO t5 VALUES (1);
+
+COMMIT;
+
+--connection node_2
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t1;
+
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t2;
+
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t3;
+
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t4;
+
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test.t2,test.t4'' on query\. Default database: 'test'\. Query: 'DROP TABLE t1, t2, t3, t4', Error_code: 1051");
+
+--connection node_1
+DROP TABLE t5;
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 00000000000..ff5332486aa
--- /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 00000000000..ae9940fc694
--- /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 00000000000..9b79b4c30b6
--- /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 00000000000..e736803a285
--- /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 00000000000..cb6f95ee687
--- /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 00000000000..bded41381a7
--- /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 00000000000..ad42f65924d
--- /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 00000000000..6adfb8195ec
--- /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 00000000000..d1f9c26762d
--- /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 00000000000..e2c19001030
--- /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 00000000000..46ba82dbf9c
--- /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_flush-master.opt b/mysql-test/suite/galera/t/galera_flush-master.opt
new file mode 100644
index 00000000000..5a1fb6748d9
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_flush-master.opt
@@ -0,0 +1 @@
+--query_cache_type=1 --query_cache_size=1000000
diff --git a/mysql-test/suite/galera/t/galera_flush.test b/mysql-test/suite/galera/t/galera_flush.test
new file mode 100644
index 00000000000..2a0fdc694fc
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_flush.test
@@ -0,0 +1,273 @@
+#
+# Test that various FLUSH commands are replicated. Whenever possible, check the slave for the effects.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_perfschema.inc
+--source include/have_query_cache.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+#
+# The following FLUSH statements should be replicated
+#
+
+--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
+FLUSH DES_KEY_FILE;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH HOSTS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--connection node_1
+SET GLOBAL wsrep_replicate_myisam = TRUE;
+INSERT INTO mysql.user VALUES('localhost','user1',PASSWORD('pass1'), 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'mysql_native_password','','N','N');
+FLUSH PRIVILEGES;
+--connect node_2a, 127.0.0.1, user1, pass1, test, $NODE_MYPORT_2
+--connection node_1
+DELETE FROM mysql.user WHERE user = 'user1';
+SET GLOBAL wsrep_replicate_myisam = FALSE;
+FLUSH PRIVILEGES;
+
+
+--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
+FLUSH QUERY CACHE;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH STATUS;
+
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH USER_RESOURCES;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH TABLES;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--connection node_1
+CREATE TABLE t2 (f1 INTEGER);
+
+--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
+FLUSH TABLES t2;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH ERROR LOGS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH SLOW LOGS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--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
+FLUSH GENERAL LOGS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--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
+FLUSH ENGINE LOGS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--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
+FLUSH RELAY LOGS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--connection node_1
+SET @userstat_old= @@userstat;
+SET GLOBAL userstat=ON;
+
+--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
+FLUSH CLIENT_STATISTICS;
+FLUSH INDEX_STATISTICS;
+FLUSH TABLE_STATISTICS;
+FLUSH USER_STATISTICS;
+--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 + 4 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--connection node_1
+SET @old_thread_statistics= @@global.thread_statistics;
+SET GLOBAL thread_statistics= ON;
+
+--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
+FLUSH THREAD_STATISTICS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+FLUSH CHANGED_PAGE_BITMAPS;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+#
+# The following statements should not be replicated: FLUSH LOGS, FLUSH TABLES WITH LOCKS
+#
+
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+
+--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
+FLUSH LOGS;
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+
+--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
+
+
+## Test LOCK TABLES with FLUSH TABLES
+## LOCK TABLES t1 write followed by flush tables t1 should succeed due to MDL upgrade.
+## LOCK tables t2 read followed by flush tables t2 should fail with ER_TABLE_NOT_LOCKED_FOR_WRITE
+
+
+--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
+LOCK TABLES t1 WRITE;
+FLUSH TABLES t1;
+UNLOCK TABLES;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+--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
+LOCK TABLES t1 READ;
+--error ER_TABLE_NOT_LOCKED_FOR_WRITE
+FLUSH TABLES t1;
+UNLOCK TABLES;
+--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
+--connection node_1
+FLUSH TABLES t1;
+--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 + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE t2;
+SET GLOBAL userstat= @userstat_old;
+SET GLOBAL thread_statistics= @old_thread_statistics;
diff --git a/mysql-test/suite/galera/t/galera_flush_local.opt b/mysql-test/suite/galera/t/galera_flush_local.opt
new file mode 100644
index 00000000000..5a1fb6748d9
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_flush_local.opt
@@ -0,0 +1 @@
+--query_cache_type=1 --query_cache_size=1000000
diff --git a/mysql-test/suite/galera/t/galera_flush_local.test b/mysql-test/suite/galera/t/galera_flush_local.test
new file mode 100644
index 00000000000..768f4ea4f1b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_flush_local.test
@@ -0,0 +1,142 @@
+#
+# Test that various FLUSH LOCAL commands are replicated. Whenever possible, check the slave for the effects.
+# PXC-391
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_query_cache.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2, x1, x2;
+--enable_warnings
+#
+# The following FLUSH LOCAL statements should *not* be replicated
+#
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
+CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE x2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
+INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+--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
+FLUSH LOCAL DES_KEY_FILE;
+FLUSH LOCAL HOSTS;
+FLUSH LOCAL QUERY CACHE;
+FLUSH LOCAL STATUS;
+FLUSH LOCAL PRIVILEGES;
+FLUSH LOCAL USER_RESOURCES;
+FLUSH LOCAL TABLES;
+FLUSH LOCAL TABLES t2;
+FLUSH LOCAL ERROR LOGS;
+FLUSH LOCAL SLOW LOGS;
+FLUSH LOCAL GENERAL LOGS;
+FLUSH LOCAL ENGINE LOGS;
+FLUSH LOCAL RELAY LOGS;
+FLUSH LOCAL CLIENT_STATISTICS;
+FLUSH LOCAL INDEX_STATISTICS;
+FLUSH LOCAL TABLE_STATISTICS;
+FLUSH LOCAL USER_STATISTICS;
+FLUSH LOCAL LOGS;
+FLUSH LOCAL BINARY LOGS;
+FLUSH LOCAL TABLES WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH LOCAL TABLES t1 WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH LOCAL TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+LOCK TABLES t1 WRITE;
+FLUSH LOCAL TABLES t1;
+UNLOCK TABLES;
+LOCK TABLES t1 READ;
+--error ER_TABLE_NOT_LOCKED_FOR_WRITE
+FLUSH LOCAL TABLES t1;
+UNLOCK TABLES;
+FLUSH LOCAL TABLES t1;
+ANALYZE LOCAL TABLE t1, t2;
+OPTIMIZE LOCAL TABLE t1, t2;
+REPAIR LOCAL TABLE x1, x2;
+--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
+
+SELECT COUNT(*) = 10 FROM t1;
+SELECT COUNT(*) = 10 FROM x1;
+SELECT COUNT(*) = 10000 FROM t2;
+SELECT COUNT(*) = 10 FROM x2;
+
+
+--connection node_1
+DROP TABLE t1, t2, x1, x2;
+CREATE TABLE t1 (f1 INTEGER);
+CREATE TABLE t2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
+CREATE TABLE x1 (f1 INTEGER) ENGINE=MyISAM;
+CREATE TABLE x2 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO x1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+INSERT INTO t2 (f2) SELECT 1 FROM t1 AS a1, t1 AS a2, t1 AS a3, t1 AS a4;
+INSERT INTO x2 (f2) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+
+--connection node_2
+--let $wsrep_last_committed_before2 = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+--connection node_1
+set wsrep_on=0;
+FLUSH DES_KEY_FILE;
+FLUSH HOSTS;
+FLUSH QUERY CACHE;
+FLUSH STATUS;
+FLUSH PRIVILEGES;
+FLUSH USER_RESOURCES;
+FLUSH TABLES;
+FLUSH TABLES t2;
+FLUSH ERROR LOGS;
+FLUSH SLOW LOGS;
+FLUSH GENERAL LOGS;
+FLUSH ENGINE LOGS;
+FLUSH RELAY LOGS;
+FLUSH CLIENT_STATISTICS;
+FLUSH INDEX_STATISTICS;
+FLUSH TABLE_STATISTICS;
+FLUSH USER_STATISTICS;
+FLUSH LOGS;
+FLUSH BINARY LOGS;
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 WITH READ LOCK;
+UNLOCK TABLES;
+FLUSH TABLES t1 FOR EXPORT;
+UNLOCK TABLES;
+LOCK TABLES t1 WRITE;
+FLUSH TABLES t1;
+UNLOCK TABLES;
+LOCK TABLES t1 READ;
+--error ER_TABLE_NOT_LOCKED_FOR_WRITE
+FLUSH TABLES t1;
+UNLOCK TABLES;
+FLUSH TABLES t1;
+ANALYZE TABLE t1, t2;
+OPTIMIZE TABLE t1, t2;
+REPAIR TABLE x1, x2;
+--connection node_2
+--let $wsrep_last_committed_after2 = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+--disable_query_log
+--eval SELECT $wsrep_last_committed_after2 = $wsrep_last_committed_before2 AS wsrep_last_committed_diff;
+--eval SELECT $wsrep_last_committed_after2 = $wsrep_last_committed_before + 9 AS wsrep_last_committed_diff2;
+--enable_query_log
+
+SELECT COUNT(*) = 10 FROM t1;
+SELECT COUNT(*) = 10 FROM x1;
+SELECT COUNT(*) = 10000 FROM t2;
+SELECT COUNT(*) = 10 FROM x2;
+
+--connection node_1
+set wsrep_on=1;
+DROP TABLE t1, t2, x1, x2;
diff --git a/mysql-test/suite/galera/t/galera_forced_binlog_format-master.opt b/mysql-test/suite/galera/t/galera_forced_binlog_format-master.opt
new file mode 100644
index 00000000000..8c58b59b45d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_forced_binlog_format-master.opt
@@ -0,0 +1 @@
+--log-bin --wsrep_forced_binlog_format=ROW
diff --git a/mysql-test/suite/galera/t/galera_forced_binlog_format.test b/mysql-test/suite/galera/t/galera_forced_binlog_format.test
new file mode 100644
index 00000000000..d621403f231
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_forced_binlog_format.test
@@ -0,0 +1,45 @@
+#
+# Test that wsrep_forced_binlog_format=ROW indeed prevents the log to be switched to STATEMENT format on a per-connection basis
+#
+
+--source include/have_log_bin.inc
+--source include/have_innodb.inc
+--source include/galera_cluster.inc
+
+--connection node_1
+RESET MASTER;
+
+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);
+
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+--replace_column 2 <Pos> 5 <End_log_pos>
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 248;
+
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-9401: wsrep_forced_binlog_format with binlog causes crash
+--echo #
+SET SESSION binlog_format = 'ROW';
+CREATE DATABASE testdb_9401;
+USE testdb_9401;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+CREATE USER dummy@localhost;
+GRANT ALL PRIVILEGES ON testdb_9401.t1 TO dummy@localhost;
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR dummy@localhost;
+# Cleanup
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
+DROP USER dummy@localhost;
+DROP DATABASE testdb_9401;
+
+--source include/galera_end.inc
+--echo # End of tests
+
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 00000000000..739255609ee
--- /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 causality 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;
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = "$wsrep_provider_options_orig";
+--enable_query_log
+
+SHOW TABLES;
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_ftwrl_drain.test b/mysql-test/suite/galera/t/galera_ftwrl_drain.test
new file mode 100644
index 00000000000..690e890cdea
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ftwrl_drain.test
@@ -0,0 +1,69 @@
+#
+# Test the following sequence of events:
+#
+# 1. issue a remote transaction
+# 2. applier is blocked from applying the transaction locally using apply_monitor_slave_enter_sync
+# 3. FTWRL is issued and blocks in ApplyOrder>::drain_common
+# 4. applier is unblocked
+# 5. remote transaction is applied
+# 6. FTWRL is granted
+#
+
+--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
+
+--connection node_1
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+
+--connection node_2
+
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+
+# Wait until applier has blocked
+--source include/galera_wait_sync_point.inc
+
+SELECT COUNT(*) = 0 FROM t1;
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+--send FLUSH TABLES WITH READ LOCK;
+
+--connection node_2
+--sleep 1
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'Init' AND INFO = 'FLUSH TABLES WITH READ LOCK'
+--source include/wait_condition.inc
+
+--source include/galera_clear_sync_point.inc
+--source include/galera_signal_sync_point.inc
+
+--connection node_2a
+--reap
+
+--connection node_2
+
+SET SESSION lock_wait_timeout = 1;
+SET SESSION innodb_lock_wait_timeout=1;
+SET SESSION wait_timeout=1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+INSERT INTO t2 VALUES (2);
+
+--connection node_2a
+UNLOCK TABLES;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+INSERT INTO t1 VALUES (3);
+
+--connection node_1
+SELECT COUNT(*) = 2 FROM t1;
+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 00000000000..a90cab1aa1a
--- /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 1K rows
+INSERT INTO t1 (f2) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3;
+
+--connection node_2
+SELECT COUNT(f2) = 1000 FROM t1 WHERE MATCH(f2) AGAINST ('foobarbaz');
+
+UPDATE t1 SET f2 = 'abcdefjhk';
+
+--connection node_1
+SELECT COUNT(f2) = 1000 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_gcache_recover.cnf b/mysql-test/suite/galera/t/galera_gcache_recover.cnf
new file mode 100644
index 00000000000..c7b59b6a27e
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcache_recover.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.recover=yes;pc.ignore_sb=true'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.recover=yes;pc.ignore_sb=true'
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover.test b/mysql-test/suite/galera/t/galera_gcache_recover.test
new file mode 100644
index 00000000000..e1bfe517d27
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcache_recover.test
@@ -0,0 +1,77 @@
+#
+# Kill entire cluster while gcache.recover=yes. Expect that node #2 will rejoin using IST
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+SET SESSION wsrep_sync_wait = 0;
+--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
+
+INSERT INTO t1 VALUES (2);
+
+--source include/kill_galera.inc
+
+--sleep 1
+
+--connection node_1
+--let $galera_wsrep_recover_server_id=1
+--source suite/galera/include/galera_wsrep_recover.inc
+
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+
+INSERT INTO t1 VALUES (3);
+
+--connection node_2
+--let $galera_wsrep_recover_server_id=2
+--source suite/galera/include/galera_wsrep_recover.inc
+
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+--connection node_1
+# Warning happens when the cluster is started for the first time
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+
+# Confirm that IST took place
+--let $assert_text = async IST sender starting to serve
+--let $assert_select = async IST sender starting to serve
+--let $assert_count = 1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let $assert_only_after = starting as process
+--source include/assert_grep.inc
+
+--connection node_2
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+
+# Confirm that gcache recovery took place
+
+--let $assert_text = Recovering GCache ring buffer: found gapless sequence
+--let $assert_select = Recovering GCache ring buffer: found gapless sequence
+--let $assert_count = 1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let $assert_only_after = starting as process
+--source include/assert_grep.inc
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.cnf b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.cnf
new file mode 100644
index 00000000000..da74ea9fc5d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.cnf
@@ -0,0 +1,9 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+max_allowed_packet=10M
+innodb_log_file_size=110M
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.recover=yes;pc.ignore_sb=true;gcache.size=10M'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.recover=yes;pc.ignore_sb=true;gcache.size=10M'
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test
new file mode 100644
index 00000000000..b7fd9cf3aed
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test
@@ -0,0 +1,59 @@
+#
+# Attempt gcache recovery on a full gcache. Node will not be able to join via IST due to gcache rollover
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 LONGBLOB) ENGINE=InnoDB;
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--source include/kill_galera.inc
+
+--connection node_1
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+--source include/kill_galera.inc
+
+--connection node_1
+--let $galera_wsrep_recover_server_id=1
+--source suite/galera/include/galera_wsrep_recover.inc
+
+--let $_expect_file_name = $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+--connection node_2
+--let $galera_wsrep_recover_server_id=2
+--source suite/galera/include/galera_wsrep_recover.inc
+
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+--connection node_1
+DROP TABLE t1;
+
+# Warning always happens when the cluster is started for the first time
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+
+# Confirm that IST did not take place
+--let $assert_text = IST first seqno 2 not found from cache, falling back to SST
+--let $assert_select = IST first seqno 2 not found from cache, falling back to SST
+--let $assert_count = 1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let $assert_only_after = starting as process
+--source include/assert_grep.inc
+
+--connection node_2
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.cnf b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.cnf
new file mode 100644
index 00000000000..c08551eae84
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.cnf
@@ -0,0 +1,9 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+innodb_log_file_size=110M
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.recover=yes;pc.ignore_sb=true;'
+
+[mysqld.2]
+innodb_log_file_size=110M
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.recover=yes;pc.ignore_sb=true;'
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test
new file mode 100644
index 00000000000..08165f30f7d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcache_recover_manytrx.test
@@ -0,0 +1,225 @@
+#
+# Kill entire cluster while various transactions are in progress
+# restore the cluster and expect that node #2 will rejoin using IST
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+--source include/have_log_bin.inc
+
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 LONGBLOB) ENGINE=InnoDB;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+DELIMITER |;
+CREATE PROCEDURE insert_simple ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ INSERT INTO t1 (f1, f2) VALUES (DEFAULT,'abcdef');
+ END WHILE;
+END|
+
+CREATE PROCEDURE insert_multi ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ INSERT INTO t1 (f1) VALUES (DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT),(DEFAULT);
+ END WHILE;
+END|
+
+CREATE PROCEDURE insert_transaction ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ SET AUTOCOMMIT = OFF;
+ WHILE 1 DO
+ START TRANSACTION;
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ INSERT INTO t1 (f1) VALUES (DEFAULT);
+ COMMIT;
+ END WHILE;
+END|
+
+DELIMITER ;|
+DELIMITER |;
+
+CREATE PROCEDURE update_simple ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ UPDATE t1 SET f2 = CONCAT(f2,f2);
+ END WHILE;
+END|
+
+CREATE PROCEDURE insert_1k ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024));
+ END WHILE;
+END|
+
+CREATE PROCEDURE insert_1m ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024));
+ END WHILE;
+END|
+
+CREATE PROCEDURE insert_10m ()
+BEGIN
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+ SET SESSION wsrep_sync_wait = 0;
+ WHILE 1 DO
+ INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
+ END WHILE;
+END|
+
+DELIMITER ;|
+
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--connect node_1_insert_simple, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1_insert_multi, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1_insert_transaction, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1_update_simple, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1_insert_1k, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1_insert_1m, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1_insert_10m, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1_insert_simple
+--send CALL insert_simple();
+
+--connection node_1_insert_multi
+--send CALL insert_multi();
+
+--connection node_1_insert_transaction
+--send CALL insert_transaction ();
+
+--connection node_1_update_simple
+--send CALL update_simple ();
+
+--connection node_1_insert_1k
+--send CALL insert_1k ();
+
+--connection node_1_insert_1m
+--send CALL insert_1m ();
+
+--connection node_1_insert_10m
+--send CALL insert_10m ();
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+
+# Make sure that node_2 is not killed while TOIs are applied.
+# Otherwhise we risk that grastate file is marked unsafe, and
+# as a consequence the node cannot rejoin with IST.
+--let $wait_condition = SELECT VARIABLE_VALUE > $wsrep_last_committed_before FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+
+--sleep 10
+--connection node_1
+--source include/kill_galera.inc
+
+--connection node_1_insert_simple
+--error 2013
+--reap
+
+--connection node_1_insert_multi
+--error 2013
+--reap
+
+--connection node_1_insert_transaction
+--error 2013
+--reap
+
+--connection node_1_update_simple
+--error 2013
+--reap
+
+--connection node_1_insert_1k
+--error 2013
+--reap
+
+--connection node_1_insert_1m
+--error 2013
+--reap
+
+--connection node_1_insert_10m
+--error 2013
+--reap
+
+--connection node_1
+--let $galera_wsrep_recover_server_id=1
+--source suite/galera/include/galera_wsrep_recover.inc
+
+--let $_expect_file_name = $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+--connection node_2
+--let $galera_wsrep_recover_server_id=2
+--source suite/galera/include/galera_wsrep_recover.inc
+
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_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
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE ten;
+DROP PROCEDURE insert_simple;
+DROP PROCEDURE insert_multi;
+DROP PROCEDURE insert_transaction;
+DROP PROCEDURE update_simple;
+DROP PROCEDURE insert_1k;
+DROP PROCEDURE insert_1m;
+
+--connection node_1
+CALL mtr.add_suppression("conflict state 7 after post commit");
+
+# Warning happens when the cluster is started for the first time
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+
+# Confirm that IST took place
+--let $assert_text = async IST sender starting to serve
+--let $assert_select = async IST sender starting to serve
+--let $assert_count = 1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let $assert_only_after = starting as process
+--source include/assert_grep.inc
+
+--connection node_2
+CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
+
+# Confirm that gcache recovery took place
+
+--let $assert_text = Recovering GCache ring buffer: found gapless sequence
+--let $assert_select = Recovering GCache ring buffer: found gapless sequence
+--let $assert_count = 1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let $assert_only_after = starting as process
+--source include/assert_grep.inc
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 00000000000..61576a39316
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcs_fc_limit.test
@@ -0,0 +1,59 @@
+#
+# 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
+SELECT COUNT(*) = 1 FROM t1;
+--sleep 1
+
+--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1';
+
+# Block the slave applier thread
+LOCK TABLE t1 WRITE;
+
+--connection node_1
+--sleep 1
+INSERT INTO t1 VALUES (2);
+--sleep 2
+INSERT INTO t1 VALUES (3);
+--sleep 2
+INSERT INTO t1 VALUES (4);
+--sleep 2
+
+# This query will hang because flow control will kick in
+--send
+INSERT INTO t1 VALUES (5);
+--sleep 2
+
+--let $galera_connection_name = node_1a
+--let $galera_server_number = 1
+--source include/galera_connect.inc
+--connection node_1a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'query end' AND INFO = 'INSERT INTO t1 VALUES (5)';
+--source include/wait_condition.inc
+
+--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_fragment.cnf b/mysql-test/suite/galera/t/galera_gcs_fragment.cnf
new file mode 100644
index 00000000000..aae3fee5904
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcs_fragment.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_fragment.test b/mysql-test/suite/galera/t/galera_gcs_fragment.test
new file mode 100644
index 00000000000..ae1e0d8bab0
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcs_fragment.test
@@ -0,0 +1,66 @@
+# Test fragmentation over configuration changes
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Prepare table
+CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 TEXT);
+
+# Stop node2
+
+# Disconnect node_2 from group
+--connection node_2
+--let $wsrep_cluster_address_orig = `select @@wsrep_cluster_address`
+SET GLOBAL wsrep_cluster_address='';
+
+# Connection for sync points
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_sync_wait=0;
+
+# Set breakpoint in gcs after first fragment send
+
+--let $galera_sync_point = gcs_core_after_frag_send
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+SET SESSION wsrep_retry_autocommit=0;
+--send INSERT INTO t1 VALUES (1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+
+--connection node_1a
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+
+# Restart node_2, wait until it joins the group and then make INSERT
+--connection node_2
+--disable_query_log
+--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig'
+--enable_query_log
+SET SESSION wsrep_on = 0;
+--source include/galera_wait_ready.inc
+SET SESSION wsrep_on = 1;
+
+INSERT INTO t1 VALUES (2, "bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+
+# Signal node_1 to continue
+--connection node_1a
+--source include/galera_signal_sync_point.inc
+
+# Deadlock error should be returned since write set send was
+# interrupted by gcs
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+# Do additional insert to verify that node_1 remain operational
+INSERT INTO t1 VALUES (3, "cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+
+
+# Nodes node_1 and node_2 should now contain rows 2 and 3
+SELECT * FROM t1;
+
+--connection node_2
+SELECT * FROM t1;
+
+--connection node_1
+
+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 00000000000..6bb11e5957a
--- /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;gcache.size=10M'
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcs.max_packet_size=64;gcache.size=10M'
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 00000000000..98be4f6a300
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gcs_max_packet_size.test
@@ -0,0 +1,26 @@
+#
+# 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
+--source include/big_test.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_gra_log.test b/mysql-test/suite/galera/t/galera_gra_log.test
new file mode 100644
index 00000000000..5329dc24546
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gra_log.test
@@ -0,0 +1,38 @@
+#
+# Test that GRA_* files are generated on applier failure and are readable.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_2
+--exec rm -rf $MYSQLTEST_VARDIR/mysqld.2/data/GRA_*.log
+
+# Create applier failure
+
+SET SESSION wsrep_on=OFF;
+CREATE TABLE t1 (f1 INTEGER);
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+# Compose a valid binlog from a header file and the GRA file
+
+--let $gra_binlog_file = $MYSQLTEST_VARDIR/tmp/gra.log
+--exec rm -rf $gra_binlog_file
+
+--exec cp std_data/binlog-header.log $gra_binlog_file
+--exec cat $MYSQLTEST_VARDIR/mysqld.2/data/GRA_*.log >> $gra_binlog_file
+
+# Make sure the binlog thus produced is readable and contains the failure
+--replace_regex /SET TIMESTAMP=[0-9]+/SET TIMESTAMP=<TIMESTAMP>/ /#[0-9]+ +[0-9]+:[0-9]+:[0-9]+/<ISO TIMESTAMP>/ /pseudo_thread_id=[0-9]+/pseudo_thread_id=<PSEUDO_THREAD_ID>/ /thread_id=[0-9]+/thread_id=<QUERY_THREAD_ID>/
+--exec $MYSQL_BINLOG $gra_binlog_file
+
+SET SESSION wsrep_on=ON;
+
+CALL mtr.add_suppression("Slave SQL: Error 'Table 't1' already exists' on query");
+
+DROP TABLE t1;
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 00000000000..8a755e98b00
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gtid-master.opt
@@ -0,0 +1 @@
+--log-bin --log-slave-updates
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 00000000000..e8369be62e6
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_gtid.test
@@ -0,0 +1,27 @@
+#
+# Test GTID for basic Galera operations
+#
+
+--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_binlog_state_node2 = `SELECT @@global.gtid_binlog_state;`
+
+--connection node_1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+
+--disable_query_log
+--eval SELECT '$gtid_binlog_state_node2' = @@global.gtid_binlog_state AS gtid_binlog_state_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 00000000000..027f70e96d9
--- /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 = 15;
+
+--connection node_2
+SET GLOBAL wsrep_sync_wait = 15;
+
+
+#
+# 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 00000000000..d62283aff69
--- /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 00000000000..41a1aab382b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_innodb_flush_logs.cnf
@@ -0,0 +1,14 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth=root:
+
+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 00000000000..07838702deb
--- /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 00000000000..357c8678658
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_mysqldump.cnf
@@ -0,0 +1,12 @@
+!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 00000000000..a9ff8c41f06
--- /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_progress.cnf b/mysql-test/suite/galera/t/galera_ist_progress.cnf
new file mode 100644
index 00000000000..0a26f6d6c83
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_progress.cnf
@@ -0,0 +1,5 @@
+!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_progress.test b/mysql-test/suite/galera/t/galera_ist_progress.test
new file mode 100644
index 00000000000..3ba63415c28
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_progress.test
@@ -0,0 +1,76 @@
+#
+# Test progress output during IST
+#
+
+--source include/galera_cluster.inc
+# This could cause out of storage if run /dev/shm
+--source include/big_test.inc
+
+# Isolate node #2
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 1';
+
+--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
+
+--connection node_2
+SET SESSION wsrep_on = OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+SET SESSION wsrep_on = ON;
+
+# Node #2 is now isolated. Run some transactions to accumulate writesets for IST
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (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);
+
+# Restore node #2, IST is performed
+
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0';
+
+--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
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+#
+# Grep for expected IST output in joiner log
+#
+
+--connection node_1
+
+--let $assert_count = 1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let $assert_only_after = Need state transfer
+
+--let $assert_text = Receiving IST: 11 writesets, seqnos
+--let $assert_select = Receiving IST: 11 writesets, seqnos
+--source include/assert_grep.inc
+
+--let $assert_text = Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete
+--let $assert_select = Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete
+--source include/assert_grep.inc
+
+--let $assert_text = Receiving IST\.\.\.100\.0% \(11/11 events\) complete
+--let $assert_select = Receiving IST\.\.\.100\.0% \(11/11 events\) complete
+--source include/assert_grep.inc
+
+# Cleanup
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_ist_recv_bind.cnf b/mysql-test/suite/galera/t/galera_ist_recv_bind.cnf
new file mode 100644
index 00000000000..2628f05eaef
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_recv_bind.cnf
@@ -0,0 +1,8 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;ist.recv_bind=127.0.0.1;pc.ignore_sb=true'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;ist.recv_bind=127.0.0.1'
+
diff --git a/mysql-test/suite/galera/t/galera_ist_recv_bind.test b/mysql-test/suite/galera/t/galera_ist_recv_bind.test
new file mode 100644
index 00000000000..a339684c158
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_recv_bind.test
@@ -0,0 +1,55 @@
+#
+# Test ist.recv_bind option. Since MTR can not do proper testing with multiple interfaces and such, we
+# simply confirm that the option can be set (in the galera_ist_recv_bind.cnf file) and that IST works as expected
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+--connection node_1
+SELECT @@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%';
+
+--connection node_2
+SELECT @@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%';
+
+# Isolate node #2
+
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 1';
+--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
+
+--connection node_2
+SET SESSION wsrep_on = OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+SET SESSION wsrep_on = ON;
+
+# Node #2 is now isolated. Run some transactions to accumulate writesets for IST
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+# Restore node #2
+
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0';
+
+--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
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+# Confirm that IST has taken place
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM t1;
+--source include/wait_condition.inc
+
+# Cleanup
+
+DROP TABLE t1;
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 00000000000..10958aad9a8
--- /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 00000000000..633318629a6
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
@@ -0,0 +1,113 @@
+#
+# 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
+# This could cause out of storage if run /dev/shm
+--source include/big_test.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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
+# 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
+# base_port setting is lost for some reason when unloading provider, so we need to restore it
+--eval SET GLOBAL wsrep_provider_options= 'base_port=$NODE_GALERAPORT_2';
+--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
+# Make sure IST will block ...
+--let $galera_sync_point = recv_IST_after_apply_trx
+--source include/galera_set_sync_point.inc
+--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
+--enable_query_log
+
+SET SESSION wsrep_on=OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'recv_IST_after_apply_trx' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters';
+--source include/wait_condition.inc
+SET SESSION wsrep_on=ON;
+
+--connection node_1
+# Perform DML while IST is in progress
+UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
+
+# 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 while node #2 is down
+UPDATE t1 SET f2 = 'e' WHERE f1 > 4;
+
+--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;
+
+--connection node_1
+DROP TABLE t1;
+
+# Restore original auto_increment_offset values.
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
+
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 00000000000..797e3651967
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_rsync.cnf
@@ -0,0 +1,13 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
+wsrep_sync_wait=1
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'
+wsrep_sync_wait=1
+
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 00000000000..1da79cd4214
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_rsync.test
@@ -0,0 +1,13 @@
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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
+--source include/auto_increment_offset_restore.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 00000000000..a762b939f69
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ist_xtrabackup-v2.cnf
@@ -0,0 +1,12 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth=root:
+
+[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 00000000000..8b399e77794
--- /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_applier.test b/mysql-test/suite/galera/t/galera_kill_applier.test
new file mode 100644
index 00000000000..e14a8b9af23
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_kill_applier.test
@@ -0,0 +1,26 @@
+#
+# This test checks that applier threads are immune to KILL QUERY and KILL STATEMENT
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+--let $applier_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE != 'wsrep aborter idle' OR STATE IS NULL LIMIT 1`
+
+--disable_query_log
+--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
+--eval KILL $applier_thread
+
+--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
+--eval KILL QUERY $applier_thread
+
+--let $aborter_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'wsrep aborter idle' LIMIT 1`
+
+--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
+--eval KILL $aborter_thread
+
+--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
+--eval KILL QUERY $aborter_thread
+--enable_query_log
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 00000000000..90f3f30cc76
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_kill_ddl.test
@@ -0,0 +1,44 @@
+#
+# 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
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1';
+
+--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 00000000000..e9a32ce813b
--- /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 00000000000..1903df449e4
--- /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 00000000000..d998032cbc3
--- /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 00000000000..bd581842f6f
--- /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 00000000000..8a755e98b00
--- /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 00000000000..b0f215c85e5
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_log_bin.test
@@ -0,0 +1,39 @@
+--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;
+
+--replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000002' LIMIT 4,18;
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+
+--replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000003' LIMIT 3,19;
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+--connection node_1
+RESET MASTER;
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 00000000000..2f71b140b65
--- /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 00000000000..94ae3dd6168
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_log_output_csv.test
@@ -0,0 +1,24 @@
+#
+# 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
+
+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 00000000000..3f596179c01
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_many_columns.test
@@ -0,0 +1,63 @@
+--source include/big_test.inc
+--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 00000000000..e01d0b23aa5
--- /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 00000000000..58ba85e1b9e
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_many_rows.test
@@ -0,0 +1,54 @@
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+SET SESSION innodb_lock_wait_timeout=600;
+SET SESSION lock_wait_timeout=600;
+
+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
+SET SESSION wsrep_sync_wait = 0;
+--let $wsrep_provider_options_node2 = `SELECT @@wsrep_provider_options`
+SET SESSION wsrep_sync_wait = 15;
+
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT1H';
+
+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;
+
+--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;
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node2';
+--enable_query_log
+
+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 00000000000..2496d145c93
--- /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 00000000000..0af7160d4d8
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_many_tables_pk.test
@@ -0,0 +1,101 @@
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# This test forces 100 tables with a PK to participate in a single transaction
+#
+
+#
+# First, create 100 tables and make sure the DDLs are all propagated
+#
+
+--connection node_1
+
+--let $count = 100
+while ($count)
+{
+ --disable_query_log
+ --let $ddl_var = `SELECT CONCAT("CREATE TABLE t", $count, " (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB")`
+ --eval $ddl_var
+ --enable_query_log
+ --dec $count
+}
+
+--connection node_2
+SELECT COUNT(*) = 100 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 = 100
+while ($count)
+{
+ --disable_query_log
+ --let $ddl_var = `SELECT CONCAT("INSERT INTO t", $count, " VALUES (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 = 100
+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) = 100 FROM sum_table;
+
+#
+# Fourth, create a deadlock
+#
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--let $count = 100
+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 t100 SET f1 = 3;
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+DROP SCHEMA test;
+CREATE SCHEMA test;
diff --git a/mysql-test/suite/galera/t/galera_mdl_race.test b/mysql-test/suite/galera/t/galera_mdl_race.test
new file mode 100644
index 00000000000..508b85add4b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_mdl_race.test
@@ -0,0 +1,79 @@
+#
+# This test tests a potential race condition in MDL locking
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+CREATE TABLE t2 (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;
+
+# block access to t2
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+LOCK TABLE t2 WRITE;
+
+# Block before MLD lock wait
+--connection node_1
+ SET GLOBAL DEBUG = "d,sync.wsrep_before_mdl_wait";
+--send SELECT * FROM t2;
+
+# Wait for SELECT to be blocked
+--connection node_1a
+#--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIS WHERE STATE = 'System lock';
+#--source include/wait_condition.inc
+#--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'init' AND INFO = 'COMMIT';
+#--source include/wait_condition.inc
+
+# block applier to wait after BF victim is locked
+SET GLOBAL DEBUG = "d,sync.wsrep_after_BF_victim_lock";
+
+# Issue a conflicting update on node #2
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 1;
+
+--sleep 3
+
+# Unblock the SELECT, to enter wsrep_thd_is_BF
+--connection node_1a
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait";
+
+--sleep 3
+
+# unblock applier to try to BF the SELECT
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_after_BF_victim_lock";
+
+
+# table lock is not needed anymore
+--sleep 3
+UNLOCK TABLES;
+
+# SELECT succeeds
+--connection node_1
+
+--error ER_LOCK_DEADLOCK
+--reap
+
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+--connection node_1a
+SET DEBUG_SYNC = "RESET";
+
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 00000000000..ed48f208e52
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_migrate.cnf
@@ -0,0 +1,59 @@
+#
+# 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 = 15
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+[mysqld.3]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+[mysqld.4]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+
+[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 00000000000..84897b66c6d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_migrate.test
@@ -0,0 +1,204 @@
+#
+# Execute a migration from MariaDB 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;
+
+--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';
+SET GLOBAL wsrep_sst_auth = 'sst:';
+
+--connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4
+GRANT ALL PRIVILEGES ON *.* TO '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 00000000000..6e06aaaa2c6
--- /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 00000000000..b01b5dc07f7
--- /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 00000000000..00e0bf3fdca
--- /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 00000000000..4292a6d6711
--- /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 00000000000..08e3b996c8e
--- /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 00000000000..bb9bcd5a593
--- /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 00000000000..e036e14ebe0
--- /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 00000000000..febb91a9725
--- /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 00000000000..f280e49d206
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test
@@ -0,0 +1,51 @@
+##
+## This test tests parallel application of multiple auto-increment insert transactions
+##
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.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 00000000000..8680d62a36d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test
@@ -0,0 +1,54 @@
+##
+## Tests the parallel application of many small-ish auto-increment insert transactions
+##
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.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 00000000000..41cd0c8e6fa
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_parallel_simple.test
@@ -0,0 +1,56 @@
+#
+# 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;
+LOCK TABLE t1 WRITE;
+
+--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
+SET SESSION wsrep_sync_wait = 0;
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for table metadata lock%';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'applied write set%';
+--source include/wait_condition.inc
+
+UNLOCK TABLES;
+
+SET SESSION wsrep_sync_wait = 15;
+
+SELECT COUNT(*) = 10 FROM t1;
+SELECT COUNT(*) = 10 FROM t2;
+
+--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 00000000000..84fd3a91857
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_pc_ignore_sb.test
@@ -0,0 +1,46 @@
+#
+# 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
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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
+
+# Restore original auto_increment_offset values.
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.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 00000000000..12a8a8f5d64
--- /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 00000000000..2bb02d5ea4e
--- /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_prepared_statement.test b/mysql-test/suite/galera/t/galera_prepared_statement.test
new file mode 100644
index 00000000000..3bee097ff39
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_prepared_statement.test
@@ -0,0 +1,45 @@
+#
+# A simple test for PREPARE / EXECUTE -style prepared statements with Galera
+#
+# C-API-level prepared-statements can not be triggered from inside mysqltest, however
+# can be exercised when running an MTR test suite with the --ps-protocol switch.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 CHAR(5)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 CHAR(5)) ENGINE=InnoDB;
+CREATE TABLE t3 (f1 CHAR(5)) ENGINE=InnoDB;
+CREATE TABLE t4 (f1 CHAR(5)) ENGINE=InnoDB;
+
+SET SESSION sql_mode='STRICT_ALL_TABLES';
+
+PREPARE st1 FROM 'INSERT INTO t1 VALUES ("abc")';
+PREPARE st2 FROM 'INSERT INTO t2 VALUES ("abc")';
+PREPARE st3 FROM 'INSERT INTO t3 VALUES ("abc")';
+PREPARE st4 FROM 'INSERT INTO t4 VALUES ("abc")';
+
+EXECUTE st1;
+EXECUTE st2;
+EXECUTE st3;
+EXECUTE st4;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) = 1 FROM t2;
+SELECT COUNT(*) = 1 FROM t3;
+SELECT COUNT(*) = 1 FROM t4;
+
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+ALTER TABLE t1 DROP COLUMN f1;
+
+--connection node_1
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+EXECUTE st1;
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
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 00000000000..915a36c0937
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_query_cache-master.opt
@@ -0,0 +1 @@
+--query_cache_type=1 --query_cache_size=1355776
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 00000000000..900faba0e1b
--- /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_query_cache_sync_wait-master.opt b/mysql-test/suite/galera/t/galera_query_cache_sync_wait-master.opt
new file mode 100644
index 00000000000..915a36c0937
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_query_cache_sync_wait-master.opt
@@ -0,0 +1 @@
+--query_cache_type=1 --query_cache_size=1355776
diff --git a/mysql-test/suite/galera/t/galera_query_cache_sync_wait.test b/mysql-test/suite/galera/t/galera_query_cache_sync_wait.test
new file mode 100644
index 00000000000..87afc2d7bb2
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_query_cache_sync_wait.test
@@ -0,0 +1,89 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+--source include/have_query_cache.inc
+
+CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT1S";
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+SELECT MAX(id) FROM t1; # first lookup miss
+
+#
+# Query cache hit, wait timeout
+#
+
+--connection node_1
+INSERT INTO t1 VALUES (2);
+
+--connection node_2
+--error ER_LOCK_WAIT_TIMEOUT
+SELECT MAX(id) FROM t1;
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+FLUSH QUERY CACHE;
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+SET DEBUG_SYNC = "RESET";
+
+#
+# Query cache miss, wait timeout
+#
+
+--connection node_1
+INSERT INTO t1 VALUES (3);
+
+--connection node_2
+--error ER_LOCK_WAIT_TIMEOUT
+SELECT MAX(id) FROM t1;
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+#
+# Query cache miss
+#
+
+--connection node_1
+INSERT INTO t1 VALUES (4);
+
+--connection node_2
+SELECT MAX(id) FROM t1;
+
+#
+# Query cache hit
+#
+
+FLUSH STATUS;
+SELECT MAX(id) FROM t1;
+SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+
+#
+# Query cache invalidated
+#
+
+--connection node_1
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--send SELECT MAX(id) FROM t1
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+--connection node_2
+--reap
+SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'Qcache_hits';
+
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = "$wsrep_provider_options_orig"
+DROP TABLE t1;
+
+--connection node_2a
+SET DEBUG_SYNC = "RESET";
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 00000000000..c0fa4af07e0
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_read_only.test
@@ -0,0 +1,39 @@
+--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;
+
+CREATE USER foo@localhost;
+
+--echo # Open connection to node 2 using 'foo' user.
+--let $port_2= \$NODE_MYPORT_2
+--connect(foo_node_2,127.0.0.1,foo,,test,$port_2,)
+
+--echo
+--echo # Connect with foo_node_2
+--connection foo_node_2
+--error ER_OPTION_PREVENTS_STATEMENT
+INSERT INTO t1 VALUES (2);
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+
+# Cleanup
+SET GLOBAL read_only=FALSE;
+DROP TABLE t1;
+DROP USER foo@localhost;
+
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 00000000000..8749c20faed
--- /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 00000000000..60b866ae018
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_repl_max_ws_size.test
@@ -0,0 +1,29 @@
+#
+# 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("Maximum writeset size exceeded by");
+CALL mtr.add_suppression("transaction size limit");
+CALL mtr.add_suppression("transaction size exceeded");
+CALL mtr.add_suppression("rbr write fail");
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 00000000000..0a6a0c5ccbe
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_restart_nochanges.test
@@ -0,0 +1,40 @@
+#
+# 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
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+--source include/restart_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
+
+--let $galera_connection_name = node_2a
+--let $galera_server_number = 2
+--source include/galera_connect.inc
+--connection node_2a
+--source include/wait_until_ready.inc
+
+SELECT COUNT(*) = 1 FROM t1;
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+DROP TABLE t1;
+
+# Restore original auto_increment_offset values.
+--let $node_2=node_2a
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
+
diff --git a/mysql-test/suite/galera/t/galera_restart_on_unknown_option.test b/mysql-test/suite/galera/t/galera_restart_on_unknown_option.test
new file mode 100644
index 00000000000..a8ea639415d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_restart_on_unknown_option.test
@@ -0,0 +1,157 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Suppress expected warnings:
+
+CALL mtr.add_suppression("Aborting");
+CALL mtr.add_suppression("unknown option '--galera-unknown-option'");
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+#
+# We should count the number of "Assertion failed" warnings
+# in the log file before and after testing. To do this we need
+# to save original log file before testing:
+#
+--let TEST_LOG=$MYSQLTEST_VARDIR/log/mysqld.2.err
+--perl
+ use strict;
+ my $test_log=$ENV{'TEST_LOG'} or die "TEST_LOG not set";
+ my $test_log_copy=$test_log . '.copy';
+ if (-e $test_log_copy) {
+ unlink $test_log_copy;
+ }
+EOF
+--copy_file $TEST_LOG $TEST_LOG.copy
+
+--connection node_2
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+INSERT INTO t1 VALUES (1, 'a'), (2, 'a'), (3, 'a');
+
+SELECT * FROM t1;
+
+# Initiate normal shutdown on the node 2 and
+# waiting until shutdown has been completed:
+
+--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
+
+# Some updates on node 1:
+
+UPDATE t1 SET f2 = 'b' WHERE f1 > 1;
+UPDATE t1 SET f2 = 'c' WHERE f1 > 2;
+
+SELECT * FROM t1;
+
+# Remove the "grastate.dat" file (to initiate new SST)
+# and restart node 2 with unknown option:
+
+--connection node_2
+
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
+--let $start_mysqld_params=--galera-unknown-option
+
+--echo Starting server ...
+--exec echo "try:$start_mysqld_params" > $_expect_file_name
+
+# Sleep to ensure that server exited...
+
+--sleep 30
+
+# Restart node 2 without unknown option:
+
+--let $start_mysqld_params=
+
+--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
+
+# Sanity check (node 2 is running now and can perform SQL operators):
+
+SELECT * FROM t1;
+
+# Initiate normal shutdown on the node 2 and
+# waiting until shutdown has been completed:
+
+--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
+
+# Some updates on node 1 - to initiate IST next time:
+
+UPDATE t1 SET f2 = 'd' WHERE f1 > 1;
+UPDATE t1 SET f2 = 'd' WHERE f1 > 2;
+
+SELECT * FROM t1;
+
+# Restart node 2 with unknown option:
+
+--connection node_2
+
+--let $start_mysqld_params=--galera-unknown-option
+
+--echo Starting server ...
+--exec echo "try:$start_mysqld_params" > $_expect_file_name
+
+# Sleep to ensure that server exited...
+
+--sleep 30
+
+# Restart node 2 without unknown option:
+
+--let $start_mysqld_params=
+
+--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
+
+# Sanity check (node 2 is running now and can perform SQL operators):
+
+SELECT * FROM t1;
+
+--connection node_1
+
+DROP TABLE t1;
+
+#
+# We should count the number of "Assertion failed" warnings
+# in the log file during test phase - to print the error message
+# if quantity of such warnings in log file increased at the end
+# of the test:
+#
+--perl
+ use strict;
+ my $test_log=$ENV{'TEST_LOG'} or die "TEST_LOG not set";
+ my $test_log_copy=$test_log . '.copy';
+ open(FILE, $test_log_copy) or die("Unable to open $test_log_copy: $!\n");
+ my $initial=grep(/Assertion * failed/gi,<FILE>);
+ close(FILE);
+ open(FILE, $test_log) or die("Unable to open $test_log: $!\n");
+ my $count_warnings=grep(/Assertion * failed/gi,<FILE>);
+ close(FILE);
+ if ($count_warnings != $initial) {
+ my $diff=$count_warnings-$initial;
+ print "Assertion failed $diff times.\n";
+ }
+EOF
+--remove_file $TEST_LOG.copy
+
+--source include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera/t/galera_roles.test b/mysql-test/suite/galera/t/galera_roles.test
new file mode 100644
index 00000000000..eea35762539
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_roles.test
@@ -0,0 +1,201 @@
+#
+# Test for CREATE/DROP/GRANT/REVOKE role.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # Testing CREATE/GRANT role
+--echo #
+
+--echo
+--echo # On node_1
+--connection node_1
+
+CREATE DATABASE test1;
+CREATE TABLE test1.t1 (a int, b int);
+CREATE TABLE test1.t2 (a int, b int);
+INSERT INTO test1.t1 values (1,2),(3,4);
+INSERT INTO test1.t2 values (5,6),(7,8);
+
+CREATE PROCEDURE test1.pr1() SELECT "pr1";
+
+CREATE USER foo@localhost;
+CREATE ROLE role1;
+
+GRANT role1 TO foo@localhost;
+GRANT RELOAD ON *.* TO role1;
+GRANT SELECT ON mysql.* TO role1;
+GRANT EXECUTE ON PROCEDURE test1.pr1 TO role1;
+GRANT SELECT ON test1.t1 TO role1;
+GRANT SELECT (a) ON test1.t2 TO role1;
+
+--echo # Open connections to the 2 nodes using 'foo' user.
+--let $port_1= \$NODE_MYPORT_1
+--connect(foo_node_1,127.0.0.1,foo,,test,$port_1,)
+
+--let $port_2= \$NODE_MYPORT_2
+--sleep 1
+--connect(foo_node_2,127.0.0.1,foo,,test,$port_2,)
+
+--echo
+--echo # Connect with foo_node_1
+--connection foo_node_1
+
+SHOW GRANTS;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+FLUSH TABLES;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM mysql.roles_mapping;
+--error ER_DBACCESS_DENIED_ERROR
+SHOW TABLES FROM test1;
+
+SET ROLE role1;
+
+FLUSH TABLES;
+--sorted_result
+SELECT * FROM mysql.roles_mapping;
+SHOW TABLES FROM test1;
+SELECT * FROM test1.t1;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM test1.t2;
+SELECT a FROM test1.t2;
+CALL test1.pr1();
+
+--echo
+--echo # Connect with foo_node_2
+--connection foo_node_2
+
+SHOW GRANTS;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+FLUSH TABLES;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM mysql.roles_mapping;
+--error ER_DBACCESS_DENIED_ERROR
+SHOW TABLES FROM test1;
+
+SET ROLE role1;
+
+FLUSH TABLES;
+--sorted_result
+SELECT * FROM mysql.roles_mapping;
+SHOW TABLES FROM test1;
+SELECT * FROM test1.t1;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM test1.t2;
+SELECT a FROM test1.t2;
+CALL test1.pr1();
+
+--echo #
+--echo # Testing REVOKE role
+--echo #
+
+--echo #
+--echo # Connect with node_1
+--connection node_1
+REVOKE EXECUTE ON PROCEDURE test1.pr1 FROM role1;
+
+--echo
+--echo # Connect with foo_node_1
+--connection foo_node_1
+
+--sleep 1
+--error ER_PROCACCESS_DENIED_ERROR
+CALL test1.pr1();
+
+--echo
+--echo # Connect with foo_node_2
+--connection foo_node_2
+
+--error ER_PROCACCESS_DENIED_ERROR
+CALL test1.pr1();
+
+--echo #
+--echo # Testing DROP role
+--echo #
+
+--echo
+--echo # Connect with node_1
+--connection node_1
+
+DROP ROLE role1;
+
+--echo
+--echo # Connect with foo_node_1
+--connection foo_node_1
+
+FLUSH TABLES;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM mysql.roles_mapping;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM test1.t1;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT a FROM test1.t2;
+
+SHOW GRANTS;
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES; # yes, repeat it twice
+SELECT CURRENT_ROLE();
+
+--echo
+--echo # Connect with foo_node_2
+--connection foo_node_2
+
+FLUSH TABLES;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM mysql.roles_mapping;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM test1.t1;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT a FROM test1.t2;
+
+SHOW GRANTS;
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES;
+SELECT * FROM INFORMATION_SCHEMA.ENABLED_ROLES; # yes, repeat it twice
+SELECT CURRENT_ROLE();
+
+# Cleanup
+disconnect foo_node_2;
+--echo # Connect with node_1
+--connection node_1
+
+DROP USER foo@localhost;
+DROP DATABASE test1;
+
+--echo #
+--echo # MDEV-10566: Create role statement replicated inconsistently in Galera Cluster
+--echo #
+--echo
+--echo # On node_1
+--connection node_1
+CREATE USER foo@localhost;
+CREATE ROLE role1;
+CREATE ROLE role2 WITH ADMIN CURRENT_USER;
+CREATE ROLE role3 WITH ADMIN foo@localhost;
+CREATE ROLE role4 WITH ADMIN role1;
+
+--sorted_result
+SELECT * FROM mysql.roles_mapping;
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.APPLICABLE_ROLES;
+
+--echo
+--echo # On node_2
+--connection node_2
+--sorted_result
+SELECT * FROM mysql.roles_mapping;
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.APPLICABLE_ROLES;
+
+# Cleanup
+DROP ROLE role1;
+DROP ROLE role2;
+DROP ROLE role3;
+DROP ROLE role4;
+DROP USER foo@localhost;
+
+--source include/galera_end.inc
+--echo # End of test
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 00000000000..7db990d7be1
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_rsu_add_pk.test
@@ -0,0 +1,43 @@
+#
+# 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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+SET SESSION 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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+SET SESSION 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 00000000000..e64259494d1
--- /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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 DROP PRIMARY KEY;
+SET SESSION 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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 DROP PRIMARY KEY;
+SET SESSION 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 00000000000..cad8154ac76
--- /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 SESSION wsrep_OSU_method = "RSU";
+--error ER_DUP_ENTRY
+ALTER TABLE t1 ADD PRIMARY KEY (f1);
+SET SESSION 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 00000000000..5841dbd8006
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_rsu_simple.test
@@ -0,0 +1,34 @@
+#
+# 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 SESSION wsrep_OSU_method = "RSU";
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+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_rsu_wsrep_desync.test b/mysql-test/suite/galera/t/galera_rsu_wsrep_desync.test
new file mode 100644
index 00000000000..dc7ff11a9f5
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_rsu_wsrep_desync.test
@@ -0,0 +1,86 @@
+#
+# Test manipulating wsrep_desync while an RSU operation is in progress
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+# First, test wsrep_desync 1 > 0 during DDL
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+
+SET GLOBAL wsrep_desync=1;
+SET wsrep_OSU_method=RSU;
+
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_open_tables'
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_desync=0;
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+SHOW CREATE TABLE t1;
+SHOW VARIABLES LIKE 'wsrep_desync';
+SET wsrep_OSU_method=TOI;
+
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
+
+# Next, test wsrep_desync 0 > 1 during DDL, currently not allowed
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+
+SET GLOBAL wsrep_desync=0;
+SET wsrep_OSU_method=RSU;
+
+SET DEBUG_SYNC = 'alter_table_before_create_table_no_lock WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_1a
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_create_table_no_lock'
+--source include/wait_condition.inc
+
+# wsrep_desync=1 will block
+--send SET GLOBAL wsrep_desync=1;
+
+
+--connection node_1b
+--sleep 2
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'exit open_tables()' and INFO = 'SET GLOBAL wsrep_desync=1'
+--source include/wait_condition.inc
+
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+--connection node_1a
+--reap
+SET GLOBAL wsrep_desync=0;
+
+SHOW CREATE TABLE t1;
+
+# Restore old state
+SET wsrep_OSU_method=TOI;
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
+
+CALL mtr.add_suppression("Protocol violation");
+CALL mtr.add_suppression("desync failed");
+
+--connection node_2
+CALL mtr.add_suppression("Protocol violation");
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 00000000000..33f45c6b532
--- /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 00000000000..beae84b3862
--- /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 00000000000..1291a4ff8a9
--- /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_serializable.test b/mysql-test/suite/galera/t/galera_serializable.test
new file mode 100644
index 00000000000..b12d57fd488
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_serializable.test
@@ -0,0 +1,76 @@
+#
+# Test that the SERIALIZABLE isolation level behaves as expected.
+# A local serializable transaction is aborted by an incoming remote update
+#
+# wsrep_sync_wait does not work well with serializable, see mysql-wsrep#130
+# hence the need to use --sleep .
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+CREATE TABLE t1 (id INT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+
+#
+# Read (local transaction) / Write (remote transaction) conflict
+#
+
+SET AUTOCOMMIT=OFF;
+SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+START TRANSACTION;
+
+SELECT * FROM t1;
+
+--connection node_2
+INSERT INTO t1 VALUES (1,1);
+
+--sleep 2
+--connection node_1
+--error ER_LOCK_DEADLOCK
+SELECT * FROM t1;
+
+ROLLBACK;
+DELETE FROM t1;
+
+#
+# Write (local transaction) / Write (remote transaction) conflict
+#
+
+--connection node_1
+INSERT INTO t1 VALUES (1,1);
+START TRANSACTION;
+SELECT * FROM t1;
+
+--connection node_2
+UPDATE t1 SET f2 = 2;
+
+--sleep 2
+--connection node_1
+--error ER_LOCK_DEADLOCK
+UPDATE t1 SET f2 = 3;
+
+ROLLBACK;
+DELETE FROM t1;
+
+#
+# Write (local transaction) / Write (remote transaction) conflict
+# Local transaction writes before remote one.
+# Nothing special happens here - ordinary deadlock on COMMIT
+#
+
+--connection node_1
+START TRANSACTION;
+
+--connection node_1
+INSERT INTO t1 VALUES (1,1);
+
+--connection node_2
+INSERT INTO t1 VALUES (1,2);
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+DROP TABLE t1;
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 00000000000..a85a2ad9b8d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_split_brain.test
@@ -0,0 +1,47 @@
+#
+# 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
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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
+
+
+--connection node_2
+--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 10
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--source include/wait_until_connected_again.inc
+
+# Restore original auto_increment_offset values.
+--let $node_2=node_2a
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.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 00000000000..b6965faa739
--- /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 00000000000..1c22580cc15
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ssl.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M;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'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M;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'
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 00000000000..e6346aa2151
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ssl.test
@@ -0,0 +1,25 @@
+#
+# 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
+--source include/big_test.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_ssl_compression.cnf b/mysql-test/suite/galera/t/galera_ssl_compression.cnf
new file mode 100644
index 00000000000..d6fd2c4d510
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ssl_compression.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+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;socket.ssl_compression=YES'
+
+[mysqld.2]
+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;socket.ssl_compression=YES'
diff --git a/mysql-test/suite/galera/t/galera_ssl_compression.test b/mysql-test/suite/galera/t/galera_ssl_compression.test
new file mode 100644
index 00000000000..75f92c5b2f4
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ssl_compression.test
@@ -0,0 +1,35 @@
+#
+# Test SSL compression. The accompanying galera_ssl_compression.cnf has a customized wsrep_provider_options setting that enables SSL and compression.
+#
+# Unfortunately there is no wire-level traffic bytes counter that would allow us to determine that compression kicked in, so we can only
+# perform a most basic replication check.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.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';
+
+--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';
+
+--connection node_1
+
+# Check that the socket.ssl_compression provider option is not dynamic
+--error ER_WRONG_ARGUMENTS
+SET GLOBAL wsrep_provider_options = "socket.ssl_compression=No";
+
+CREATE TABLE t1 (f1 VARCHAR(333) PRIMARY KEY, f2 BLOB) Engine=InnoDB;
+INSERT INTO t1 VALUES (REPEAT('a', 333), REPEAT('b', 65535));
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = REPEAT('a', 333) AND f2 = REPEAT('b', 65535);
+
+--connection node_1
+DROP TABLE t1;
+
+CALL mtr.add_suppression("Unknown parameter 'socket\.ssl_compression'");
+CALL mtr.add_suppression("Set options returned 7");
diff --git a/mysql-test/suite/galera/t/galera_ssl_upgrade.cnf b/mysql-test/suite/galera/t/galera_ssl_upgrade.cnf
new file mode 100644
index 00000000000..2954ae0f4cb
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ssl_upgrade.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+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'
+
+[mysqld.2]
+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'
diff --git a/mysql-test/suite/galera/t/galera_ssl_upgrade.test b/mysql-test/suite/galera/t/galera_ssl_upgrade.test
new file mode 100644
index 00000000000..a424942da30
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_ssl_upgrade.test
@@ -0,0 +1,49 @@
+#
+# Test upgrading the SSL certificates in a rolling fashion.
+#
+# 1. The starting state with the old key and cert is is described in galera_ssl_upgrade.cnf
+#
+
+--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';
+
+# 2. Restart node #1 with a socket.ssl_ca that includes both the new and the old certificate
+
+--connection node_1
+--source include/shutdown_mysqld.inc
+--let $start_mysqld_params = --wsrep-cluster-address=gcomm://127.0.0.1:$NODE_GALERAPORT_2 --wsrep_provider_options=base_port=$NODE_GALERAPORT_1;socket.ssl=yes;socket.ssl_ca=$MYSQL_TEST_DIR/std_data/galera-upgrade-ca-cert.pem;socket.ssl_cert=$MYSQL_TEST_DIR/std_data/galera-cert.pem;socket.ssl_key=$MYSQL_TEST_DIR/std_data/galera-key.pem
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.inc
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# 3. Restart node #2 with the new socket.ssl_ca , socket.ssl_cert and socket.ssl_key
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+--let $start_mysqld_params = --wsrep_provider_options=base_port=$NODE_GALERAPORT_2;socket.ssl=yes;socket.ssl_ca=$MYSQL_TEST_DIR/std_data/galera-upgrade-ca-cert.pem;socket.ssl_cert=$MYSQL_TEST_DIR/std_data/galera-upgrade-server-cert.pem;socket.ssl_key=$MYSQL_TEST_DIR/std_data/galera-upgrade-server-key.pem
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.inc
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# 4. Restart node #1 with the new socket.ssl_ca , socket.ssl_cert and socket.ssl_key
+
+--connection node_1
+--source include/shutdown_mysqld.inc
+--let $start_mysqld_params = --wsrep-cluster-address=gcomm://127.0.0.1:$NODE_GALERAPORT_2 --wsrep_provider_options=base_port=$NODE_GALERAPORT_1;socket.ssl=yes;socket.ssl_ca=$MYSQL_TEST_DIR/std_data/galera-upgrade-ca-cert.pem;socket.ssl_cert=$MYSQL_TEST_DIR/std_data/galera-upgrade-server-cert.pem;socket.ssl_key=$MYSQL_TEST_DIR/std_data/galera-upgrade-server-key.pem
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.inc
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Upgrade complete. Both nodes now use the new key and certificate
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 00000000000..574ae28b54a
--- /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 00000000000..0b7171597dd
--- /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_mysqldump_with_key.cnf b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf
new file mode 100644
index 00000000000..e108484b248
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf
@@ -0,0 +1,22 @@
+!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'
+
+[mysqld]
+wsrep_debug=ON
+
+ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/galera-cert.pem
+ssl-cert=@ENV.MYSQL_TEST_DIR/std_data/galera-cert.pem
+ssl-key=@ENV.MYSQL_TEST_DIR/std_data/galera-key.pem
+
+[client]
+ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem
+ssl-cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem
+ssl-key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem
diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test
new file mode 100644
index 00000000000..c813e04169f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test
@@ -0,0 +1,29 @@
+#
+# Test mysqldump SST with client SSL key. See galera_sst_mysqldump_with_key.cnf for the configuration on the client side.
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_openssl.inc
+
+--source suite/galera/include/galera_sst_set_mysqldump.inc
+
+--connection node_1
+CREATE USER sslsst;
+GRANT ALL PRIVILEGES ON *.* TO sslsst;
+GRANT USAGE ON *.* TO sslsst REQUIRE SSL;
+
+SET GLOBAL wsrep_sst_auth = 'sslsst:';
+
+--source suite/galera/include/galera_st_disconnect_slave.inc
+
+--source suite/galera/include/galera_sst_restore.inc
+DROP USER sslsst;
+
+--connection node_2
+# We have to manually restore global_log and slow_query_log due to mysql-wsrep#108
+# Otherwise MTR's check_testcases complains
+
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
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 00000000000..93981d9daa7
--- /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 00000000000..c6823795e59
--- /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-options.cnf b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf
new file mode 100644
index 00000000000..31bd1af07c2
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.cnf
@@ -0,0 +1,24 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth="root:"
+wsrep_debug=ON
+
+[xtrabackup]
+backup-locks
+close-files
+compact
+# compression requires qpress from the Percona repositories
+# compress
+# compress-threads=2
+encryption=AES256
+encrypt-key=4FA92C5873672E20FB163A0BCB2BB4A4
+galera-info
+history=backup
+parallel=2
+
+[SST]
+encrypt=1
+encrypt-algo=AES256
+encrypt-key=4FA92C5873672E20FB163A0BCB2BB4A4
diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test
new file mode 100644
index 00000000000..4573f176482
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2-options.test
@@ -0,0 +1,13 @@
+#
+# This test checks that various options can be passed to xtrabackup via the my.cnf file
+# Initial SST happens via xtrabackup, so there is not much to do in the body of the test
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+SELECT 1;
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.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 00000000000..47cb3e02292
--- /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 00000000000..aac6822170a
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2.test
@@ -0,0 +1,19 @@
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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
+
+# Restore original auto_increment_offset values.
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf
new file mode 100644
index 00000000000..969516f5f3b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.cnf
@@ -0,0 +1,11 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth="root:"
+wsrep_debug=ON
+
+[SST]
+tkey=@ENV.MYSQL_TEST_DIR/std_data/galera-key.pem
+tcert=@ENV.MYSQL_TEST_DIR/std_data/galera-cert.pem
+encrypt=3
diff --git a/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test
new file mode 100644
index 00000000000..24d9589d111
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sst_xtrabackup-v2_encrypt_with_key.test
@@ -0,0 +1,13 @@
+#
+# This test checks that key and cert encryption options can be passed to xtrabackup via the my.cnf file
+# Initial SST happens via xtrabackup, so there is not much to do in the body of the test
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+SELECT 1;
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.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 00000000000..3299613d584
--- /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_index.test b/mysql-test/suite/galera/t/galera_status_local_index.test
new file mode 100644
index 00000000000..b61b8ced863
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_status_local_index.test
@@ -0,0 +1,21 @@
+#
+# Test that a two-node cluster has distinct values for wsrep_local_index for its nodes
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE wsrep_local_indexes (wsrep_local_index INTEGER);
+INSERT INTO wsrep_local_indexes VALUES ((SELECT variable_value FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_local_index'));
+
+--connection node_2
+INSERT INTO wsrep_local_indexes VALUES ((SELECT variable_value FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_local_index'));
+
+
+--connection node_1
+SELECT COUNT(*) = 2 FROM wsrep_local_indexes;
+SELECT COUNT(DISTINCT wsrep_local_index) = 2 FROM wsrep_local_indexes;
+SELECT COUNT(*) = 0 FROM wsrep_local_indexes WHERE wsrep_local_index NOT IN (0, 1);
+
+DROP TABLE wsrep_local_indexes;
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 00000000000..09cdb25f80c
--- /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 00000000000..d2a4ed16335
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_suspend_slave.test
@@ -0,0 +1,64 @@
+##
+## 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
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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 -SIGSTOP $mysqld_pid");
+ exit(0);
+EOF
+
+--error ER_UNKNOWN_COM_ERROR,ER_LOCK_WAIT_TIMEOUT,ER_LOCK_DEADLOCK
+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 -SIGCONT $mysqld_pid");
+ exit(0);
+EOF
+
+SET SESSION wsrep_sync_wait = 1;
+--sleep 10
+--source include/wait_until_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
+
+SET SESSION wsrep_sync_wait = 1;
+--source include/wait_until_ready.inc
+SELECT COUNT(*) = 1 FROM t1;
+
+SET SESSION wsrep_sync_wait = 15;
+DROP TABLE t1;
+
+# Restore original auto_increment_offset values.
+--let $node_2=node_2a
+--source include/auto_increment_offset_restore.inc
+
diff --git a/mysql-test/suite/galera/t/galera_sync_wait_show.test b/mysql-test/suite/galera/t/galera_sync_wait_show.test
new file mode 100644
index 00000000000..58de5433030
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_sync_wait_show.test
@@ -0,0 +1,70 @@
+#
+# Test that the various SHOW commands obey wsrep_sync_wait - codership/mysql-wsrep#228
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug.inc
+
+--connection node_2
+# MW-86 SHOW commands have now bitmap value 8
+SET SESSION wsrep_sync_wait = 8;
+
+
+--connection node_1
+CREATE DATABASE db1;
+
+--connection node_2
+SHOW CREATE DATABASE db1;
+DROP DATABASE db1;
+
+
+--connection node_1
+CREATE PROCEDURE p1 () SELECT 1 FROM DUAL;
+
+--connection node_2
+SHOW CREATE PROCEDURE p1;
+DROP PROCEDURE p1;
+
+
+
+--connection node_1
+CREATE PROCEDURE p1 () SELECT 1 FROM DUAL;
+
+--connection node_2
+SHOW PROCEDURE CODE p1;
+DROP PROCEDURE p1;
+
+
+
+--connection node_1
+CREATE FUNCTION f1 () RETURNS INTEGER RETURN 123;
+
+--connection node_2
+SHOW CREATE FUNCTION f1;
+DROP FUNCTION f1;
+
+
+--connection node_1
+CREATE FUNCTION f1 () RETURNS INTEGER RETURN 123;
+
+--connection node_2
+SHOW FUNCTION CODE f1;
+DROP FUNCTION f1;
+
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.f1 = 'a';
+
+--connection node_2
+SHOW CREATE TRIGGER tr1;
+DROP TABLE t1;
+
+
+--connection node_1
+CREATE EVENT event1 ON SCHEDULE AT '2038-01-01 23:59:59' DO SELECT 1;
+
+--connection node_2
+SHOW CREATE EVENT event1;
+DROP EVENT event1;
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 00000000000..641d2101c80
--- /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 00000000000..c586d97bdb5
--- /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 00000000000..1f446938775
--- /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_fk_update.test b/mysql-test/suite/galera/t/galera_toi_ddl_fk_update.test
new file mode 100644
index 00000000000..f42fae4ed51
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_toi_ddl_fk_update.test
@@ -0,0 +1,49 @@
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# This test creates a new FK constraint while an UPDATE is 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,
+ KEY (id)
+) ENGINE=InnoDB;
+
+CREATE TABLE child (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ parent_id INT
+) ENGINE=InnoDB;
+
+INSERT INTO parent VALUES (1);
+
+INSERT INTO child (parent_id) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_1
+--sleep 1
+--send ALTER TABLE child ADD FOREIGN KEY (parent_id) REFERENCES parent(id) ON UPDATE CASCADE;
+
+--connection node_2
+--sleep 1
+--send UPDATE parent SET id = 2 WHERE id = 1;
+
+--connection node_1
+--reap
+
+--connection node_2
+--reap
+
+--connection node_2
+SELECT COUNT(*) = 10000 FROM child WHERE parent_id = 2;
+
+--connection node_1
+SELECT COUNT(*) = 10000 FROM child WHERE parent_id = 2;
+
+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 00000000000..ebab030d9d6
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_toi_ddl_locking.test
@@ -0,0 +1,76 @@
+--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;
+
+--connection node_1
+SET DEBUG_SYNC= 'RESET';
+
+--connection node_1b
+SET DEBUG_SYNC= 'RESET';
+
+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 00000000000..821f7a6eb2c
--- /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 00000000000..51eae7005df
--- /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_drop_database.test b/mysql-test/suite/galera/t/galera_toi_drop_database.test
new file mode 100644
index 00000000000..e790a0ba812
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_toi_drop_database.test
@@ -0,0 +1,56 @@
+#
+# Test the operation of DDLs that affect multiple database objects
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--let $galera_connection_name = node_1a
+--let $galera_server_number = 1
+--source include/galera_connect.inc
+
+--connection node_1
+CREATE DATABASE database1;
+USE database1;
+
+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;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+
+# Make sure autocommit retrying does not kick in as this will mask the error we expect to get
+SET SESSION wsrep_retry_autocommit = 0;
+# Attemp to insert 1M rows
+--send INSERT INTO t1 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;
+
+--connection node_1a
+USE database1;
+SET SESSION wsrep_retry_autocommit = 0;
+--send INSERT INTO t2 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;
+
+--connection node_2
+--sleep 1
+--send DROP DATABASE database1;
+
+--connection node_1
+--sleep 1
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_1a
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+--reap
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'database1';
+--error ER_BAD_DB_ERROR
+USE database1;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'database1';
+--error ER_BAD_DB_ERROR
+USE database1;
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 00000000000..4d0edefda8e
--- /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 00000000000..3c66286a3e6
--- /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 00000000000..6857a0e08ca
--- /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_toi_truncate.test b/mysql-test/suite/galera/t/galera_toi_truncate.test
new file mode 100644
index 00000000000..59ef5c2028f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_toi_truncate.test
@@ -0,0 +1,43 @@
+#
+# Test the operation of TRUNCATE with concurrent DML.
+# The DML should be BF-aborted if the DDL arrives from another node
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# INSERT and TRUNCATE on different nodes
+#
+
+--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) ENGINE=InnoDB;
+
+# Insert 100K rows
+--connection node_2
+# Prevent autocommit retring from masking the deadlock error we expect to get
+SET SESSION wsrep_retry_autocommit = 0;
+--send INSERT INTO t1 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;
+
+--connection node_1
+--sleep 1
+--send TRUNCATE TABLE t1;
+
+--connection node_1
+--reap
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+
+DROP TABLE t1;
+DROP TABLE ten;
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 00000000000..386d73fd3ca
--- /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 00000000000..29870829ba3
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_transaction_replay.test
@@ -0,0 +1,124 @@
+#
+# 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
+--let $galera_sync_point = commit_monitor_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+--send COMMIT;
+
+# Wait until commit is blocked
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--source include/galera_wait_sync_point.inc
+
+# Issue a conflicting update on node #2
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+
+# Wait for both transactions to be blocked
+--connection node_1a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Update_rows_log_event::find_row%';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'init' AND INFO = 'COMMIT';
+--source include/wait_condition.inc
+
+# Unblock the commit
+--connection node_1a
+--source include/galera_clear_sync_point.inc
+--source include/galera_signal_sync_point.inc
+
+# 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;
+
+#echo "# test for PS replaying"
+
+#
+# test replaying of prepared statements
+#
+--connection node_1
+CREATE TABLE t1 (i int primary key, j int) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1, 0), (3, 0);
+SELECT * FROM t1;
+
+PREPARE stmt1 FROM "UPDATE t1 SET j = 1 where i > 0";
+
+# block the commit of PS
+--connection node_1a
+--let $galera_sync_point = commit_monitor_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+--send EXECUTE stmt1;
+
+# Wait until commit is blocked
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--source include/galera_wait_sync_point.inc
+
+# Issue a conflicting update on node_2
+--connection node_2
+#UPDATE t1 SET j=2;
+INSERT INTO t1 VALUES(2,2);
+
+
+# Wait until applying begins in node_1
+--connection node_1a
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Write_rows_log_event::write_row%';
+--source include/wait_condition.inc
+
+# Unblock the PS commit
+--connection node_1a
+--source include/galera_clear_sync_point.inc
+--source include/galera_signal_sync_point.inc
+
+# Commit succeeds
+--connection node_1
+--reap
+SELECT * FROM t1;
+
+--connection node_2
+SELECT * FROM t1;
+
+--connection node_1
+DEALLOCATE PREPARE stmt1;
+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 00000000000..79f9bad1f1b
--- /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 00000000000..3ad94eb9930
--- /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 00000000000..14dfe3e20bc
--- /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 00000000000..f3df60a6415
--- /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 = 15;
+
+--connection node_2
+SET GLOBAL wsrep_sync_wait = 15;
+
+--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 (1, 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 00000000000..0d571f5cfd7
--- /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 00000000000..baacf2a60b2
--- /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 00000000000..dc82542128e
--- /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 00000000000..0c0a044510e
--- /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_OSU_method.test b/mysql-test/suite/galera/t/galera_var_OSU_method.test
new file mode 100644
index 00000000000..fcf964c4f89
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_OSU_method.test
@@ -0,0 +1,45 @@
+#
+# Test that the wsrep_var_OSU_method variable can be changed in the middle of an ALTER without adverse effects.
+# In-depth testing of various OSU methods is implemented in separate tests.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+
+--connection node_1
+SET SESSION wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_open_tables'
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+
+--connection node_2
+# The ALTER above is not visible on node_2
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+
+--connection node_1
+SET SESSION wsrep_OSU_method = "TOI";
+
+--connection node_1
+SET DEBUG_SYNC= 'RESET';
+
+--connection node_1a
+SET DEBUG_SYNC= 'RESET';
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_var_OSU_method2.test b/mysql-test/suite/galera/t/galera_var_OSU_method2.test
new file mode 100644
index 00000000000..099e2cc6612
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_OSU_method2.test
@@ -0,0 +1,47 @@
+#
+# Test that the wsrep_var_OSU_method variable can be changed in the middle of an ALTER without adverse effects.
+# In-depth testing of various OSU methods is implemented in separate tests.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+
+--connection node_1
+SET SESSION wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+
+SET SESSION wsrep_sync_wait = 0;
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_open_tables'
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+INSERT INTO t1 VALUES (1,2);
+
+--connection node_2
+# The ALTER above is visible on node_2
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+INSERT INTO t1 VALUES (3,4);
+
+--connection node_1
+SET GLOBAL wsrep_OSU_method = "TOI";
+DROP TABLE t1;
+SET DEBUG_SYNC= 'RESET';
+
+--connection node_1a
+SET DEBUG_SYNC= 'RESET';
+
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 00000000000..c0bbe5af8cf
--- /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 00000000000..d65a35be4d1
--- /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 @@global.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 @@global.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 00000000000..f7967daebe7
--- /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 00000000000..984a262c7bd
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test
@@ -0,0 +1,76 @@
+#
+# Check the handling of @@wsrep_cluster_address
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+#
+# Set to invalid value
+#
+
+--connection node_2
+--let $wsrep_cluster_address_node2 = `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 COUNT(*) > 0 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_1
+--sleep 1
+# Node #1 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_2
+--disable_query_log
+--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node2';
+--enable_query_log
+
+--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';
+
+--connection node_2
+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("gcs connect failed: Connection timed out");
+CALL mtr.add_suppression("WSREP: wsrep::connect\\(foo://\\) failed: 7");
+# Restore original auto_increment_offset values.
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
+--echo # End of test
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 00000000000..06c5d30a769
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_desync_on.test
@@ -0,0 +1,62 @@
+#
+# 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;
+
+CALL mtr.add_suppression("Protocol violation");
+DROP TABLE t1;
+
+--connection node_1
+CALL mtr.add_suppression("Protocol violation");
diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
new file mode 100644
index 00000000000..df4c033ab3d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
@@ -0,0 +1,77 @@
+#
+# Check the handling of @@wsrep_dirty_reads
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+--connection node_2
+--let $wsrep_cluster_address_saved = `SELECT @@global.wsrep_cluster_address`
+
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+SELECT * FROM t1;
+
+SET @@global.wsrep_cluster_address = '';
+SET @@session.wsrep_dirty_reads=OFF;
+
+# Set wsrep_sync_wait to avoid ER_LOCK_WAIT_TIMEOUT.
+SET SESSION wsrep_sync_wait=0;
+
+# Must return 'OFF'
+SHOW STATUS LIKE 'wsrep_ready';
+
+# Must return 'Non-primary'
+SHOW STATUS LIKE 'wsrep_cluster_status';
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT * FROM t1;
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT 1 FROM t1;
+
+SET @@session.wsrep_dirty_reads=ON;
+
+SELECT * FROM t1;
+SELECT 1 FROM t1;
+
+SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
+
+SET @@session.wsrep_dirty_reads=OFF;
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT 1;
+
+--error ER_UNKNOWN_COM_ERROR
+USE information_schema;
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT * FROM information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads";
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history;
+
+--disable_query_log
+--eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved'
+--enable_query_log
+--source include/wait_until_connected_again.inc
+
+--connection node_1
+USE test;
+SELECT * FROM t1;
+# Cleanup
+DROP TABLE t1;
+
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
+--echo # End of test
+
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 00000000000..c771b50c06c
--- /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 00000000000..c08483b63ad
--- /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 00000000000..38dab0a981b
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_load_data_splitting.test
@@ -0,0 +1,39 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.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_log_bin.cnf b/mysql-test/suite/galera/t/galera_var_log_bin.cnf
new file mode 100644
index 00000000000..f7f17e3720a
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_log_bin.cnf
@@ -0,0 +1,5 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+log-bin
+
diff --git a/mysql-test/suite/galera/t/galera_var_log_bin.test b/mysql-test/suite/galera/t/galera_var_log_bin.test
new file mode 100644
index 00000000000..1b1886b996d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_log_bin.test
@@ -0,0 +1,22 @@
+#
+# A simple test that confirms that Galera works with log-bin enabled, that is
+# when MySQL's binlog is in effect rather than the Galera 'dummy' implementation.
+#
+
+--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_max_ws_rows.test b/mysql-test/suite/galera/t/galera_var_max_ws_rows.test
new file mode 100644
index 00000000000..944238bf1aa
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_max_ws_rows.test
@@ -0,0 +1,155 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+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;
+
+--let $wsrep_max_ws_rows_orig = `SELECT @@wsrep_max_ws_rows`
+SET GLOBAL wsrep_max_ws_rows = 4;
+
+# Test that wsrep_max_ws_rows is enforced with multi statement transactions
+
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (3);
+INSERT INTO t1 (f2) VALUES (4);
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) VALUES (5);
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1;
+
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (3);
+INSERT INTO t1 (f2) VALUES (4);
+--error ER_ERROR_DURING_COMMIT
+UPDATE t1 SET f2 = 10 WHERE f2 = 4;
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1;
+
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (3);
+INSERT INTO t1 (f2) VALUES (4);
+--error ER_ERROR_DURING_COMMIT
+DELETE FROM t1 WHERE f2 = 1;
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1;
+
+
+# Test that wsrep_max_ws_rows is enforced on sigle statements
+
+SET GLOBAL wsrep_max_ws_rows = 5;
+INSERT INTO t1 (f2) VALUES (1),(2),(3),(4),(5);
+SET GLOBAL wsrep_max_ws_rows = 4;
+
+--error ER_ERROR_DURING_COMMIT
+UPDATE t1 SET f2 = f2 + 10;
+SELECT COUNT(*) = 5 FROM t1;
+
+--error ER_ERROR_DURING_COMMIT
+DELETE FROM t1 WHERE f2 < 10;
+SELECT COUNT(*) = 5 FROM t1;
+
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) SELECT * FROM ten;
+SELECT COUNT(*) = 5 FROM t1;
+
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) VALUES (10),(20),(30),(40),(50);
+SELECT COUNT(*) = 5 FROM t1;
+
+# Fewer than wsrep_max_ws_rows is OK
+
+SET GLOBAL wsrep_max_ws_rows = 10;
+DELETE FROM t1 WHERE f2 < 10;
+SELECT COUNT(*) = 0 FROM t1;
+
+# Test a series of transactions
+
+--disable_query_log
+SET GLOBAL wsrep_max_ws_rows = 5;
+let $i= 100;
+while ($i)
+{
+ START TRANSACTION;
+ --eval INSERT INTO t1 (f2) VALUES ($i);
+ COMMIT;
+ dec $i;
+}
+--enable_query_log
+SET GLOBAL wsrep_max_ws_rows = 100;
+SELECT COUNT(*) = 100 FROM t1;
+DELETE FROM t1 WHERE f2 < 101;
+SELECT COUNT(*) = 0 FROM t1;
+
+# Test large statements
+
+SET GLOBAL wsrep_max_ws_rows = 9999;
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+SET GLOBAL wsrep_max_ws_rows = 10000;
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+SET GLOBAL wsrep_max_ws_rows = 9999;
+--error ER_ERROR_DURING_COMMIT
+UPDATE t1 SET f2 = 2 WHERE f2 = 1;
+SET GLOBAL wsrep_max_ws_rows = 10000;
+UPDATE t1 SET f2 = 2 WHERE f2 = 1;
+
+SET GLOBAL wsrep_max_ws_rows = 9999;
+--error ER_ERROR_DURING_COMMIT
+DELETE FROM t1 WHERE f2 = 2;
+SET GLOBAL wsrep_max_ws_rows = 10000;
+DELETE FROM t1 WHERE f2 = 2;
+
+SELECT COUNT(*) = 0 FROM t1;
+
+
+# Test that wsrep_max_ws_rows is reset when switching autocommit mode
+
+SET AUTOCOMMIT = ON;
+SET GLOBAL wsrep_max_ws_rows = 1;
+
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) VALUES (2);
+
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (2);
+
+
+SET AUTOCOMMIT = OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) VALUES (2);
+
+INSERT INTO t1 (f2) VALUES (1);
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) VALUES (2);
+
+
+# Test that wsrep_max_ws_rows is reset on implicit commits
+
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+--error ER_ERROR_DURING_COMMIT
+INSERT INTO t1 (f2) VALUES (2);
+
+
+--disable_query_log
+--eval SET GLOBAL wsrep_max_ws_rows = $wsrep_max_ws_rows_orig
+--enable_query_log
+
+DROP TABLE t1;
+DROP TABLE ten;
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 00000000000..8eb93bda9be
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_max_ws_size.test
@@ -0,0 +1,46 @@
+#
+# 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
+
+--connection node_1
+
+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;
+
+#
+# Changing repl.max_ws_size also changes wsrep_max_ws_size
+#
+
+SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=10000';
+SELECT @@wsrep_max_ws_size = 10000;
+
+
+#
+# Changing wsrep_max_ws_size is equivalent to changing repl.max_ws_size
+#
+
+SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=20000';
+--let $provider_options = `SELECT @@wsrep_provider_options`
+SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=10000';
+
+SET GLOBAL wsrep_max_ws_size = 20000;
+--let $provider_options_updated = `SELECT @@wsrep_provider_options`
+
+--disable_query_log
+--eval SELECT STRCMP('$provider_options', '$provider_options_updated') = 0 AS provider_options_match
+--enable_query_log
+
+--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 00000000000..642d939692c
--- /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_node_address.cnf b/mysql-test/suite/galera/t/galera_var_node_address.cnf
new file mode 100644
index 00000000000..0de0edaa396
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_node_address.cnf
@@ -0,0 +1,10 @@
+!include ../galera_4nodes.cnf
+
+[mysqld.2]
+wsrep_node_address=127.0.0.1
+
+[mysqld.3]
+wsrep_node_address=localhost
+
+[mysqld.4]
+wsrep_node_address=lo
diff --git a/mysql-test/suite/galera/t/galera_var_node_address.test b/mysql-test/suite/galera/t/galera_var_node_address.test
new file mode 100644
index 00000000000..3353652d8b9
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_node_address.test
@@ -0,0 +1,25 @@
+#
+# Test wsrep_node_address . The galera_var_node_address.cnf contains various settings for
+# wsrep_node_address, so in this test we simply confirm that the cluster has started up correctly.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+call mtr.add_suppression("WSREP: Stray state UUID msg: .* current group state WAIT_STATE_UUID .*");
+call mtr.add_suppression("WSREP: Protocol violation. JOIN message sender .* is not in state transfer (.*). Message ignored.");
+
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+
+--connection node_2
+INSERT INTO t1 VALUES (1);
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+SELECT COUNT(*) = 1 FROM t1;
+
+--connection node_1
+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 00000000000..70dfc98736b
--- /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 00000000000..4fea69f62bb
--- /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 00000000000..a9811283918
--- /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 00000000000..9cb0edf1810
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test
@@ -0,0 +1,139 @@
+#
+# Simple test for wsrep-replicate-myisam = ON
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+--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_retry_autocommit.test b/mysql-test/suite/galera/t/galera_var_retry_autocommit.test
new file mode 100644
index 00000000000..bf4da3234c5
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_retry_autocommit.test
@@ -0,0 +1,98 @@
+#
+# Test that the wsrep_retry_autocommit variable is respected. We use an INSERT that
+# proceeds very slowly due to extra SLEEP() in a trigger
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW SET NEW.f2 = SLEEP(5);
+
+#
+# With wsrep_retry_autocommit = 0, error is certain
+#
+
+--connection node_1
+SET SESSION wsrep_retry_autocommit = 0;
+--send INSERT INTO t1 (f1) VALUES (1),(2);
+
+--connection node_2
+--sleep 1
+TRUNCATE TABLE t1;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+#
+# With wsrep_retry_autocommit = 1, success against one TRUNCATE
+#
+
+--connection node_1
+SET SESSION wsrep_retry_autocommit = 1;
+--send INSERT INTO t1 (f1) VALUES (3),(4);
+
+--connection node_2
+--sleep 1
+TRUNCATE TABLE t1;
+
+--connection node_1
+--error 0
+--reap
+SELECT * FROM test.t1;
+
+#
+# With wsrep_retry_autocommit = 1, failure against multiple TRUNCATEs
+#
+
+--connection node_2
+DELIMITER |;
+CREATE PROCEDURE repeated_truncate ()
+BEGIN
+ DECLARE i INT;
+ DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+
+ SET i = 0;
+ WHILE i <= 1000 DO
+ TRUNCATE TABLE t1;
+ SET i = i + 1;
+ END WHILE;
+END|
+DELIMITER ;|
+
+# Begin streaming TRUNCATEs
+--let $truncate_connection_id = `SELECT CONNECTION_ID()`
+--send CALL repeated_truncate()
+
+--connection node_1
+SET SESSION wsrep_retry_autocommit = 1;
+--sleep 1
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 (f1) VALUES (5),(6);
+
+#
+# With wsrep_retry_autocommit = 1024, success against multiple TRUNCATEs
+#
+
+--connection node_1
+SET SESSION wsrep_retry_autocommit = 1024;
+--send INSERT INTO t1 (f1) VALUES (7),(8);
+
+--sleep 6
+
+# Once he stream of TRUNCATEs is complete
+--connection node_2
+--reap
+
+# the INSERT will eventually be sucessfull
+--connection node_1
+--error 0
+--reap
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+DROP TABLE t1;
+DROP PROCEDURE repeated_truncate;
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 00000000000..50e22fbef66
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_slave_threads.test
@@ -0,0 +1,84 @@
+#
+# 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;
+
+--echo #
+--echo # lp:1372840 - Changing wsrep_slave_threads causes future connections to hang
+--echo #
+
+--connection node_1
+CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY) ENGINE=INNODB;
+
+--connection node_2
+SET GLOBAL wsrep_slave_threads = 4;
+SET GLOBAL wsrep_slave_threads = 1;
+DROP TABLE t1;
+
+--echo # End of tests
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 00000000000..046724e1635
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_sync_wait.test
@@ -0,0 +1,46 @@
+#
+# 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
+
+# MW-86 SHOW commands have now their own bitmask
+# 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 00000000000..783b78792e6
--- /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 00000000000..0effd59403b
--- /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;gcache.size=10M;gmcast.segment=1'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M;gmcast.segment=1'
+
+[mysqld.3]
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;gcache.size=10M;gmcast.segment=2'
+
+[mysqld.4]
+wsrep_provider_options='base_port=@mysqld.4.#galera_port;gcache.size=10M;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 00000000000..a8fd351b168
--- /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_wan_restart_ist.cnf b/mysql-test/suite/galera/t/galera_wan_restart_ist.cnf
new file mode 100644
index 00000000000..3f7d2a2448f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wan_restart_ist.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=2'
+
diff --git a/mysql-test/suite/galera/t/galera_wan_restart_ist.test b/mysql-test/suite/galera/t/galera_wan_restart_ist.test
new file mode 100644
index 00000000000..1cf5d4c7f74
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wan_restart_ist.test
@@ -0,0 +1,161 @@
+#
+# Test that even after multiple restarts in a WAN context with two segments, the cluster continues to operate correctly.
+#
+# We can not easily restart the first node, so instead we restart all the other nodes. MTR does not allow multiple nodes
+# to be down at the same time, so restarts are sequential.
+#
+# 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/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--let $node_4=node_4
+--source include/auto_increment_offset_save.inc
+
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+INSERT INTO t1 VALUES (2);
+
+--connection node_3
+INSERT INTO t1 VALUES (3);
+
+--connection node_4
+INSERT INTO t1 VALUES (4);
+
+#
+# Restart node #3
+#
+
+--connection node_3
+INSERT INTO t1 VALUES (13);
+
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+--sleep 5
+
+--connection node_1
+INSERT INTO t1 VALUES (11);
+
+--connection node_2
+INSERT INTO t1 VALUES (12);
+
+--connection node_4
+INSERT INTO t1 VALUES (14);
+
+--connection node_3
+--source include/start_mysqld.inc
+--sleep 5
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (131);
+
+#
+# Restart node #2
+#
+
+--connection node_2
+INSERT INTO t1 VALUES (22);
+
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+--sleep 5
+
+--connection node_1
+INSERT INTO t1 VALUES (21);
+
+--connection node_3
+INSERT INTO t1 VALUES (23);
+
+--connection node_4
+INSERT INTO t1 VALUES (24);
+
+--connection node_2
+--source include/start_mysqld.inc
+--sleep 5
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (221);
+
+#
+# Restart node #4
+#
+
+--connection node_4
+INSERT INTO t1 VALUES (34);
+
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+--sleep 5
+
+--connection node_1
+INSERT INTO t1 VALUES (31);
+
+--connection node_2
+INSERT INTO t1 VALUES (32);
+
+--connection node_3
+INSERT INTO t1 VALUES (33);
+
+--connection node_4
+--source include/start_mysqld.inc
+--sleep 5
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (341);
+
+
+#
+# Check all nodes
+#
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_2
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_3
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_4
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_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");
+
+--connection node_2
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+
+--connection node_3
+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");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+
+--connection node_4
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+
+# Restore original auto_increment_offset values.
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
diff --git a/mysql-test/suite/galera/t/galera_wan_restart_sst.cnf b/mysql-test/suite/galera/t/galera_wan_restart_sst.cnf
new file mode 100644
index 00000000000..3f7d2a2448f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wan_restart_sst.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=2'
+
diff --git a/mysql-test/suite/galera/t/galera_wan_restart_sst.test b/mysql-test/suite/galera/t/galera_wan_restart_sst.test
new file mode 100644
index 00000000000..9b12eeed1ac
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wan_restart_sst.test
@@ -0,0 +1,149 @@
+#
+# Test that even after multiple restarts in a WAN context with two segments, the cluster continues to operate correctly.
+#
+# We can not easily restart the first node, so instead we restart all the other nodes. MTR does not allow multiple nodes
+# to be down at the same time, so restarts are sequential.
+#
+# 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/big_test.inc
+--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);
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+INSERT INTO t1 VALUES (2);
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+INSERT INTO t1 VALUES (3);
+
+--connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4
+--connection node_4
+INSERT INTO t1 VALUES (4);
+
+#
+# Restart node #3
+#
+
+--connection node_3
+INSERT INTO t1 VALUES (13);
+
+--source include/kill_galera.inc
+--sleep 5
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+INSERT INTO t1 VALUES (11);
+
+--connection node_2
+INSERT INTO t1 VALUES (12);
+
+--connection node_4
+INSERT INTO t1 VALUES (14);
+
+--connection node_3
+--source include/start_mysqld.inc
+--sleep 5
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (131);
+
+#
+# Restart node #2
+#
+
+--connection node_2
+INSERT INTO t1 VALUES (22);
+
+--source include/kill_galera.inc
+--sleep 5
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+INSERT INTO t1 VALUES (21);
+
+--connection node_3
+INSERT INTO t1 VALUES (23);
+
+--connection node_4
+INSERT INTO t1 VALUES (24);
+
+--connection node_2
+--source include/start_mysqld.inc
+--sleep 5
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (221);
+
+#
+# Restart node #4
+#
+
+--connection node_4
+INSERT INTO t1 VALUES (34);
+
+--source include/kill_galera.inc
+--sleep 5
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+INSERT INTO t1 VALUES (31);
+
+--connection node_2
+INSERT INTO t1 VALUES (32);
+
+--connection node_3
+INSERT INTO t1 VALUES (33);
+
+--connection node_4
+--source include/start_mysqld.inc
+--sleep 5
+--source include/wait_until_connected_again.inc
+
+INSERT INTO t1 VALUES (341);
+
+
+#
+# Check all nodes
+#
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_2
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_3
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_4
+SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT COUNT(*) = 19 FROM t1;
+
+--connection node_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");
+CALL mtr.add_suppression("WSREP: gcs_caused\\(\\) returned -1 \\(Operation not permitted\\)");
+
+--connection node_2
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+
+--connection node_3
+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");
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
+
+--connection node_4
+CALL mtr.add_suppression("Action message in non-primary configuration from member 0");
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 00000000000..3c7988a4924
--- /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_log_conficts-master.opt b/mysql-test/suite/galera/t/galera_wsrep_log_conficts-master.opt
new file mode 100644
index 00000000000..930c483bd64
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wsrep_log_conficts-master.opt
@@ -0,0 +1 @@
+--wsrep_log_conflicts=ON
diff --git a/mysql-test/suite/galera/t/galera_wsrep_log_conficts.test b/mysql-test/suite/galera/t/galera_wsrep_log_conficts.test
new file mode 100644
index 00000000000..3af08cbf637
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wsrep_log_conficts.test
@@ -0,0 +1,55 @@
+#
+# Test --wsrep_log_conflicts=ON
+#
+
+--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 ('abc');
+
+--connection node_2
+SELECT f1 = 'abc' FROM t1;
+
+#
+# Provoke a conflict
+#
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'klm';
+
+--connection node_2
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'xyz';
+
+--connection node_1
+COMMIT;
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+--let $wait_condition = SELECT f1 = 'klm' FROM t1;
+--source include/wait_condition.inc
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+#
+# We can not really check the log output very much because it is quite variable
+#
+
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let $assert_only_after = CURRENT_TEST
+
+--let $assert_text = cluster conflict due to high priority abort for threads
+--let $assert_select = cluster conflict due to high priority abort for threads
+--let $assert_match = cluster conflict due to high priority abort for threads
+--source include/assert_grep.inc
+
+DROP TABLE t1;
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 00000000000..c31150c46af
--- /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 00000000000..6ba8ce786c8
--- /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_options_syntax.test b/mysql-test/suite/galera/t/galera_wsrep_provider_options_syntax.test
new file mode 100644
index 00000000000..fe1abcf6c35
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wsrep_provider_options_syntax.test
@@ -0,0 +1,20 @@
+#
+# PXC-318: Typo in wsrep_provider_options causes an unhandled exception
+#
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--let LOGF=$MYSQLTEST_VARDIR/log/mysqld.1.err
+--disable_info
+call mtr.add_suppression("WSREP\: Unknown parameter 'gmcasts\.segment'");
+call mtr.add_suppression("WSREP\: Set options returned 7");
+--error ER_WRONG_ARGUMENTS
+SET GLOBAL wsrep_provider_options="gmcasts.segment=1";
+# Search for unhandled exception message.
+perl;
+ use strict;
+ my $logf= $ENV{'LOGF'} or die "LOGF not set";
+ open(FILE, "$logf") or die("Unable to open $logf: $!\n");
+ my $count_warnings=grep(/terminate called after throwing an instance of /gi,<FILE>);
+ print "Unhandled exceptions: $count_warnings\n";
+ close(FILE);
+EOF
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 00000000000..7f91495fcc4
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_wsrep_provider_unset_set.test
@@ -0,0 +1,50 @@
+#
+# 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
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.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
+
+SET SESSION wsrep_sync_wait = 0;
+
+--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;
+
+--source include/auto_increment_offset_restore.inc
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 00000000000..6ae81a83271
--- /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/grant.test b/mysql-test/suite/galera/t/grant.test
new file mode 100644
index 00000000000..de1c202cfbb
--- /dev/null
+++ b/mysql-test/suite/galera/t/grant.test
@@ -0,0 +1,25 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV#6266: Changing password fails on galera cluster
+--echo #
+
+--echo
+--echo # On node_1
+--connection node_1
+GRANT SELECT ON *.* TO 'user_6266'@'localhost' IDENTIFIED BY 'pass';
+--echo
+--echo # Now, try changing password for 'user_6266'. This command should also
+--echo # execute successfully on the other node.
+SET PASSWORD FOR 'user_6266'@'localhost' = PASSWORD('newpass');
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT user FROM mysql.user WHERE user='user_6266';
+# cleanup
+DROP USER 'user_6266'@'localhost';
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/lp1276424.test b/mysql-test/suite/galera/t/lp1276424.test
new file mode 100644
index 00000000000..a37e950b6a1
--- /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 00000000000..96d42867c6a
--- /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/lp1376747-2.test b/mysql-test/suite/galera/t/lp1376747-2.test
new file mode 100644
index 00000000000..360681d7674
--- /dev/null
+++ b/mysql-test/suite/galera/t/lp1376747-2.test
@@ -0,0 +1,22 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+FLUSH TABLES t1 FOR EXPORT;
+
+--connection node_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+INSERT INTO t1 VALUES (2,3);
+
+--connection node_2
+UNLOCK TABLES;
+
+--echo ### t1 should have column f2
+SHOW CREATE TABLE t1;
+SELECT * from t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/lp1376747-3.test b/mysql-test/suite/galera/t/lp1376747-3.test
new file mode 100644
index 00000000000..75fe7d276cd
--- /dev/null
+++ b/mysql-test/suite/galera/t/lp1376747-3.test
@@ -0,0 +1,28 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+FLUSH TABLE WITH READ LOCK;
+--echo ### This shouldn't block.
+FLUSH TABLES t1 FOR EXPORT;
+
+--connection node_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_2
+UNLOCK TABLES;
+
+--echo ### t1 should have column f2
+SHOW CREATE TABLE t1;
+
+--connection node_1
+INSERT INTO t1 VALUES (2,3);
+
+--connection node_2
+SELECT * from t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/lp1376747-4.test b/mysql-test/suite/galera/t/lp1376747-4.test
new file mode 100644
index 00000000000..0c707d6d681
--- /dev/null
+++ b/mysql-test/suite/galera/t/lp1376747-4.test
@@ -0,0 +1,53 @@
+#
+# Test Flush tables with read lock along with
+# flush tables <table> with read lock for compatibility.
+# Also, making sure all DDL and DMLs are propagated
+# after provider is unpaused
+#
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--let $galera_connection_name = node_2a
+--let $galera_server_number = 2
+--source include/galera_connect.inc
+
+--connection node_1
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET session wsrep_sync_wait=0;
+SET session wsrep_causal_reads=OFF;
+FLUSH TABLE WITH READ LOCK;
+
+--connection node_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+INSERT INTO t1 VALUES (2,3);
+
+--connection node_2a
+SET session wsrep_sync_wait=0;
+SET session wsrep_causal_reads=OFF;
+SHOW CREATE TABLE t1;
+--sleep 1
+--send FLUSH TABLES t1 WITH READ LOCK;
+
+--connection node_2
+# let the flush table wait in pause state before we unlock
+# table otherwise there is window where-in flush table is
+# yet to wait in pause and unlock allows alter table to proceed.
+# this is because send in asynchronous.
+--sleep 3
+# this will release existing lock but will not resume
+# the cluster as there is new FTRL that is still pausing it.
+UNLOCK TABLES;
+SHOW CREATE TABLE t1;
+
+--connection node_2a
+--reap
+UNLOCK TABLES;
+--sleep 2
+SHOW CREATE TABLE t1;
+SELECT * from t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/lp1376747.test b/mysql-test/suite/galera/t/lp1376747.test
new file mode 100644
index 00000000000..769bb665c77
--- /dev/null
+++ b/mysql-test/suite/galera/t/lp1376747.test
@@ -0,0 +1,24 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+FLUSH TABLES t1 WITH READ LOCK;
+
+--connection node_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+INSERT INTO t1 VALUES (2,3);
+
+--sleep 2
+
+--connection node_2
+UNLOCK TABLES;
+
+--echo ### t1 should have column f2
+SHOW CREATE TABLE t1;
+SELECT * from t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/lp1438990.test b/mysql-test/suite/galera/t/lp1438990.test
new file mode 100644
index 00000000000..5d54c3338e5
--- /dev/null
+++ b/mysql-test/suite/galera/t/lp1438990.test
@@ -0,0 +1,38 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t3 (f1 INTEGER PRIMARY KEY);
+
+CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1);
+
+
+DELIMITER |;
+
+CREATE PROCEDURE p1 (IN x INT)
+BEGIN
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK TO event_logging;
+ INSERT t3 VALUES (x);
+ END;
+ SAVEPOINT event_logging;
+
+ INSERT INTO t2 VALUES (x);
+
+ RELEASE SAVEPOINT event_logging;
+END|
+DELIMITER ;|
+
+
+INSERT INTO t2 VALUES (1);
+INSERT INTO t1 VALUES (1);
+
+DROP PROCEDURE p1;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
diff --git a/mysql-test/suite/galera/t/lp959512.test b/mysql-test/suite/galera/t/lp959512.test
new file mode 100644
index 00000000000..bcc0db24ea7
--- /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/t/mdev_9290.test b/mysql-test/suite/galera/t/mdev_9290.test
new file mode 100644
index 00000000000..39e02011a09
--- /dev/null
+++ b/mysql-test/suite/galera/t/mdev_9290.test
@@ -0,0 +1,24 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-9290 : InnoDB: Assertion failure in file trx0sys.cc line 353
+--echo # InnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno
+--echo #
+
+--connection node_1
+CREATE TABLE t1 (i INT) ENGINE=InnoDB;
+
+--connection node_2
+# Note: a multi-statement transaction should always be the "first" one to execute
+# on this node.
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+COMMIT;
+
+--connection node_1
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--source include/galera_end.inc
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#110.test b/mysql-test/suite/galera/t/mysql-wsrep#110.test
new file mode 100644
index 00000000000..43520f257a1
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#110.test
@@ -0,0 +1,51 @@
+#
+# codership/mysql-wsrep/110 - Assertion `table_found' failed in unpack_row() with SAVEPOINT, trigger, error handler
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t3 (f1 INTEGER PRIMARY KEY);
+
+CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1);
+
+
+DELIMITER |;
+
+CREATE PROCEDURE p1 (IN x INT)
+BEGIN
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK TO event_logging;
+ INSERT t3 VALUES (x);
+ END;
+ SAVEPOINT event_logging;
+
+ INSERT INTO t2 VALUES (x);
+END|
+DELIMITER ;|
+
+
+INSERT INTO t2 VALUES (1);
+INSERT INTO t1 VALUES (1);
+
+SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) = 1 FROM t2;
+SELECT COUNT(*) = 1 FROM t3;
+
+--connection node_2
+
+SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) = 1 FROM t2;
+SELECT COUNT(*) = 1 FROM t3;
+
+--connection node_1
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#198.test b/mysql-test/suite/galera/t/mysql-wsrep#198.test
new file mode 100644
index 00000000000..a80d030a8b0
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#198.test
@@ -0,0 +1,39 @@
+--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
+# Ensure that the tables have been created on node #2
+SELECT 1 FROM DUAL;
+
+LOCK TABLE t2 WRITE;
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+--send OPTIMIZE TABLE t1,t2;
+
+--connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2b
+--send REPAIR TABLE t1,t2;
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'Waiting for table metadata lock'
+--source include/wait_condition.inc
+
+--connection node_1
+INSERT INTO t2 VALUES (1);
+
+--connection node_2
+UNLOCK TABLES;
+
+--connection node_2a
+--reap
+
+--connection node_2b
+--reap
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#201-master.opt b/mysql-test/suite/galera/t/mysql-wsrep#201-master.opt
new file mode 100644
index 00000000000..a00258bc48c
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#201-master.opt
@@ -0,0 +1 @@
+--query_cache_type=1
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#201.test b/mysql-test/suite/galera/t/mysql-wsrep#201.test
new file mode 100644
index 00000000000..21cf05db008
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#201.test
@@ -0,0 +1,32 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_query_cache.inc
+
+CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (DEFAULT);
+
+--connection node_2
+--let $qcache_size_orig = `SELECT @@GLOBAL.query_cache_size`
+SET GLOBAL query_cache_size=1355776;
+
+--disable_query_log
+
+--let $count = 500
+while ($count)
+{
+ --connection node_1
+ INSERT INTO t1 VALUES (DEFAULT);
+ --let $val1 = `SELECT LAST_INSERT_ID()`
+ --connection node_2
+ --let $val2 = `SELECT MAX(id) FROM t1`
+ --let $val3 = `SELECT $val1 != $val2`
+ if ($val3)
+ {
+ --echo $val1 $val2
+ --die wsrep_sync_wait failed
+ }
+ --dec $count
+}
+
+--eval SET GLOBAL query_cache_size = $qcache_size_orig
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#237.test b/mysql-test/suite/galera/t/mysql-wsrep#237.test
new file mode 100644
index 00000000000..4a539e1ba15
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#237.test
@@ -0,0 +1,36 @@
+# hang because of replicated FLUSH TABLE command
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+CREATE TABLE t (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+
+--connection node_1
+SET DEBUG_SYNC = 'wsrep_before_replication WAIT_FOR continue';
+--send INSERT INTO t values (1);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: wsrep_before_replication'
+--source include/wait_condition.inc
+
+--connection node_2
+FLUSH TABLES;
+
+
+--connection node_1a
+SELECT SLEEP(1);
+
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+# Cleanup
+DROP TABLE t;
+
+--connection node_1a
+SET DEBUG_SYNC= 'RESET';
+
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#247.test b/mysql-test/suite/galera/t/mysql-wsrep#247.test
new file mode 100644
index 00000000000..8bcd58607a1
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#247.test
@@ -0,0 +1,23 @@
+#
+# codership/mysql-wsrep/247 MW-246 -
+# DDL with RSU fails if node is desynced upfont
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+SET GLOBAL wsrep_desync=1;
+
+SET wsrep_OSU_method=RSU;
+
+CREATE TABLE t1 (i int primary key);
+
+SHOW VARIABLES LIKE 'wsrep_desync';
+
+SET GLOBAL wsrep_desync=0;
+--sleep 1
+DROP TABLE t1;
+SHOW VARIABLES LIKE 'wsrep_desync';
+
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#31.test b/mysql-test/suite/galera/t/mysql-wsrep#31.test
new file mode 100644
index 00000000000..c669d4834ba
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#31.test
@@ -0,0 +1,53 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+--connection node_1
+
+CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES('test');
+CREATE DATABASE db;
+
+--connection node_2
+--let $expected_position_uuid = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_uuid'`
+--let $expected_position_seqno = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--let $expected_position = $expected_position_uuid:$expected_position_seqno
+
+--echo Shutting down server 2 ...
+--source include/shutdown_mysqld.inc
+
+--echo Recovering server 2 ...
+--let $galera_wsrep_recover_server_id=2
+--source suite/galera/include/galera_wsrep_recover.inc
+
+if ($galera_wsrep_start_position != $expected_position)
+{
+ die(Expected position: $expected_position, found $galera_wsrep_start_position);
+}
+
+--echo Restarting 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
+--source include/wait_until_ready.inc
+
+--connection node_1
+DROP TABLE t1;
+DROP DATABASE db;
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--source include/wait_until_connected_again.inc
+
+# Restore original auto_increment_offset values.
+--let $node_2=node_2a
+--source include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
+
+
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#33.cnf b/mysql-test/suite/galera/t/mysql-wsrep#33.cnf
new file mode 100644
index 00000000000..f1c3d802e4b
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#33.cnf
@@ -0,0 +1,8 @@
+!include ../galera_2nodes.cnf
+
+[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/mysql-wsrep#33.test b/mysql-test/suite/galera/t/mysql-wsrep#33.test
new file mode 100644
index 00000000000..acc7c735849
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#33.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
+
+--source suite/galera/include/galera_sst_restore.inc
+
+--connection node_2
+# We have to manually restore global_log and slow_query_log due to mysql-wsrep#108
+# Otherwise MTR's check_testcases complains
+
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#90.test b/mysql-test/suite/galera/t/mysql-wsrep#90.test
new file mode 100644
index 00000000000..5af86fb2872
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#90.test
@@ -0,0 +1,65 @@
+# Crash in galera_to_execute_end when wsrep_OSU_method is changed from RSU to TOI during a DDL
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+
+--connection node_1
+SET GLOBAL wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_open_tables'
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+
+--connection node_1
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
+
+--connection node_1
+SET GLOBAL wsrep_OSU_method = "TOI";
+SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: alter_table_before_open_tables'
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_OSU_method = "RSU";
+SET DEBUG_SYNC= 'now SIGNAL continue';
+
+--connection node_1
+--reap
+
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+INSERT INTO t1 VALUES (1,2);
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
+INSERT INTO t1 VALUES (3,4);
+
+--connection node_1
+DROP TABLE t1;
+
+SET GLOBAL WSREP_OSU_METHOD = TOI;
diff --git a/mysql-test/suite/galera/t/partition.test b/mysql-test/suite/galera/t/partition.test
new file mode 100644
index 00000000000..bb5a02411c3
--- /dev/null
+++ b/mysql-test/suite/galera/t/partition.test
@@ -0,0 +1,207 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_partition.inc
+
+--echo #
+--echo # MDEV#4953 Galera: DELETE from a partitioned table is not replicated
+--echo #
+
+USE test;
+CREATE TABLE t1 (pk INT PRIMARY KEY, i INT) ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+INSERT INTO t1 VALUES (1,100), (2,200);
+SELECT * FROM t1;
+
+DELETE FROM t1;
+SELECT * FROM t1;
+
+--echo
+--echo # On node_1
+--connection node_1
+SELECT * FROM t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM t1;
+
+# Cleanup
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV#7501 : alter table exchange partition is not replicated in
+--echo # galera cluster
+--echo #
+
+--echo
+--echo # On node_1
+--connection node_1
+
+CREATE TABLE test.t1 (
+ i INT UNSIGNED NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (i)
+ ) ENGINE=INNODB
+ PARTITION BY RANGE (i)
+ (PARTITION p1 VALUES LESS THAN (10) ENGINE = INNODB,
+ PARTITION p2 VALUES LESS THAN (20) ENGINE = INNODB,
+ PARTITION pMax VALUES LESS THAN MAXVALUE ENGINE = INNODB);
+
+INSERT INTO test.t1 (i) VALUE (9),(19);
+CREATE TABLE test.p1 LIKE test.t1;
+ALTER TABLE test.p1 REMOVE PARTITIONING;
+
+ALTER TABLE test.t1 EXCHANGE PARTITION p1 WITH TABLE test.p1;
+SELECT * FROM test.t1;
+SELECT * FROM test.p1;
+
+--echo
+--echo # On node_2
+--connection node_2
+
+SHOW CREATE TABLE t1;
+SHOW CREATE TABLE p1;
+
+SELECT * FROM test.t1;
+SELECT * FROM test.p1;
+
+--echo
+--echo # On node_1
+--connection node_1
+ALTER TABLE t1 TRUNCATE PARTITION p2;
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_1
+--connection node_1
+ALTER TABLE t1 DROP PARTITION p2;
+SHOW CREATE TABLE t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SHOW CREATE TABLE t1;
+
+
+# Cleanup
+DROP TABLE t1, p1;
+
+--echo #
+--echo # MDEV-5146: Bulk loads into partitioned table not working
+--echo #
+
+# Create 2 files with 20002 & 101 entries in each.
+--perl
+open(FILE, ">", "$ENV{'MYSQLTEST_VARDIR'}/tmp/mdev-5146-1.dat") or die;
+foreach my $i (1..20002) {
+ print FILE "$i\n";
+}
+
+open(FILE, ">", "$ENV{'MYSQLTEST_VARDIR'}/tmp/mdev-5146-2.dat") or die;
+foreach my $i (1..101) {
+ print FILE "$i\n";
+}
+EOF
+
+--connection node_1
+
+--let $wsrep_load_data_splitting_orig = `SELECT @@wsrep_load_data_splitting`
+
+--echo # Case 1: wsrep_load_data_splitting = ON & LOAD DATA with 20002
+--echo # entries.
+
+SET GLOBAL wsrep_load_data_splitting = ON;
+
+CREATE TABLE t1 (pk INT PRIMARY KEY)
+ ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+
+# Record wsrep_last_committed as it was before LOAD DATA
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--disable_query_log
+--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/mdev-5146-1.dat' INTO TABLE t1;
+--enable_query_log
+
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--connection node_2
+SELECT COUNT(*) = 20002 FROM t1;
+
+# LOAD-ing 20002 rows causes 3 commits to be registered
+--disable_query_log
+--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 3 AS wsrep_last_committed_diff;
+--enable_query_log
+
+DROP TABLE t1;
+
+--echo # Case 2: wsrep_load_data_splitting = ON & LOAD DATA with 101 entries.
+
+--connection node_1
+
+SET GLOBAL wsrep_load_data_splitting = ON;
+
+CREATE TABLE t1 (pk INT PRIMARY KEY)
+ ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+
+# Record wsrep_last_committed as it was before LOAD DATA
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--disable_query_log
+--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/mdev-5146-2.dat' INTO TABLE t1;
+--enable_query_log
+
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--connection node_2
+SELECT COUNT(*) = 101 FROM t1;
+
+# LOAD-ing 101 rows causes 1 commit to be registered
+--disable_query_log
+--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+DROP TABLE t1;
+
+--echo # Case 3: wsrep_load_data_splitting = OFF & LOAD DATA with 20002
+--echo # entries.
+
+--connection node_1
+
+SET GLOBAL wsrep_load_data_splitting = OFF;
+
+CREATE TABLE t1 (pk INT PRIMARY KEY)
+ ENGINE=INNODB PARTITION BY HASH(pk) PARTITIONS 2;
+
+# Record wsrep_last_committed as it was before LOAD DATA
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--disable_query_log
+--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/mdev-5146-1.dat' INTO TABLE t1;
+--enable_query_log
+
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--connection node_2
+SELECT COUNT(*) = 20002 FROM t1;
+
+# LOAD-ing 20002 rows causes 1 commit to be registered
+--disable_query_log
+--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 1 AS wsrep_last_committed_diff;
+--enable_query_log
+
+DROP TABLE t1;
+
+--connection node_1
+# Restore the original value
+--eval SET GLOBAL wsrep_load_data_splitting = $wsrep_load_data_splitting_orig;
+
+# Cleanup
+remove_file '$MYSQLTEST_VARDIR/tmp/mdev-5146-1.dat';
+remove_file '$MYSQLTEST_VARDIR/tmp/mdev-5146-2.dat';
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/pxc-421.test b/mysql-test/suite/galera/t/pxc-421.test
new file mode 100644
index 00000000000..381f9bb4494
--- /dev/null
+++ b/mysql-test/suite/galera/t/pxc-421.test
@@ -0,0 +1,65 @@
+#
+# PXC-421: Test deadlock involving updates of
+# wsrep_provider, wsrep_cluster_address and wsrep_slave_threads.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+--let $wsrep_slave_1 = `SELECT @@wsrep_slave_threads`
+set GLOBAL wsrep_slave_threads=26;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 (f1) SELECT * from t1 as x1;
+
+--connection node_2
+--let $wsrep_slave_2 = `SELECT @@wsrep_slave_threads`
+set GLOBAL wsrep_slave_threads=16;
+--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
+
+set SESSION wsrep_sync_wait=0;
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+
+INSERT INTO t1 VALUES (4);
+set GLOBAL wsrep_slave_threads=5;
+
+# Node #2 has all the inserts
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+set GLOBAL wsrep_slave_threads=12;
+# Node #1 is missing the insert made while Node #2 was not replicated
+SELECT COUNT(*) = 4 FROM t1;
+INSERT INTO t1 VALUES (100), (101), (102);
+
+--connection node_2
+set GLOBAL wsrep_slave_threads=5;
+INSERT INTO t1 (f1) SELECT * from t1 as x1;
+show global variables like 'wsrep_slave_threads';
+--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_2
+SELECT COUNT(*) FROM t1;
+
+SET GLOBAL auto_increment_offset = 2;
+
+--connection node_1
+SELECT COUNT(*) FROM t1;
+show global variables like 'wsrep_slave_threads';
+--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_1
+DROP TABLE t1;
+
+SET GLOBAL auto_increment_offset = 1;
diff --git a/mysql-test/suite/galera/t/query_cache.test b/mysql-test/suite/galera/t/query_cache.test
new file mode 100644
index 00000000000..24ed8ecd077
--- /dev/null
+++ b/mysql-test/suite/galera/t/query_cache.test
@@ -0,0 +1,1002 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_query_cache.inc
+
+--echo
+--echo # Execute FLUSH/RESET commands.
+--echo # On node-1
+--connection node_1
+SET @query_cache_size_saved=@@GLOBAL.query_cache_size;
+SET @query_cache_type_saved=@@GLOBAL.query_cache_type;
+set GLOBAL query_cache_size=1355776;
+flush query cache; # This crashed in some versions
+reset query cache;
+flush status;
+
+--echo # On node-2
+--connection node_2
+SET @query_cache_size_saved=@@GLOBAL.query_cache_size;
+SET @query_cache_type_saved=@@GLOBAL.query_cache_type;
+set GLOBAL query_cache_size=1355776;
+flush query cache; # This crashed in some versions
+reset query cache;
+flush status;
+
+#
+# INSERT/UPDATE/DELETE/DROP/SELECT
+#
+
+--echo # On node-1
+--connection node_1
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+select * from t1;
+select sql_no_cache * from t1;
+select length(now()) from t1;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+
+select * from t1;
+select * from t1;
+select sql_no_cache * from t1;
+select length(now()) from t1;
+
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+# DELETE should invalidate cache on both the nodes.
+--echo # On node-1
+--connection node_1
+delete from t1 where a=1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+# Add a SELECT to the cache.
+--echo # On node-1
+--connection node_1
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+# UPDATE should invalidate cache on both the nodes.
+--echo # On node-1
+--connection node_1
+update t1 set a=1 where a=3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+# Add a SELECT to the cache.
+--echo # On node-1
+--connection node_1
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+# DROP should invalidate cache on both the nodes.
+--echo # On node-1
+--connection node_1
+drop table t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+#
+# MERGE TABLES with INSERT/UPDATE and DELETE
+#
+--echo
+--echo # On node-1
+--connection node_1
+create table t1 (a int not null) ENGINE=MyISAM;
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null) ENGINE=MyISAM;
+insert into t2 values (4),(5),(6);
+create table t3 (a int not null) engine=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
+# insert
+select * from t3;
+select * from t3;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+insert into t2 values (7);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t1;
+select * from t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+insert into t3 values (8);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+# update
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+update t2 set a=9 where a=7;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+update t3 set a=10 where a=1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+#delete
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+delete from t2 where a=9;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+delete from t3 where a=10;
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+# MERGE table, expect no records.
+select * from t3;
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1, t2, t3;
+
+#
+# SELECT SQL_CACHE ...
+#
+--echo # On node-1
+--connection node_1
+set query_cache_type=demand;
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select sql_cache * from t1 union select * from t1;
+set query_cache_type=2;
+select sql_cache * from t1 union select * from t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+set query_cache_type=on;
+
+--echo # On node-2
+--connection node_2
+set query_cache_type=demand;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select sql_cache * from t1 union select * from t1;
+set query_cache_type=2;
+select sql_cache * from t1 union select * from t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+set query_cache_type=on;
+
+#
+# RESET QUERY CACHE
+#
+--echo # On node-1
+--connection node_1
+reset query cache;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+--echo # On node-2
+--connection node_2
+reset query cache;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+#
+# SELECT SQL_NO_CACHE
+#
+--echo # On node-1
+--connection node_1
+select sql_no_cache * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+--echo # On node-2
+--connection node_2
+select sql_no_cache * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+
+#
+# Check that queries that uses NOW(), LAST_INSERT_ID()... are not cached.
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a text not null) engine=innodb;
+select CONNECTION_ID() from t1;
+select FOUND_ROWS();
+select NOW() from t1;
+select CURDATE() from t1;
+select CURTIME() from t1;
+select DATABASE() from t1;
+select ENCRYPT("test") from t1;
+select LAST_INSERT_ID() from t1;
+select RAND() from t1;
+select UNIX_TIMESTAMP() from t1;
+select USER() from t1;
+select CURRENT_USER() from t1;
+select benchmark(1,1) from t1;
+explain extended select benchmark(1,1) from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+--echo # On node-2
+--connection node_2
+select CONNECTION_ID() from t1;
+select FOUND_ROWS();
+select NOW() from t1;
+select CURDATE() from t1;
+select CURTIME() from t1;
+select DATABASE() from t1;
+select ENCRYPT("test") from t1;
+select LAST_INSERT_ID() from t1;
+select RAND() from t1;
+select UNIX_TIMESTAMP() from t1;
+select USER() from t1;
+select CURRENT_USER() from t1;
+select benchmark(1,1) from t1;
+explain extended select benchmark(1,1) from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+
+#
+# Non-cachable ODBC work around (and prepare cache for drop database)
+#
+--echo # On node-1
+--connection node_1
+create database mysqltest;
+create table mysqltest.t1 (i int not null auto_increment, a int, primary key
+ (i)) engine=innodb;
+insert into mysqltest.t1 values (1, 1);
+select * from mysqltest.t1 where i is null;
+create table t1(a int) engine=innodb;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from mysqltest.t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from mysqltest.t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+#
+# drop db
+#
+drop database mysqltest;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+
+#
+# Charset conversion (cp1251_koi8 always present)
+# Note: Queries using different default character sets are cached separately.
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a char(1) not null collate koi8r_general_ci) engine=innodb;
+insert into t1 values(_koi8r"á");
+set CHARACTER SET koi8r;
+select * from t1;
+set CHARACTER SET cp1251_koi8;
+select * from t1;
+set CHARACTER SET DEFAULT;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+set CHARACTER SET koi8r;
+select * from t1;
+set CHARACTER SET cp1251_koi8;
+select * from t1;
+set CHARACTER SET DEFAULT;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+
+#
+# Same tables in different dbs
+#
+--echo # On node-1
+--connection node_1
+create database if not exists mysqltest;
+create table mysqltest.t1 (i int not null) engine=innodb;
+create table t1 (i int not null) engine=innodb;
+insert into mysqltest.t1 (i) values (1);
+insert into t1 (i) values (2);
+
+select * from t1;
+use mysqltest;
+select * from t1;
+select * from t1;
+use test;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+use mysqltest;
+select * from t1;
+select * from t1;
+use test;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop database mysqltest;
+drop table t1;
+
+#
+# FOUND_ROWS()
+#
+--echo # On node-1
+--connection node_1
+create table t1 (i int not null) engine=innodb;
+insert into t1 (i) values (1),(2),(3),(4);
+
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select * from t1 where i=1;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select * from t1 where i=1;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+--echo # On node-2
+--connection node_2
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select * from t1 where i=1;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select SQL_CALC_FOUND_ROWS * from t1 limit 2;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+select * from t1 where i=1;
+select FOUND_ROWS();
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+drop table t1;
+
+#
+# Test insert delayed (MYISAM)
+#
+
+--echo # On node-2
+--connection node_2
+flush query cache;
+reset query cache;
+
+--echo # On node-1
+--connection node_1
+flush query cache;
+reset query cache;
+
+create table t1 (a int not null) ENGINE=MYISAM;
+insert into t1 values (1),(2),(3);
+select * from t1;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+insert delayed into t1 values (4);
+--sleep 5 # Wait for insert delayed to be executed.
+select a from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+insert delayed into t1 values (4);
+--sleep 5 # Wait for insert delayed to be executed.
+select a from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+drop table t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-1
+--connection node_1
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+#
+# Test of min result data unit size changing
+#
+--echo # On node-2
+--connection node_2
+show global variables like "query_cache_min_res_unit";
+set GLOBAL query_cache_min_res_unit=1001;
+show global variables like "query_cache_min_res_unit";
+
+--echo # On node-1
+--connection node_1
+show global variables like "query_cache_min_res_unit";
+set GLOBAL query_cache_min_res_unit=1001;
+show global variables like "query_cache_min_res_unit";
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1),(2),(3);
+create table t2 (a int not null) engine=innodb;
+insert into t2 values (1),(2),(3);
+select * from t1;
+select * from t1;
+select * from t2;
+select * from t2;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+select * from t1;
+select * from t2;
+select * from t2;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+drop table t1;
+select a from t2;
+select a from t2;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+set GLOBAL query_cache_min_res_unit=default;
+show global variables like "query_cache_min_res_unit";
+
+--echo # On node-1
+--connection node_1
+select a from t2;
+select a from t2;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+drop table t2;
+set GLOBAL query_cache_min_res_unit=default;
+show global variables like "query_cache_min_res_unit";
+
+#
+# Case sensitive test
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a int not null) engine=innodb;
+insert into t1 values (1);
+select "aaa" from t1;
+select "AAA" from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select "aaa" from t1;
+select "AAA" from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+
+#
+# Test of query cache resizing
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a int) engine=innodb;
+set GLOBAL query_cache_size=1000;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=1024;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=10240;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=20480;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=40960;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=51200;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=61440;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=81920;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=102400;
+show global variables like "query_cache_size";
+select * from t1;
+
+--echo # On node-2
+--connection node_2
+set GLOBAL query_cache_size=1000;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=1024;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=10240;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=20480;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=40960;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=51200;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=61440;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=81920;
+show global variables like "query_cache_size";
+select * from t1;
+set GLOBAL query_cache_size=102400;
+show global variables like "query_cache_size";
+select * from t1;
+
+drop table t1;
+
+#
+# Temporary tables (ignored by Galera)
+#
+--echo # On node-1
+--connection node_1
+set GLOBAL query_cache_size=1048576;
+create table t1 (i int not null) engine=innodb;
+create table t2 (i int not null) engine=innodb;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+create temporary table t3 (i int not null);
+select * from t2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t3;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+update t1 set i=(select distinct 1 from (select * from t2) a);
+drop table t3;
+
+--echo # On node-2
+--connection node_2
+set GLOBAL query_cache_size=1048576;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+drop table t1, t2;
+
+#
+# System databse test (no need to perform it on node_2)
+# Note: Queries on system tables are not cached.
+#
+--echo # On node-1
+--connection node_1
+use mysql;
+disable_result_log;
+select * from db;
+enable_result_log;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+use test;
+disable_result_log;
+select * from mysql.db;
+enable_result_log;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+#
+# Simple rename test
+#
+--echo # On node-1
+--connection node_1
+create table t1(id int auto_increment primary key) engine=innodb;
+insert into t1 values (1), (2), (3);
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-1
+--connection node_1
+alter table t1 rename to t2;
+--error ER_NO_SUCH_TABLE
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+--error ER_NO_SUCH_TABLE
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t2;
+
+#
+# Load data invalidation test
+#
+--echo # On node-1
+--connection node_1
+create table t1 (word char(20) not null) engine=innodb;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval load data infile '$MYSQLTEST_VARDIR/std_data/words.dat' into table t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select count(*) from t1;
+
+# Wait for "load data" to replicate.
+--sleep 5
+
+--echo # On node-2
+--connection node_2
+select count(*) from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval load data infile '$MYSQLTEST_VARDIR/std_data/words.dat' into table t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select count(*) from t1;
+
+drop table t1;
+
+#
+# INTO OUTFILE/DUMPFILE test
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a int) engine=innodb;
+insert into t1 values (1),(2),(3);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t1 into outfile "query_cache.out.file";
+--error ER_FILE_EXISTS_ERROR
+select * from t1 into outfile "query_cache.out.file";
+select * from t1 limit 1 into dumpfile "query_cache.dump.file";
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+drop table t1;
+let $datadir=`select @@datadir`;
+--remove_file $datadir/test/query_cache.dump.file
+--remove_file $datadir/test/query_cache.out.file
+
+#
+# Test of SQL_SELECT_LIMIT
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a int) engine=innodb;
+insert into t1 values (1),(2);
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t1;
+SET SQL_SELECT_LIMIT=1;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+SET SQL_SELECT_LIMIT=DEFAULT;
+
+--echo # On node-2
+--connection node_2
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+select * from t1;
+SET SQL_SELECT_LIMIT=1;
+select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+SET SQL_SELECT_LIMIT=DEFAULT;
+
+drop table t1;
+
+#
+# WRITE LOCK & QC
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a int not null) engine=innodb;
+create table t2 (a int not null) engine=innodb;
+
+set query_cache_wlock_invalidate=1;
+create view v1 as select * from t1;
+select * from t1;
+select * from t2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+lock table t1 write, t2 read;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+unlock table;
+select * from t1;
+# Implicit locking of t1 does not invalidate QC
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+lock table v1 write;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+unlock table;
+drop view v1;
+set query_cache_wlock_invalidate=default;
+
+--echo # On node-2
+--connection node_2
+set query_cache_wlock_invalidate=1;
+create view v1 as select * from t1;
+select * from t1;
+select * from t2;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+lock table t1 write, t2 read;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+unlock table;
+select * from t1;
+# Implicit locking of t1 does not invalidate QC
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+lock table v1 write;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_hits";
+unlock table;
+drop view v1;
+set query_cache_wlock_invalidate=default;
+
+drop table t1,t2;
+
+#
+# Hiding real table stored in query cache by temporary table
+#
+--echo # On node-1
+--connection node_1
+create table t1 (id int primary key) engine=innodb;
+insert into t1 values (1),(2),(3);
+select * from t1;
+create temporary table t1 (a int not null auto_increment primary key);
+select * from t1;
+drop table t1;
+drop table t1;
+
+#
+# Test character set related variables:
+# character_set_result
+# character_set_client
+# charactet_set_connection/collation_connection
+# If at least one of the above variables has changed,
+# the cached query can't be reused. In the below test
+# absolutely the same query is used several times,
+# SELECT should fetch different results for every instance.
+# No hits should be produced.
+# New cache entry should appear for every SELECT.
+#
+
+--echo # On node-1
+--connection node_1
+SET NAMES koi8r;
+CREATE TABLE t1 (a char(1) character set koi8r) engine=innodb;
+INSERT INTO t1 VALUES (_koi8r'á'),(_koi8r'Ã');
+#
+# Run select
+#
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+#
+# Change collation_connection and run the same query again
+#
+set collation_connection=koi8r_bin;
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+#
+# Now change character_set_client and run the same query again
+#
+set character_set_client=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+#
+# And finally change character_set_results and run the same query again
+#
+set character_set_results=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+SET NAMES default;
+
+--echo # On node-2
+--connection node_2
+#
+# Run select
+#
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+#
+# Change collation_connection and run the same query again
+#
+set collation_connection=koi8r_bin;
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+#
+# Now change character_set_client and run the same query again
+#
+set character_set_client=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+#
+# And finally change character_set_results and run the same query again
+#
+set character_set_results=cp1251;
+SELECT a,'Â','â'='Â' FROM t1;
+show status like "Qcache_hits";
+show status like "Qcache_queries_in_cache";
+
+drop table t1;
+
+#
+# Comments before command
+#
+--echo # On node-1
+--connection node_1
+create table t1 (a int) engine=innodb;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+/**/ select * from t1;
+/**/ select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+/**/ select * from t1;
+/**/ select * from t1;
+show status like "Qcache_queries_in_cache";
+show status like "Qcache_inserts";
+show status like "Qcache_hits";
+
+drop table t1;
+
+#
+# Information schema & query cache test
+#
+--echo # On node-1
+--connection node_1
+set session query_cache_type = 2;
+create table t1(a int) engine=innodb;
+select table_name from information_schema.tables
+where table_schema="test";
+drop table t1;
+select table_name from information_schema.tables
+where table_schema="test";
+# Bug #8480: REPAIR TABLE needs to flush the table from the query cache
+set session query_cache_type = 1;
+set global query_cache_size=1024*1024;
+flush query cache;
+create table t1 ( a int ) engine=myisam; # myisam for repair tables
+insert into t1 values (1);
+select a from t1;
+select a from t1;
+show status like 'qcache_queries_in_cache';
+show status like "Qcache_hits";
+repair table t1;
+show status like 'qcache_queries_in_cache';
+show status like "Qcache_hits";
+
+--echo # On node-2
+--connection node_2
+select a from t1;
+select a from t1;
+show status like 'qcache_queries_in_cache';
+show status like "Qcache_hits";
+repair table t1;
+show status like 'qcache_queries_in_cache';
+show status like "Qcache_hits";
+drop table t1;
+
+--echo # Restore original settings.
+--echo # On node-1
+--connection node_1
+SET GLOBAL query_cache_size=@query_cache_size_saved;
+SET GLOBAL query_cache_type=@query_cache_type_saved;
+--echo
+--echo # On node-2
+--connection node_2
+SET GLOBAL query_cache_size=@query_cache_size_saved;
+SET GLOBAL query_cache_type=@query_cache_type_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/rename.test b/mysql-test/suite/galera/t/rename.test
new file mode 100644
index 00000000000..27811678bf5
--- /dev/null
+++ b/mysql-test/suite/galera/t/rename.test
@@ -0,0 +1,52 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-8598 : Failed MySQL DDL commands and Galera replication
+--echo #
+--echo # On node 1
+--connection node_1
+USE test;
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUE(1);
+SELECT * FROM t1;
+
+--echo # Create a new user 'foo' with limited privileges
+GRANT SELECT on test.* TO foo@localhost;
+
+--echo # Open connection to the 1st node using 'test_user1' user.
+--let $port_1= \$NODE_MYPORT_1
+--connect(foo_node_1,localhost,foo,,test,$port_1,)
+
+--connection foo_node_1
+SELECT * FROM t1;
+--echo # Following RENAME should not replicate to other node.
+--error ER_TABLEACCESS_DENIED_ERROR
+RENAME TABLE t1 TO t2;
+
+--echo # On node 2
+--connection node_2
+USE test;
+SELECT * FROM t1;
+
+--echo # On node_1
+--connection node_1
+RENAME TABLE t1 TO t2;
+SHOW TABLES;
+
+--echo # On node 2
+--connection node_2
+USE test;
+SELECT * FROM t2;
+
+# Cleanup
+--connection node_1
+DROP USER foo@localhost;
+DROP TABLE t2;
+
+--echo # End of tests
+
diff --git a/mysql-test/suite/galera/t/rpl_row_annotate.cnf b/mysql-test/suite/galera/t/rpl_row_annotate.cnf
new file mode 100644
index 00000000000..1f1d83dfa0b
--- /dev/null
+++ b/mysql-test/suite/galera/t/rpl_row_annotate.cnf
@@ -0,0 +1,6 @@
+!include ../galera_2nodes.cnf
+
+[mysqld]
+log-bin
+log-slave-updates
+binlog-annotate-row-events=ON
diff --git a/mysql-test/suite/galera/t/rpl_row_annotate.test b/mysql-test/suite/galera/t/rpl_row_annotate.test
new file mode 100644
index 00000000000..b1cfdb36639
--- /dev/null
+++ b/mysql-test/suite/galera/t/rpl_row_annotate.test
@@ -0,0 +1,42 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo # On node_2
+--connection node_2
+RESET MASTER;
+
+--echo # On node_1
+--connection node_1
+RESET MASTER;
+CREATE TABLE t1(i INT)ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+DELETE FROM t1 WHERE i = 1;
+
+--echo # On node_2
+--connection node_2
+INSERT INTO t1 VALUES(2);
+DELETE FROM t1 WHERE i = 2;
+
+--echo # On node_1
+--connection node_1
+--source include/binlog_start_pos.inc
+let $start_pos= `select @binlog_start_pos`;
+--replace_column 2 # 5 #
+--replace_result $start_pos <start_pos>
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
+--eval SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM $start_pos
+
+--echo # On node_2
+--connection node_2
+--source include/binlog_start_pos.inc
+let $start_pos= `select @binlog_start_pos`;
+--replace_column 2 # 5 #
+--replace_result $start_pos <start_pos>
+--replace_regex /table_id: [0-9]+/table_id: #/ /\/\* xid=.* \*\//\/* xid= *\//
+--eval SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM $start_pos
+
+# Cleanup
+DROP TABLE t1;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/unique_key.test b/mysql-test/suite/galera/t/unique_key.test
new file mode 100644
index 00000000000..00b85d57165
--- /dev/null
+++ b/mysql-test/suite/galera/t/unique_key.test
@@ -0,0 +1,54 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV#5552 Deadlock when inserting NULL column value in column with
+--echo # UNIQUE index
+--echo #
+
+USE test;
+--echo
+--echo # On node_1
+--connection node_1
+CREATE TABLE t1(c1 INT DEFAULT NULL, UNIQUE KEY c1(c1)) ENGINE=INNODB;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM test.t1;
+
+
+--echo
+--echo # On node_1
+--connection node_1
+INSERT INTO t1 VALUES (1);
+UPDATE t1 SET c1=NULL WHERE c1=1;
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_1
+--connection node_1
+DELETE FROM t1 WHERE c1<=>NULL;
+SELECT * FROM test.t1;
+
+--echo
+--echo # On node_2
+--connection node_2
+SELECT * FROM test.t1;
+
+--let $galera_diff_statement = SELECT * FROM t1
+--source include/galera_diff.inc
+
+# Cleanup
+DROP TABLE t1;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/mysql-test/suite/galera/t/view.test b/mysql-test/suite/galera/t/view.test
new file mode 100644
index 00000000000..fa2cd8b2a67
--- /dev/null
+++ b/mysql-test/suite/galera/t/view.test
@@ -0,0 +1,50 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-7222: Cluster Node Crash at CREATE DEFINER statement
+--echo #
+USE test;
+CREATE DEFINER=CURRENT_USER VIEW v1 AS SELECT 1;
+DROP VIEW v1;
+
+--echo #
+--echo # MDEV-8464 : ALTER VIEW not replicated in some cases
+--echo #
+--echo # On node_1
+--connection node_1
+USE test;
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+CREATE DEFINER=CURRENT_USER VIEW v1 AS SELECT * FROM t1;
+CREATE ALGORITHM=MERGE VIEW v2 AS SELECT * FROM t1;
+CREATE ALGORITHM=TEMPTABLE VIEW v3 AS SELECT * FROM t1;
+CREATE ALGORITHM=UNDEFINED DEFINER=CURRENT_USER VIEW v4 AS SELECT * FROM t1;
+
+--echo # On node_2
+--connection node_2
+USE test;
+SHOW CREATE VIEW v1;
+SHOW CREATE VIEW v2;
+SHOW CREATE VIEW v3;
+SHOW CREATE VIEW v4;
+
+--echo # On node_1
+--connection node_1
+ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1;
+ALTER ALGORITHM=UNDEFINED VIEW v2 AS SELECT * FROM t1;
+ALTER DEFINER=CURRENT_USER VIEW v3 AS SELECT * FROM t1;
+ALTER ALGORITHM=TEMPTABLE DEFINER=CURRENT_USER VIEW v4 AS SELECT * FROM t1;
+
+--echo # On node_2
+--connection node_2
+SHOW CREATE VIEW v1;
+SHOW CREATE VIEW v2;
+SHOW CREATE VIEW v3;
+SHOW CREATE VIEW v4;
+
+--echo # Cleanup
+DROP VIEW v1, v2, v3, v4;
+DROP TABLE t1;
+
+--echo # End of tests
+
diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def
new file mode 100644
index 00000000000..a9b9b00b40c
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/disabled.def
@@ -0,0 +1,3 @@
+galera_slave_options_do :MDEV-8798
+galera_slave_options_ignore : MDEV-8798
+
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 00000000000..babbb9731e3
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
@@ -0,0 +1,64 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+binlog-format=row
+innodb-autoinc-lock-mode=2
+default-storage-engine=innodb
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep_node_address=127.0.0.1
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=15
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep-cluster-address='gcomm://'
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
+
+wsrep_sst_receive_address=127.0.0.2:@mysqld.1.#sst_port
+wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
+
+wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+
+[mysqld.3]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
+
+wsrep_sst_receive_address=127.0.0.2:@mysqld.3.#sst_port
+wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+
+[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/include/galera_suspend.inc b/mysql-test/suite/galera_3nodes/include/galera_suspend.inc
new file mode 100644
index 00000000000..3495ad2342b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/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/suite/galera_3nodes/include/have_ipv6.inc b/mysql-test/suite/galera_3nodes/include/have_ipv6.inc
new file mode 100644
index 00000000000..560cad03350
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/include/have_ipv6.inc
@@ -0,0 +1,15 @@
+# Check if ipv6 is available.
+#
+--disable_query_log
+--disable_result_log
+connect (checkcon123456789,::1,root,,test);
+if($mysql_errno)
+{
+ skip No IPv6 support;
+}
+connection default;
+disconnect checkcon123456789;
+--enable_result_log
+--enable_query_log
+# end check
+
diff --git a/mysql-test/suite/galera_3nodes/my.cnf b/mysql-test/suite/galera_3nodes/my.cnf
new file mode 100644
index 00000000000..bb25b95ceea
--- /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/GAL-501.result b/mysql-test/suite/galera_3nodes/r/GAL-501.result
new file mode 100644
index 00000000000..a2bf5f4d98c
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/GAL-501.result
@@ -0,0 +1,14 @@
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+VARIABLE_VALUE LIKE '%[::1]%'
+1
+SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 3
+1
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
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 00000000000..96a2bec0d7f
--- /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 00000000000..9dc735d5d3d
--- /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 00000000000..7e0d282ec7f
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result
@@ -0,0 +1,20 @@
+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
+SET SESSION wsrep_sync_wait = DEFAULT;
+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 00000000000..180aade029c
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_garbd.result
@@ -0,0 +1,17 @@
+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
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
diff --git a/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result b/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result
new file mode 100644
index 00000000000..85000db8e77
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result
@@ -0,0 +1,11 @@
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+Killing server ...
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+SELECT COUNT(*) = 20 FROM t1;
+COUNT(*) = 20
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result
new file mode 100644
index 00000000000..f519654952b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result
@@ -0,0 +1,26 @@
+GRANT ALL PRIVILEGES ON *.* TO 'sst';
+SET GLOBAL wsrep_sst_auth = 'sst:';
+SET GLOBAL wsrep_sst_method = 'mysqldump';
+Unloading wsrep provider ...
+SET GLOBAL wsrep_provider = 'none';
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+Loading wsrep provider ...
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+VARIABLE_VALUE LIKE '%[::1]%'
+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");
+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");
+CALL mtr.add_suppression("Unsupported protocol downgrade: incremental data collection disabled. Expect abort");
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result
new file mode 100644
index 00000000000..a2bf5f4d98c
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result
@@ -0,0 +1,14 @@
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+VARIABLE_VALUE LIKE '%[::1]%'
+1
+SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 3
+1
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result
new file mode 100644
index 00000000000..53e35939a79
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result
@@ -0,0 +1,18 @@
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+VARIABLE_VALUE LIKE '%[::1]%'
+1
+SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 3
+1
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+include/assert_grep.inc [Streaming the backup to joiner at \[::1\]]
+include/assert_grep.inc [async IST sender starting to serve tcp://\[::1\]:]
+include/assert_grep.inc [IST receiver addr using tcp://\[::1\]]
+include/assert_grep.inc [Prepared IST receiver, listening at: tcp://\[::1\]]
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 00000000000..6c66bf4a891
--- /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 = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=ist_sender_send_after_get_buffers';
+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 00000000000..ec97d392c0f
--- /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_bootstrap.result b/mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result
new file mode 100644
index 00000000000..69995acb982
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result
@@ -0,0 +1,26 @@
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'pc.bootstrap=1';
+SHOW STATUS LIKE 'wsrep_cluster_size';
+Variable_name Value
+wsrep_cluster_size 1
+SHOW STATUS LIKE 'wsrep_cluster_status';
+Variable_name Value
+wsrep_cluster_status Primary
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+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 00000000000..6fb931638ef
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result
@@ -0,0 +1,121 @@
+SET GLOBAL wsrep_provider_options = 'pc.weight=3';
+Suspending node ...
+SET SESSION wsrep_sync_wait=0;
+SET SESSION wsrep_on=OFF;
+SET SESSION wsrep_on=ON;
+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 = '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 GLOBAL wsrep_provider_options = 'pc.weight=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
+SET GLOBAL wsrep_provider_options = 'pc.weight=1';
+CALL mtr.add_suppression('WSREP: gcs_caused\\(\\) returned -1');
+CALL mtr.add_suppression('overriding reported weight for');
+CALL mtr.add_suppression('WSREP: user message in state LEAVING');
+CALL mtr.add_suppression('sending install message failed: Transport endpoint is not connected');
+CALL mtr.add_suppression('overriding reported weight for');
diff --git a/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result b/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result
new file mode 100644
index 00000000000..21f747d280b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result
@@ -0,0 +1,26 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 1']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+SET SESSION wsrep_on = OFF;
+Killing server ...
+safe_to_bootstrap: 1
+safe_to_bootstrap: 0
+safe_to_bootstrap: 0
+CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_slave_options_do.result b/mysql-test/suite/galera_3nodes/r/galera_slave_options_do.result
new file mode 100644
index 00000000000..7185e92863d
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_slave_options_do.result
@@ -0,0 +1,28 @@
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+CREATE TABLE db1.t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2A (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2B (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO db1.t1 VALUES (1);
+INSERT INTO db2.t2A VALUES (2);
+INSERT INTO db2.t2B VALUES (3);
+SELECT COUNT(*) = 0 FROM db1.t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM db2.t2A;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 1 FROM db2.t2B;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM db1.t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 1 FROM db2.t2A;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM db2.t2B;
+COUNT(*) = 1
+1
+DROP SCHEMA db1;
+DROP SCHEMA db2;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_slave_options_ignore.result b/mysql-test/suite/galera_3nodes/r/galera_slave_options_ignore.result
new file mode 100644
index 00000000000..7185e92863d
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_slave_options_ignore.result
@@ -0,0 +1,28 @@
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+CREATE TABLE db1.t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2A (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2B (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO db1.t1 VALUES (1);
+INSERT INTO db2.t2A VALUES (2);
+INSERT INTO db2.t2B VALUES (3);
+SELECT COUNT(*) = 0 FROM db1.t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM db2.t2A;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 1 FROM db2.t2B;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM db1.t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 1 FROM db2.t2A;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM db2.t2B;
+COUNT(*) = 1
+1
+DROP SCHEMA db1;
+DROP SCHEMA db2;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result b/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result
new file mode 100644
index 00000000000..88780a2c87f
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result
@@ -0,0 +1,48 @@
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_dirty_reads = 1;
+SELECT f1 FROM t1;
+f1
+1
+USE test;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+LOCK TABLE t1 WRITE;
+UNLOCK TABLES;
+FLUSH TABLES WITH READ LOCK;
+UNLOCK TABLES;
+PREPARE stmt_select FROM 'SELECT f1 FROM t1';
+EXECUTE stmt_select;
+f1
+1
+PREPARE stmt_update FROM 'UPDATE t1 SET f1 = f1 + f1';
+SET GLOBAL wsrep_dirty_reads = 1;
+SET GLOBAL wsrep_sync_wait = 0;
+SET GLOBAL wsrep_dirty_reads = 0;
+SET GLOBAL wsrep_sync_wait = 15;
+SET SESSION wsrep_dirty_reads = 1;
+INSERT INTO t1 SELECT * FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+DELETE FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+UPDATE t1 SET f1 = f1 + 1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+DROP TABLE t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+EXECUTE stmt_update;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET SESSION wsrep_dirty_reads = 0;
+SELECT * FROM t1;
+ERROR 08S01: WSREP has not yet prepared node for application use
+EXECUTE stmt_select;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST;
+COUNT(*) > 0
+1
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/suite.pm b/mysql-test/suite/galera_3nodes/suite.pm
new file mode 100644
index 00000000000..c91e6e07d76
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/suite.pm
@@ -0,0 +1,55 @@
+package My::Suite::GALERA_3NODES;
+use File::Basename;
+use My::Find;
+
+@ISA = qw(My::Suite);
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+return "WSREP is not compiled in" unless defined $::mysqld_variables{'wsrep-on'};
+
+my ($provider) = grep { -f $_ } $ENV{WSREP_PROVIDER},
+ "/usr/lib/galera/libgalera_smm.so",
+ "/usr/lib64/galera/libgalera_smm.so";
+
+return "No wsrep provider library" unless -f $provider;
+
+$ENV{WSREP_PROVIDER} = $provider;
+
+my ($spath) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir;
+return "No SST scripts" unless $spath;
+
+my ($epath) = grep { -f "$_/my_print_defaults"; } "$::bindir/extra", $::path_client_bindir;
+return "No my_print_defaults" unless $epath;
+
+push @::global_suppressions,
+ (
+ qr(WSREP: wsrep_sst_receive_address is set to '127.0.0.1),
+ qr(WSREP: Could not open saved state file for reading: ),
+ qr(WSREP: Could not open state file for reading: ),
+ qr(WSREP: Gap in state sequence. Need state transfer.),
+ qr(WSREP: Failed to prepare for incremental state transfer:),
+ qr(WSREP:.*down context.*),
+ qr(WSREP: Failed to send state UUID:),
+ qr(WSREP: last inactive check more than .* skipping check),
+ qr(WSREP: SQL statement was ineffective),
+ qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.),
+ qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|,
+ qr(WSREP: Quorum: No node with complete state),
+ qr(WSREP: Initial position was provided by configuration or SST, avoiding override),
+ qr|WSREP: discarding established \(time wait\) .*|,
+ qr(WSREP: There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside. Will use that one.),
+ qr(WSREP: evs::proto.*),
+ qr|WSREP: Ignoring possible split-brain (allowed by configuration) from view:.*|,
+ qr(WSREP: Member .* requested state transfer from .* but it is impossible to select State Transfer donor: Resource temporarily unavailable),
+ qr(WSREP: Could not find peer:),
+ qr(WSREP: Protocol violation. JOIN message sender .*),
+ qr(WSREP: JOIN message from member [0-9]* in non-primary configuration. Ignored.),
+ );
+
+
+$ENV{PATH}="$epath:$ENV{PATH}";
+$ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath;
+
+bless { };
+
diff --git a/mysql-test/suite/galera_3nodes/t/GAL-501.cnf b/mysql-test/suite/galera_3nodes/t/GAL-501.cnf
new file mode 100644
index 00000000000..7002cb5bdfd
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/GAL-501.cnf
@@ -0,0 +1,26 @@
+!include ../galera_3nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+
+
+[mysqld.1]
+wsrep-cluster-address=gcomm://
+wsrep_node_address=[::1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]'
+wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.1.port'
+
+[mysqld.2]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_node_address=[::1]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]'
+wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.2.port'
+
+[mysqld.3]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_node_address=[::1]
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]'
+wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.3.port'
diff --git a/mysql-test/suite/galera_3nodes/t/GAL-501.test b/mysql-test/suite/galera_3nodes/t/GAL-501.test
new file mode 100644
index 00000000000..60ed5989227
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/GAL-501.test
@@ -0,0 +1,38 @@
+#
+# Test GAL-501 Improved URI parsing for IPv6 addresses
+# The .cnf file contains
+# wsrep_node_address=[::1]
+# ist.recv_addr=[::1]
+
+--source include/galera_cluster.inc
+--source include/have_ipv6.inc
+
+# Confirm that initial handshake happened over ipv6
+
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Force IST
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--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
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--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 COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
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 00000000000..b4fe10bff0d
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_certification_ccc.test
@@ -0,0 +1,53 @@
+#
+# 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
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.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/wait_until_ready.inc
+
+--connection node_1
+DROP TABLE t1;
+
+# Restore original auto_increment_offset values.
+--source ../galera/include/auto_increment_offset_restore.inc
+
+--source include/galera_end.inc
+
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 00000000000..a2ad0765028
--- /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 00000000000..03236a3cb93
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test
@@ -0,0 +1,68 @@
+#
+# 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
+SET SESSION wsrep_sync_wait = DEFAULT;
+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 00000000000..a68ba8ce15b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_garbd.test
@@ -0,0 +1,64 @@
+#
+# 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
+
+--sleep 5
+
+--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
+
+
+# Workaround for galera#101
+
+--connection node_1
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+
+--connection node_2
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+
+--connection node_3
+CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
diff --git a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test b/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test
new file mode 100644
index 00000000000..cc3f42c7290
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test
@@ -0,0 +1,58 @@
+#
+# This test uses innobackupex to take a backup on node #2 and then restores that node from backup
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+--connection node_2
+SELECT COUNT(*) = 10 FROM t1;
+
+--exec rm -rf $MYSQL_TMP_DIR/innobackupex_backup
+--exec innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 $MYSQL_TMP_DIR/innobackupex_backup --galera-info --port=$NODE_MYPORT_2 --host=127.0.0.1 --no-timestamp > $MYSQL_TMP_DIR/innobackupex-backup.log
+--exec innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 $MYSQL_TMP_DIR/innobackupex_backup --apply-log --galera-info --port=$NODE_MYPORT_2 --host=127.0.0.1 --no-timestamp > $MYSQL_TMP_DIR/innobackupex-apply.log
+
+--source ../galera/include/kill_galera.inc
+--sleep 1
+
+--connection node_1
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+
+--exec rm -rf $MYSQLTEST_VARDIR/mysqld.2/data/*
+--exec innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 --copy-back $MYSQL_TMP_DIR/innobackupex_backup --port=$NODE_MYPORT_2 --host=127.0.0.1 > $MYSQL_TMP_DIR/innobackupex-restore.log
+
+#
+# Convert the xtrabackup_galera_info into a grastate.dat file
+#
+
+--perl
+ use strict;
+ my $xtrabackup_galera_info_file = $ENV{'MYSQL_TMP_DIR'}.'/innobackupex_backup/xtrabackup_galera_info';
+ open(XTRABACKUP_GALERA_INFO, $xtrabackup_galera_info_file) or die "Can not open $xtrabackup_galera_info_file: $!";
+ my $xtrabackup_galera_info = <XTRABACKUP_GALERA_INFO>;
+ my ($uuid, $seqno) = split(':', $xtrabackup_galera_info);
+
+ my $grastate_dat_file = $ENV{'MYSQLTEST_VARDIR'}.'/mysqld.2/data/grastate.dat';
+ die "grastate.dat already exists" if -e $grastate_dat_file;
+
+ open(GRASTATE_DAT, ">$grastate_dat_file") or die "Can not write to $grastate_dat_file: $!";
+ print GRASTATE_DAT "version: 2.1\n";
+ print GRASTATE_DAT "uuid: $uuid\n";
+ print GRASTATE_DAT "seqno: $seqno\n";
+ print GRASTATE_DAT "cert_index:\n";
+ exit(0);
+EOF
+
+--source include/start_mysqld.inc
+--sleep 5
+
+--source include/wait_until_connected_again.inc
+SELECT COUNT(*) = 20 FROM t1;
+
+DROP TABLE t1;
+
+--sleep 10
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf
new file mode 100644
index 00000000000..3728e1ce005
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf
@@ -0,0 +1,22 @@
+!include ../galera_3nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+
+[mysqld.1]
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.1.port'
+
+[mysqld.2]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.2.port'
+
+[mysqld.3]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.3.port'
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test
new file mode 100644
index 00000000000..5b06e617eef
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test
@@ -0,0 +1,56 @@
+--source include/galera_cluster.inc
+--source include/have_ipv6.inc
+
+--connection node_1
+GRANT ALL PRIVILEGES ON *.* TO 'sst';
+
+--let $wsrep_sst_auth_orig = `SELECT @@wsrep_sst_auth`
+SET GLOBAL wsrep_sst_auth = 'sst:';
+
+--connection node_2
+--source include/wait_until_connected_again.inc
+--let $wsrep_sst_method_orig = `SELECT @@wsrep_sst_method`
+--let $wsrep_sst_receive_address_orig = `SELECT @@wsrep_sst_receive_address`
+
+--disable_query_log
+--eval SET GLOBAL wsrep_sst_receive_address = '[::1]:$NODE_MYPORT_2';
+--enable_query_log
+SET GLOBAL wsrep_sst_method = 'mysqldump';
+
+
+#
+# Force mysqldump SST
+#
+
+--connection node_2
+--source suite/galera/include/galera_unload_provider.inc
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
+--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
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+
+--connection node_2
+--source suite/galera/include/galera_load_provider.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--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 COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
+
+# Confirm that initial handshake happened over ipv6
+
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+
+--source suite/galera/include/galera_sst_restore.inc
+--connection node_2
+CALL mtr.add_suppression("Unsupported protocol downgrade: incremental data collection disabled. Expect abort");
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf
new file mode 100644
index 00000000000..3728e1ce005
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf
@@ -0,0 +1,22 @@
+!include ../galera_3nodes.cnf
+
+[mysqld]
+wsrep_sst_method=rsync
+
+[mysqld.1]
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.1.port'
+
+[mysqld.2]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.2.port'
+
+[mysqld.3]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.3.port'
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test
new file mode 100644
index 00000000000..7ee209d8e72
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test
@@ -0,0 +1,32 @@
+--source include/galera_cluster.inc
+--source include/have_ipv6.inc
+
+# Confirm that initial handshake happened over ipv6
+
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Force IST
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--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
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--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 COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf
new file mode 100644
index 00000000000..8a80be0d2a9
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf
@@ -0,0 +1,26 @@
+!include ../galera_3nodes.cnf
+
+[mysqld]
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth="root:"
+
+[mysqld.1]
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.1.port'
+
+[mysqld.2]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.2.port'
+
+[mysqld.3]
+wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
+wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port'
+wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port'
+wsrep_node_incoming_address='[::1]:@mysqld.3.port'
+
+[SST]
+sockopt=",pf=ip6"
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test
new file mode 100644
index 00000000000..84eee017700
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test
@@ -0,0 +1,62 @@
+--source include/galera_cluster.inc
+--source include/have_ipv6.inc
+
+# Confirm that initial handshake happened over ipv6
+
+SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Force IST
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--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
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--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 COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
+
+# Confirm that key messages around SST and IST reference IPv6
+
+--connection node_1
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let $assert_only_after = CURRENT_TEST
+
+--let $assert_count = 2
+--let $assert_text = Streaming the backup to joiner at \[::1\]
+--let $assert_select = Streaming the backup to joiner at \[::1\]
+--source include/assert_grep.inc
+
+--let $assert_count = 1
+--let $assert_text = async IST sender starting to serve tcp://\[::1\]:
+--let $assert_select = async IST sender starting to serve tcp://\[::1\]:
+--source include/assert_grep.inc
+
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+
+--let $assert_text = IST receiver addr using tcp://\[::1\]
+--let $assert_select = IST receiver addr using tcp://\[::1\]
+--source include/assert_grep.inc
+
+--let $assert_text = Prepared IST receiver, listening at: tcp://\[::1\]
+--let $assert_select = Prepared IST receiver, listening at: tcp://\[::1\]
+--source include/assert_grep.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 00000000000..821175220ac
--- /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 00000000000..8575d99f066
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test
@@ -0,0 +1,101 @@
+#
+# 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 ...
+--let $galera_sync_point = ist_sender_send_after_get_buffers
+--source include/galera_set_sync_point.inc
+
+# ... 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
+--source include/galera_clear_sync_point.inc
+--source include/galera_signal_sync_point.inc
+
+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
+
+sleep 5;
+
+# 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 00000000000..7d80d8036a1
--- /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_bootstrap.cnf b/mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.cnf
new file mode 100644
index 00000000000..d560b675427
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.cnf
@@ -0,0 +1,5 @@
+# We need a dedicated .cnf file, even if empty, in order to force this test to run
+# alone on a freshly started cluster. Otherwise there are adverse interactions with
+# prior tests such as galera_3nodes.galera_innobackupex_backup
+
+!include ../galera_3nodes.cnf
diff --git a/mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.test b/mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.test
new file mode 100644
index 00000000000..f8381a3324b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_pc_bootstrap.test
@@ -0,0 +1,91 @@
+#
+# Test the operation of pc.bootstrap
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER);
+
+# Force all nodes to become non-primary
+--connection node_1
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+
+--sleep 10
+
+# Node #2 should be non-primary
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT variable_value = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+# Signal node #2 to bootstrap
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'pc.bootstrap=1';
+
+# Wait until node becomes available for queries again
+--source include/wait_until_connected_again.inc
+
+# Node #2 should now be a primary of a 1-node cluster
+
+SHOW STATUS LIKE 'wsrep_cluster_size';
+SHOW STATUS LIKE 'wsrep_cluster_status';
+
+# Perform an insert on node #2
+INSERT INTO t1 VALUES (1);
+
+# Reconnect all nodes
+--connection node_2
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+--sleep 10
+--source include/wait_until_connected_again.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+
+--connection node_1
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+--source include/wait_until_connected_again.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.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_3
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+--sleep 10
+--source include/wait_until_connected_again.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+# Check that all nodes have the same view of the database
+
+--connection node_1
+SELECT COUNT(*) FROM t1;
+
+--connection node_2
+SELECT COUNT(*) FROM t1;
+
+--connection node_3
+SELECT COUNT(*) FROM t1;
+
+# Test cleanup
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf
new file mode 100644
index 00000000000..57026ce6928
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf
@@ -0,0 +1,5 @@
+# We need a dedicated .cnf file, even if empty, in order to force this test to run
+# alone on a freshly started cluster. Otherwise there are adverse interactions with
+# following tests such as galera_3nodes.galera_var_dirty_reads2
+
+!include ../galera_3nodes.cnf
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 00000000000..c118b7481bc
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test
@@ -0,0 +1,128 @@
+#
+# 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
+
+--connection node_1
+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
+
+SET SESSION wsrep_on=OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'
+--source include/wait_condition.inc
+SET SESSION wsrep_on=ON;
+
+# 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 10
+--source include/wait_until_connected_again.inc
+
+# For Node #1, we expect a primary component of size 1
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.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 = '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';
+
+SET GLOBAL wsrep_provider_options = 'pc.weight=1';
+
+# 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
+
+SET GLOBAL wsrep_provider_options = 'pc.weight=1';
+--let $wait_condition = SELECT @@wsrep_provider_options LIKE '%pc.weight = 1%'
+--source include/wait_condition.inc
+
+CALL mtr.add_suppression('WSREP: gcs_caused\\(\\) returned -1');
+
+--connection node_2
+CALL mtr.add_suppression('overriding reported weight for');
+
+--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');
+CALL mtr.add_suppression('overriding reported weight for');
diff --git a/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test
new file mode 100644
index 00000000000..10322125acd
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test
@@ -0,0 +1,164 @@
+#
+# Test the safe_to_bootstrap in grastate.dat
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+#
+# At start, all grastate.dat files have safe_to_boostrap: 0
+#
+
+--let $assert_text= grastate.dat does not have 'safe_to_bootstrap: 0'
+--let $assert_select= safe_to_bootstrap: 0
+--let $assert_count= 1
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.3/data/grastate.dat
+--source include/assert_grep.inc
+
+#
+# Shut down one node
+#
+
+--connection node_2
+--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
+
+# Still, all grastate.dat files should have safe_to_boostrap: 0
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.3/data/grastate.dat
+--source include/assert_grep.inc
+
+#
+# Shut down one more node
+#
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+--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
+
+# Now, nodes 2,3 should have safe_to_boostrap: 0
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.3/data/grastate.dat
+--source include/assert_grep.inc
+
+# But node #1 should have safe_to_boostrap: 1
+
+--let $assert_text= grastate.dat does not have 'safe_to_bootstrap: 1'
+--let $assert_select= safe_to_bootstrap: 1
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--source include/assert_grep.inc
+
+# Restart one node
+
+--connection node_2
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_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
+
+# All nodes should be back to 'safe_to_bootstrap: 0'
+
+--let $assert_text= grastate.dat does not have 'safe_to_bootstrap: 0'
+--let $assert_select= safe_to_bootstrap: 0
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+--source include/assert_grep.inc
+
+--let $assert_file= $MYSQLTEST_VARDIR/mysqld.3/data/grastate.dat
+--source include/assert_grep.inc
+
+#
+# Kill the cluster
+#
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+SET SESSION wsrep_on = OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+--source ../galera/include/kill_galera.inc
+
+#
+# Only node #1 should have safe_to_bootstrap: 1
+# include/assert_grep.inc requires a running server, so we revert to simple grep
+#
+
+--error 0
+--exec grep 'safe_to_bootstrap: 1' $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+
+--error 0
+--exec grep 'safe_to_bootstrap: 0' $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
+--error 0
+--exec grep 'safe_to_bootstrap: 0' $MYSQLTEST_VARDIR/mysqld.3/data/grastate.dat
+
+#
+# Attempt to bootstrap nodes #2, #3, should fail
+#
+
+--error 1
+--exec $MYSQLD --defaults-group-suffix=.2 --defaults-file=$MYSQLTEST_VARDIR/my.cnf --wsrep-new-cluster | grep 'This node is not safe to bootstrap the cluster'
+--error 1
+--exec $MYSQLD --defaults-group-suffix=.3 --defaults-file=$MYSQLTEST_VARDIR/my.cnf --wsrep-new-cluster | grep 'This node is not safe to bootstrap the cluster'
+
+#
+# Attempt to bootstrap starting from node #1, should succeed
+#
+
+--connection node_1
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--connection node_2
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
+
+--connection node_3
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
+--source include/start_mysqld.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+--connection node_2
+CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+
+--connection node_3
+CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+SHOW CREATE TABLE t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_slave_options_do.cnf b/mysql-test/suite/galera_3nodes/t/galera_slave_options_do.cnf
new file mode 100644
index 00000000000..1ebde6186c1
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_slave_options_do.cnf
@@ -0,0 +1,7 @@
+!include ../galera_3nodes.cnf
+
+[mysqld.1]
+binlog-do-db=db2
+
+[mysqld.2]
+replicate-wild-do-table=db2.t2B
diff --git a/mysql-test/suite/galera_3nodes/t/galera_slave_options_do.test b/mysql-test/suite/galera_3nodes/t/galera_slave_options_do.test
new file mode 100644
index 00000000000..1437c90c670
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_slave_options_do.test
@@ -0,0 +1,34 @@
+#
+# This tests checks the operation of binlog-do-db , replicate-wild-do-table
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+
+CREATE TABLE db1.t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2A (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2B (f1 INTEGER) ENGINE=InnoDB;
+
+INSERT INTO db1.t1 VALUES (1);
+INSERT INTO db2.t2A VALUES (2);
+INSERT INTO db2.t2B VALUES (3);
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM db1.t1;
+SELECT COUNT(*) = 0 FROM db2.t2A;
+SELECT COUNT(*) = 1 FROM db2.t2B;
+
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+SELECT COUNT(*) = 0 FROM db1.t1;
+SELECT COUNT(*) = 1 FROM db2.t2A;
+SELECT COUNT(*) = 1 FROM db2.t2B;
+
+--connection node_1
+DROP SCHEMA db1;
+DROP SCHEMA db2;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.cnf b/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.cnf
new file mode 100644
index 00000000000..9b78d47e254
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.cnf
@@ -0,0 +1,7 @@
+!include ../galera_3nodes.cnf
+
+[mysqld.1]
+binlog-ignore-db=db1
+
+[mysqld.2]
+replicate-wild-ignore-table=db2.t2A
diff --git a/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test b/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test
new file mode 100644
index 00000000000..3e8b1557e7b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test
@@ -0,0 +1,34 @@
+#
+# This tests checks the operation of binlog-ignore-db , replicate-wild-ignore-table
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+
+CREATE TABLE db1.t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2A (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE db2.t2B (f1 INTEGER) ENGINE=InnoDB;
+
+INSERT INTO db1.t1 VALUES (1);
+INSERT INTO db2.t2A VALUES (2);
+INSERT INTO db2.t2B VALUES (3);
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM db1.t1;
+SELECT COUNT(*) = 0 FROM db2.t2A;
+SELECT COUNT(*) = 1 FROM db2.t2B;
+
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+SELECT COUNT(*) = 0 FROM db1.t1;
+SELECT COUNT(*) = 1 FROM db2.t2A;
+SELECT COUNT(*) = 1 FROM db2.t2B;
+
+--connection node_1
+DROP SCHEMA db1;
+DROP SCHEMA db2;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test b/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test
new file mode 100644
index 00000000000..129ba2e1f38
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test
@@ -0,0 +1,112 @@
+#
+# Additional tests for wsrep_dirty_reads
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--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
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+SET SESSION wsrep_dirty_reads = 1;
+
+# Those statements should succeed
+
+--error 0
+SELECT f1 FROM t1;
+
+--error 0
+USE test;
+
+--error 0
+SHOW CREATE TABLE t1;
+
+--error 0
+LOCK TABLE t1 WRITE;
+
+--error 0
+UNLOCK TABLES;
+
+--error 0
+FLUSH TABLES WITH READ LOCK;
+
+--error 0
+UNLOCK TABLES;
+
+--error 0
+PREPARE stmt_select FROM 'SELECT f1 FROM t1';
+
+--error 0
+EXECUTE stmt_select;
+
+--error 0
+PREPARE stmt_update FROM 'UPDATE t1 SET f1 = f1 + f1';
+
+# Mysqldump should succeed
+
+SET GLOBAL wsrep_dirty_reads = 1;
+SET GLOBAL wsrep_sync_wait = 0;
+--error 0
+--exec $MYSQL_DUMP -u root -S $NODE_MYSOCK_2 test >/dev/null
+SET GLOBAL wsrep_dirty_reads = 0;
+SET GLOBAL wsrep_sync_wait = 15;
+
+# Those statements should fail
+
+SET SESSION wsrep_dirty_reads = 1;
+
+--error ER_UNKNOWN_COM_ERROR
+INSERT INTO t1 SELECT * FROM t1;
+
+--error ER_UNKNOWN_COM_ERROR
+DELETE FROM t1;
+
+--error ER_UNKNOWN_COM_ERROR
+UPDATE t1 SET f1 = f1 + 1;
+
+--error ER_UNKNOWN_COM_ERROR
+DROP TABLE t1;
+
+--error ER_UNKNOWN_COM_ERROR
+EXECUTE stmt_update;
+
+# With wsrep_dirty_reads = 0 , even SELECTS are not allowed
+
+SET SESSION wsrep_dirty_reads = 0;
+
+--error ER_UNKNOWN_COM_ERROR
+SELECT * FROM t1;
+
+--error ER_UNKNOWN_COM_ERROR
+EXECUTE stmt_select;
+
+# But reads from INFORMATION_SCHEMA are allowed
+
+--error 0
+SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST;
+
+# Restore cluster
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result
index 4af674adc6a..a34f6aec831 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
@@ -874,7 +875,7 @@ ERROR 22003: Out of range value for column 'c1' at row 1
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
@@ -1264,7 +1265,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
@@ -1282,7 +1283,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/r/innodb_uninstall.result b/mysql-test/suite/innodb/r/innodb_uninstall.result
index 2064269a02e..d0270c1cf3e 100644
--- a/mysql-test/suite/innodb/r/innodb_uninstall.result
+++ b/mysql-test/suite/innodb/r/innodb_uninstall.result
@@ -1,4 +1,6 @@
install plugin innodb soname 'ha_innodb';
+Warnings:
+Warning 1105 Cannot enable tc-log at run-time. XA features of InnoDB are disabled
create table t1(a int not null primary key) engine=innodb;
begin;
insert into t1 values(1);
@@ -11,6 +13,8 @@ Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
drop table t1;
install plugin innodb soname 'ha_innodb';
+Warnings:
+Warning 1105 Cannot enable tc-log at run-time. XA features of InnoDB are disabled
create table t2(a int not null primary key) engine=innodb;
insert into t2 values(1);
drop table t2;
diff --git a/mysql-test/suite/innodb/t/galera.skip b/mysql-test/suite/innodb/t/galera.skip
new file mode 100644
index 00000000000..fbc9e466ddb
--- /dev/null
+++ b/mysql-test/suite/innodb/t/galera.skip
@@ -0,0 +1,49 @@
+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
+innodb-lock-inherit-read_commited : Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT
+innodb-index-debug : Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT
+flush-hang : Unsafe statement written to the binary log
+innodb_deadlock_with_autoinc : Test uses autoinc_lock_mode = 0
+innodb_stats_del_mark : Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
+
diff --git a/mysql-test/suite/innodb/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test
index 9835a9779cf..48da99bd67c 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 1467
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);
@@ -446,7 +448,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);
@@ -642,7 +644,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);
@@ -654,7 +656,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/innodb/t/innodb_bug27216817.test b/mysql-test/suite/innodb/t/innodb_bug27216817.test
deleted file mode 100644
index a93932b4a04..00000000000
--- a/mysql-test/suite/innodb/t/innodb_bug27216817.test
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# BUG#27216817: INNODB: FAILING ASSERTION:
-# PREBUILT->TABLE->N_MYSQL_HANDLES_OPENED == 1
-#
-
-source include/have_innodb.inc;
-create table t1 (a int not null, b int not null) engine=innodb;
-insert t1 values (1,2),(3,4);
-
-lock table t1 write, t1 tr read;
-flush status;
-alter table t1 add primary key (b);
-show status like 'Handler_read_rnd_next';
-unlock tables;
-alter table t1 drop primary key;
-
-lock table t1 write;
-flush status;
-alter table t1 add primary key (b);
-show status like 'Handler_read_rnd_next';
-unlock tables;
-alter table t1 drop primary key;
-
-flush status;
-alter table t1 add primary key (b);
-show status like 'Handler_read_rnd_next';
-
-drop table t1;
diff --git a/mysql-test/suite/jp/disabled.def b/mysql-test/suite/jp/disabled.def
index 888298bbb09..b74382895d2 100644
--- a/mysql-test/suite/jp/disabled.def
+++ b/mysql-test/suite/jp/disabled.def
@@ -9,3 +9,5 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
+
+binlog_index : codership/mysql-wsrep##71 Regression: Duplicate "file was not purged because it is the active log file" warning
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 77b91f19e8f..7193a6c99a1 100755
--- 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 4f569605f5f..a87d658cfb6 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/rpl_statements.result b/mysql-test/suite/perfschema/r/rpl_statements.result
index 42ced0f5e10..081710f1d54 100644
--- a/mysql-test/suite/perfschema/r/rpl_statements.result
+++ b/mysql-test/suite/perfschema/r/rpl_statements.result
@@ -11,7 +11,7 @@ include/master-slave.inc
*** 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;
@@ -55,7 +55,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/rpl_statements.test b/mysql-test/suite/perfschema/t/rpl_statements.test
index 1aa52efd937..4f65cdcbd7b 100644
--- a/mysql-test/suite/perfschema/t/rpl_statements.test
+++ b/mysql-test/suite/perfschema/t/rpl_statements.test
@@ -64,7 +64,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;
@@ -129,7 +129,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/mysql-wsrep#110-2.result b/mysql-test/suite/rpl/r/mysql-wsrep#110-2.result
new file mode 100644
index 00000000000..fd07dfce188
--- /dev/null
+++ b/mysql-test/suite/rpl/r/mysql-wsrep#110-2.result
@@ -0,0 +1,24 @@
+include/master-slave.inc
+[connection master]
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t3 (f1 INTEGER PRIMARY KEY);
+CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1);
+CREATE PROCEDURE p1 (IN x INT)
+BEGIN
+DECLARE EXIT HANDLER FOR SQLEXCEPTION
+BEGIN
+ROLLBACK TO event_logging;
+INSERT t3 VALUES (x);
+END;
+SAVEPOINT event_logging;
+INSERT INTO t2 VALUES (x);
+RELEASE SAVEPOINT event_logging;
+END|
+INSERT INTO t2 VALUES (1);
+INSERT INTO t1 VALUES (1);
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
+DROP PROCEDURE p1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/mysql-wsrep#110-2.test b/mysql-test/suite/rpl/t/mysql-wsrep#110-2.test
new file mode 100644
index 00000000000..2b6d07913ab
--- /dev/null
+++ b/mysql-test/suite/rpl/t/mysql-wsrep#110-2.test
@@ -0,0 +1,44 @@
+#
+# codership/mysql-wsrep/110 - Assertion `table_found' failed in unpack_row() with SAVEPOINT, trigger, error handler
+#
+
+--source include/have_innodb.inc
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t3 (f1 INTEGER PRIMARY KEY);
+
+CREATE TRIGGER tr1 AFTER INSERT ON t1 FOR EACH ROW CALL p1(NEW.f1);
+
+DELIMITER |;
+
+CREATE PROCEDURE p1 (IN x INT)
+BEGIN
+ DECLARE EXIT HANDLER FOR SQLEXCEPTION
+ BEGIN
+ ROLLBACK TO event_logging;
+ INSERT t3 VALUES (x);
+ END;
+ SAVEPOINT event_logging;
+
+ INSERT INTO t2 VALUES (x);
+
+ RELEASE SAVEPOINT event_logging;
+END|
+DELIMITER ;|
+
+INSERT INTO t2 VALUES (1);
+INSERT INTO t1 VALUES (1);
+
+
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
+
+DROP PROCEDURE p1;
+
+sync_slave_with_master;
+--source include/rpl_end.inc
+
diff --git a/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result b/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result
new file mode 100644
index 00000000000..bfb6b67b5d8
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result
@@ -0,0 +1,45 @@
+#
+# innodb_disallow_writes
+#
+# save the initial value
+SET @innodb_disallow_writes_global_saved = @@global.innodb_disallow_writes;
+# default
+SELECT @@global.innodb_disallow_writes;
+@@global.innodb_disallow_writes
+0
+
+# scope
+SELECT @@session.innodb_disallow_writes;
+ERROR HY000: Variable 'innodb_disallow_writes' is a GLOBAL variable
+SET @@global.innodb_disallow_writes=OFF;
+SELECT @@global.innodb_disallow_writes;
+@@global.innodb_disallow_writes
+0
+SET @@global.innodb_disallow_writes=ON;
+SELECT @@global.innodb_disallow_writes;
+@@global.innodb_disallow_writes
+1
+
+# valid values
+SET @@global.innodb_disallow_writes='OFF';
+SELECT @@global.innodb_disallow_writes;
+@@global.innodb_disallow_writes
+0
+SET @@global.innodb_disallow_writes=ON;
+SELECT @@global.innodb_disallow_writes;
+@@global.innodb_disallow_writes
+1
+SET @@global.innodb_disallow_writes=default;
+SELECT @@global.innodb_disallow_writes;
+@@global.innodb_disallow_writes
+0
+
+# invalid values
+SET @@global.innodb_disallow_writes=NULL;
+ERROR 42000: Variable 'innodb_disallow_writes' can't be set to the value of 'NULL'
+SET @@global.innodb_disallow_writes='junk';
+ERROR 42000: Variable 'innodb_disallow_writes' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.innodb_disallow_writes = @innodb_disallow_writes_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/log_tc_size_basic.result b/mysql-test/suite/sys_vars/r/log_tc_size_basic.result
new file mode 100644
index 00000000000..8097fcf61bd
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/log_tc_size_basic.result
@@ -0,0 +1,4 @@
+SET GLOBAL log_tc_size=1;
+ERROR HY000: Variable 'log_tc_size' is a read only variable
+SET SESSION log_tc_size=1;
+ERROR HY000: Variable 'log_tc_size' is a read only variable
diff --git a/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result
new file mode 100644
index 00000000000..2608e58b986
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_auto_increment_control_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_auto_increment_control
+#
+# save the initial value
+SET @wsrep_auto_increment_control_global_saved = @@global.wsrep_auto_increment_control;
+# default
+SELECT @@global.wsrep_auto_increment_control;
+@@global.wsrep_auto_increment_control
+1
+
+# scope
+SELECT @@session.wsrep_auto_increment_control;
+ERROR HY000: Variable 'wsrep_auto_increment_control' is a GLOBAL variable
+SET @@global.wsrep_auto_increment_control=OFF;
+SELECT @@global.wsrep_auto_increment_control;
+@@global.wsrep_auto_increment_control
+0
+SET @@global.wsrep_auto_increment_control=ON;
+SELECT @@global.wsrep_auto_increment_control;
+@@global.wsrep_auto_increment_control
+1
+
+# valid values
+SET @@global.wsrep_auto_increment_control='OFF';
+SELECT @@global.wsrep_auto_increment_control;
+@@global.wsrep_auto_increment_control
+0
+SET @@global.wsrep_auto_increment_control=ON;
+SELECT @@global.wsrep_auto_increment_control;
+@@global.wsrep_auto_increment_control
+1
+SET @@global.wsrep_auto_increment_control=default;
+SELECT @@global.wsrep_auto_increment_control;
+@@global.wsrep_auto_increment_control
+1
+
+# invalid values
+SET @@global.wsrep_auto_increment_control=NULL;
+ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of 'NULL'
+SET @@global.wsrep_auto_increment_control='junk';
+ERROR 42000: Variable 'wsrep_auto_increment_control' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_auto_increment_control = @wsrep_auto_increment_control_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result
new file mode 100644
index 00000000000..501117dda9f
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_causal_reads_basic.result
@@ -0,0 +1,50 @@
+#
+# wsrep_causal_reads
+#
+# save the initial values
+SET @wsrep_causal_reads_global_saved = @@global.wsrep_causal_reads;
+SET @wsrep_causal_reads_session_saved = @@session.wsrep_causal_reads;
+# default
+SELECT @@global.wsrep_causal_reads;
+@@global.wsrep_causal_reads
+0
+SELECT @@session.wsrep_causal_reads;
+@@session.wsrep_causal_reads
+0
+
+# scope and valid values
+SET @@global.wsrep_causal_reads=OFF;
+SELECT @@global.wsrep_causal_reads;
+@@global.wsrep_causal_reads
+0
+SET @@global.wsrep_causal_reads=ON;
+SELECT @@global.wsrep_causal_reads;
+@@global.wsrep_causal_reads
+1
+SET @@session.wsrep_causal_reads=OFF;
+SELECT @@session.wsrep_causal_reads;
+@@session.wsrep_causal_reads
+0
+SET @@session.wsrep_causal_reads=ON;
+SELECT @@session.wsrep_causal_reads;
+@@session.wsrep_causal_reads
+1
+SET @@session.wsrep_causal_reads=default;
+SELECT @@session.wsrep_causal_reads;
+@@session.wsrep_causal_reads
+1
+
+# invalid values
+SET @@global.wsrep_causal_reads=NULL;
+ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'NULL'
+SET @@global.wsrep_causal_reads='junk';
+ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'junk'
+SET @@session.wsrep_causal_reads=NULL;
+ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'NULL'
+SET @@session.wsrep_causal_reads='junk';
+ERROR 42000: Variable 'wsrep_causal_reads' can't be set to the value of 'junk'
+
+# restore the initial values
+SET @@global.wsrep_causal_reads = @wsrep_causal_reads_global_saved;
+SET @@session.wsrep_causal_reads = @wsrep_causal_reads_session_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result
new file mode 100644
index 00000000000..7200d14f75f
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_certify_nonpk_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_certify_nonpk
+#
+# save the initial value
+SET @wsrep_certify_nonpk_global_saved = @@global.wsrep_certify_nonpk;
+# default
+SELECT @@global.wsrep_certify_nonpk;
+@@global.wsrep_certify_nonpk
+1
+
+# scope
+SELECT @@session.wsrep_certify_nonpk;
+ERROR HY000: Variable 'wsrep_certify_nonPK' is a GLOBAL variable
+SET @@global.wsrep_certify_nonpk=OFF;
+SELECT @@global.wsrep_certify_nonpk;
+@@global.wsrep_certify_nonpk
+0
+SET @@global.wsrep_certify_nonpk=ON;
+SELECT @@global.wsrep_certify_nonpk;
+@@global.wsrep_certify_nonpk
+1
+
+# valid values
+SET @@global.wsrep_certify_nonpk='OFF';
+SELECT @@global.wsrep_certify_nonpk;
+@@global.wsrep_certify_nonpk
+0
+SET @@global.wsrep_certify_nonpk=ON;
+SELECT @@global.wsrep_certify_nonpk;
+@@global.wsrep_certify_nonpk
+1
+SET @@global.wsrep_certify_nonpk=default;
+SELECT @@global.wsrep_certify_nonpk;
+@@global.wsrep_certify_nonpk
+1
+
+# invalid values
+SET @@global.wsrep_certify_nonpk=NULL;
+ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of 'NULL'
+SET @@global.wsrep_certify_nonpk='junk';
+ERROR 42000: Variable 'wsrep_certify_nonPK' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_certify_nonpk = @wsrep_certify_nonpk_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result
new file mode 100644
index 00000000000..8497e220523
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_address_basic.result
@@ -0,0 +1,54 @@
+#
+# wsrep_cluster_address
+#
+call mtr.add_suppression("safe_mutex: Found wrong usage of mutex.*");
+# save the initial value
+SET @wsrep_cluster_address_global_saved = @@global.wsrep_cluster_address;
+# default
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+
+
+# scope
+SELECT @@session.wsrep_cluster_address;
+ERROR HY000: Variable 'wsrep_cluster_address' is a GLOBAL variable
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+
+
+# valid values
+SET @@global.wsrep_cluster_address='127.0.0.1';
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+127.0.0.1
+SET @@global.wsrep_cluster_address=AUTO;
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+AUTO
+SET @@global.wsrep_cluster_address=default;
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+
+
+# invalid values
+SET @@global.wsrep_node_address=NULL;
+ERROR 42000: Variable 'wsrep_node_address' can't be set to the value of 'NULL'
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+
+SET @@global.wsrep_cluster_address=ON;
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+ON
+SET @@global.wsrep_cluster_address='OFF';
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+OFF
+SET @@global.wsrep_cluster_address='junk';
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+junk
+
+# restore the initial value
+SET @@global.wsrep_cluster_address = @wsrep_cluster_address_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result
new file mode 100644
index 00000000000..29a2d966489
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_cluster_name_basic.result
@@ -0,0 +1,43 @@
+#
+# wsrep_cluster_name
+#
+# save the initial value
+SET @wsrep_cluster_name_global_saved = @@global.wsrep_cluster_name;
+# default
+SELECT @@global.wsrep_cluster_name;
+@@global.wsrep_cluster_name
+my_wsrep_cluster
+
+# scope
+SELECT @@session.wsrep_cluster_name;
+ERROR HY000: Variable 'wsrep_cluster_name' is a GLOBAL variable
+SET @@global.wsrep_cluster_name='my_galera_cluster';
+SELECT @@global.wsrep_cluster_name;
+@@global.wsrep_cluster_name
+my_galera_cluster
+
+# valid values
+SET @@global.wsrep_cluster_name='my_quoted_galera_cluster';
+SELECT @@global.wsrep_cluster_name;
+@@global.wsrep_cluster_name
+my_quoted_galera_cluster
+SET @@global.wsrep_cluster_name=my_unquoted_cluster;
+SELECT @@global.wsrep_cluster_name;
+@@global.wsrep_cluster_name
+my_unquoted_cluster
+SET @@global.wsrep_cluster_name=OFF;
+SELECT @@global.wsrep_cluster_name;
+@@global.wsrep_cluster_name
+OFF
+SET @@global.wsrep_cluster_name=default;
+SELECT @@global.wsrep_cluster_name;
+@@global.wsrep_cluster_name
+my_wsrep_cluster
+
+# invalid values
+SET @@global.wsrep_cluster_name=NULL;
+ERROR 42000: Variable 'wsrep_cluster_name' can't be set to the value of 'NULL'
+
+# restore the initial value
+SET @@global.wsrep_cluster_name = @wsrep_cluster_name_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result
new file mode 100644
index 00000000000..80210c4c4b6
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_convert_lock_to_trx_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_convert_lock_to_trx
+#
+# save the initial value
+SET @wsrep_convert_lock_to_trx_global_saved = @@global.wsrep_convert_lock_to_trx;
+# default
+SELECT @@global.wsrep_convert_lock_to_trx;
+@@global.wsrep_convert_lock_to_trx
+0
+
+# scope
+SELECT @@session.wsrep_convert_lock_to_trx;
+ERROR HY000: Variable 'wsrep_convert_LOCK_to_trx' is a GLOBAL variable
+SET @@global.wsrep_convert_lock_to_trx=OFF;
+SELECT @@global.wsrep_convert_lock_to_trx;
+@@global.wsrep_convert_lock_to_trx
+0
+SET @@global.wsrep_convert_lock_to_trx=ON;
+SELECT @@global.wsrep_convert_lock_to_trx;
+@@global.wsrep_convert_lock_to_trx
+1
+
+# valid values
+SET @@global.wsrep_convert_lock_to_trx='OFF';
+SELECT @@global.wsrep_convert_lock_to_trx;
+@@global.wsrep_convert_lock_to_trx
+0
+SET @@global.wsrep_convert_lock_to_trx=ON;
+SELECT @@global.wsrep_convert_lock_to_trx;
+@@global.wsrep_convert_lock_to_trx
+1
+SET @@global.wsrep_convert_lock_to_trx=default;
+SELECT @@global.wsrep_convert_lock_to_trx;
+@@global.wsrep_convert_lock_to_trx
+0
+
+# invalid values
+SET @@global.wsrep_convert_lock_to_trx=NULL;
+ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of 'NULL'
+SET @@global.wsrep_convert_lock_to_trx='junk';
+ERROR 42000: Variable 'wsrep_convert_LOCK_to_trx' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_convert_lock_to_trx = @wsrep_convert_lock_to_trx_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result
new file mode 100644
index 00000000000..e0f4b478c90
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_data_home_dir_basic.result
@@ -0,0 +1,59 @@
+#
+# wsrep_data_home_dir (readonly)
+#
+# default
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+
+# scope
+SELECT @@session.wsrep_data_home_dir;
+ERROR HY000: Variable 'wsrep_data_home_dir' is a GLOBAL variable
+SET @@global.wsrep_data_home_dir='/tmp/data';
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+
+# valid values
+SET @@global.wsrep_data_home_dir='/tmp/data';
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+SET @@global.wsrep_data_home_dir=junk-dir;
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+SET @@global.wsrep_data_home_dir=junk/dir;
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+SET @@global.wsrep_data_home_dir=OFF;
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+SET @@global.wsrep_data_home_dir=default;
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+SELECT COUNT(@@global.wsrep_data_home_dir);
+COUNT(@@global.wsrep_data_home_dir)
+1
+
+# invalid values
+SET @@global.wsrep_data_home_dir=NULL;
+ERROR HY000: Variable 'wsrep_data_home_dir' is a read only variable
+#
+# MDEV-6717 : wsrep_data_home_dir should default to @@datadir
+#
+SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='datadir';
+@@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE
+1
+SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='wsrep_data_home_dir';
+@@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE
+1
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result
new file mode 100644
index 00000000000..2092d54681e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_dbug_option_basic.result
@@ -0,0 +1,47 @@
+#
+# wsrep_dbug_option
+#
+# save the initial value
+SET @wsrep_dbug_option_global_saved = @@global.wsrep_dbug_option;
+# default
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+
+
+# scope
+SELECT @@session.wsrep_dbug_option;
+ERROR HY000: Variable 'wsrep_dbug_option' is a GLOBAL variable
+SET @@global.wsrep_dbug_option='test-dbug-string';
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+test-dbug-string
+
+# valid values
+SET @@global.wsrep_dbug_option='quoted-dbug-string';
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+quoted-dbug-string
+SET @@global.wsrep_dbug_option=unquoted_dbug_string;
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+unquoted_dbug_string
+SET @@global.wsrep_dbug_option=OFF;
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+OFF
+SET @@global.wsrep_dbug_option=NULL;
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+NULL
+SET @@global.wsrep_dbug_option=default;
+SELECT @@global.wsrep_dbug_option;
+@@global.wsrep_dbug_option
+
+
+# invalid values
+SET @@global.wsrep_dbug_option=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_dbug_option'
+
+# restore the initial value
+SET @@global.wsrep_dbug_option = @wsrep_dbug_option_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result
new file mode 100644
index 00000000000..96c262c110c
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_debug_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_debug
+#
+# save the initial value
+SET @wsrep_debug_global_saved = @@global.wsrep_debug;
+# default
+SELECT @@global.wsrep_debug;
+@@global.wsrep_debug
+0
+
+# scope
+SELECT @@session.wsrep_debug;
+ERROR HY000: Variable 'wsrep_debug' is a GLOBAL variable
+SET @@global.wsrep_debug=OFF;
+SELECT @@global.wsrep_debug;
+@@global.wsrep_debug
+0
+SET @@global.wsrep_debug=ON;
+SELECT @@global.wsrep_debug;
+@@global.wsrep_debug
+1
+
+# valid values
+SET @@global.wsrep_debug='OFF';
+SELECT @@global.wsrep_debug;
+@@global.wsrep_debug
+0
+SET @@global.wsrep_debug=ON;
+SELECT @@global.wsrep_debug;
+@@global.wsrep_debug
+1
+SET @@global.wsrep_debug=default;
+SELECT @@global.wsrep_debug;
+@@global.wsrep_debug
+0
+
+# invalid values
+SET @@global.wsrep_debug=NULL;
+ERROR 42000: Variable 'wsrep_debug' can't be set to the value of 'NULL'
+SET @@global.wsrep_debug='junk';
+ERROR 42000: Variable 'wsrep_debug' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_debug = @wsrep_debug_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result
new file mode 100644
index 00000000000..5cd2a2e5720
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result
@@ -0,0 +1,56 @@
+#
+# wsrep_desync
+#
+call mtr.add_suppression("WSREP: SET desync failed 9 for schema: test, query: SET @@global.wsrep_desync=ON");
+# save the initial value
+SET @wsrep_desync_global_saved = @@global.wsrep_desync;
+# default
+SELECT @@global.wsrep_desync;
+@@global.wsrep_desync
+0
+
+# scope
+SELECT @@session.wsrep_desync;
+ERROR HY000: Variable 'wsrep_desync' is a GLOBAL variable
+SET @@global.wsrep_desync=OFF;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+SELECT @@global.wsrep_desync;
+@@global.wsrep_desync
+0
+SET @@global.wsrep_desync=ON;
+ERROR HY000: Operation 'desync' failed for SET @@global.wsrep_desync=ON
+SELECT @@global.wsrep_desync;
+@@global.wsrep_desync
+0
+
+# valid values
+SET @@global.wsrep_desync='OFF';
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+SELECT @@global.wsrep_desync;
+@@global.wsrep_desync
+0
+SET @@global.wsrep_desync=ON;
+ERROR HY000: Operation 'desync' failed for SET @@global.wsrep_desync=ON
+SELECT @@global.wsrep_desync;
+@@global.wsrep_desync
+0
+SET @@global.wsrep_desync=default;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+SELECT @@global.wsrep_desync;
+@@global.wsrep_desync
+0
+
+# invalid values
+SET @@global.wsrep_desync=NULL;
+ERROR 42000: Variable 'wsrep_desync' can't be set to the value of 'NULL'
+SET @@global.wsrep_desync='junk';
+ERROR 42000: Variable 'wsrep_desync' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_desync = @wsrep_desync_global_saved;
+Warnings:
+Warning 1231 'wsrep_desync' is already OFF.
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result
new file mode 100644
index 00000000000..1968103873a
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_dirty_reads_basic.result
@@ -0,0 +1,54 @@
+#
+# wsrep_dirty_reads
+#
+# save the initial value
+SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads;
+# default
+SELECT @@global.wsrep_dirty_reads;
+@@global.wsrep_dirty_reads
+0
+SELECT @@session.wsrep_dirty_reads;
+@@session.wsrep_dirty_reads
+0
+
+# valid values for session
+SET @@session.wsrep_dirty_reads=OFF;
+SELECT @@session.wsrep_dirty_reads;
+@@session.wsrep_dirty_reads
+0
+SET @@session.wsrep_dirty_reads=ON;
+SELECT @@session.wsrep_dirty_reads;
+@@session.wsrep_dirty_reads
+1
+SET @@session.wsrep_dirty_reads=default;
+SELECT @@session.wsrep_dirty_reads;
+@@session.wsrep_dirty_reads
+0
+
+# valid values for global
+SET @@global.wsrep_dirty_reads=OFF;
+SELECT @@global.wsrep_dirty_reads;
+@@global.wsrep_dirty_reads
+0
+SET @@global.wsrep_dirty_reads=ON;
+SELECT @@global.wsrep_dirty_reads;
+@@global.wsrep_dirty_reads
+1
+SET @@global.wsrep_dirty_reads=default;
+SELECT @@global.wsrep_dirty_reads;
+@@global.wsrep_dirty_reads
+0
+
+# invalid values
+SET @@session.wsrep_dirty_reads=NULL;
+ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL'
+SET @@session.wsrep_dirty_reads='junk';
+ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk'
+SET @@global.wsrep_dirty_reads=NULL;
+ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'NULL'
+SET @@global.wsrep_dirty_reads='junk';
+ERROR 42000: Variable 'wsrep_dirty_reads' can't be set to the value of 'junk'
+
+# restore the initial values
+SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result
new file mode 100644
index 00000000000..52bfc01e810
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_drupal_282555_workaround_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_drupal_282555_workaround
+#
+# save the initial value
+SET @wsrep_drupal_282555_workaround_global_saved = @@global.wsrep_drupal_282555_workaround;
+# default
+SELECT @@global.wsrep_drupal_282555_workaround;
+@@global.wsrep_drupal_282555_workaround
+0
+
+# scope
+SELECT @@session.wsrep_drupal_282555_workaround;
+ERROR HY000: Variable 'wsrep_drupal_282555_workaround' is a GLOBAL variable
+SET @@global.wsrep_drupal_282555_workaround=OFF;
+SELECT @@global.wsrep_drupal_282555_workaround;
+@@global.wsrep_drupal_282555_workaround
+0
+SET @@global.wsrep_drupal_282555_workaround=ON;
+SELECT @@global.wsrep_drupal_282555_workaround;
+@@global.wsrep_drupal_282555_workaround
+1
+
+# valid values
+SET @@global.wsrep_drupal_282555_workaround='OFF';
+SELECT @@global.wsrep_drupal_282555_workaround;
+@@global.wsrep_drupal_282555_workaround
+0
+SET @@global.wsrep_drupal_282555_workaround=ON;
+SELECT @@global.wsrep_drupal_282555_workaround;
+@@global.wsrep_drupal_282555_workaround
+1
+SET @@global.wsrep_drupal_282555_workaround=default;
+SELECT @@global.wsrep_drupal_282555_workaround;
+@@global.wsrep_drupal_282555_workaround
+0
+
+# invalid values
+SET @@global.wsrep_drupal_282555_workaround=NULL;
+ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of 'NULL'
+SET @@global.wsrep_drupal_282555_workaround='junk';
+ERROR 42000: Variable 'wsrep_drupal_282555_workaround' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_drupal_282555_workaround = @wsrep_drupal_282555_workaround_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result
new file mode 100644
index 00000000000..3cf5ffcaf4e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_forced_binlog_format_basic.result
@@ -0,0 +1,51 @@
+#
+# wsrep_forced_binlog_format
+#
+# save the initial value
+SET @wsrep_forced_binlog_format_global_saved = @@global.wsrep_forced_binlog_format;
+# default
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+NONE
+
+# scope
+SELECT @@session.wsrep_forced_binlog_format;
+ERROR HY000: Variable 'wsrep_forced_binlog_format' is a GLOBAL variable
+SET @@global.wsrep_forced_binlog_format=STATEMENT;
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+STATEMENT
+
+# valid values
+SET @@global.wsrep_forced_binlog_format=STATEMENT;
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+STATEMENT
+SET @@global.wsrep_forced_binlog_format=ROW;
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+ROW
+SET @@global.wsrep_forced_binlog_format=MIXED;
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+MIXED
+SET @@global.wsrep_forced_binlog_format=NONE;
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+NONE
+SET @@global.wsrep_forced_binlog_format=default;
+SELECT @@global.wsrep_forced_binlog_format;
+@@global.wsrep_forced_binlog_format
+NONE
+
+# invalid values
+SET @@global.wsrep_forced_binlog_format=NULL;
+ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'NULL'
+SET @@global.wsrep_forced_binlog_format='junk';
+ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'junk'
+SET @@global.wsrep_forced_binlog_format=ON;
+ERROR 42000: Variable 'wsrep_forced_binlog_format' can't be set to the value of 'ON'
+
+# restore the initial value
+SET @@global.wsrep_forced_binlog_format = @wsrep_forced_binlog_format_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result
new file mode 100644
index 00000000000..687934a7705
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_load_data_splitting_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_load_data_splitting
+#
+# save the initial value
+SET @wsrep_load_data_splitting_global_saved = @@global.wsrep_load_data_splitting;
+# default
+SELECT @@global.wsrep_load_data_splitting;
+@@global.wsrep_load_data_splitting
+1
+
+# scope
+SELECT @@session.wsrep_load_data_splitting;
+ERROR HY000: Variable 'wsrep_load_data_splitting' is a GLOBAL variable
+SET @@global.wsrep_load_data_splitting=OFF;
+SELECT @@global.wsrep_load_data_splitting;
+@@global.wsrep_load_data_splitting
+0
+SET @@global.wsrep_load_data_splitting=ON;
+SELECT @@global.wsrep_load_data_splitting;
+@@global.wsrep_load_data_splitting
+1
+
+# valid values
+SET @@global.wsrep_load_data_splitting='OFF';
+SELECT @@global.wsrep_load_data_splitting;
+@@global.wsrep_load_data_splitting
+0
+SET @@global.wsrep_load_data_splitting=ON;
+SELECT @@global.wsrep_load_data_splitting;
+@@global.wsrep_load_data_splitting
+1
+SET @@global.wsrep_load_data_splitting=default;
+SELECT @@global.wsrep_load_data_splitting;
+@@global.wsrep_load_data_splitting
+1
+
+# invalid values
+SET @@global.wsrep_load_data_splitting=NULL;
+ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of 'NULL'
+SET @@global.wsrep_load_data_splitting='junk';
+ERROR 42000: Variable 'wsrep_load_data_splitting' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_load_data_splitting = @wsrep_load_data_splitting_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result
new file mode 100644
index 00000000000..4d577daa904
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_log_conflicts_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_log_conflicts
+#
+# save the initial value
+SET @wsrep_log_conflicts_global_saved = @@global.wsrep_log_conflicts;
+# default
+SELECT @@global.wsrep_log_conflicts;
+@@global.wsrep_log_conflicts
+0
+
+# scope
+SELECT @@session.wsrep_log_conflicts;
+ERROR HY000: Variable 'wsrep_log_conflicts' is a GLOBAL variable
+SET @@global.wsrep_log_conflicts=OFF;
+SELECT @@global.wsrep_log_conflicts;
+@@global.wsrep_log_conflicts
+0
+SET @@global.wsrep_log_conflicts=ON;
+SELECT @@global.wsrep_log_conflicts;
+@@global.wsrep_log_conflicts
+1
+
+# valid values
+SET @@global.wsrep_log_conflicts='OFF';
+SELECT @@global.wsrep_log_conflicts;
+@@global.wsrep_log_conflicts
+0
+SET @@global.wsrep_log_conflicts=ON;
+SELECT @@global.wsrep_log_conflicts;
+@@global.wsrep_log_conflicts
+1
+SET @@global.wsrep_log_conflicts=default;
+SELECT @@global.wsrep_log_conflicts;
+@@global.wsrep_log_conflicts
+0
+
+# invalid values
+SET @@global.wsrep_log_conflicts=NULL;
+ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of 'NULL'
+SET @@global.wsrep_log_conflicts='junk';
+ERROR 42000: Variable 'wsrep_log_conflicts' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_log_conflicts = @wsrep_log_conflicts_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result
new file mode 100644
index 00000000000..d96bc8708c5
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result
@@ -0,0 +1,51 @@
+#
+# wsrep_max_ws_rows
+#
+# save the initial value
+SET @wsrep_max_ws_rows_global_saved = @@global.wsrep_max_ws_rows;
+# default
+SELECT @@global.wsrep_max_ws_rows;
+@@global.wsrep_max_ws_rows
+0
+
+# scope
+SELECT @@session.wsrep_max_ws_rows;
+ERROR HY000: Variable 'wsrep_max_ws_rows' is a GLOBAL variable
+SET @@global.wsrep_max_ws_rows=1;
+SELECT @@global.wsrep_max_ws_rows;
+@@global.wsrep_max_ws_rows
+1
+
+# valid values
+SET @@global.wsrep_max_ws_rows=131072;
+SELECT @@global.wsrep_max_ws_rows;
+@@global.wsrep_max_ws_rows
+131072
+SET @@global.wsrep_max_ws_rows=131073;
+SELECT @@global.wsrep_max_ws_rows;
+@@global.wsrep_max_ws_rows
+131073
+SET @@global.wsrep_max_ws_rows=0;
+SELECT @@global.wsrep_max_ws_rows;
+@@global.wsrep_max_ws_rows
+0
+SET @@global.wsrep_max_ws_rows=default;
+SELECT @global.wsrep_max_ws_rows;
+@global.wsrep_max_ws_rows
+NULL
+
+# invalid values
+SET @@global.wsrep_max_ws_rows=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_rows'
+SET @@global.wsrep_max_ws_rows='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_rows'
+SET @@global.wsrep_max_ws_rows=-1;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '-1'
+SELECT @global.wsrep_max_ws_rows;
+@global.wsrep_max_ws_rows
+NULL
+
+# restore the initial value
+SET @@global.wsrep_max_ws_rows = @wsrep_max_ws_rows_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result
new file mode 100644
index 00000000000..d7e72869be3
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result
@@ -0,0 +1,60 @@
+#
+# wsrep_max_ws_size
+#
+# save the initial value
+SET @wsrep_max_ws_size_global_saved = @@global.wsrep_max_ws_size;
+SET @wsrep_provider_options_saved = @@global.wsrep_provider_options;
+# default
+SELECT @@global.wsrep_max_ws_size;
+@@global.wsrep_max_ws_size
+2147483647
+
+# scope
+SELECT @@session.wsrep_max_ws_size;
+ERROR HY000: Variable 'wsrep_max_ws_size' is a GLOBAL variable
+SET @@global.wsrep_max_ws_size=1;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_max_ws_size value: '1'
+SELECT @@global.wsrep_max_ws_size;
+@@global.wsrep_max_ws_size
+1024
+
+# valid values
+SET @@global.wsrep_max_ws_size=1073741824;
+SELECT @@global.wsrep_max_ws_size;
+@@global.wsrep_max_ws_size
+1073741824
+SET @@global.wsrep_max_ws_size=1073741825;
+SELECT @@global.wsrep_max_ws_size;
+@@global.wsrep_max_ws_size
+1073741825
+SET @@global.wsrep_max_ws_size=0;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_max_ws_size value: '0'
+SELECT @@global.wsrep_max_ws_size;
+@@global.wsrep_max_ws_size
+1024
+SET @@global.wsrep_max_ws_size=default;
+SELECT @global.wsrep_max_ws_size;
+@global.wsrep_max_ws_size
+NULL
+
+# invalid values
+SET @@global.wsrep_max_ws_size=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_size'
+SET @@global.wsrep_max_ws_size='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_max_ws_size'
+SELECT @global.wsrep_max_ws_size;
+@global.wsrep_max_ws_size
+NULL
+SET @@global.wsrep_max_ws_size=-1;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_max_ws_size value: '-1'
+SELECT @global.wsrep_max_ws_size;
+@global.wsrep_max_ws_size
+NULL
+
+# restore the initial value
+SET @@global.wsrep_max_ws_size = @wsrep_max_ws_size_global_saved;
+SET @@global.wsrep_provider_options = @wsrep_provider_options_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result
new file mode 100644
index 00000000000..1d69d800703
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_mysql_replication_bundle_basic.result
@@ -0,0 +1,52 @@
+#
+# wsrep_mysql_replication_bundle
+#
+# save the initial value
+SET @wsrep_mysql_replication_bundle_global_saved = @@global.wsrep_mysql_replication_bundle;
+# default
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+0
+
+# scope
+SELECT @@session.wsrep_mysql_replication_bundle;
+ERROR HY000: Variable 'wsrep_mysql_replication_bundle' is a GLOBAL variable
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+0
+
+# valid values
+SET @@global.wsrep_mysql_replication_bundle=0;
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+0
+SET @@global.wsrep_mysql_replication_bundle=1000;
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+1000
+SET @@global.wsrep_mysql_replication_bundle=default;
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+0
+
+# invalid values
+SET @@global.wsrep_mysql_replication_bundle=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_mysql_replication_bundle'
+SET @@global.wsrep_mysql_replication_bundle='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_mysql_replication_bundle'
+SET @@global.wsrep_mysql_replication_bundle=-1;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '-1'
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+0
+SET @@global.wsrep_mysql_replication_bundle=1001;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_mysql_replication_bundle value: '1001'
+SELECT @@global.wsrep_mysql_replication_bundle;
+@@global.wsrep_mysql_replication_bundle
+1000
+
+# restore the initial value
+SET @@global.wsrep_mysql_replication_bundle = @wsrep_mysql_replication_bundle_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result
new file mode 100644
index 00000000000..e9a93d2fcd6
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_node_address_basic.result
@@ -0,0 +1,49 @@
+#
+# wsrep_node_address
+#
+# save the initial value
+SET @wsrep_node_address_global_saved = @@global.wsrep_node_address;
+# default
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+
+
+# scope
+SELECT @@session.wsrep_node_address;
+ERROR HY000: Variable 'wsrep_node_address' is a GLOBAL variable
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+
+
+# valid values
+SET @@global.wsrep_node_address='127.0.0.1';
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+127.0.0.1
+SET @@global.wsrep_node_address=default;
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+
+
+# invalid values
+SET @@global.wsrep_node_address=NULL;
+ERROR 42000: Variable 'wsrep_node_address' can't be set to the value of 'NULL'
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+
+SET @@global.wsrep_node_address=ON;
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+ON
+SET @@global.wsrep_node_address='OFF';
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+OFF
+SET @@global.wsrep_node_address='junk';
+SELECT @@global.wsrep_node_address;
+@@global.wsrep_node_address
+junk
+
+# restore the initial value
+SET @@global.wsrep_node_address = @wsrep_node_address_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result
new file mode 100644
index 00000000000..2340c61db28
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_node_incoming_address_basic.result
@@ -0,0 +1,56 @@
+#
+# wsrep_node_incoming_address
+#
+# save the initial value
+SET @wsrep_node_incoming_address_global_saved = @@global.wsrep_node_incoming_address;
+# default
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+AUTO
+
+# scope
+SELECT @@session.wsrep_node_incoming_address;
+ERROR HY000: Variable 'wsrep_node_incoming_address' is a GLOBAL variable
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+AUTO
+
+# valid values
+SET @@global.wsrep_node_incoming_address='127.0.0.1:4444';
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+127.0.0.1:4444
+SET @@global.wsrep_node_incoming_address='127.0.0.1';
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+127.0.0.1
+SET @@global.wsrep_node_incoming_address=AUTO;
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+AUTO
+SET @@global.wsrep_node_incoming_address=default;
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+AUTO
+
+# invalid values
+SET @@global.wsrep_node_incoming_address=ON;
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+ON
+SET @@global.wsrep_node_incoming_address='OFF';
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+OFF
+SET @@global.wsrep_node_incoming_address=NULL;
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+NULL
+SET @@global.wsrep_node_incoming_address='junk';
+SELECT @@global.wsrep_node_incoming_address;
+@@global.wsrep_node_incoming_address
+junk
+
+# restore the initial value
+SET @@global.wsrep_node_incoming_address = @wsrep_node_incoming_address_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result
new file mode 100644
index 00000000000..763d0612a1b
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_node_name_basic.result
@@ -0,0 +1,61 @@
+#
+# wsrep_node_name
+#
+call mtr.add_suppression("WSREP: Failed to get provider options");
+# save the initial value
+SET @wsrep_node_name_global_saved = @@global.wsrep_node_name;
+# default (expect 1)
+SELECT COUNT(@@global.wsrep_node_name);
+COUNT(@@global.wsrep_node_name)
+1
+
+# scope
+SELECT @@session.wsrep_node_name;
+ERROR HY000: Variable 'wsrep_node_name' is a GLOBAL variable
+SET @@global.wsrep_node_name='node_name';
+SELECT @@global.wsrep_node_name;
+@@global.wsrep_node_name
+node_name
+
+# valid values
+SET @@global.wsrep_node_name='my_node';
+SELECT @@global.wsrep_node_name;
+@@global.wsrep_node_name
+my_node
+SET @@global.wsrep_node_name='hyphenated-node-name';
+SELECT @@global.wsrep_node_name;
+@@global.wsrep_node_name
+hyphenated-node-name
+SET @@global.wsrep_node_name=default;
+# default (expect 1)
+SELECT COUNT(@@global.wsrep_node_name);
+COUNT(@@global.wsrep_node_name)
+1
+
+# invalid values
+SET @@global.wsrep_node_name=NULL;
+ERROR 42000: Variable 'wsrep_node_name' can't be set to the value of 'NULL'
+SELECT COUNT(@@global.wsrep_node_name);
+COUNT(@@global.wsrep_node_name)
+1
+SET @@global.wsrep_node_name=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_node_name'
+SELECT COUNT(@@global.wsrep_node_name);
+COUNT(@@global.wsrep_node_name)
+1
+#
+# MDEV-6699 : wsrep_node_name not automaticly set to hostname
+#
+SET @@global.wsrep_node_name=default;
+SELECT @@GLOBAL.wsrep_node_name = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='hostname';
+@@GLOBAL.wsrep_node_name = VARIABLE_VALUE
+1
+SELECT @@GLOBAL.wsrep_node_name = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='wsrep_node_name';
+@@GLOBAL.wsrep_node_name = VARIABLE_VALUE
+1
+
+# restore the initial value
+SET @@global.wsrep_node_name = @wsrep_node_name_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result
new file mode 100644
index 00000000000..056ff8c817b
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_notify_cmd_basic.result
@@ -0,0 +1,47 @@
+#
+# wsrep_notify_cmd
+#
+call mtr.add_suppression("WSREP: Failed to get provider options");
+# save the initial value
+SET @wsrep_notify_cmd_global_saved = @@global.wsrep_notify_cmd;
+# default
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+
+
+# scope
+SELECT @@session.wsrep_notify_cmd;
+ERROR HY000: Variable 'wsrep_notify_cmd' is a GLOBAL variable
+SET @@global.wsrep_notify_cmd='notify_cmd';
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+notify_cmd
+
+# valid values
+SET @@global.wsrep_notify_cmd='command';
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+command
+SET @@global.wsrep_notify_cmd='hyphenated-command';
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+hyphenated-command
+SET @@global.wsrep_notify_cmd=default;
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+
+SET @@global.wsrep_notify_cmd=NULL;
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+NULL
+
+# invalid values
+SET @@global.wsrep_notify_cmd=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_notify_cmd'
+SELECT @@global.wsrep_notify_cmd;
+@@global.wsrep_notify_cmd
+NULL
+
+# restore the initial value
+SET @@global.wsrep_notify_cmd = @wsrep_notify_cmd_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_on_basic.result b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result
new file mode 100644
index 00000000000..735e2d77180
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_on_basic.result
@@ -0,0 +1,50 @@
+#
+# wsrep_on
+#
+# save the initial values
+SET @wsrep_on_global_saved = @@global.wsrep_on;
+SET @wsrep_on_session_saved = @@session.wsrep_on;
+# default
+SELECT @@global.wsrep_on;
+@@global.wsrep_on
+0
+SELECT @@session.wsrep_on;
+@@session.wsrep_on
+0
+
+# scope and valid values
+SET @@global.wsrep_on=OFF;
+SELECT @@global.wsrep_on;
+@@global.wsrep_on
+0
+SET @@global.wsrep_on=ON;
+SELECT @@global.wsrep_on;
+@@global.wsrep_on
+1
+SET @@session.wsrep_on=OFF;
+SELECT @@session.wsrep_on;
+@@session.wsrep_on
+0
+SET @@session.wsrep_on=ON;
+SELECT @@session.wsrep_on;
+@@session.wsrep_on
+1
+SET @@session.wsrep_on=default;
+SELECT @@session.wsrep_on;
+@@session.wsrep_on
+1
+
+# invalid values
+SET @@global.wsrep_on=NULL;
+ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'NULL'
+SET @@global.wsrep_on='junk';
+ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'junk'
+SET @@session.wsrep_on=NULL;
+ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'NULL'
+SET @@session.wsrep_on='junk';
+ERROR 42000: Variable 'wsrep_on' can't be set to the value of 'junk'
+
+# restore the initial values
+SET @@global.wsrep_on = @wsrep_on_global_saved;
+SET @@session.wsrep_on = @wsrep_on_session_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result
new file mode 100644
index 00000000000..10f1d654c12
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result
@@ -0,0 +1,61 @@
+#
+# wsrep_osu_method
+#
+# save the initial value
+SET @wsrep_osu_method_global_saved = @@global.wsrep_osu_method;
+# default
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+TOI
+
+# scope
+SELECT @@session.wsrep_osu_method;
+@@session.wsrep_osu_method
+TOI
+SET @@global.wsrep_osu_method=TOI;
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+TOI
+
+# valid values
+SET @@global.wsrep_osu_method=TOI;
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+TOI
+SET @@global.wsrep_osu_method=RSU;
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+RSU
+SET @@global.wsrep_osu_method="RSU";
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+RSU
+SET @@global.wsrep_osu_method=default;
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+TOI
+SET @@global.wsrep_osu_method=1;
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+RSU
+
+# invalid values
+SET @@global.wsrep_osu_method=4;
+ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of '4'
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+RSU
+SET @@global.wsrep_osu_method=NULL;
+ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'NULL'
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+RSU
+SET @@global.wsrep_osu_method='junk';
+ERROR 42000: Variable 'wsrep_OSU_method' can't be set to the value of 'junk'
+SELECT @@global.wsrep_osu_method;
+@@global.wsrep_osu_method
+RSU
+
+# restore the initial value
+SET @@global.wsrep_osu_method = @wsrep_osu_method_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result
new file mode 100644
index 00000000000..3e4ac8ca883
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_provider_basic.result
@@ -0,0 +1,40 @@
+#
+# wsrep_provider
+#
+# save the initial value
+SET @wsrep_provider_global_saved = @@global.wsrep_provider;
+# default
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+none
+
+# scope
+SELECT @@session.wsrep_provider;
+ERROR HY000: Variable 'wsrep_provider' is a GLOBAL variable
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+none
+
+# valid values
+SET @@global.wsrep_provider=default;
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+none
+
+# invalid values
+SET @@global.wsrep_provider='/invalid/libgalera_smm.so';
+ERROR 42000: Variable 'wsrep_provider' can't be set to the value of '/invalid/libgalera_smm.so'
+SET @@global.wsrep_provider=NULL;
+ERROR 42000: Variable 'wsrep_provider' can't be set to the value of 'NULL'
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+none
+SET @@global.wsrep_provider=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_provider'
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+none
+
+# restore the initial value
+SET @@global.wsrep_provider = @wsrep_provider_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result
new file mode 100644
index 00000000000..ed6b125e064
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result
@@ -0,0 +1,48 @@
+#
+# wsrep_provider_options
+#
+call mtr.add_suppression("WSREP: Failed to get provider options");
+# save the initial value
+SET @wsrep_provider_options_global_saved = @@global.wsrep_provider_options;
+# default
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+
+
+# scope
+SELECT @@session.wsrep_provider_options;
+ERROR HY000: Variable 'wsrep_provider_options' is a GLOBAL variable
+SET @@global.wsrep_provider_options='option1';
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+option1
+
+# valid values
+SET @@global.wsrep_provider_options='name1=value1;name2=value2';
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+name1=value1;name2=value2
+SET @@global.wsrep_provider_options='hyphenated-name:value';
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+hyphenated-name:value
+SET @@global.wsrep_provider_options=default;
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+
+
+# invalid values
+SET @@global.wsrep_provider_options=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_provider_options'
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+
+SET @@global.wsrep_provider_options=NULL;
+ERROR HY000: Incorrect arguments to SET
+SELECT @@global.wsrep_provider_options;
+@@global.wsrep_provider_options
+NULL
+
+# restore the initial value
+SET @@global.wsrep_provider_options = @wsrep_provider_options_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result
new file mode 100644
index 00000000000..b26c1121a4c
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_recover_basic.result
@@ -0,0 +1,22 @@
+#
+# wsrep_recover
+#
+# default
+SELECT @@global.wsrep_recover;
+@@global.wsrep_recover
+0
+SELECT @@session.wsrep_recover;
+ERROR HY000: Variable 'wsrep_recover' is a GLOBAL variable
+
+# scope and valid values
+SET @@global.wsrep_recover=OFF;
+ERROR HY000: Variable 'wsrep_recover' is a read only variable
+SET @@global.wsrep_recover=ON;
+ERROR HY000: Variable 'wsrep_recover' is a read only variable
+
+# invalid values
+SET @@global.wsrep_recover=NULL;
+ERROR HY000: Variable 'wsrep_recover' is a read only variable
+SET @@global.wsrep_recover='junk';
+ERROR HY000: Variable 'wsrep_recover' is a read only variable
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result
new file mode 100644
index 00000000000..3625f29aa0f
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_replicate_myisam_basic.result
@@ -0,0 +1,31 @@
+#
+# wsrep_replicate_myisam
+#
+# save the initial value
+SET @wsrep_replicate_myisam_global_saved = @@global.wsrep_replicate_myisam;
+# default
+SELECT @@global.wsrep_replicate_myisam;
+@@global.wsrep_replicate_myisam
+0
+SELECT @@session.wsrep_replicate_myisam;
+ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable
+
+# scope and valid values
+SET @@global.wsrep_replicate_myisam=OFF;
+SELECT @@global.wsrep_replicate_myisam;
+@@global.wsrep_replicate_myisam
+0
+SET @@global.wsrep_replicate_myisam=ON;
+SELECT @@global.wsrep_replicate_myisam;
+@@global.wsrep_replicate_myisam
+1
+
+# invalid values
+SET @@global.wsrep_replicate_myisam=NULL;
+ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of 'NULL'
+SET @@global.wsrep_replicate_myisam='junk';
+ERROR 42000: Variable 'wsrep_replicate_myisam' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_replicate_myisam = @wsrep_replicate_myisam_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result
new file mode 100644
index 00000000000..0ecdf915992
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_restart_slave_basic.result
@@ -0,0 +1,31 @@
+#
+# wsrep_restart_slave
+#
+# save the initial value
+SET @wsrep_restart_slave_global_saved = @@global.wsrep_restart_slave;
+# default
+SELECT @@global.wsrep_restart_slave;
+@@global.wsrep_restart_slave
+0
+SELECT @@session.wsrep_restart_slave;
+ERROR HY000: Variable 'wsrep_restart_slave' is a GLOBAL variable
+
+# scope and valid values
+SET @@global.wsrep_restart_slave=OFF;
+SELECT @@global.wsrep_restart_slave;
+@@global.wsrep_restart_slave
+0
+SET @@global.wsrep_restart_slave=ON;
+SELECT @@global.wsrep_restart_slave;
+@@global.wsrep_restart_slave
+1
+
+# invalid values
+SET @@global.wsrep_restart_slave=NULL;
+ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of 'NULL'
+SET @@global.wsrep_restart_slave='junk';
+ERROR 42000: Variable 'wsrep_restart_slave' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_restart_slave = @wsrep_restart_slave_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result
new file mode 100644
index 00000000000..d848dadd24d
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_retry_autocommit_basic.result
@@ -0,0 +1,63 @@
+#
+# wsrep_retry_autocommit
+#
+# save the initial values
+SET @wsrep_retry_autocommit_global_saved = @@global.wsrep_retry_autocommit;
+SET @wsrep_retry_autocommit_session_saved = @@session.wsrep_retry_autocommit;
+# default
+SELECT @@global.wsrep_retry_autocommit;
+@@global.wsrep_retry_autocommit
+1
+
+# scope
+SET @@session.wsrep_retry_autocommit=1;
+SELECT @@session.wsrep_retry_autocommit;
+@@session.wsrep_retry_autocommit
+1
+SET @@global.wsrep_retry_autocommit=1;
+SELECT @@global.wsrep_retry_autocommit;
+@@global.wsrep_retry_autocommit
+1
+
+# valid values
+SET @@global.wsrep_retry_autocommit=10;
+SELECT @@global.wsrep_retry_autocommit;
+@@global.wsrep_retry_autocommit
+10
+SET @@global.wsrep_retry_autocommit=0;
+SELECT @@global.wsrep_retry_autocommit;
+@@global.wsrep_retry_autocommit
+0
+SET @@global.wsrep_retry_autocommit=default;
+SELECT @global.wsrep_retry_autocommit;
+@global.wsrep_retry_autocommit
+NULL
+SET @@session.wsrep_retry_autocommit=10;
+SELECT @@session.wsrep_retry_autocommit;
+@@session.wsrep_retry_autocommit
+10
+SET @@session.wsrep_retry_autocommit=0;
+SELECT @@session.wsrep_retry_autocommit;
+@@session.wsrep_retry_autocommit
+0
+SET @@session.wsrep_retry_autocommit=default;
+SELECT @session.wsrep_retry_autocommit;
+@session.wsrep_retry_autocommit
+NULL
+
+# invalid values
+SET @@global.wsrep_retry_autocommit=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_retry_autocommit'
+SET @@global.wsrep_retry_autocommit='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_retry_autocommit'
+SET @@global.wsrep_retry_autocommit=-1;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_retry_autocommit value: '-1'
+SELECT @global.wsrep_retry_autocommit;
+@global.wsrep_retry_autocommit
+NULL
+
+# restore the initial value
+SET @@global.wsrep_retry_autocommit = @wsrep_retry_autocommit_global_saved;
+SET @@session.wsrep_retry_autocommit = @wsrep_retry_autocommit_session_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result
new file mode 100644
index 00000000000..40b3270e221
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_slave_fk_checks
+#
+# save the initial value
+SET @wsrep_slave_fk_checks_global_saved = @@global.wsrep_slave_fk_checks;
+# default
+SELECT @@global.wsrep_slave_fk_checks;
+@@global.wsrep_slave_fk_checks
+1
+
+# scope
+SELECT @@session.wsrep_slave_fk_checks;
+ERROR HY000: Variable 'wsrep_slave_FK_checks' is a GLOBAL variable
+SET @@global.wsrep_slave_fk_checks=OFF;
+SELECT @@global.wsrep_slave_fk_checks;
+@@global.wsrep_slave_fk_checks
+0
+SET @@global.wsrep_slave_fk_checks=ON;
+SELECT @@global.wsrep_slave_fk_checks;
+@@global.wsrep_slave_fk_checks
+1
+
+# valid values
+SET @@global.wsrep_slave_fk_checks='OFF';
+SELECT @@global.wsrep_slave_fk_checks;
+@@global.wsrep_slave_fk_checks
+0
+SET @@global.wsrep_slave_fk_checks=ON;
+SELECT @@global.wsrep_slave_fk_checks;
+@@global.wsrep_slave_fk_checks
+1
+SET @@global.wsrep_slave_fk_checks=default;
+SELECT @@global.wsrep_slave_fk_checks;
+@@global.wsrep_slave_fk_checks
+1
+
+# invalid values
+SET @@global.wsrep_slave_fk_checks=NULL;
+ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'NULL'
+SET @@global.wsrep_slave_fk_checks='junk';
+ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result
new file mode 100644
index 00000000000..62be5a42416
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_slave_threads_basic.result
@@ -0,0 +1,49 @@
+#
+# wsrep_slave_threads
+#
+# save the initial value
+SET @wsrep_slave_threads_global_saved = @@global.wsrep_slave_threads;
+# default
+SELECT @@global.wsrep_slave_threads;
+@@global.wsrep_slave_threads
+1
+
+# scope
+SELECT @@session.wsrep_slave_threads;
+ERROR HY000: Variable 'wsrep_slave_threads' is a GLOBAL variable
+SET @@global.wsrep_slave_threads=1;
+SELECT @@global.wsrep_slave_threads;
+@@global.wsrep_slave_threads
+1
+
+# valid values
+SET @@global.wsrep_slave_threads=10;
+SELECT @@global.wsrep_slave_threads;
+@@global.wsrep_slave_threads
+10
+SET @@global.wsrep_slave_threads=0;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_slave_threads value: '0'
+SELECT @@global.wsrep_slave_threads;
+@@global.wsrep_slave_threads
+1
+SET @@global.wsrep_slave_threads=default;
+SELECT @global.wsrep_slave_threads;
+@global.wsrep_slave_threads
+NULL
+
+# invalid values
+SET @@global.wsrep_slave_threads=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_slave_threads'
+SET @@global.wsrep_slave_threads='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_slave_threads'
+SET @@global.wsrep_slave_threads=-1;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_slave_threads value: '-1'
+SELECT @global.wsrep_slave_threads;
+@global.wsrep_slave_threads
+NULL
+
+# restore the initial value
+SET @@global.wsrep_slave_threads = @wsrep_slave_threads_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result
new file mode 100644
index 00000000000..b78a83b547d
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_slave_uk_checks_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_slave_uk_checks
+#
+# save the initial value
+SET @wsrep_slave_uk_checks_global_saved = @@global.wsrep_slave_uk_checks;
+# default
+SELECT @@global.wsrep_slave_uk_checks;
+@@global.wsrep_slave_uk_checks
+0
+
+# scope
+SELECT @@session.wsrep_slave_uk_checks;
+ERROR HY000: Variable 'wsrep_slave_UK_checks' is a GLOBAL variable
+SET @@global.wsrep_slave_uk_checks=OFF;
+SELECT @@global.wsrep_slave_uk_checks;
+@@global.wsrep_slave_uk_checks
+0
+SET @@global.wsrep_slave_uk_checks=ON;
+SELECT @@global.wsrep_slave_uk_checks;
+@@global.wsrep_slave_uk_checks
+1
+
+# valid values
+SET @@global.wsrep_slave_uk_checks='OFF';
+SELECT @@global.wsrep_slave_uk_checks;
+@@global.wsrep_slave_uk_checks
+0
+SET @@global.wsrep_slave_uk_checks=ON;
+SELECT @@global.wsrep_slave_uk_checks;
+@@global.wsrep_slave_uk_checks
+1
+SET @@global.wsrep_slave_uk_checks=default;
+SELECT @@global.wsrep_slave_uk_checks;
+@@global.wsrep_slave_uk_checks
+0
+
+# invalid values
+SET @@global.wsrep_slave_uk_checks=NULL;
+ERROR 42000: Variable 'wsrep_slave_UK_checks' can't be set to the value of 'NULL'
+SET @@global.wsrep_slave_uk_checks='junk';
+ERROR 42000: Variable 'wsrep_slave_UK_checks' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_slave_uk_checks = @wsrep_slave_uk_checks_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result
new file mode 100644
index 00000000000..e6b532c6bba
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sst_auth_basic.result
@@ -0,0 +1,52 @@
+#
+# wsrep_sst_auth
+#
+# save the initial value
+SET @wsrep_sst_auth_global_saved = @@global.wsrep_sst_auth;
+# default
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+NULL
+
+# scope
+SELECT @@session.wsrep_sst_auth;
+ERROR HY000: Variable 'wsrep_sst_auth' is a GLOBAL variable
+SET @@global.wsrep_sst_auth='user:pass';
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+********
+
+# valid values
+SET @@global.wsrep_sst_auth=user;
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+********
+SET @@global.wsrep_sst_auth='user:1234';
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+********
+SET @@global.wsrep_sst_auth='hyphenated-user-name:';
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+********
+SET @@global.wsrep_sst_auth=default;
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+NULL
+SET @@global.wsrep_sst_auth=NULL;
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+NULL
+
+# invalid values
+SET @@global.wsrep_sst_auth=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_sst_auth'
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+NULL
+SET @@global.wsrep_sst_auth=user:pass;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ':pass' at line 1
+
+# restore the initial value
+SET @@global.wsrep_sst_auth = @wsrep_sst_auth_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result
new file mode 100644
index 00000000000..3d4fc24df7f
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_basic.result
@@ -0,0 +1,50 @@
+#
+# wsrep_sst_donor
+#
+# save the initial value
+SET @wsrep_sst_donor_global_saved = @@global.wsrep_sst_donor;
+# default
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+
+
+# scope
+SELECT @@session.wsrep_sst_donor;
+ERROR HY000: Variable 'wsrep_sst_donor' is a GLOBAL variable
+SET @@global.wsrep_sst_donor=rsync;
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+rsync
+
+# valid values
+SET @@global.wsrep_sst_donor=node1;
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+node1
+SET @@global.wsrep_sst_donor='node1,node2';
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+node1,node2
+SET @@global.wsrep_sst_donor='hyphenated-donor-name';
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+hyphenated-donor-name
+SET @@global.wsrep_sst_donor=default;
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+
+SET @@global.wsrep_sst_donor=NULL;
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+NULL
+
+# invalid values
+SET @@global.wsrep_sst_donor=1;
+ERROR 42000: Incorrect argument type to variable 'wsrep_sst_donor'
+SELECT @@global.wsrep_sst_donor;
+@@global.wsrep_sst_donor
+NULL
+
+# restore the initial value
+SET @@global.wsrep_sst_donor = @wsrep_sst_donor_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result
new file mode 100644
index 00000000000..c9f95beec0a
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sst_donor_rejects_queries_basic.result
@@ -0,0 +1,45 @@
+#
+# wsrep_sst_donor_rejects_queries
+#
+# save the initial value
+SET @wsrep_sst_donor_rejects_queries_global_saved = @@global.wsrep_sst_donor_rejects_queries;
+# default
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+@@global.wsrep_sst_donor_rejects_queries
+0
+
+# scope
+SELECT @@session.wsrep_sst_donor_rejects_queries;
+ERROR HY000: Variable 'wsrep_sst_donor_rejects_queries' is a GLOBAL variable
+SET @@global.wsrep_sst_donor_rejects_queries=OFF;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+@@global.wsrep_sst_donor_rejects_queries
+0
+SET @@global.wsrep_sst_donor_rejects_queries=ON;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+@@global.wsrep_sst_donor_rejects_queries
+1
+
+# valid values
+SET @@global.wsrep_sst_donor_rejects_queries='OFF';
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+@@global.wsrep_sst_donor_rejects_queries
+0
+SET @@global.wsrep_sst_donor_rejects_queries=ON;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+@@global.wsrep_sst_donor_rejects_queries
+1
+SET @@global.wsrep_sst_donor_rejects_queries=default;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+@@global.wsrep_sst_donor_rejects_queries
+0
+
+# invalid values
+SET @@global.wsrep_sst_donor_rejects_queries=NULL;
+ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of 'NULL'
+SET @@global.wsrep_sst_donor_rejects_queries='junk';
+ERROR 42000: Variable 'wsrep_sst_donor_rejects_queries' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_sst_donor_rejects_queries = @wsrep_sst_donor_rejects_queries_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result
new file mode 100644
index 00000000000..cbdac640c36
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sst_method_basic.result
@@ -0,0 +1,54 @@
+#
+# wsrep_sst_method
+#
+# save the initial value
+SET @wsrep_sst_method_global_saved = @@global.wsrep_sst_method;
+# default
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+rsync
+
+# scope
+SELECT @@session.wsrep_sst_method;
+ERROR HY000: Variable 'wsrep_sst_method' is a GLOBAL variable
+SET @@global.wsrep_sst_method=rsync;
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+rsync
+
+# valid values
+SET @@global.wsrep_sst_method=rsync;
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+rsync
+SET @@global.wsrep_sst_method=mysqldump;
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+mysqldump
+SET @@global.wsrep_sst_method=xtrabackup;
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+xtrabackup
+SET @@global.wsrep_sst_method="xtrabackup-v2";
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+xtrabackup-v2
+SET @@global.wsrep_sst_method=default;
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+rsync
+SET @@global.wsrep_sst_method='junk';
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+junk
+
+# invalid values
+SET @@global.wsrep_sst_method=NULL;
+ERROR 42000: Variable 'wsrep_sst_method' can't be set to the value of 'NULL'
+SELECT @@global.wsrep_sst_method;
+@@global.wsrep_sst_method
+junk
+
+# restore the initial value
+SET @@global.wsrep_sst_method = @wsrep_sst_method_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result
new file mode 100644
index 00000000000..6db52eb8150
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sst_receive_address_basic.result
@@ -0,0 +1,64 @@
+#
+# wsrep_sst_receive_address
+#
+# save the initial value
+SET @wsrep_sst_receive_address_global_saved = @@global.wsrep_sst_receive_address;
+# default
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+AUTO
+
+# scope
+SELECT @@session.wsrep_sst_receive_address;
+ERROR HY000: Variable 'wsrep_sst_receive_address' is a GLOBAL variable
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+AUTO
+
+# valid values
+SET @@global.wsrep_sst_receive_address=AUTO;
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+AUTO
+SET @@global.wsrep_sst_receive_address=default;
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+AUTO
+SET @@global.wsrep_sst_receive_address='192.168.2.254';
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+192.168.2.254
+
+# invalid values
+SET @@global.wsrep_sst_receive_address='127.0.0.1:4444';
+ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1:4444'
+SET @@global.wsrep_sst_receive_address='127.0.0.1';
+ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of '127.0.0.1'
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+192.168.2.254
+SET @@global.wsrep_sst_receive_address=NULL;
+ERROR 42000: Variable 'wsrep_sst_receive_address' can't be set to the value of 'NULL'
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+192.168.2.254
+SET @@global.wsrep_sst_receive_address='OFF';
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+OFF
+SET @@global.wsrep_sst_receive_address=ON;
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+ON
+SET @@global.wsrep_sst_receive_address='';
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+
+SET @@global.wsrep_sst_receive_address='junk';
+SELECT @@global.wsrep_sst_receive_address;
+@@global.wsrep_sst_receive_address
+junk
+
+# restore the initial value
+SET @@global.wsrep_sst_receive_address = @wsrep_sst_receive_address_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result
new file mode 100644
index 00000000000..a49e6135d47
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_start_position_basic.result
@@ -0,0 +1,57 @@
+#
+# wsrep_start_position
+#
+# save the initial value
+SET @wsrep_start_position_global_saved = @@global.wsrep_start_position;
+# default
+SELECT @@global.wsrep_start_position;
+@@global.wsrep_start_position
+00000000-0000-0000-0000-000000000000:-1
+
+# scope
+SELECT @@session.wsrep_start_position;
+ERROR HY000: Variable 'wsrep_start_position' is a GLOBAL variable
+SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-1';
+SELECT @@global.wsrep_start_position;
+@@global.wsrep_start_position
+00000000-0000-0000-0000-000000000000:-1
+
+# valid values
+SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-2';
+SELECT @@global.wsrep_start_position;
+@@global.wsrep_start_position
+00000000-0000-0000-0000-000000000000:-2
+SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:100';
+SELECT @@global.wsrep_start_position;
+@@global.wsrep_start_position
+12345678-1234-1234-1234-123456789012:100
+SET @@global.wsrep_start_position=default;
+SELECT @@global.wsrep_start_position;
+@@global.wsrep_start_position
+00000000-0000-0000-0000-000000000000:-1
+
+# invalid values
+SET @@global.wsrep_start_position='000000000000000-0000-0000-0000-000000000000:-1';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '000000000000000-0000-0000-0000-000000000000:-1'
+SET @@global.wsrep_start_position='12345678-1234-1234-12345-123456789012:100';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-1234-12345-123456789012:100'
+SET @@global.wsrep_start_position='12345678-1234-123-12345-123456789012:0';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-123-12345-123456789012:0'
+SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:_99999';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-1234-1234-123456789012:_99999'
+SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:a';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of '12345678-1234-1234-1234-123456789012:a'
+SET @@global.wsrep_start_position='OFF';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'OFF'
+SET @@global.wsrep_start_position=ON;
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'ON'
+SET @@global.wsrep_start_position='';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of ''
+SET @@global.wsrep_start_position=NULL;
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'NULL'
+SET @@global.wsrep_start_position='junk';
+ERROR 42000: Variable 'wsrep_start_position' can't be set to the value of 'junk'
+
+# restore the initial value
+SET @@global.wsrep_start_position = @wsrep_start_position_global_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result
new file mode 100644
index 00000000000..0df3dff8990
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result
@@ -0,0 +1,54 @@
+#
+# wsrep_sync_wait
+#
+# save the initial values
+SET @wsrep_sync_wait_global_saved = @@global.wsrep_sync_wait;
+SET @wsrep_sync_wait_session_saved = @@session.wsrep_sync_wait;
+# default
+SELECT @@global.wsrep_sync_wait;
+@@global.wsrep_sync_wait
+0
+SELECT @@session.wsrep_sync_wait;
+@@session.wsrep_sync_wait
+0
+
+# scope and valid values
+SET @@global.wsrep_sync_wait=0;
+SELECT @@global.wsrep_sync_wait;
+@@global.wsrep_sync_wait
+0
+SET @@global.wsrep_sync_wait=7;
+SELECT @@global.wsrep_sync_wait;
+@@global.wsrep_sync_wait
+7
+SET @@session.wsrep_sync_wait=0;
+SELECT @@session.wsrep_sync_wait;
+@@session.wsrep_sync_wait
+0
+SET @@session.wsrep_sync_wait=7;
+SELECT @@session.wsrep_sync_wait;
+@@session.wsrep_sync_wait
+7
+SET @@session.wsrep_sync_wait=default;
+SELECT @@session.wsrep_sync_wait;
+@@session.wsrep_sync_wait
+7
+SET @@session.wsrep_sync_wait=8;
+SELECT @@session.wsrep_sync_wait;
+@@session.wsrep_sync_wait
+8
+
+# invalid values
+SET @@global.wsrep_sync_wait=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait'
+SET @@global.wsrep_sync_wait='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait'
+SET @@session.wsrep_sync_wait=NULL;
+ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait'
+SET @@session.wsrep_sync_wait='junk';
+ERROR 42000: Incorrect argument type to variable 'wsrep_sync_wait'
+
+# restore the initial values
+SET @@global.wsrep_sync_wait = @wsrep_sync_wait_global_saved;
+SET @@session.wsrep_sync_wait = @wsrep_sync_wait_session_saved;
+# End of test
diff --git a/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test b/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test
new file mode 100644
index 00000000000..b8e5c127377
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test
@@ -0,0 +1,42 @@
+--source include/have_innodb_disallow_writes.inc
+
+--echo #
+--echo # innodb_disallow_writes
+--echo #
+
+--echo # save the initial value
+SET @innodb_disallow_writes_global_saved = @@global.innodb_disallow_writes;
+
+--echo # default
+SELECT @@global.innodb_disallow_writes;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.innodb_disallow_writes;
+SET @@global.innodb_disallow_writes=OFF;
+SELECT @@global.innodb_disallow_writes;
+SET @@global.innodb_disallow_writes=ON;
+SELECT @@global.innodb_disallow_writes;
+
+--echo
+--echo # valid values
+SET @@global.innodb_disallow_writes='OFF';
+SELECT @@global.innodb_disallow_writes;
+SET @@global.innodb_disallow_writes=ON;
+SELECT @@global.innodb_disallow_writes;
+SET @@global.innodb_disallow_writes=default;
+SELECT @@global.innodb_disallow_writes;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.innodb_disallow_writes=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.innodb_disallow_writes='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.innodb_disallow_writes = @innodb_disallow_writes_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/log_tc_size_basic.test b/mysql-test/suite/sys_vars/t/log_tc_size_basic.test
new file mode 100644
index 00000000000..221338d0304
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/log_tc_size_basic.test
@@ -0,0 +1,5 @@
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET GLOBAL log_tc_size=1;
+
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET SESSION log_tc_size=1;
diff --git a/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test
new file mode 100644
index 00000000000..5dc23cf2ad6
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_auto_increment_control_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_auto_increment_control
+--echo #
+
+--echo # save the initial value
+SET @wsrep_auto_increment_control_global_saved = @@global.wsrep_auto_increment_control;
+
+--echo # default
+SELECT @@global.wsrep_auto_increment_control;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_auto_increment_control;
+SET @@global.wsrep_auto_increment_control=OFF;
+SELECT @@global.wsrep_auto_increment_control;
+SET @@global.wsrep_auto_increment_control=ON;
+SELECT @@global.wsrep_auto_increment_control;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_auto_increment_control='OFF';
+SELECT @@global.wsrep_auto_increment_control;
+SET @@global.wsrep_auto_increment_control=ON;
+SELECT @@global.wsrep_auto_increment_control;
+SET @@global.wsrep_auto_increment_control=default;
+SELECT @@global.wsrep_auto_increment_control;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_auto_increment_control=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_auto_increment_control='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_auto_increment_control = @wsrep_auto_increment_control_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test
new file mode 100644
index 00000000000..6539e5cba85
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_causal_reads_basic.test
@@ -0,0 +1,45 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_causal_reads
+--echo #
+
+--echo # save the initial values
+SET @wsrep_causal_reads_global_saved = @@global.wsrep_causal_reads;
+SET @wsrep_causal_reads_session_saved = @@session.wsrep_causal_reads;
+
+--echo # default
+SELECT @@global.wsrep_causal_reads;
+SELECT @@session.wsrep_causal_reads;
+
+--echo
+--echo # scope and valid values
+SET @@global.wsrep_causal_reads=OFF;
+SELECT @@global.wsrep_causal_reads;
+SET @@global.wsrep_causal_reads=ON;
+SELECT @@global.wsrep_causal_reads;
+
+SET @@session.wsrep_causal_reads=OFF;
+SELECT @@session.wsrep_causal_reads;
+SET @@session.wsrep_causal_reads=ON;
+SELECT @@session.wsrep_causal_reads;
+SET @@session.wsrep_causal_reads=default;
+SELECT @@session.wsrep_causal_reads;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_causal_reads=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_causal_reads='junk';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@session.wsrep_causal_reads=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@session.wsrep_causal_reads='junk';
+
+--echo
+--echo # restore the initial values
+SET @@global.wsrep_causal_reads = @wsrep_causal_reads_global_saved;
+SET @@session.wsrep_causal_reads = @wsrep_causal_reads_session_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test
new file mode 100644
index 00000000000..a2c690e5954
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_certify_nonpk_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_certify_nonpk
+--echo #
+
+--echo # save the initial value
+SET @wsrep_certify_nonpk_global_saved = @@global.wsrep_certify_nonpk;
+
+--echo # default
+SELECT @@global.wsrep_certify_nonpk;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_certify_nonpk;
+SET @@global.wsrep_certify_nonpk=OFF;
+SELECT @@global.wsrep_certify_nonpk;
+SET @@global.wsrep_certify_nonpk=ON;
+SELECT @@global.wsrep_certify_nonpk;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_certify_nonpk='OFF';
+SELECT @@global.wsrep_certify_nonpk;
+SET @@global.wsrep_certify_nonpk=ON;
+SELECT @@global.wsrep_certify_nonpk;
+SET @@global.wsrep_certify_nonpk=default;
+SELECT @@global.wsrep_certify_nonpk;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_certify_nonpk=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_certify_nonpk='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_certify_nonpk = @wsrep_certify_nonpk_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test
new file mode 100644
index 00000000000..b9e00901eb6
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_address_basic.test
@@ -0,0 +1,48 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_cluster_address
+--echo #
+
+call mtr.add_suppression("safe_mutex: Found wrong usage of mutex.*");
+
+--echo # save the initial value
+SET @wsrep_cluster_address_global_saved = @@global.wsrep_cluster_address;
+
+--echo # default
+SELECT @@global.wsrep_cluster_address;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_cluster_address;
+SELECT @@global.wsrep_cluster_address;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_cluster_address='127.0.0.1';
+SELECT @@global.wsrep_cluster_address;
+SET @@global.wsrep_cluster_address=AUTO;
+SELECT @@global.wsrep_cluster_address;
+SET @@global.wsrep_cluster_address=default;
+SELECT @@global.wsrep_cluster_address;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_node_address=NULL;
+SELECT @@global.wsrep_node_address;
+# The values being assigned to wsrep_node_address are not verified so the
+# following alues are currently valid too.
+SET @@global.wsrep_cluster_address=ON;
+SELECT @@global.wsrep_cluster_address;
+SET @@global.wsrep_cluster_address='OFF';
+SELECT @@global.wsrep_cluster_address;
+SET @@global.wsrep_cluster_address='junk';
+SELECT @@global.wsrep_cluster_address;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_cluster_address = @wsrep_cluster_address_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test
new file mode 100644
index 00000000000..a6fc3ef7b1e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_cluster_name_basic.test
@@ -0,0 +1,40 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_cluster_name
+--echo #
+
+--echo # save the initial value
+SET @wsrep_cluster_name_global_saved = @@global.wsrep_cluster_name;
+
+--echo # default
+SELECT @@global.wsrep_cluster_name;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_cluster_name;
+SET @@global.wsrep_cluster_name='my_galera_cluster';
+SELECT @@global.wsrep_cluster_name;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_cluster_name='my_quoted_galera_cluster';
+SELECT @@global.wsrep_cluster_name;
+SET @@global.wsrep_cluster_name=my_unquoted_cluster;
+SELECT @@global.wsrep_cluster_name;
+SET @@global.wsrep_cluster_name=OFF;
+SELECT @@global.wsrep_cluster_name;
+SET @@global.wsrep_cluster_name=default;
+SELECT @@global.wsrep_cluster_name;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_cluster_name=NULL;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_cluster_name = @wsrep_cluster_name_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test
new file mode 100644
index 00000000000..486832fb394
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_convert_lock_to_trx_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_convert_lock_to_trx
+--echo #
+
+--echo # save the initial value
+SET @wsrep_convert_lock_to_trx_global_saved = @@global.wsrep_convert_lock_to_trx;
+
+--echo # default
+SELECT @@global.wsrep_convert_lock_to_trx;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_convert_lock_to_trx;
+SET @@global.wsrep_convert_lock_to_trx=OFF;
+SELECT @@global.wsrep_convert_lock_to_trx;
+SET @@global.wsrep_convert_lock_to_trx=ON;
+SELECT @@global.wsrep_convert_lock_to_trx;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_convert_lock_to_trx='OFF';
+SELECT @@global.wsrep_convert_lock_to_trx;
+SET @@global.wsrep_convert_lock_to_trx=ON;
+SELECT @@global.wsrep_convert_lock_to_trx;
+SET @@global.wsrep_convert_lock_to_trx=default;
+SELECT @@global.wsrep_convert_lock_to_trx;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_convert_lock_to_trx=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_convert_lock_to_trx='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_convert_lock_to_trx = @wsrep_convert_lock_to_trx_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test
new file mode 100644
index 00000000000..cd50fbc389e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_data_home_dir_basic.test
@@ -0,0 +1,49 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_data_home_dir (readonly)
+--echo #
+
+--echo # default
+SELECT COUNT(@@global.wsrep_data_home_dir);
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_data_home_dir;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir='/tmp/data';
+SELECT COUNT(@@global.wsrep_data_home_dir);
+
+--echo
+--echo # valid values
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir='/tmp/data';
+SELECT COUNT(@@global.wsrep_data_home_dir);
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir=junk-dir;
+SELECT COUNT(@@global.wsrep_data_home_dir);
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir=junk/dir;
+SELECT COUNT(@@global.wsrep_data_home_dir);
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir=OFF;
+SELECT COUNT(@@global.wsrep_data_home_dir);
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir=default;
+SELECT COUNT(@@global.wsrep_data_home_dir);
+
+--echo
+--echo # invalid values
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_data_home_dir=NULL;
+
+--echo #
+--echo # MDEV-6717 : wsrep_data_home_dir should default to @@datadir
+--echo #
+SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='datadir';
+SELECT @@GLOBAL.wsrep_data_home_dir = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='wsrep_data_home_dir';
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test
new file mode 100644
index 00000000000..80ce190a154
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_dbug_option_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_dbug_option
+--echo #
+
+--echo # save the initial value
+SET @wsrep_dbug_option_global_saved = @@global.wsrep_dbug_option;
+
+--echo # default
+SELECT @@global.wsrep_dbug_option;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_dbug_option;
+SET @@global.wsrep_dbug_option='test-dbug-string';
+SELECT @@global.wsrep_dbug_option;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_dbug_option='quoted-dbug-string';
+SELECT @@global.wsrep_dbug_option;
+SET @@global.wsrep_dbug_option=unquoted_dbug_string;
+SELECT @@global.wsrep_dbug_option;
+SET @@global.wsrep_dbug_option=OFF;
+SELECT @@global.wsrep_dbug_option;
+SET @@global.wsrep_dbug_option=NULL;
+SELECT @@global.wsrep_dbug_option;
+SET @@global.wsrep_dbug_option=default;
+SELECT @@global.wsrep_dbug_option;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_dbug_option=1;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_dbug_option = @wsrep_dbug_option_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test
new file mode 100644
index 00000000000..50576ff064e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_debug_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_debug
+--echo #
+
+--echo # save the initial value
+SET @wsrep_debug_global_saved = @@global.wsrep_debug;
+
+--echo # default
+SELECT @@global.wsrep_debug;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_debug;
+SET @@global.wsrep_debug=OFF;
+SELECT @@global.wsrep_debug;
+SET @@global.wsrep_debug=ON;
+SELECT @@global.wsrep_debug;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_debug='OFF';
+SELECT @@global.wsrep_debug;
+SET @@global.wsrep_debug=ON;
+SELECT @@global.wsrep_debug;
+SET @@global.wsrep_debug=default;
+SELECT @@global.wsrep_debug;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_debug=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_debug='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_debug = @wsrep_debug_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test
new file mode 100644
index 00000000000..0af1d3307f9
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_desync_basic.test
@@ -0,0 +1,49 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_desync
+--echo #
+
+# expected as no wsrep provider is currently loaded
+call mtr.add_suppression("WSREP: SET desync failed 9 for schema: test, query: SET @@global.wsrep_desync=ON");
+
+--echo # save the initial value
+SET @wsrep_desync_global_saved = @@global.wsrep_desync;
+
+--echo # default
+SELECT @@global.wsrep_desync;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_desync;
+SET @@global.wsrep_desync=OFF;
+SELECT @@global.wsrep_desync;
+# expected as no wsrep provider is currently loaded
+--error ER_CANNOT_USER
+SET @@global.wsrep_desync=ON;
+SELECT @@global.wsrep_desync;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_desync='OFF';
+SELECT @@global.wsrep_desync;
+# expected as no wsrep provider is currently loaded
+--error ER_CANNOT_USER
+SET @@global.wsrep_desync=ON;
+SELECT @@global.wsrep_desync;
+SET @@global.wsrep_desync=default;
+SELECT @@global.wsrep_desync;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_desync=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_desync='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_desync = @wsrep_desync_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test
new file mode 100644
index 00000000000..ffe767a051b
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_dirty_reads_basic.test
@@ -0,0 +1,48 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_dirty_reads
+--echo #
+
+--echo # save the initial value
+SET @wsrep_dirty_reads_session_saved = @@session.wsrep_dirty_reads;
+
+--echo # default
+
+SELECT @@global.wsrep_dirty_reads;
+SELECT @@session.wsrep_dirty_reads;
+
+--echo
+--echo # valid values for session
+SET @@session.wsrep_dirty_reads=OFF;
+SELECT @@session.wsrep_dirty_reads;
+SET @@session.wsrep_dirty_reads=ON;
+SELECT @@session.wsrep_dirty_reads;
+SET @@session.wsrep_dirty_reads=default;
+SELECT @@session.wsrep_dirty_reads;
+
+--echo
+--echo # valid values for global
+SET @@global.wsrep_dirty_reads=OFF;
+SELECT @@global.wsrep_dirty_reads;
+SET @@global.wsrep_dirty_reads=ON;
+SELECT @@global.wsrep_dirty_reads;
+SET @@global.wsrep_dirty_reads=default;
+SELECT @@global.wsrep_dirty_reads;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@session.wsrep_dirty_reads=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@session.wsrep_dirty_reads='junk';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_dirty_reads=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_dirty_reads='junk';
+
+--echo
+--echo # restore the initial values
+SET @@session.wsrep_dirty_reads = @wsrep_dirty_reads_session_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test
new file mode 100644
index 00000000000..e24f6a15265
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_drupal_282555_workaround_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_drupal_282555_workaround
+--echo #
+
+--echo # save the initial value
+SET @wsrep_drupal_282555_workaround_global_saved = @@global.wsrep_drupal_282555_workaround;
+
+--echo # default
+SELECT @@global.wsrep_drupal_282555_workaround;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_drupal_282555_workaround;
+SET @@global.wsrep_drupal_282555_workaround=OFF;
+SELECT @@global.wsrep_drupal_282555_workaround;
+SET @@global.wsrep_drupal_282555_workaround=ON;
+SELECT @@global.wsrep_drupal_282555_workaround;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_drupal_282555_workaround='OFF';
+SELECT @@global.wsrep_drupal_282555_workaround;
+SET @@global.wsrep_drupal_282555_workaround=ON;
+SELECT @@global.wsrep_drupal_282555_workaround;
+SET @@global.wsrep_drupal_282555_workaround=default;
+SELECT @@global.wsrep_drupal_282555_workaround;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_drupal_282555_workaround=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_drupal_282555_workaround='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_drupal_282555_workaround = @wsrep_drupal_282555_workaround_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test
new file mode 100644
index 00000000000..455034bb623
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_forced_binlog_format_basic.test
@@ -0,0 +1,46 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_forced_binlog_format
+--echo #
+
+--echo # save the initial value
+SET @wsrep_forced_binlog_format_global_saved = @@global.wsrep_forced_binlog_format;
+
+--echo # default
+SELECT @@global.wsrep_forced_binlog_format;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_forced_binlog_format;
+SET @@global.wsrep_forced_binlog_format=STATEMENT;
+SELECT @@global.wsrep_forced_binlog_format;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_forced_binlog_format=STATEMENT;
+SELECT @@global.wsrep_forced_binlog_format;
+SET @@global.wsrep_forced_binlog_format=ROW;
+SELECT @@global.wsrep_forced_binlog_format;
+SET @@global.wsrep_forced_binlog_format=MIXED;
+SELECT @@global.wsrep_forced_binlog_format;
+SET @@global.wsrep_forced_binlog_format=NONE;
+SELECT @@global.wsrep_forced_binlog_format;
+SET @@global.wsrep_forced_binlog_format=default;
+SELECT @@global.wsrep_forced_binlog_format;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_forced_binlog_format=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_forced_binlog_format='junk';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_forced_binlog_format=ON;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_forced_binlog_format = @wsrep_forced_binlog_format_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test
new file mode 100644
index 00000000000..d52e388fc60
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_load_data_splitting_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_load_data_splitting
+--echo #
+
+--echo # save the initial value
+SET @wsrep_load_data_splitting_global_saved = @@global.wsrep_load_data_splitting;
+
+--echo # default
+SELECT @@global.wsrep_load_data_splitting;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_load_data_splitting;
+SET @@global.wsrep_load_data_splitting=OFF;
+SELECT @@global.wsrep_load_data_splitting;
+SET @@global.wsrep_load_data_splitting=ON;
+SELECT @@global.wsrep_load_data_splitting;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_load_data_splitting='OFF';
+SELECT @@global.wsrep_load_data_splitting;
+SET @@global.wsrep_load_data_splitting=ON;
+SELECT @@global.wsrep_load_data_splitting;
+SET @@global.wsrep_load_data_splitting=default;
+SELECT @@global.wsrep_load_data_splitting;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_load_data_splitting=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_load_data_splitting='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_load_data_splitting = @wsrep_load_data_splitting_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test
new file mode 100644
index 00000000000..eee4d966855
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_log_conflicts_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_log_conflicts
+--echo #
+
+--echo # save the initial value
+SET @wsrep_log_conflicts_global_saved = @@global.wsrep_log_conflicts;
+
+--echo # default
+SELECT @@global.wsrep_log_conflicts;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_log_conflicts;
+SET @@global.wsrep_log_conflicts=OFF;
+SELECT @@global.wsrep_log_conflicts;
+SET @@global.wsrep_log_conflicts=ON;
+SELECT @@global.wsrep_log_conflicts;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_log_conflicts='OFF';
+SELECT @@global.wsrep_log_conflicts;
+SET @@global.wsrep_log_conflicts=ON;
+SELECT @@global.wsrep_log_conflicts;
+SET @@global.wsrep_log_conflicts=default;
+SELECT @@global.wsrep_log_conflicts;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_log_conflicts=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_log_conflicts='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_log_conflicts = @wsrep_log_conflicts_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test
new file mode 100644
index 00000000000..ed78662c02d
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_rows_basic.test
@@ -0,0 +1,45 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_max_ws_rows
+--echo #
+
+--echo # save the initial value
+SET @wsrep_max_ws_rows_global_saved = @@global.wsrep_max_ws_rows;
+
+--echo # default
+SELECT @@global.wsrep_max_ws_rows;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_max_ws_rows;
+SET @@global.wsrep_max_ws_rows=1;
+SELECT @@global.wsrep_max_ws_rows;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_max_ws_rows=131072;
+SELECT @@global.wsrep_max_ws_rows;
+SET @@global.wsrep_max_ws_rows=131073;
+SELECT @@global.wsrep_max_ws_rows;
+SET @@global.wsrep_max_ws_rows=0;
+SELECT @@global.wsrep_max_ws_rows;
+SET @@global.wsrep_max_ws_rows=default;
+SELECT @global.wsrep_max_ws_rows;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_max_ws_rows=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_max_ws_rows='junk';
+# expect warnings (Truncated incorrect wsrep_max_ws_rows value: '-1')
+SET @@global.wsrep_max_ws_rows=-1;
+SELECT @global.wsrep_max_ws_rows;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_max_ws_rows = @wsrep_max_ws_rows_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test
new file mode 100644
index 00000000000..2e302015136
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test
@@ -0,0 +1,47 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_max_ws_size
+--echo #
+
+--echo # save the initial value
+SET @wsrep_max_ws_size_global_saved = @@global.wsrep_max_ws_size;
+SET @wsrep_provider_options_saved = @@global.wsrep_provider_options;
+
+--echo # default
+SELECT @@global.wsrep_max_ws_size;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_max_ws_size;
+SET @@global.wsrep_max_ws_size=1;
+SELECT @@global.wsrep_max_ws_size;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_max_ws_size=1073741824;
+SELECT @@global.wsrep_max_ws_size;
+SET @@global.wsrep_max_ws_size=1073741825;
+SELECT @@global.wsrep_max_ws_size;
+SET @@global.wsrep_max_ws_size=0;
+SELECT @@global.wsrep_max_ws_size;
+SET @@global.wsrep_max_ws_size=default;
+SELECT @global.wsrep_max_ws_size;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_max_ws_size=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_max_ws_size='junk';
+SELECT @global.wsrep_max_ws_size;
+SET @@global.wsrep_max_ws_size=-1;
+SELECT @global.wsrep_max_ws_size;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_max_ws_size = @wsrep_max_ws_size_global_saved;
+SET @@global.wsrep_provider_options = @wsrep_provider_options_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test
new file mode 100644
index 00000000000..c293048c43f
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_mysql_replication_bundle_basic.test
@@ -0,0 +1,45 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_mysql_replication_bundle
+--echo #
+
+--echo # save the initial value
+SET @wsrep_mysql_replication_bundle_global_saved = @@global.wsrep_mysql_replication_bundle;
+
+--echo # default
+SELECT @@global.wsrep_mysql_replication_bundle;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_mysql_replication_bundle;
+SELECT @@global.wsrep_mysql_replication_bundle;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_mysql_replication_bundle=0;
+SELECT @@global.wsrep_mysql_replication_bundle;
+SET @@global.wsrep_mysql_replication_bundle=1000;
+SELECT @@global.wsrep_mysql_replication_bundle;
+SET @@global.wsrep_mysql_replication_bundle=default;
+SELECT @@global.wsrep_mysql_replication_bundle;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_mysql_replication_bundle=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_mysql_replication_bundle='junk';
+# expect warning (truncated incorrect value)
+SET @@global.wsrep_mysql_replication_bundle=-1;
+SELECT @@global.wsrep_mysql_replication_bundle;
+# expect warning (truncated incorrect value)
+SET @@global.wsrep_mysql_replication_bundle=1001;
+SELECT @@global.wsrep_mysql_replication_bundle;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_mysql_replication_bundle = @wsrep_mysql_replication_bundle_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test
new file mode 100644
index 00000000000..fccb40de6bf
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_node_address_basic.test
@@ -0,0 +1,45 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_node_address
+--echo #
+
+--echo # save the initial value
+SET @wsrep_node_address_global_saved = @@global.wsrep_node_address;
+
+--echo # default
+SELECT @@global.wsrep_node_address;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_node_address;
+SELECT @@global.wsrep_node_address;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_node_address='127.0.0.1';
+SELECT @@global.wsrep_node_address;
+# default == ''
+SET @@global.wsrep_node_address=default;
+SELECT @@global.wsrep_node_address;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_node_address=NULL;
+SELECT @@global.wsrep_node_address;
+# The values being assigned to wsrep_node_address are not verified so the
+# following alues are currently valid too.
+SET @@global.wsrep_node_address=ON;
+SELECT @@global.wsrep_node_address;
+SET @@global.wsrep_node_address='OFF';
+SELECT @@global.wsrep_node_address;
+SET @@global.wsrep_node_address='junk';
+SELECT @@global.wsrep_node_address;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_node_address = @wsrep_node_address_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test
new file mode 100644
index 00000000000..9ab9525d2a9
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_node_incoming_address_basic.test
@@ -0,0 +1,47 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_node_incoming_address
+--echo #
+
+--echo # save the initial value
+SET @wsrep_node_incoming_address_global_saved = @@global.wsrep_node_incoming_address;
+
+--echo # default
+SELECT @@global.wsrep_node_incoming_address;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_node_incoming_address;
+SELECT @@global.wsrep_node_incoming_address;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_node_incoming_address='127.0.0.1:4444';
+SELECT @@global.wsrep_node_incoming_address;
+SET @@global.wsrep_node_incoming_address='127.0.0.1';
+SELECT @@global.wsrep_node_incoming_address;
+SET @@global.wsrep_node_incoming_address=AUTO;
+SELECT @@global.wsrep_node_incoming_address;
+SET @@global.wsrep_node_incoming_address=default;
+SELECT @@global.wsrep_node_incoming_address;
+
+--echo
+--echo # invalid values
+# The values being assigned to wsrep_node_incoming_address are not verified so
+# the following values are currently valid too.
+SET @@global.wsrep_node_incoming_address=ON;
+SELECT @@global.wsrep_node_incoming_address;
+SET @@global.wsrep_node_incoming_address='OFF';
+SELECT @@global.wsrep_node_incoming_address;
+SET @@global.wsrep_node_incoming_address=NULL;
+SELECT @@global.wsrep_node_incoming_address;
+SET @@global.wsrep_node_incoming_address='junk';
+SELECT @@global.wsrep_node_incoming_address;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_node_incoming_address = @wsrep_node_incoming_address_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test
new file mode 100644
index 00000000000..7bc9bec8b95
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_node_name_basic.test
@@ -0,0 +1,54 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_node_name
+--echo #
+
+call mtr.add_suppression("WSREP: Failed to get provider options");
+
+--echo # save the initial value
+SET @wsrep_node_name_global_saved = @@global.wsrep_node_name;
+
+--echo # default (expect 1)
+SELECT COUNT(@@global.wsrep_node_name);
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_node_name;
+SET @@global.wsrep_node_name='node_name';
+SELECT @@global.wsrep_node_name;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_node_name='my_node';
+SELECT @@global.wsrep_node_name;
+SET @@global.wsrep_node_name='hyphenated-node-name';
+SELECT @@global.wsrep_node_name;
+SET @@global.wsrep_node_name=default;
+--echo # default (expect 1)
+SELECT COUNT(@@global.wsrep_node_name);
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_node_name=NULL;
+SELECT COUNT(@@global.wsrep_node_name);
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_node_name=1;
+SELECT COUNT(@@global.wsrep_node_name);
+
+--echo #
+--echo # MDEV-6699 : wsrep_node_name not automaticly set to hostname
+--echo #
+SET @@global.wsrep_node_name=default;
+SELECT @@GLOBAL.wsrep_node_name = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='hostname';
+SELECT @@GLOBAL.wsrep_node_name = VARIABLE_VALUE FROM
+INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='wsrep_node_name';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_node_name = @wsrep_node_name_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test
new file mode 100644
index 00000000000..6d1535ba148
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_notify_cmd_basic.test
@@ -0,0 +1,43 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_notify_cmd
+--echo #
+
+call mtr.add_suppression("WSREP: Failed to get provider options");
+
+--echo # save the initial value
+SET @wsrep_notify_cmd_global_saved = @@global.wsrep_notify_cmd;
+
+--echo # default
+SELECT @@global.wsrep_notify_cmd;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_notify_cmd;
+SET @@global.wsrep_notify_cmd='notify_cmd';
+SELECT @@global.wsrep_notify_cmd;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_notify_cmd='command';
+SELECT @@global.wsrep_notify_cmd;
+SET @@global.wsrep_notify_cmd='hyphenated-command';
+SELECT @@global.wsrep_notify_cmd;
+SET @@global.wsrep_notify_cmd=default;
+SELECT @@global.wsrep_notify_cmd;
+SET @@global.wsrep_notify_cmd=NULL;
+SELECT @@global.wsrep_notify_cmd;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_notify_cmd=1;
+SELECT @@global.wsrep_notify_cmd;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_notify_cmd = @wsrep_notify_cmd_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_on_basic.test b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test
new file mode 100644
index 00000000000..229d771b5e7
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_on_basic.test
@@ -0,0 +1,45 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_on
+--echo #
+
+--echo # save the initial values
+SET @wsrep_on_global_saved = @@global.wsrep_on;
+SET @wsrep_on_session_saved = @@session.wsrep_on;
+
+--echo # default
+SELECT @@global.wsrep_on;
+SELECT @@session.wsrep_on;
+
+--echo
+--echo # scope and valid values
+SET @@global.wsrep_on=OFF;
+SELECT @@global.wsrep_on;
+SET @@global.wsrep_on=ON;
+SELECT @@global.wsrep_on;
+
+SET @@session.wsrep_on=OFF;
+SELECT @@session.wsrep_on;
+SET @@session.wsrep_on=ON;
+SELECT @@session.wsrep_on;
+SET @@session.wsrep_on=default;
+SELECT @@session.wsrep_on;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_on=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_on='junk';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@session.wsrep_on=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@session.wsrep_on='junk';
+
+--echo
+--echo # restore the initial values
+SET @@global.wsrep_on = @wsrep_on_global_saved;
+SET @@session.wsrep_on = @wsrep_on_session_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test
new file mode 100644
index 00000000000..ce3a3def88b
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test
@@ -0,0 +1,49 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_osu_method
+--echo #
+
+--echo # save the initial value
+SET @wsrep_osu_method_global_saved = @@global.wsrep_osu_method;
+
+--echo # default
+SELECT @@global.wsrep_osu_method;
+
+--echo
+--echo # scope
+SELECT @@session.wsrep_osu_method;
+SET @@global.wsrep_osu_method=TOI;
+SELECT @@global.wsrep_osu_method;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_osu_method=TOI;
+SELECT @@global.wsrep_osu_method;
+SET @@global.wsrep_osu_method=RSU;
+SELECT @@global.wsrep_osu_method;
+SET @@global.wsrep_osu_method="RSU";
+SELECT @@global.wsrep_osu_method;
+SET @@global.wsrep_osu_method=default;
+SELECT @@global.wsrep_osu_method;
+# numeric value
+SET @@global.wsrep_osu_method=1;
+SELECT @@global.wsrep_osu_method;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_osu_method=4;
+SELECT @@global.wsrep_osu_method;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_osu_method=NULL;
+SELECT @@global.wsrep_osu_method;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_osu_method='junk';
+SELECT @@global.wsrep_osu_method;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_osu_method = @wsrep_osu_method_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test
new file mode 100644
index 00000000000..1190ab41bb0
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_provider_basic.test
@@ -0,0 +1,39 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_provider
+--echo #
+
+--echo # save the initial value
+SET @wsrep_provider_global_saved = @@global.wsrep_provider;
+
+--echo # default
+SELECT @@global.wsrep_provider;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_provider;
+SELECT @@global.wsrep_provider;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_provider=default;
+SELECT @@global.wsrep_provider;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_provider='/invalid/libgalera_smm.so';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_provider=NULL;
+SELECT @@global.wsrep_provider;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_provider=1;
+SELECT @@global.wsrep_provider;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_provider = @wsrep_provider_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test
new file mode 100644
index 00000000000..10ca8298029
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test
@@ -0,0 +1,44 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_provider_options
+--echo #
+
+call mtr.add_suppression("WSREP: Failed to get provider options");
+
+--echo # save the initial value
+SET @wsrep_provider_options_global_saved = @@global.wsrep_provider_options;
+
+--echo # default
+SELECT @@global.wsrep_provider_options;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_provider_options;
+SET @@global.wsrep_provider_options='option1';
+SELECT @@global.wsrep_provider_options;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_provider_options='name1=value1;name2=value2';
+SELECT @@global.wsrep_provider_options;
+SET @@global.wsrep_provider_options='hyphenated-name:value';
+SELECT @@global.wsrep_provider_options;
+SET @@global.wsrep_provider_options=default;
+SELECT @@global.wsrep_provider_options;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_provider_options=1;
+SELECT @@global.wsrep_provider_options;
+--error ER_WRONG_ARGUMENTS
+SET @@global.wsrep_provider_options=NULL;
+SELECT @@global.wsrep_provider_options;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_provider_options = @wsrep_provider_options_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test
new file mode 100644
index 00000000000..f935e12e258
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_recover_basic.test
@@ -0,0 +1,26 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_recover
+--echo #
+
+--echo # default
+SELECT @@global.wsrep_recover;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_recover;
+
+--echo
+--echo # scope and valid values
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_recover=OFF;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_recover=ON;
+
+--echo
+--echo # invalid values
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_recover=NULL;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_recover='junk';
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test
new file mode 100644
index 00000000000..812fb0cfd73
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_replicate_myisam_basic.test
@@ -0,0 +1,36 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_replicate_myisam
+--echo #
+
+--echo # save the initial value
+SET @wsrep_replicate_myisam_global_saved = @@global.wsrep_replicate_myisam;
+
+--echo # default
+SELECT @@global.wsrep_replicate_myisam;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_replicate_myisam;
+
+--echo
+--echo # scope and valid values
+#--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+#TODO: check if it is expected for variable to be dynamic?
+SET @@global.wsrep_replicate_myisam=OFF;
+SELECT @@global.wsrep_replicate_myisam;
+#--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_replicate_myisam=ON;
+SELECT @@global.wsrep_replicate_myisam;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_replicate_myisam=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_replicate_myisam='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_replicate_myisam = @wsrep_replicate_myisam_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test
new file mode 100644
index 00000000000..c656111aed6
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_restart_slave_basic.test
@@ -0,0 +1,36 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_restart_slave
+--echo #
+
+--echo # save the initial value
+SET @wsrep_restart_slave_global_saved = @@global.wsrep_restart_slave;
+
+--echo # default
+SELECT @@global.wsrep_restart_slave;
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_restart_slave;
+
+--echo
+--echo # scope and valid values
+#--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+#TODO: check if it is expected for variable to be dynamic?
+SET @@global.wsrep_restart_slave=OFF;
+SELECT @@global.wsrep_restart_slave;
+#--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@global.wsrep_restart_slave=ON;
+SELECT @@global.wsrep_restart_slave;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_restart_slave=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_restart_slave='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_restart_slave = @wsrep_restart_slave_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test
new file mode 100644
index 00000000000..aa6f27f816d
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_retry_autocommit_basic.test
@@ -0,0 +1,52 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_retry_autocommit
+--echo #
+
+--echo # save the initial values
+SET @wsrep_retry_autocommit_global_saved = @@global.wsrep_retry_autocommit;
+SET @wsrep_retry_autocommit_session_saved = @@session.wsrep_retry_autocommit;
+
+--echo # default
+SELECT @@global.wsrep_retry_autocommit;
+
+--echo
+--echo # scope
+SET @@session.wsrep_retry_autocommit=1;
+SELECT @@session.wsrep_retry_autocommit;
+SET @@global.wsrep_retry_autocommit=1;
+SELECT @@global.wsrep_retry_autocommit;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_retry_autocommit=10;
+SELECT @@global.wsrep_retry_autocommit;
+SET @@global.wsrep_retry_autocommit=0;
+SELECT @@global.wsrep_retry_autocommit;
+SET @@global.wsrep_retry_autocommit=default;
+SELECT @global.wsrep_retry_autocommit;
+
+SET @@session.wsrep_retry_autocommit=10;
+SELECT @@session.wsrep_retry_autocommit;
+SET @@session.wsrep_retry_autocommit=0;
+SELECT @@session.wsrep_retry_autocommit;
+SET @@session.wsrep_retry_autocommit=default;
+SELECT @session.wsrep_retry_autocommit;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_retry_autocommit=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_retry_autocommit='junk';
+# expect warning : Truncated incorrect wsrep_retry_autocommit value: '-1'
+SET @@global.wsrep_retry_autocommit=-1;
+SELECT @global.wsrep_retry_autocommit;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_retry_autocommit = @wsrep_retry_autocommit_global_saved;
+SET @@session.wsrep_retry_autocommit = @wsrep_retry_autocommit_session_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test
new file mode 100644
index 00000000000..dd60eb8694b
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_slave_fk_checks_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_slave_fk_checks
+--echo #
+
+--echo # save the initial value
+SET @wsrep_slave_fk_checks_global_saved = @@global.wsrep_slave_fk_checks;
+
+--echo # default
+SELECT @@global.wsrep_slave_fk_checks;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_slave_fk_checks;
+SET @@global.wsrep_slave_fk_checks=OFF;
+SELECT @@global.wsrep_slave_fk_checks;
+SET @@global.wsrep_slave_fk_checks=ON;
+SELECT @@global.wsrep_slave_fk_checks;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_slave_fk_checks='OFF';
+SELECT @@global.wsrep_slave_fk_checks;
+SET @@global.wsrep_slave_fk_checks=ON;
+SELECT @@global.wsrep_slave_fk_checks;
+SET @@global.wsrep_slave_fk_checks=default;
+SELECT @@global.wsrep_slave_fk_checks;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_slave_fk_checks=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_slave_fk_checks='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test
new file mode 100644
index 00000000000..80b4648982d
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_slave_threads_basic.test
@@ -0,0 +1,43 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_slave_threads
+--echo #
+
+--echo # save the initial value
+SET @wsrep_slave_threads_global_saved = @@global.wsrep_slave_threads;
+
+--echo # default
+SELECT @@global.wsrep_slave_threads;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_slave_threads;
+SET @@global.wsrep_slave_threads=1;
+SELECT @@global.wsrep_slave_threads;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_slave_threads=10;
+SELECT @@global.wsrep_slave_threads;
+SET @@global.wsrep_slave_threads=0;
+SELECT @@global.wsrep_slave_threads;
+SET @@global.wsrep_slave_threads=default;
+SELECT @global.wsrep_slave_threads;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_slave_threads=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_slave_threads='junk';
+# expect warning : Truncated incorrect wsrep_slave_threads value: '-1'
+SET @@global.wsrep_slave_threads=-1;
+SELECT @global.wsrep_slave_threads;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_slave_threads = @wsrep_slave_threads_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test b/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test
new file mode 100644
index 00000000000..c9012954371
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_slave_uk_checks_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_slave_uk_checks
+--echo #
+
+--echo # save the initial value
+SET @wsrep_slave_uk_checks_global_saved = @@global.wsrep_slave_uk_checks;
+
+--echo # default
+SELECT @@global.wsrep_slave_uk_checks;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_slave_uk_checks;
+SET @@global.wsrep_slave_uk_checks=OFF;
+SELECT @@global.wsrep_slave_uk_checks;
+SET @@global.wsrep_slave_uk_checks=ON;
+SELECT @@global.wsrep_slave_uk_checks;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_slave_uk_checks='OFF';
+SELECT @@global.wsrep_slave_uk_checks;
+SET @@global.wsrep_slave_uk_checks=ON;
+SELECT @@global.wsrep_slave_uk_checks;
+SET @@global.wsrep_slave_uk_checks=default;
+SELECT @@global.wsrep_slave_uk_checks;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_slave_uk_checks=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_slave_uk_checks='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_slave_uk_checks = @wsrep_slave_uk_checks_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test
new file mode 100644
index 00000000000..aa901ef9ff7
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_sst_auth_basic.test
@@ -0,0 +1,45 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_sst_auth
+--echo #
+
+--echo # save the initial value
+SET @wsrep_sst_auth_global_saved = @@global.wsrep_sst_auth;
+
+--echo # default
+SELECT @@global.wsrep_sst_auth;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth='user:pass';
+SELECT @@global.wsrep_sst_auth;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_sst_auth=user;
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth='user:1234';
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth='hyphenated-user-name:';
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth=default;
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth=NULL;
+SELECT @@global.wsrep_sst_auth;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_sst_auth=1;
+SELECT @@global.wsrep_sst_auth;
+--error ER_PARSE_ERROR
+SET @@global.wsrep_sst_auth=user:pass;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_sst_auth = @wsrep_sst_auth_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test
new file mode 100644
index 00000000000..7d3d6598557
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_basic.test
@@ -0,0 +1,43 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_sst_donor
+--echo #
+
+--echo # save the initial value
+SET @wsrep_sst_donor_global_saved = @@global.wsrep_sst_donor;
+
+--echo # default
+SELECT @@global.wsrep_sst_donor;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_sst_donor;
+SET @@global.wsrep_sst_donor=rsync;
+SELECT @@global.wsrep_sst_donor;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_sst_donor=node1;
+SELECT @@global.wsrep_sst_donor;
+SET @@global.wsrep_sst_donor='node1,node2';
+SELECT @@global.wsrep_sst_donor;
+SET @@global.wsrep_sst_donor='hyphenated-donor-name';
+SELECT @@global.wsrep_sst_donor;
+SET @@global.wsrep_sst_donor=default;
+SELECT @@global.wsrep_sst_donor;
+SET @@global.wsrep_sst_donor=NULL;
+SELECT @@global.wsrep_sst_donor;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_sst_donor=1;
+SELECT @@global.wsrep_sst_donor;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_sst_donor = @wsrep_sst_donor_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test
new file mode 100644
index 00000000000..bd34e23cd2a
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_sst_donor_rejects_queries_basic.test
@@ -0,0 +1,42 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_sst_donor_rejects_queries
+--echo #
+
+--echo # save the initial value
+SET @wsrep_sst_donor_rejects_queries_global_saved = @@global.wsrep_sst_donor_rejects_queries;
+
+--echo # default
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_sst_donor_rejects_queries;
+SET @@global.wsrep_sst_donor_rejects_queries=OFF;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+SET @@global.wsrep_sst_donor_rejects_queries=ON;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_sst_donor_rejects_queries='OFF';
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+SET @@global.wsrep_sst_donor_rejects_queries=ON;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+SET @@global.wsrep_sst_donor_rejects_queries=default;
+SELECT @@global.wsrep_sst_donor_rejects_queries;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_sst_donor_rejects_queries=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_sst_donor_rejects_queries='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_sst_donor_rejects_queries = @wsrep_sst_donor_rejects_queries_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test
new file mode 100644
index 00000000000..3f40a3922dd
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_sst_method_basic.test
@@ -0,0 +1,47 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_sst_method
+--echo #
+
+--echo # save the initial value
+SET @wsrep_sst_method_global_saved = @@global.wsrep_sst_method;
+
+--echo # default
+SELECT @@global.wsrep_sst_method;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_sst_method;
+SET @@global.wsrep_sst_method=rsync;
+SELECT @@global.wsrep_sst_method;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_sst_method=rsync;
+SELECT @@global.wsrep_sst_method;
+SET @@global.wsrep_sst_method=mysqldump;
+SELECT @@global.wsrep_sst_method;
+SET @@global.wsrep_sst_method=xtrabackup;
+SELECT @@global.wsrep_sst_method;
+SET @@global.wsrep_sst_method="xtrabackup-v2";
+SELECT @@global.wsrep_sst_method;
+SET @@global.wsrep_sst_method=default;
+SELECT @@global.wsrep_sst_method;
+
+# Its a valid name for an SST method
+SET @@global.wsrep_sst_method='junk';
+SELECT @@global.wsrep_sst_method;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_sst_method=NULL;
+SELECT @@global.wsrep_sst_method;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_sst_method = @wsrep_sst_method_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test
new file mode 100644
index 00000000000..9e50cbf8947
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_sst_receive_address_basic.test
@@ -0,0 +1,53 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_sst_receive_address
+--echo #
+
+--echo # save the initial value
+SET @wsrep_sst_receive_address_global_saved = @@global.wsrep_sst_receive_address;
+
+--echo # default
+SELECT @@global.wsrep_sst_receive_address;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_sst_receive_address;
+SELECT @@global.wsrep_sst_receive_address;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_sst_receive_address=AUTO;
+SELECT @@global.wsrep_sst_receive_address;
+SET @@global.wsrep_sst_receive_address=default;
+SELECT @@global.wsrep_sst_receive_address;
+SET @@global.wsrep_sst_receive_address='192.168.2.254';
+SELECT @@global.wsrep_sst_receive_address;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_sst_receive_address='127.0.0.1:4444';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_sst_receive_address='127.0.0.1';
+SELECT @@global.wsrep_sst_receive_address;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_sst_receive_address=NULL;
+SELECT @@global.wsrep_sst_receive_address;
+# Currently there is no strict checking performed for wsrep_sst_receive_address
+# so following values jusr pass through.
+SET @@global.wsrep_sst_receive_address='OFF';
+SELECT @@global.wsrep_sst_receive_address;
+SET @@global.wsrep_sst_receive_address=ON;
+SELECT @@global.wsrep_sst_receive_address;
+SET @@global.wsrep_sst_receive_address='';
+SELECT @@global.wsrep_sst_receive_address;
+SET @@global.wsrep_sst_receive_address='junk';
+SELECT @@global.wsrep_sst_receive_address;
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_sst_receive_address = @wsrep_sst_receive_address_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test
new file mode 100644
index 00000000000..3e57cfa6da2
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_start_position_basic.test
@@ -0,0 +1,56 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_start_position
+--echo #
+
+--echo # save the initial value
+SET @wsrep_start_position_global_saved = @@global.wsrep_start_position;
+
+--echo # default
+SELECT @@global.wsrep_start_position;
+
+--echo
+--echo # scope
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_start_position;
+SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-1';
+SELECT @@global.wsrep_start_position;
+
+--echo
+--echo # valid values
+SET @@global.wsrep_start_position='00000000-0000-0000-0000-000000000000:-2';
+SELECT @@global.wsrep_start_position;
+SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:100';
+SELECT @@global.wsrep_start_position;
+SET @@global.wsrep_start_position=default;
+SELECT @@global.wsrep_start_position;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='000000000000000-0000-0000-0000-000000000000:-1';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='12345678-1234-1234-12345-123456789012:100';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='12345678-1234-123-12345-123456789012:0';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:_99999';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='12345678-1234-1234-1234-123456789012:a';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='OFF';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position=ON;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='';
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position=NULL;
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.wsrep_start_position='junk';
+
+--echo
+--echo # restore the initial value
+SET @@global.wsrep_start_position = @wsrep_start_position_global_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test b/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test
new file mode 100644
index 00000000000..cd0d545f80e
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_sync_wait_basic.test
@@ -0,0 +1,47 @@
+--source include/have_wsrep.inc
+
+--echo #
+--echo # wsrep_sync_wait
+--echo #
+
+--echo # save the initial values
+SET @wsrep_sync_wait_global_saved = @@global.wsrep_sync_wait;
+SET @wsrep_sync_wait_session_saved = @@session.wsrep_sync_wait;
+
+--echo # default
+SELECT @@global.wsrep_sync_wait;
+SELECT @@session.wsrep_sync_wait;
+
+--echo
+--echo # scope and valid values
+SET @@global.wsrep_sync_wait=0;
+SELECT @@global.wsrep_sync_wait;
+SET @@global.wsrep_sync_wait=7;
+SELECT @@global.wsrep_sync_wait;
+
+SET @@session.wsrep_sync_wait=0;
+SELECT @@session.wsrep_sync_wait;
+SET @@session.wsrep_sync_wait=7;
+SELECT @@session.wsrep_sync_wait;
+SET @@session.wsrep_sync_wait=default;
+SELECT @@session.wsrep_sync_wait;
+SET @@session.wsrep_sync_wait=8;
+SELECT @@session.wsrep_sync_wait;
+
+--echo
+--echo # invalid values
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_sync_wait=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.wsrep_sync_wait='junk';
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@session.wsrep_sync_wait=NULL;
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@session.wsrep_sync_wait='junk';
+
+--echo
+--echo # restore the initial values
+SET @@global.wsrep_sync_wait = @wsrep_sync_wait_global_saved;
+SET @@session.wsrep_sync_wait = @wsrep_sync_wait_session_saved;
+
+--echo # End of test
diff --git a/mysql-test/suite/wsrep/README b/mysql-test/suite/wsrep/README
new file mode 100644
index 00000000000..988096071a4
--- /dev/null
+++ b/mysql-test/suite/wsrep/README
@@ -0,0 +1,7 @@
+* 'wsrep' suite is designated for tests which do not require a multi-node
+ galera cluster.
+
+* As these tests are specific to wsrep-related functionalities, they must skip
+ on server built without wsrep patch (vanilla). (-DWITH_WSREP=OFF)
+ See : include/have_wsrep.inc, include/have_wsrep_enabled.inc, not_wsrep.inc
+
diff --git a/mysql-test/suite/wsrep/disabled.def b/mysql-test/suite/wsrep/disabled.def
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/mysql-test/suite/wsrep/disabled.def
@@ -0,0 +1 @@
+
diff --git a/mysql-test/suite/wsrep/include/check_galera_version.inc b/mysql-test/suite/wsrep/include/check_galera_version.inc
new file mode 100644
index 00000000000..e495da8f1ee
--- /dev/null
+++ b/mysql-test/suite/wsrep/include/check_galera_version.inc
@@ -0,0 +1,39 @@
+# ==== Purpose ====
+# Enable tests to check the galera library version.
+#
+# ==== Usage ====
+# --let $galera_version=3.6
+# source include/check_galera_lib_version.inc;
+#
+# Parameters:
+# $galera_version
+# Version of the galera library required by the test.
+#
+
+--disable_query_log
+
+# Required Version
+
+eval SET @GALERA_VERSION='$galera_version';
+SELECT CAST(REGEXP_REPLACE(@GALERA_VERSION,'^(\\d+)\\.(\\d+).*','\\1') AS UNSIGNED) INTO @GALERA_MAJOR_VERSION;
+SELECT CAST(REGEXP_REPLACE(@GALERA_VERSION,'^(\\d+)\\.(\\d+).*','\\2') AS UNSIGNED) INTO @GALERA_MINOR_VERSION;
+
+# Actual
+SELECT VARIABLE_VALUE INTO @ACTUAL_GALERA_VERSION FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME LIKE 'wsrep_provider_version';
+
+SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^(\\d+)\\.(\\d+).*','\\1') AS UNSIGNED) INTO @ACTUAL_GALERA_MAJOR_VERSION;
+SELECT CAST(REGEXP_REPLACE(@ACTUAL_GALERA_VERSION,'^(\\d+)\\.(\\d+).*','\\2') AS UNSIGNED) INTO @ACTUAL_GALERA_MINOR_VERSION;
+
+# For testing
+#SELECT @GALERA_MAJOR_VERSION, @GALERA_MINOR_VERSION;
+#SELECT @ACTUAL_GALERA_VERSION;
+#SELECT @ACTUAL_GALERA_MAJOR_VERSION, @ACTUAL_GALERA_MINOR_VERSION;
+
+if (!`SELECT (@ACTUAL_GALERA_MAJOR_VERSION > @GALERA_MAJOR_VERSION) OR
+ (@ACTUAL_GALERA_MAJOR_VERSION = @GALERA_MAJOR_VERSION AND @ACTUAL_GALERA_MINOR_VERSION >= @GALERA_MINOR_VERSION)
+ `)
+{
+ skip Test requires Galera library version $galera_version;
+}
+
+--enable_query_log
diff --git a/mysql-test/suite/wsrep/my.cnf b/mysql-test/suite/wsrep/my.cnf
new file mode 100644
index 00000000000..0b5144b774e
--- /dev/null
+++ b/mysql-test/suite/wsrep/my.cnf
@@ -0,0 +1,9 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M'
+
diff --git a/mysql-test/suite/wsrep/r/alter_table_innodb.result b/mysql-test/suite/wsrep/r/alter_table_innodb.result
new file mode 100644
index 00000000000..85017cec6e0
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/alter_table_innodb.result
@@ -0,0 +1,8 @@
+#
+# MDEV-7374 : Losing connection to MySQL while running ALTER TABLE
+#
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+INSERT INTO t1 SELECT a.* FROM t1 a, t1 b, t1 c, t1 d, t1 e;
+ALTER TABLE t1 MODIFY i FLOAT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/wsrep/r/binlog_format.result b/mysql-test/suite/wsrep/r/binlog_format.result
new file mode 100644
index 00000000000..d996371c056
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/binlog_format.result
@@ -0,0 +1,61 @@
+call mtr.add_suppression("WSREP: MariaDB Galera does not support binlog format.*");
+call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID");
+#
+# MDEV-4227: Galera server should stop crashing on setting binlog_format STATEMENT
+#
+SHOW VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format ROW
+SET binlog_format=STATEMENT;
+Warnings:
+Warning 1105 MariaDB Galera does not support binlog format: STATEMENT
+SHOW WARNINGS;
+Level Code Message
+Warning 1105 MariaDB Galera does not support binlog format: STATEMENT
+SHOW VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format STATEMENT
+CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0;
+SET binlog_format=MIXED;
+Warnings:
+Warning 1105 MariaDB Galera does not support binlog format: MIXED
+SHOW WARNINGS;
+Level Code Message
+Warning 1105 MariaDB Galera does not support binlog format: MIXED
+SHOW VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format MIXED
+CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0;
+SET binlog_format=ROW;
+SHOW WARNINGS;
+Level Code Message
+SHOW VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format ROW
+CREATE TABLE IF NOT EXISTS test.t3 AS SELECT * FROM information_schema.routines WHERE 1 = 0;
+DROP TABLE IF EXISTS test.t1;
+DROP TABLE IF EXISTS test.t2;
+DROP TABLE IF EXISTS test.t3;
+#
+# MDEV-7322: Option to allow setting the binlog_format with Galera
+#
+SET @@GLOBAL.binlog_format=STATEMENT;
+ERROR 42000: Variable 'binlog_format' can't be set to the value of 'STATEMENT'
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format ROW
+SET @@GLOBAL.binlog_format=MIXED;
+ERROR 42000: Variable 'binlog_format' can't be set to the value of 'MIXED'
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format ROW
+SET @@GLOBAL.binlog_format=DEFAULT;
+ERROR 42000: Variable 'binlog_format' can't be set to the value of 'DEFAULT'
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format ROW
+SET @@GLOBAL.binlog_format=ROW;
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+Variable_name Value
+binlog_format ROW
+# End of test.
diff --git a/mysql-test/suite/wsrep/r/foreign_key.result b/mysql-test/suite/wsrep/r/foreign_key.result
new file mode 100644
index 00000000000..c8407480f17
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/foreign_key.result
@@ -0,0 +1,19 @@
+USE test;
+create table p(v varchar(20), i int, primary key(v,i)) engine=innodb character set = utf8;
+create table c(k int primary key, v varchar(20), i int, foreign key(v,i) references p(v,i)) engine=innodb character set = utf8;
+insert into p values (_utf32 0x000004100000041100000412, 1);
+insert into c values (1, _utf32 0x000004100000041100000412, 1);
+SELECT * FROM test.p;
+v i
+??? 1
+SELECT * FROM test.c;
+k v i
+1 ??? 1
+SELECT * FROM test.p;
+v i
+??? 1
+SELECT * FROM test.c;
+k v i
+1 ??? 1
+DROP TABLE c;
+DROP TABLE p;
diff --git a/mysql-test/suite/wsrep/r/mdev_6832.result b/mysql-test/suite/wsrep/r/mdev_6832.result
new file mode 100644
index 00000000000..43894a6ec49
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/mdev_6832.result
@@ -0,0 +1,11 @@
+#
+# MDEV-6832: ER_LOCK_WAIT_TIMEOUT on SHOW STATUS
+#
+SHOW STATUS LIKE 'wsrep_ready';
+Variable_name Value
+wsrep_ready ON
+SHOW STATUS LIKE 'wsrep_ready';
+Variable_name Value
+wsrep_ready OFF
+SET @@global.wsrep_cluster_address='gcomm://';
+# End of test.
diff --git a/mysql-test/suite/wsrep/r/mdev_7798.result b/mysql-test/suite/wsrep/r/mdev_7798.result
new file mode 100644
index 00000000000..83a02f3a606
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/mdev_7798.result
@@ -0,0 +1,13 @@
+#
+# MDEV-7798: mysql.server init script can't stop mysqld when WSREP is
+# turned off
+#
+SELECT @@GLOBAL.WSREP_ON;
+@@GLOBAL.WSREP_ON
+1
+SET GLOBAL WSREP_ON= 0;
+Restart the node.
+SELECT @@GLOBAL.WSREP_ON;
+@@GLOBAL.WSREP_ON
+1
+# End of test.
diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result
new file mode 100644
index 00000000000..f77a655773a
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result
@@ -0,0 +1,70 @@
+#
+# MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above
+#
+# Verbose run
+SET GLOBAL wsrep_replicate_myisam= ON;
+TRUNCATE TABLE time_zone;
+TRUNCATE TABLE time_zone_name;
+TRUNCATE TABLE time_zone_transition;
+TRUNCATE TABLE time_zone_transition_type;
+INSERT INTO time_zone (Use_leap_seconds) VALUES ('N');
+SET @time_zone_id= LAST_INSERT_ID();
+INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id);
+INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES
+ (@time_zone_id, 0, 0, 0, 'GMT')
+;
+Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/garbage' as time zone. Skipping it.
+Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/ignored.tab' as time zone. Skipping it.
+INSERT INTO time_zone (Use_leap_seconds) VALUES ('N');
+SET @time_zone_id= LAST_INSERT_ID();
+INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('posix/GMT', @time_zone_id);
+INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES
+ (@time_zone_id, 0, 0, 0, 'GMT')
+;
+Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it.
+Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it.
+Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion.
+ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time;
+ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id;
+SET GLOBAL wsrep_replicate_myisam= OFF;
+# Silent run
+SET GLOBAL wsrep_replicate_myisam= ON;
+TRUNCATE TABLE time_zone;
+TRUNCATE TABLE time_zone_name;
+TRUNCATE TABLE time_zone_transition;
+TRUNCATE TABLE time_zone_transition_type;
+INSERT INTO time_zone (Use_leap_seconds) VALUES ('N');
+SET @time_zone_id= LAST_INSERT_ID();
+INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id);
+INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES
+ (@time_zone_id, 0, 0, 0, 'GMT')
+;
+Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/garbage' as time zone. Skipping it.
+INSERT INTO time_zone (Use_leap_seconds) VALUES ('N');
+SET @time_zone_id= LAST_INSERT_ID();
+INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('posix/GMT', @time_zone_id);
+INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES
+ (@time_zone_id, 0, 0, 0, 'GMT')
+;
+Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it.
+ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time;
+ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id;
+SET GLOBAL wsrep_replicate_myisam= OFF;
+#
+# Testing with explicit timezonefile
+#
+SET GLOBAL wsrep_replicate_myisam= ON;
+INSERT INTO time_zone (Use_leap_seconds) VALUES ('N');
+SET @time_zone_id= LAST_INSERT_ID();
+INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('XXX', @time_zone_id);
+INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES
+ (@time_zone_id, 0, 0, 0, 'GMT')
+;
+SET GLOBAL wsrep_replicate_myisam= OFF;
+#
+# Testing --leap
+#
+SET GLOBAL wsrep_replicate_myisam= ON;
+TRUNCATE TABLE time_zone_leap_second;
+ALTER TABLE time_zone_leap_second ORDER BY Transition_time;
+SET GLOBAL wsrep_replicate_myisam= OFF;
diff --git a/mysql-test/suite/wsrep/r/pool_of_threads.result b/mysql-test/suite/wsrep/r/pool_of_threads.result
new file mode 100644
index 00000000000..ffe309f2580
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/pool_of_threads.result
@@ -0,0 +1,8 @@
+
+#
+# MDEV#5687: Maria doesn't shutdown following upgrade to 5.5.35-galera
+#
+SELECT @@GLOBAL.thread_handling;
+@@GLOBAL.thread_handling
+pool-of-threads
+# End of test.
diff --git a/mysql-test/suite/wsrep/r/trans.result b/mysql-test/suite/wsrep/r/trans.result
new file mode 100644
index 00000000000..bc225897103
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/trans.result
@@ -0,0 +1,9 @@
+#
+# MDEV-4222 : Assertion `( ((global_system_variables.wsrep_on) &&
+# (thd && thd->variables.wsrep_on)) && srep_emulate_bin_log)
+# || mysql_bin_log .is_open()' fails on SAVEPOINT with
+# disabled wsrep_provider
+#
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+SAVEPOINT A;
+End of test.
diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result
new file mode 100644
index 00000000000..9d5d319afef
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/variables.result
@@ -0,0 +1,237 @@
+SET @wsrep_provider_options_saved= @@global.wsrep_provider_options;
+
+# MDEV#5534: mysql_tzinfo_to_sql generates wrong query
+#
+# Testing wsrep_replicate_myisam variable.
+SELECT @@session.wsrep_replicate_myisam;
+ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable
+SELECT @@global.wsrep_replicate_myisam;
+@@global.wsrep_replicate_myisam
+0
+SET SESSION wsrep_replicate_myisam= ON;
+ERROR HY000: Variable 'wsrep_replicate_myisam' is a GLOBAL variable and should be set with SET GLOBAL
+SET GLOBAL wsrep_replicate_myisam= ON;
+SET GLOBAL wsrep_replicate_myisam= OFF;
+SET GLOBAL wsrep_provider=none;
+#
+# MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of
+# variables when using "_"
+#
+CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*");
+SHOW GLOBAL STATUS LIKE 'wsrep%';
+Variable_name Value
+wsrep_local_state_uuid #
+wsrep_protocol_version #
+wsrep_last_committed #
+wsrep_replicated #
+wsrep_replicated_bytes #
+wsrep_repl_keys #
+wsrep_repl_keys_bytes #
+wsrep_repl_data_bytes #
+wsrep_repl_other_bytes #
+wsrep_received #
+wsrep_received_bytes #
+wsrep_local_commits #
+wsrep_local_cert_failures #
+wsrep_local_replays #
+wsrep_local_send_queue #
+wsrep_local_send_queue_max #
+wsrep_local_send_queue_min #
+wsrep_local_send_queue_avg #
+wsrep_local_recv_queue #
+wsrep_local_recv_queue_max #
+wsrep_local_recv_queue_min #
+wsrep_local_recv_queue_avg #
+wsrep_local_cached_downto #
+wsrep_flow_control_paused_ns #
+wsrep_flow_control_paused #
+wsrep_flow_control_sent #
+wsrep_flow_control_recv #
+wsrep_cert_deps_distance #
+wsrep_apply_oooe #
+wsrep_apply_oool #
+wsrep_apply_window #
+wsrep_commit_oooe #
+wsrep_commit_oool #
+wsrep_commit_window #
+wsrep_local_state #
+wsrep_local_state_comment #
+wsrep_cert_index_size #
+wsrep_causal_reads #
+wsrep_cert_interval #
+wsrep_incoming_addresses #
+wsrep_cluster_conf_id #
+wsrep_cluster_size #
+wsrep_cluster_state_uuid #
+wsrep_cluster_status #
+wsrep_connected #
+wsrep_local_bf_aborts #
+wsrep_local_index #
+wsrep_provider_name #
+wsrep_provider_vendor #
+wsrep_provider_version #
+wsrep_ready #
+wsrep_thread_count #
+
+SHOW GLOBAL STATUS LIKE 'wsrep_%';
+Variable_name Value
+wsrep_local_state_uuid #
+wsrep_protocol_version #
+wsrep_last_committed #
+wsrep_replicated #
+wsrep_replicated_bytes #
+wsrep_repl_keys #
+wsrep_repl_keys_bytes #
+wsrep_repl_data_bytes #
+wsrep_repl_other_bytes #
+wsrep_received #
+wsrep_received_bytes #
+wsrep_local_commits #
+wsrep_local_cert_failures #
+wsrep_local_replays #
+wsrep_local_send_queue #
+wsrep_local_send_queue_max #
+wsrep_local_send_queue_min #
+wsrep_local_send_queue_avg #
+wsrep_local_recv_queue #
+wsrep_local_recv_queue_max #
+wsrep_local_recv_queue_min #
+wsrep_local_recv_queue_avg #
+wsrep_local_cached_downto #
+wsrep_flow_control_paused_ns #
+wsrep_flow_control_paused #
+wsrep_flow_control_sent #
+wsrep_flow_control_recv #
+wsrep_cert_deps_distance #
+wsrep_apply_oooe #
+wsrep_apply_oool #
+wsrep_apply_window #
+wsrep_commit_oooe #
+wsrep_commit_oool #
+wsrep_commit_window #
+wsrep_local_state #
+wsrep_local_state_comment #
+wsrep_cert_index_size #
+wsrep_causal_reads #
+wsrep_cert_interval #
+wsrep_incoming_addresses #
+wsrep_cluster_conf_id #
+wsrep_cluster_size #
+wsrep_cluster_state_uuid #
+wsrep_cluster_status #
+wsrep_connected #
+wsrep_local_bf_aborts #
+wsrep_local_index #
+wsrep_provider_name #
+wsrep_provider_vendor #
+wsrep_provider_version #
+wsrep_ready #
+wsrep_thread_count #
+SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+Variable_name Value
+wsrep_local_state_comment #
+# Should show nothing.
+SHOW STATUS LIKE 'x';
+Variable_name Value
+SET GLOBAL wsrep_provider=none;
+#
+# MDEV#6079: xtrabackup SST failing with maria-10.0-galera
+#
+
+SHOW STATUS LIKE 'wsrep_local_state_uuid';
+Variable_name Value
+wsrep_local_state_uuid #
+
+SHOW STATUS LIKE 'wsrep_last_committed';
+Variable_name Value
+wsrep_last_committed #
+SET GLOBAL wsrep_provider=none;
+
+#
+# MDEV#6206: wsrep_slave_threads subtracts from max_connections
+#
+call mtr.add_suppression("WSREP: Failed to get provider options");
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+libgalera_smm.so
+SELECT @@global.wsrep_slave_threads;
+@@global.wsrep_slave_threads
+1
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+NULL
+SHOW STATUS LIKE 'threads_connected';
+Variable_name Value
+Threads_connected 1
+SHOW STATUS LIKE 'wsrep_thread_count';
+Variable_name Value
+wsrep_thread_count 0
+
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+libgalera_smm.so
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+NULL
+SHOW STATUS LIKE 'threads_connected';
+Variable_name Value
+Threads_connected 1
+SHOW STATUS LIKE 'wsrep_thread_count';
+Variable_name Value
+wsrep_thread_count 0
+
+# Setting wsrep_cluster_address triggers the creation of
+# applier/rollbacker threads.
+SET GLOBAL wsrep_cluster_address= 'gcomm://';
+# Wait for applier threads to get created.
+SELECT @@global.wsrep_provider;
+@@global.wsrep_provider
+libgalera_smm.so
+SELECT @@global.wsrep_cluster_address;
+@@global.wsrep_cluster_address
+gcomm://
+SHOW STATUS LIKE 'threads_connected';
+Variable_name Value
+Threads_connected 1
+SHOW STATUS LIKE 'wsrep_thread_count';
+Variable_name Value
+wsrep_thread_count 2
+
+SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads;
+SET GLOBAL wsrep_slave_threads= 10;
+# Wait for applier threads to get created.
+SHOW STATUS LIKE 'threads_connected';
+Variable_name Value
+Threads_connected 1
+SHOW STATUS LIKE 'wsrep_thread_count';
+Variable_name Value
+wsrep_thread_count 11
+set wsrep_on=0;
+set wsrep_on=1;
+create user test@localhost;
+set auto_increment_increment=10;
+set wsrep_on=0;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+drop user test@localhost;
+#
+# MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash
+#
+SET @wsrep_sst_auth_saved= @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth= 'user:pass';
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+********
+SET @@global.wsrep_sst_auth= '';
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+
+SET @@global.wsrep_sst_auth= NULL;
+SELECT @@global.wsrep_sst_auth;
+@@global.wsrep_sst_auth
+NULL
+SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved;
+SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved;
+SET GLOBAL wsrep_provider= none;
+SET GLOBAL wsrep_cluster_address= '';
+SET GLOBAL wsrep_provider_options= @wsrep_provider_options_saved;
+# End of test.
diff --git a/mysql-test/suite/wsrep/r/wsrep_rpl.result b/mysql-test/suite/wsrep/r/wsrep_rpl.result
new file mode 100644
index 00000000000..a5db3b28ec0
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/wsrep_rpl.result
@@ -0,0 +1,22 @@
+include/master-slave.inc
+[connection master]
+#
+# MDEV-10714: Could not execute Delete_rows event on table;
+# wsrep_max_ws_rows exceeded. Error_Code 1180
+#
+CREATE TABLE t1(i INT) ENGINE = INNODB;
+SET @@GLOBAL.wsrep_max_ws_rows = 2;
+INSERT INTO t1 VALUES(1), (2);
+SELECT COUNT(*) = 2 FROM t1;
+COUNT(*) = 2
+1
+SET @@GLOBAL.wsrep_max_ws_rows = 2;
+DELETE FROM t1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+SET @@GLOBAL.wsrep_max_ws_rows = 0;
+SET @@GLOBAL.wsrep_max_ws_rows = 0;
+include/rpl_end.inc
+# End of test.
diff --git a/mysql-test/suite/wsrep/suite.pm b/mysql-test/suite/wsrep/suite.pm
new file mode 100644
index 00000000000..31d9faeb0dd
--- /dev/null
+++ b/mysql-test/suite/wsrep/suite.pm
@@ -0,0 +1,38 @@
+package My::Suite::WSREP;
+use File::Basename;
+use My::Find;
+
+@ISA = qw(My::Suite);
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+return "WSREP is not compiled in" unless defined $::mysqld_variables{'wsrep-on'};
+
+my ($provider) = grep { -f $_ } $ENV{WSREP_PROVIDER},
+ "/usr/lib/galera/libgalera_smm.so",
+ "/usr/lib64/galera/libgalera_smm.so";
+
+return "No wsrep provider library" unless -f $provider;
+
+$ENV{WSREP_PROVIDER} = $provider;
+
+my ($spath) = grep { -f "$_/wsrep_sst_rsync"; } "$::bindir/scripts", $::path_client_bindir;
+return "No SST scripts" unless $spath;
+
+my ($epath) = grep { -f "$_/my_print_defaults"; } "$::bindir/extra", $::path_client_bindir;
+return "No my_print_defaults" unless $epath;
+
+push @::global_suppressions,
+ (
+ qr(WSREP: Could not open saved state file for reading: ),
+ qr(WSREP: Could not open state file for reading: .*),
+ qr(WSREP: option --wsrep-causal-reads is deprecated),
+ qr(WSREP: --wsrep-causal-reads=ON takes precedence over --wsrep-sync-wait=0),
+ qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|,
+ );
+
+$ENV{PATH}="$epath:$ENV{PATH}";
+$ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath;
+
+bless { };
+
diff --git a/mysql-test/suite/wsrep/t/alter_table_innodb.opt b/mysql-test/suite/wsrep/t/alter_table_innodb.opt
new file mode 100644
index 00000000000..1e84570d7f6
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/alter_table_innodb.opt
@@ -0,0 +1 @@
+--wsrep-on=0
diff --git a/mysql-test/suite/wsrep/t/alter_table_innodb.test b/mysql-test/suite/wsrep/t/alter_table_innodb.test
new file mode 100644
index 00000000000..ca06be02a85
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/alter_table_innodb.test
@@ -0,0 +1,10 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-7374 : Losing connection to MySQL while running ALTER TABLE
+--echo #
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+INSERT INTO t1 SELECT a.* FROM t1 a, t1 b, t1 c, t1 d, t1 e;
+ALTER TABLE t1 MODIFY i FLOAT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/wsrep/t/binlog_format.opt b/mysql-test/suite/wsrep/t/binlog_format.opt
new file mode 100644
index 00000000000..e3f2470c6e5
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/binlog_format.opt
@@ -0,0 +1 @@
+--innodb_autoinc_lock_mode=2 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm://
diff --git a/mysql-test/suite/wsrep/t/binlog_format.test b/mysql-test/suite/wsrep/t/binlog_format.test
new file mode 100644
index 00000000000..a2dc8542322
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/binlog_format.test
@@ -0,0 +1,47 @@
+--source include/have_wsrep_provider.inc
+--source include/have_binlog_format_row.inc
+
+call mtr.add_suppression("WSREP: MariaDB Galera does not support binlog format.*");
+call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID");
+
+--echo #
+--echo # MDEV-4227: Galera server should stop crashing on setting binlog_format STATEMENT
+--echo #
+
+SHOW VARIABLES LIKE 'binlog_format';
+SET binlog_format=STATEMENT;
+SHOW WARNINGS;
+SHOW VARIABLES LIKE 'binlog_format';
+CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0;
+SET binlog_format=MIXED;
+SHOW WARNINGS;
+SHOW VARIABLES LIKE 'binlog_format';
+CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0;
+SET binlog_format=ROW;
+SHOW WARNINGS;
+SHOW VARIABLES LIKE 'binlog_format';
+CREATE TABLE IF NOT EXISTS test.t3 AS SELECT * FROM information_schema.routines WHERE 1 = 0;
+DROP TABLE IF EXISTS test.t1;
+DROP TABLE IF EXISTS test.t2;
+DROP TABLE IF EXISTS test.t3;
+
+--echo #
+--echo # MDEV-7322: Option to allow setting the binlog_format with Galera
+--echo #
+
+-- error ER_WRONG_VALUE_FOR_VAR
+SET @@GLOBAL.binlog_format=STATEMENT;
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+
+-- error ER_WRONG_VALUE_FOR_VAR
+SET @@GLOBAL.binlog_format=MIXED;
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+
+-- error ER_WRONG_VALUE_FOR_VAR
+SET @@GLOBAL.binlog_format=DEFAULT;
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+
+SET @@GLOBAL.binlog_format=ROW;
+SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+
+--echo # End of test.
diff --git a/mysql-test/suite/wsrep/t/foreign_key.opt b/mysql-test/suite/wsrep/t/foreign_key.opt
new file mode 100644
index 00000000000..e3f2470c6e5
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/foreign_key.opt
@@ -0,0 +1 @@
+--innodb_autoinc_lock_mode=2 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm://
diff --git a/mysql-test/suite/wsrep/t/foreign_key.test b/mysql-test/suite/wsrep/t/foreign_key.test
new file mode 100644
index 00000000000..71f6076a1d7
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/foreign_key.test
@@ -0,0 +1,20 @@
+--source include/have_wsrep_enabled.inc
+--source include/have_binlog_format_row.inc
+--source include/have_innodb.inc
+
+USE test;
+create table p(v varchar(20), i int, primary key(v,i)) engine=innodb character set = utf8;
+create table c(k int primary key, v varchar(20), i int, foreign key(v,i) references p(v,i)) engine=innodb character set = utf8;
+insert into p values (_utf32 0x000004100000041100000412, 1);
+insert into c values (1, _utf32 0x000004100000041100000412, 1);
+
+SELECT * FROM test.p;
+SELECT * FROM test.c;
+
+SELECT * FROM test.p;
+SELECT * FROM test.c;
+
+# Cleanup
+DROP TABLE c;
+DROP TABLE p;
+
diff --git a/mysql-test/suite/wsrep/t/mdev_6832.opt b/mysql-test/suite/wsrep/t/mdev_6832.opt
new file mode 100644
index 00000000000..459a9702707
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_6832.opt
@@ -0,0 +1 @@
+--wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep-on=1 --wsrep_causal_reads=ON
diff --git a/mysql-test/suite/wsrep/t/mdev_6832.test b/mysql-test/suite/wsrep/t/mdev_6832.test
new file mode 100644
index 00000000000..9efccface57
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_6832.test
@@ -0,0 +1,15 @@
+--source include/have_wsrep_provider.inc
+--source include/have_binlog_format_row.inc
+
+--echo #
+--echo # MDEV-6832: ER_LOCK_WAIT_TIMEOUT on SHOW STATUS
+--echo #
+
+SHOW STATUS LIKE 'wsrep_ready';
+--disable_query_log
+eval SET @@global.wsrep_provider='$WSREP_PROVIDER';
+--enable_query_log
+SHOW STATUS LIKE 'wsrep_ready';
+SET @@global.wsrep_cluster_address='gcomm://';
+
+--echo # End of test.
diff --git a/mysql-test/suite/wsrep/t/mdev_7798.opt b/mysql-test/suite/wsrep/t/mdev_7798.opt
new file mode 100644
index 00000000000..459a9702707
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_7798.opt
@@ -0,0 +1 @@
+--wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep-on=1 --wsrep_causal_reads=ON
diff --git a/mysql-test/suite/wsrep/t/mdev_7798.test b/mysql-test/suite/wsrep/t/mdev_7798.test
new file mode 100644
index 00000000000..9dfff0959bc
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_7798.test
@@ -0,0 +1,17 @@
+--source include/have_wsrep_provider.inc
+--source include/have_binlog_format_row.inc
+
+--echo #
+--echo # MDEV-7798: mysql.server init script can't stop mysqld when WSREP is
+--echo # turned off
+--echo #
+
+SELECT @@GLOBAL.WSREP_ON;
+SET GLOBAL WSREP_ON= 0;
+
+--echo Restart the node.
+--source include/restart_mysqld.inc
+
+SELECT @@GLOBAL.WSREP_ON;
+
+--echo # End of test.
diff --git a/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test
new file mode 100644
index 00000000000..100e09d3afb
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mysql_tzinfo_to_sql_symlink.test
@@ -0,0 +1,40 @@
+--source include/have_wsrep.inc
+--source include/have_symlink.inc
+--source include/not_windows.inc
+
+--echo #
+--echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above
+--echo #
+
+--exec mkdir $MYSQLTEST_VARDIR/zoneinfo
+--exec ln -s $MYSQLTEST_VARDIR/zoneinfo $MYSQLTEST_VARDIR/zoneinfo/posix
+--copy_file std_data/zoneinfo/GMT $MYSQLTEST_VARDIR/zoneinfo/GMT
+--copy_file std_data/words.dat $MYSQLTEST_VARDIR/zoneinfo/garbage
+--copy_file std_data/words.dat $MYSQLTEST_VARDIR/zoneinfo/ignored.tab
+
+--echo # Verbose run
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--exec $MYSQL_TZINFO_TO_SQL --verbose $MYSQLTEST_VARDIR/zoneinfo 2>&1
+
+--echo # Silent run
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--exec $MYSQL_TZINFO_TO_SQL $MYSQLTEST_VARDIR/zoneinfo 2>&1
+
+--echo #
+--echo # Testing with explicit timezonefile
+--echo #
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--exec $MYSQL_TZINFO_TO_SQL $MYSQLTEST_VARDIR/zoneinfo/GMT XXX 2>&1
+
+--echo #
+--echo # Testing --leap
+--echo #
+
+--exec $MYSQL_TZINFO_TO_SQL --leap $MYSQLTEST_VARDIR/zoneinfo/GMT 2>&1
+
+#
+# Cleanup
+#
+
+--exec rm -rf $MYSQLTEST_VARDIR/zoneinfo
diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.opt b/mysql-test/suite/wsrep/t/pool_of_threads.opt
new file mode 100644
index 00000000000..814417e5b0f
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/pool_of_threads.opt
@@ -0,0 +1 @@
+--innodb_autoinc_lock_mode=2 --wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --thread_handling=pool-of-threads
diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.test b/mysql-test/suite/wsrep/t/pool_of_threads.test
new file mode 100644
index 00000000000..dbf429e3f01
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/pool_of_threads.test
@@ -0,0 +1,12 @@
+--source include/have_wsrep.inc
+--source include/have_binlog_format_row.inc
+
+--echo
+--echo #
+--echo # MDEV#5687: Maria doesn't shutdown following upgrade to 5.5.35-galera
+--echo #
+
+# Note: This test is to ensure that server shuts down properly.
+SELECT @@GLOBAL.thread_handling;
+
+--echo # End of test.
diff --git a/mysql-test/suite/wsrep/t/trans.test b/mysql-test/suite/wsrep/t/trans.test
new file mode 100644
index 00000000000..d8c4a4722a0
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/trans.test
@@ -0,0 +1,14 @@
+--source include/have_wsrep.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-4222 : Assertion `( ((global_system_variables.wsrep_on) &&
+--echo # (thd && thd->variables.wsrep_on)) && srep_emulate_bin_log)
+--echo # || mysql_bin_log .is_open()' fails on SAVEPOINT with
+--echo # disabled wsrep_provider
+--echo #
+
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+SAVEPOINT A;
+
+--echo End of test.
diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test
new file mode 100644
index 00000000000..c77d70c356c
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/variables.test
@@ -0,0 +1,153 @@
+--source include/have_wsrep.inc
+
+SET @wsrep_provider_options_saved= @@global.wsrep_provider_options;
+
+--echo
+--echo # MDEV#5534: mysql_tzinfo_to_sql generates wrong query
+--echo #
+--echo # Testing wsrep_replicate_myisam variable.
+
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SELECT @@session.wsrep_replicate_myisam;
+SELECT @@global.wsrep_replicate_myisam;
+
+--error ER_GLOBAL_VARIABLE
+SET SESSION wsrep_replicate_myisam= ON;
+SET GLOBAL wsrep_replicate_myisam= ON;
+
+# Reset it back.
+SET GLOBAL wsrep_replicate_myisam= OFF;
+SET GLOBAL wsrep_provider=none;
+
+--echo #
+--echo # MDEV#5790: SHOW GLOBAL STATUS LIKE does not show the correct list of
+--echo # variables when using "_"
+--echo #
+
+CALL mtr.add_suppression("WSREP: Could not open saved state file for reading.*");
+
+--disable_query_log
+eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER';
+--let $galera_version=25.3.17
+source include/check_galera_version.inc;
+--enable_query_log
+
+--replace_column 2 #
+SHOW GLOBAL STATUS LIKE 'wsrep%';
+
+--echo
+--replace_column 2 #
+SHOW GLOBAL STATUS LIKE 'wsrep_%';
+
+--replace_column 2 #
+SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+
+--echo # Should show nothing.
+SHOW STATUS LIKE 'x';
+
+# Reset it back.
+SET GLOBAL wsrep_provider=none;
+
+--echo #
+--echo # MDEV#6079: xtrabackup SST failing with maria-10.0-galera
+--echo #
+
+--disable_query_log
+eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER';
+--enable_query_log
+
+# The following 2 variables are used in innobackupex during xtrabackup-based
+# SST.
+--echo
+--replace_column 2 #
+SHOW STATUS LIKE 'wsrep_local_state_uuid';
+--echo
+--replace_column 2 #
+SHOW STATUS LIKE 'wsrep_last_committed';
+
+# Reset it back.
+SET GLOBAL wsrep_provider=none;
+
+--echo
+--echo #
+--echo # MDEV#6206: wsrep_slave_threads subtracts from max_connections
+--echo #
+call mtr.add_suppression("WSREP: Failed to get provider options");
+
+--disable_query_log
+eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER';
+--enable_query_log
+
+--replace_regex /.*libgalera_smm.*/libgalera_smm.so/
+SELECT @@global.wsrep_provider;
+SELECT @@global.wsrep_slave_threads;
+SELECT @@global.wsrep_cluster_address;
+SHOW STATUS LIKE 'threads_connected';
+SHOW STATUS LIKE 'wsrep_thread_count';
+--echo
+
+--disable_query_log
+eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER';
+--enable_query_log
+
+--replace_regex /.*libgalera_smm.*/libgalera_smm.so/
+SELECT @@global.wsrep_provider;
+SELECT @@global.wsrep_cluster_address;
+SHOW STATUS LIKE 'threads_connected';
+SHOW STATUS LIKE 'wsrep_thread_count';
+--echo
+
+--echo # Setting wsrep_cluster_address triggers the creation of
+--echo # applier/rollbacker threads.
+SET GLOBAL wsrep_cluster_address= 'gcomm://';
+--echo # Wait for applier threads to get created.
+sleep 3;
+
+--replace_regex /.*libgalera_smm.*/libgalera_smm.so/
+SELECT @@global.wsrep_provider;
+SELECT @@global.wsrep_cluster_address;
+SHOW STATUS LIKE 'threads_connected';
+SHOW STATUS LIKE 'wsrep_thread_count';
+--echo
+
+SET @wsrep_slave_threads_saved= @@global.wsrep_slave_threads;
+SET GLOBAL wsrep_slave_threads= 10;
+--echo # Wait for applier threads to get created.
+sleep 3;
+SHOW STATUS LIKE 'threads_connected';
+SHOW STATUS LIKE 'wsrep_thread_count';
+
+#
+# privileges for wsrep_on
+#
+set wsrep_on=0;
+set wsrep_on=1;
+create user test@localhost;
+connect con1,localhost,test;
+set auto_increment_increment=10;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+set wsrep_on=0;
+disconnect con1;
+connection default;
+drop user test@localhost;
+
+--echo #
+--echo # MDEV#6411: Setting set @@global.wsrep_sst_auth=NULL causes crash
+--echo #
+SET @wsrep_sst_auth_saved= @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth= 'user:pass';
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth= '';
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth= NULL;
+SELECT @@global.wsrep_sst_auth;
+SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved;
+
+# Reset (for mtr internal checks)
+SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved;
+SET GLOBAL wsrep_provider= none;
+SET GLOBAL wsrep_cluster_address= '';
+SET GLOBAL wsrep_provider_options= @wsrep_provider_options_saved;
+
+--echo # End of test.
+
diff --git a/mysql-test/suite/wsrep/t/wsrep_rpl.cnf b/mysql-test/suite/wsrep/t/wsrep_rpl.cnf
new file mode 100644
index 00000000000..56e874f22e1
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/wsrep_rpl.cnf
@@ -0,0 +1 @@
+!include ../../rpl/my.cnf
diff --git a/mysql-test/suite/wsrep/t/wsrep_rpl.test b/mysql-test/suite/wsrep/t/wsrep_rpl.test
new file mode 100644
index 00000000000..4f34aadc365
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/wsrep_rpl.test
@@ -0,0 +1,44 @@
+--source include/have_wsrep.inc
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+--echo #
+--echo # MDEV-10714: Could not execute Delete_rows event on table;
+--echo # wsrep_max_ws_rows exceeded. Error_Code 1180
+--echo #
+# Save wsrep_max_ws_rows on master and slave.
+connection master;
+let $wsrep_max_ws_rows_master = `SELECT @@GLOBAL.wsrep_max_ws_rows`;
+connection slave;
+let $wsrep_max_ws_rows_slave = `SELECT @@GLOBAL.wsrep_max_ws_rows`;
+
+connection master;
+CREATE TABLE t1(i INT) ENGINE = INNODB;
+
+SET @@GLOBAL.wsrep_max_ws_rows = 2;
+INSERT INTO t1 VALUES(1), (2);
+sync_slave_with_master;
+SELECT COUNT(*) = 2 FROM t1;
+
+connection slave;
+SET @@GLOBAL.wsrep_max_ws_rows = 2;
+
+connection master;
+DELETE FROM t1;
+
+sync_slave_with_master;
+SELECT COUNT(*) = 0 FROM t1;
+
+connection master;
+DROP TABLE t1;
+
+sync_slave_with_master;
+# Restore wsrep_max_ws_rows on master and slave
+connection master;
+eval SET @@GLOBAL.wsrep_max_ws_rows = $wsrep_max_ws_rows_master;
+connection slave;
+eval SET @@GLOBAL.wsrep_max_ws_rows = $wsrep_max_ws_rows_slave;
+
+--source include/rpl_end.inc
+--echo # End of test.
+
diff --git a/mysql-test/t/file_contents.test b/mysql-test/t/file_contents.test
index 186394df4e3..788d3b755c4 100644
--- a/mysql-test/t/file_contents.test
+++ b/mysql-test/t/file_contents.test
@@ -30,7 +30,7 @@ if ($dir_bin eq '/usr/') {
$dir_docs = glob "$dir_docs/packages/*-server*";
} else {
# RedHat/Debian: version number in directory name
- $dir_docs = glob "$dir_docs/mariadb-server-*";
+ $dir_docs = glob "$dir_docs/mariadb-galera-server-*";
$dir_docs = glob "$dir_docs/MySQL-server*" unless -d $dir_docs;
}
# Slackware
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index 2a00ad75a8d..ecfaa651076 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -1344,28 +1344,8 @@ explain select count(*) from information_schema.views;
#
# Bug#39955 SELECT on INFORMATION_SCHEMA.GLOBAL_VARIABLES takes too long
#
-set global init_connect="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 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 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 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 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;";
-select * from information_schema.global_variables where variable_name='init_connect';
+set global init_connect=repeat("drop table if exists t1;", 100);
+select length(@@global.init_connect), length(variable_value) from information_schema.global_variables where variable_name='init_connect';
set global init_connect="";
#
diff --git a/mysql-test/t/innodb_load_xa.test b/mysql-test/t/innodb_load_xa.test
index 9ecddde5d13..9ebcb3faaba 100644
--- a/mysql-test/t/innodb_load_xa.test
+++ b/mysql-test/t/innodb_load_xa.test
@@ -2,6 +2,7 @@
# MDEV-6082 Assertion `0' fails in TC_LOG_DUMMY::log_and_order on DML after installing TokuDB at runtime on server with disabled InnoDB
#
--source include/not_embedded.inc
+--source include/not_wsrep.inc
if (!$HA_INNODB_SO) {
--skip Need InnoDB plugin
diff --git a/mysql-test/t/innodb_load_xa_with_wsrep.opt b/mysql-test/t/innodb_load_xa_with_wsrep.opt
new file mode 100644
index 00000000000..4ff27e659ce
--- /dev/null
+++ b/mysql-test/t/innodb_load_xa_with_wsrep.opt
@@ -0,0 +1 @@
+--ignore-builtin-innodb --loose-innodb --log-bin
diff --git a/mysql-test/t/innodb_load_xa_with_wsrep.test b/mysql-test/t/innodb_load_xa_with_wsrep.test
new file mode 100644
index 00000000000..6755d209a02
--- /dev/null
+++ b/mysql-test/t/innodb_load_xa_with_wsrep.test
@@ -0,0 +1,22 @@
+#
+# MDEV-6082 Assertion `0' fails in TC_LOG_DUMMY::log_and_order on DML after installing TokuDB at runtime on server with disabled InnoDB
+#
+--source include/not_embedded.inc
+--source include/have_wsrep.inc
+
+if (!$HA_INNODB_SO) {
+ --skip Need InnoDB plugin
+}
+install plugin innodb soname 'ha_innodb';
+select engine,support,transactions,xa from information_schema.engines where engine='innodb';
+create table t1 (a int) engine=innodb;
+start transaction;
+insert t1 values (1);
+insert t1 values (2);
+commit;
+--source include/show_binlog_events.inc
+drop table t1;
+uninstall plugin innodb;
+
+--source include/restart_mysqld.inc
+
diff --git a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test
index 8ca82b87e30..ee83c8f4c53 100644
--- a/mysql-test/t/mysql_tzinfo_to_sql_symlink.test
+++ b/mysql-test/t/mysql_tzinfo_to_sql_symlink.test
@@ -1,6 +1,11 @@
--source include/have_symlink.inc
--source include/not_windows.inc
+# Note: The output of mysql_tzinfo_to_sql is different if server is compiled
+# with wsrep. Hence a copy of this test has been placed under wsrep suite with
+# the updated result. (lp:1161432)
+--source include/not_wsrep.inc
+
--echo #
--echo # MDEV-5226 mysql_tzinfo_to_sql errors with tzdata 2013f and above
--echo #
diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test
index 96774d829ec..c2dcf96b2b3 100644
--- a/mysql-test/t/mysqld--help.test
+++ b/mysql-test/t/mysqld--help.test
@@ -11,7 +11,7 @@
# force symbolic-links=0 (valgrind build has a different default)
#
-exec $MYSQLD_BOOTSTRAP_CMD --symbolic-links=0 --lower-case-table-names=1 --help --verbose > $MYSQL_TMP_DIR/mysqld--help.txt 2>&1;
+exec $MYSQLD_BOOTSTRAP_CMD --symbolic-links=0 --lower-case-table-names=1 --help --verbose > $MYSQL_TMP_DIR/mysqld--help.txt;
# The inline perl code below will copy $MYSQL_TMP_DIR/mysqld--help.txt
# to output, but filter away some variable stuff (e.g. paths).
@@ -24,7 +24,7 @@ perl;
datadir slave-load-tmpdir tmpdir socket thread-pool-size
large-files-support lower-case-file-system system-time-zone
collation-server character-set-server
- version.*/;
+ wsrep-node-name wsrep-data-home-dir log-tc-size version.*/;
# Plugins which may or may not be there:
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster
diff --git a/mysql-test/t/read_only_innodb.test b/mysql-test/t/read_only_innodb.test
index f89cf745973..de237fecbb6 100644
--- a/mysql-test/t/read_only_innodb.test
+++ b/mysql-test/t/read_only_innodb.test
@@ -244,15 +244,6 @@ SELECT * FROM temp1, temp2;
DROP TABLE temp1, temp2;
--echo
---echo # MDEV-14185 CREATE TEMPORARY TABLE AS SELECT causes error 1290 with read_only and InnoDB.
---echo
-
-CREATE TEMPORARY TABLE temp1 ENGINE=INNODB AS SELECT a FROM t1;
-SELECT * FROM temp1;
-DROP TABLE temp1;
-
-
---echo
--echo # Disconnect and cleanup
--echo
disconnect con1;
diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp
index 9114a8fc7bd..adb62681ba5 100644
--- a/mysql-test/valgrind.supp
+++ b/mysql-test/valgrind.supp
@@ -1399,3 +1399,234 @@
obj:*/libssl.so.0.9.8
...
}
+
+{
+ GitHub codership/galera#330
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:CRYPTO_malloc
+ fun:sk_new
+ obj:/usr/lib64/libssl.so.1.0.1e
+ fun:SSL_COMP_get_compression_methods
+ fun:SSL_library_init
+ fun:_ZN4asio3ssl6detail12openssl_initILb1EE7do_initC1Ev
+ fun:_ZN4asio3ssl6detail12openssl_initILb1EE7do_init8instanceEv
+ fun:_ZN4asio3ssl6detail12openssl_initILb1EEC1Ev
+ fun:_Z41__static_initialization_and_destruction_0ii.constprop.120
+ fun:call_init.part.0
+ fun:_dl_init
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+}
+{
+ GitHub codership/galera#330
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:CRYPTO_malloc
+ fun:sk_new
+ obj:/usr/lib64/libssl.so.1.0.1e
+ fun:SSL_COMP_get_compression_methods
+ fun:SSL_library_init
+ fun:_ZN4asio3ssl6detail12openssl_initILb1EE7do_initC1Ev
+ fun:_ZN4asio3ssl6detail12openssl_initILb1EE7do_init8instanceEv
+ fun:_ZN4asio3ssl6detail12openssl_initILb1EEC1Ev
+ fun:_Z41__static_initialization_and_destruction_0ii.constprop.120
+ fun:call_init.part.0
+ fun:_dl_init
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+}
+
+{
+ GitHub codership/mysql-wsrep#175
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:calloc
+ fun:do_lookup_x
+ fun:_dl_lookup_symbol_x
+ fun:_dl_relocate_object
+ fun:dl_open_worker
+ fun:_dl_catch_error
+ fun:_dl_open
+ fun:dlopen_doit
+ fun:_dl_catch_error
+ fun:_dlerror_run
+ fun:dlopen@@GLIBC_2.2.5
+ fun:wsrep_load
+ fun:_Z10wsrep_initv
+ fun:_Z18wsrep_init_startupb
+ fun:_ZL22init_server_componentsv
+ fun:_Z11mysqld_mainiPPc
+}
+
+{
+ galera/mysql-wsrep#147
+ Memcheck:Leak
+ match-leak-kinds: possible
+ fun:malloc
+ fun:_ZNK6galera13ReplicatorSMM9stats_getEv
+ fun:_ZL28export_wsrep_status_to_mysqlP3THD
+ fun:_Z17wsrep_show_statusP3THDP17st_mysql_show_varPc
+ fun:_ZL17show_status_arrayP3THDPKcP17st_mysql_show_var13enum_var_typeP17system_status_varS2_P5TABLEbP4Item
+ fun:_Z11fill_statusP3THDP10TABLE_LISTP4Item
+ fun:_ZL13do_fill_tableP3THDP10TABLE_LISTP13st_join_table
+ fun:_Z24get_schema_tables_resultP4JOIN23enum_schema_table_state
+ fun:_ZN4JOIN14prepare_resultEPP4ListI4ItemE
+ fun:_ZN4JOIN4execEv
+ fun:_ZL20mysql_execute_selectP3THDP13st_select_lexb
+ fun:_Z12mysql_selectP3THDP10TABLE_LISTjR4ListI4ItemEPS4_P10SQL_I_ListI8st_orderESB_S7_yP13select_resultP18st_select_lex_unitP13st_select_lex
+ fun:_Z13handle_selectP3THDP13select_resultm
+ fun:_ZL21execute_sqlcom_selectP3THDP10TABLE_LIST
+ fun:_Z21mysql_execute_commandP3THD
+ fun:_Z11mysql_parseP3THDPcjP12Parser_state
+}
+
+{
+ codership/mysql-wsrep/issues#176
+ Memcheck:Leak
+ fun:_Z16wsrep_set_paramsRN6galera10ReplicatorEPKc
+}
+
+{
+ codership/mysql-wsrep/issues#176
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:DbugMalloc
+ fun:ListParse
+ fun:_gu_db_push_
+ fun:_Z16wsrep_set_paramsRN6galera10ReplicatorEPKc
+ fun:galera_parameters_set
+ fun:_Z29wsrep_provider_options_updateP7sys_varP3THD13enum_var_type
+ fun:_ZN7sys_var6updateEP3THDP7set_var
+ fun:_ZN7set_var6updateEP3THD
+ fun:_Z17sql_set_variablesP3THDP4ListI12set_var_baseE
+ fun:_Z21mysql_execute_commandP3THD
+ fun:_Z11mysql_parseP3THDPcjP12Parser_state
+ fun:_ZL17wsrep_mysql_parseP3THDPcjP12Parser_state
+ fun:_Z16dispatch_command19enum_server_commandP3THDPcj
+ fun:_Z10do_commandP3THD
+ fun:_Z24do_handle_one_connectionP3THD
+}
+
+{
+ codership/mysql-wsrep/issues#176
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:state_map_insert
+ fun:code_state
+ fun:_gu_db_push_
+ fun:_Z16wsrep_set_paramsRN6galera10ReplicatorEPKc
+ fun:galera_parameters_set
+ fun:_Z29wsrep_provider_options_updateP7sys_varP3THD13enum_var_type
+ fun:_ZN7sys_var6updateEP3THDP7set_var
+ fun:_ZN7set_var6updateEP3THD
+ fun:_Z17sql_set_variablesP3THDP4ListI12set_var_baseE
+ fun:_Z21mysql_execute_commandP3THD
+ fun:_Z11mysql_parseP3THDPcjP12Parser_state
+ fun:_ZL17wsrep_mysql_parseP3THDPcjP12Parser_state
+ fun:_Z16dispatch_command19enum_server_commandP3THDPcj
+ fun:_Z10do_commandP3THD
+ fun:_Z24do_handle_one_connectionP3THD
+}
+
+{
+ codership/mysql-wsrep/issues#176
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:DbugMalloc
+ fun:StrDup
+ fun:ListParse
+ fun:_gu_db_push_
+ fun:_Z16wsrep_set_paramsRN6galera10ReplicatorEPKc
+ fun:galera_parameters_set
+ fun:_Z29wsrep_provider_options_updateP7sys_varP3THD13enum_var_type
+ fun:_ZN7sys_var6updateEP3THDP7set_var
+ fun:_ZN7set_var6updateEP3THD
+ fun:_Z17sql_set_variablesP3THDP4ListI12set_var_baseE
+ fun:_Z21mysql_execute_commandP3THD
+ fun:_Z11mysql_parseP3THDPcjP12Parser_state
+ fun:_ZL17wsrep_mysql_parseP3THDPcjP12Parser_state
+ fun:_Z16dispatch_command19enum_server_commandP3THDPcj
+ fun:_Z10do_commandP3THD
+}
+
+{
+ codership/mysql-wsrep/issues#176
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:code_state
+ fun:_gu_db_push_
+ fun:_Z16wsrep_set_paramsRN6galera10ReplicatorEPKc
+ fun:galera_parameters_set
+ fun:_Z29wsrep_provider_options_updateP7sys_varP3THD13enum_var_type
+ fun:_ZN7sys_var6updateEP3THDP7set_var
+ fun:_ZN7set_var6updateEP3THD
+ fun:_Z17sql_set_variablesP3THDP4ListI12set_var_baseE
+ fun:_Z21mysql_execute_commandP3THD
+ fun:_Z11mysql_parseP3THDPcjP12Parser_state
+ fun:_ZL17wsrep_mysql_parseP3THDPcjP12Parser_state
+ fun:_Z16dispatch_command19enum_server_commandP3THDPcj
+ fun:_Z10do_commandP3THD
+ fun:_Z24do_handle_one_connectionP3THD
+ fun:handle_one_connection
+}
+
+{
+ codership/mysql-wsrep/issues#176
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:DbugMalloc
+ fun:PushState
+ fun:_gu_db_push_
+ fun:_Z16wsrep_set_paramsRN6galera10ReplicatorEPKc
+ fun:galera_parameters_set
+ fun:_Z29wsrep_provider_options_updateP7sys_varP3THD13enum_var_type
+ fun:_ZN7sys_var6updateEP3THDP7set_var
+ fun:_ZN7set_var6updateEP3THD
+ fun:_Z17sql_set_variablesP3THDP4ListI12set_var_baseE
+ fun:_Z21mysql_execute_commandP3THD
+ fun:_Z11mysql_parseP3THDPcjP12Parser_state
+ fun:_ZL17wsrep_mysql_parseP3THDPcjP12Parser_state
+ fun:_Z16dispatch_command19enum_server_commandP3THDPcj
+ fun:_Z10do_commandP3THD
+ fun:_Z24do_handle_one_connectionP3THD
+}
+
+{
+ codership/galera#331
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:state_map_insert
+ fun:code_state
+ fun:_gu_db_keyword_
+ fun:_ZN6galera3ist6Sender4sendEll
+ fun:run_async_sender
+ fun:start_thread
+ fun:clone
+}
+
+{
+ codership/galera#331
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ fun:code_state
+ fun:_gu_db_keyword_
+ fun:_ZN6galera3ist6Sender4sendEll
+ fun:run_async_sender
+ fun:start_thread
+ fun:clone
+}
+
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index 05b6cac6733..362bf8773cd 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -107,6 +107,7 @@ void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
size_t pre_alloc_size __attribute__((unused)))
{
+ DBUG_ENTER("reset_root_defaults");
DBUG_ASSERT(alloc_root_inited(mem_root));
mem_root->block_size= (((block_size - ALLOC_ROOT_MIN_BLOCK_SIZE) & ~1) |
@@ -129,7 +130,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
{
/* We found a suitable block, no need to do anything else */
mem_root->pre_alloc= mem;
- return;
+ DBUG_VOID_RETURN;
}
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
{
@@ -160,6 +161,8 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
else
#endif
mem_root->pre_alloc= 0;
+
+ DBUG_VOID_RETURN;
}
diff --git a/mysys/my_create.c b/mysys/my_create.c
index 32ad3d44a7a..014b65c4e14 100644
--- a/mysys/my_create.c
+++ b/mysys/my_create.c
@@ -43,7 +43,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
#if defined(_WIN32)
fd= my_win_open(FileName, access_flags | O_CREAT);
#else
- fd= open((char *) FileName, access_flags | O_CREAT,
+ fd= open((char *) FileName, access_flags | O_CREAT | O_CLOEXEC,
CreateFlags ? CreateFlags : my_umask);
#endif
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index f3d64845526..a7a0967f909 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -42,7 +42,7 @@ static void make_ftype(char * to,int flag);
FILE *my_fopen(const char *filename, int flags, myf MyFlags)
{
FILE *fd;
- char type[5];
+ char type[10];
DBUG_ENTER("my_fopen");
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %lu",
filename, flags, MyFlags));
@@ -345,9 +345,11 @@ static void make_ftype(register char * to, register int flag)
else
*to++= 'r';
-#if FILE_BINARY /* If we have binary-files */
if (flag & FILE_BINARY)
*to++='b';
-#endif
+
+ if (O_CLOEXEC)
+ *to++= 'e';
+
*to='\0';
} /* make_ftype */
diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c
index 06f6a29e4a0..8580fac3595 100644
--- a/mysys/my_symlink.c
+++ b/mysys/my_symlink.c
@@ -244,7 +244,7 @@ const char *my_open_parent_dir_nosymlinks(const char *pathname, int *pdfd)
return pathname + (s - buf);
}
- fd = openat(dfd, s, O_NOFOLLOW | O_PATH);
+ fd = openat(dfd, s, O_NOFOLLOW | O_PATH | O_CLOEXEC);
if (fd < 0)
goto err;
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 8dce58dd58a..4a4e275332f 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -95,6 +95,24 @@ 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 1000
#define MAX_LOCKS 1000
@@ -646,6 +664,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
static enum enum_thr_lock_result
thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
@@ -654,6 +774,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
struct st_lock_list *wait_queue;
enum thr_lock_type lock_type= data->type;
+#ifdef WITH_WSREP
+ my_bool wsrep_lock_inserted= FALSE;
+#endif
MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */
DBUG_ENTER("thr_lock");
@@ -723,6 +846,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
}
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 */
@@ -750,6 +881,14 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
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 */
@@ -758,12 +897,25 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
{
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;
@@ -788,6 +940,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
/* 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 */
@@ -894,9 +1053,22 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
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);
@@ -1159,7 +1331,6 @@ static void sort_locks(THR_LOCK_DATA **data,uint count)
}
}
-
enum enum_thr_lock_result
thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_INFO *owner,
ulong lock_wait_timeout)
diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc
index 4e362e647a1..471f395e7d2 100644
--- a/mysys_ssl/my_md5.cc
+++ b/mysys_ssl/my_md5.cc
@@ -72,3 +72,4 @@ 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 */
}
+
diff --git a/policy/apparmor/README b/policy/apparmor/README
new file mode 100644
index 00000000000..271655f1e37
--- /dev/null
+++ b/policy/apparmor/README
@@ -0,0 +1,5 @@
+Note: The included AppArmor profiles can be used for MariaDB Galera cluster.
+However, since these profiles had been tested for a limited set of scenarios,
+it is highly recommended to run them in "complain" mode and report any denials
+on mariadb.org/jira.
+
diff --git a/policy/apparmor/usr.sbin.mysqld b/policy/apparmor/usr.sbin.mysqld
new file mode 100644
index 00000000000..307872c0fff
--- /dev/null
+++ b/policy/apparmor/usr.sbin.mysqld
@@ -0,0 +1,150 @@
+# Last Modified: Fri Mar 1 18:55:47 2013
+# Based on usr.sbin.mysqld packaged in mysql-server in Ubuntu.
+# This AppArmor profile has been copied under BSD License from
+# Percona XtraDB Cluster, along with some additions.
+
+#include <tunables/global>
+
+/usr/sbin/mysqld flags=(complain) {
+ #include <abstractions/base>
+ #include <abstractions/mysql>
+ #include <abstractions/nameservice>
+ #include <abstractions/user-tmp>
+ #include <abstractions/winbind>
+
+ capability chown,
+ capability dac_override,
+ capability setgid,
+ capability setuid,
+ capability sys_rawio,
+ capability sys_resource,
+
+ network tcp,
+
+ /bin/dash rcx,
+ /dev/dm-0 r,
+ /etc/gai.conf r,
+ /etc/group r,
+ /etc/hosts.allow r,
+ /etc/hosts.deny r,
+ /etc/ld.so.cache r,
+ /etc/mtab r,
+ /etc/my.cnf r,
+ /etc/mysql/*.cnf r,
+ /etc/mysql/*.pem r,
+ /etc/mysql/conf.d/ r,
+ /etc/mysql/conf.d/* r,
+ /etc/nsswitch.conf r,
+ /etc/passwd r,
+ /etc/services r,
+ /run/mysqld/mysqld.pid w,
+ /run/mysqld/mysqld.sock w,
+ /sys/devices/system/cpu/ r,
+ owner /tmp/** lk,
+ /tmp/** rw,
+ /usr/lib/mysql/plugin/ r,
+ /usr/lib/mysql/plugin/*.so* mr,
+ /usr/sbin/mysqld mr,
+ /usr/share/mysql/** r,
+ /var/lib/mysql/ r,
+ /var/lib/mysql/** rwk,
+ /var/log/mysql.err rw,
+ /var/log/mysql.log rw,
+ /var/log/mysql/ r,
+ /var/log/mysql/* rw,
+ /var/run/mysqld/mysqld.pid w,
+ /var/run/mysqld/mysqld.sock w,
+
+
+ profile /bin/dash flags=(complain) {
+ #include <abstractions/base>
+ #include <abstractions/bash>
+ #include <abstractions/mysql>
+ #include <abstractions/nameservice>
+ #include <abstractions/perl>
+
+
+
+ /bin/cat rix,
+ /bin/dash rix,
+ /bin/date rix,
+ /bin/grep rix,
+ /bin/nc.openbsd rix,
+ /bin/netstat rix,
+ /bin/ps rix,
+ /bin/rm rix,
+ /bin/sed rix,
+ /bin/sleep rix,
+ /bin/tar rix,
+ /bin/which rix,
+ /dev/tty rw,
+ /etc/ld.so.cache r,
+ /etc/my.cnf r,
+ /proc/ r,
+ /proc/*/cmdline r,
+ /proc/*/fd/ r,
+ /proc/*/net/dev r,
+ /proc/*/net/if_inet6 r,
+ /proc/*/net/tcp r,
+ /proc/*/net/tcp6 r,
+ /proc/*/stat r,
+ /proc/*/status r,
+ /proc/sys/kernel/pid_max r,
+ /proc/tty/drivers r,
+ /proc/uptime r,
+ /proc/version r,
+ /sbin/ifconfig rix,
+ /sys/devices/system/cpu/ r,
+ /tmp/** rw,
+ /usr/bin/cut rix,
+ /usr/bin/dirname rix,
+ /usr/bin/gawk rix,
+ /usr/bin/innobackupex rix,
+ /usr/bin/mysql rix,
+ /usr/bin/perl rix,
+ /usr/bin/seq rix,
+ /usr/bin/wsrep_sst* rix,
+ /usr/bin/wsrep_sst_common r,
+ /usr/bin/xtrabackup* rix,
+ /var/lib/mysql/ r,
+ /var/lib/mysql/** rw,
+ /var/lib/mysql/*.log w,
+ /var/lib/mysql/*.err w,
+
+# MariaDB additions
+ ptrace peer=@{profile_name},
+
+ /bin/hostname rix,
+ /bin/ip rix,
+ /bin/mktemp rix,
+ /bin/ss rix,
+ /bin/sync rix,
+ /bin/touch rix,
+ /bin/uname rix,
+ /etc/mysql/*.cnf r,
+ /etc/mysql/conf.d/ r,
+ /etc/mysql/conf.d/* r,
+ /proc/*/attr/current r,
+ /proc/*/fdinfo/* r,
+ /proc/*/net/* r,
+ /proc/locks r,
+ /proc/sys/net/ipv4/ip_local_port_range r,
+ /run/mysqld/mysqld.sock rw,
+ /sbin/ip rix,
+ /usr/bin/basename rix,
+ /usr/bin/du rix,
+ /usr/bin/find rix,
+ /usr/bin/lsof rix,
+ /usr/bin/my_print_defaults rix,
+ /usr/bin/mysqldump rix,
+ /usr/bin/pv rix,
+ /usr/bin/rsync rix,
+ /usr/bin/socat rix,
+ /usr/bin/tail rix,
+ /usr/bin/timeout rix,
+ /usr/bin/xargs rix,
+ /usr/bin/xbstream rix,
+ }
+ # Site-specific additions and overrides. See local/README for details.
+ #include <local/usr.sbin.mysqld>
+}
diff --git a/policy/apparmor/usr.sbin.mysqld.local b/policy/apparmor/usr.sbin.mysqld.local
new file mode 100644
index 00000000000..a0b8a0279de
--- /dev/null
+++ b/policy/apparmor/usr.sbin.mysqld.local
@@ -0,0 +1,4 @@
+# Site-specific additions and overrides for usr.sbin.mysqld..
+# For more details, please see /etc/apparmor.d/local/README.
+# This AppArmor profile has been copied under BSD License from
+# Percona XtraDB Cluster, along with some additions.
diff --git a/policy/selinux/README b/policy/selinux/README
new file mode 100644
index 00000000000..3f695dc27a3
--- /dev/null
+++ b/policy/selinux/README
@@ -0,0 +1,20 @@
+Note: The included SELinux policy files can be used for MariaDB Galera cluster.
+However, since these policies had been tested for a limited set of scenarios,
+it is highly recommended that you run mysqld in "permissive" mode even with
+these policies installed and report any denials on mariadb.org/jira.
+
+
+How to generate and load the policy module of MariaDB Galera cluster ?
+ * Generate the SELinux policy module.
+ # cd <source>/policy/selinux/
+ # make -f /usr/share/selinux/devel/Makefile mariadb-server.pp
+
+ * Load the generated policy module.
+ # semodule -i /path/to/mariadb-server.pp
+
+ * Lastly, run the following command to allow tcp/4568 and udp/4567.
+ # semanage port -a -t mysqld_port_t -p tcp 4568
+ # semanage port -a -t mysqld_port_t -p udp 4567
+
+How to run mysqld in permissve mode ?
+ # semanage permissive -a mysqld_t
diff --git a/policy/selinux/mariadb-server.fc b/policy/selinux/mariadb-server.fc
new file mode 100644
index 00000000000..409f72923aa
--- /dev/null
+++ b/policy/selinux/mariadb-server.fc
@@ -0,0 +1,10 @@
+# This SELinux file contexts (.fc) file has been copied under New BSD License from
+# Percona XtraDB Cluster.
+
+/etc/init\.d/rc\.d/mysql -- gen_context(system_u:object_r:mysqld_initrc_exec_t,s0)
+/var/lib/mysql/.*\.log -- gen_context(system_u:object_r:mysqld_log_t,s0)
+/var/lib/mysql/.*\.err -- gen_context(system_u:object_r:mysqld_log_t,s0)
+/var/lib/mysql/.*\.pid -- gen_context(system_u:object_r:mysqld_var_run_t,s0)
+/var/lib/mysql/.*\.cnf -- gen_context(system_u:object_r:mysqld_etc_t,s0)
+/usr/bin/xtrabackup.* -- gen_context(system_u:object_r:mysqld_exec_t,s0)
+/usr/bin/wsrep.* -- gen_context(system_u:object_r:mysqld_safe_exec_t,s0)
diff --git a/policy/selinux/mariadb-server.te b/policy/selinux/mariadb-server.te
new file mode 100644
index 00000000000..45ef40f4153
--- /dev/null
+++ b/policy/selinux/mariadb-server.te
@@ -0,0 +1,99 @@
+# This SELinux type enforcement (.te) file has been copied under New BSD License
+# from Percona XtraDB Cluster, along with some additions.
+
+module mariadb-server 1.0;
+
+require {
+ type user_tmp_t;
+ #type kerberos_master_port_t;
+ type mysqld_safe_t;
+ type tmp_t;
+ type tmpfs_t;
+ type hostname_exec_t;
+ type ifconfig_exec_t;
+ type sysctl_net_t;
+ type proc_net_t;
+ type port_t;
+ type mysqld_t;
+ type var_lib_t;
+ type rsync_exec_t;
+ type bin_t;
+ type shell_exec_t;
+ type anon_inodefs_t;
+ type fixed_disk_device_t;
+ class lnk_file read;
+ class process { getattr signull };
+ class unix_stream_socket connectto;
+ class capability { sys_resource sys_nice };
+ class tcp_socket { name_bind name_connect };
+ class file { execute setattr read create getattr execute_no_trans write ioctl open append unlink };
+ class sock_file { create unlink getattr };
+ class blk_file { read write open };
+ class dir { write search getattr add_name read remove_name open };
+
+# MariaDB additions
+ type kerberos_port_t;
+ type tram_port_t;
+ type mysqld_port_t;
+ class udp_socket name_bind;
+ class process setpgid;
+ class netlink_tcpdiag_socket { create nlmsg_read };
+}
+
+
+#============= mysqld_safe_t ==============
+allow mysqld_safe_t mysqld_t:process signull;
+allow mysqld_safe_t self:capability { sys_resource sys_nice };
+allow mysqld_safe_t tmp_t:file { create read write open getattr unlink ioctl setattr };
+allow mysqld_safe_t tmp_t:dir { write remove_name add_name };
+allow mysqld_safe_t tmp_t:sock_file { getattr unlink };
+allow mysqld_safe_t user_tmp_t:sock_file { getattr unlink };
+allow mysqld_safe_t var_lib_t:dir { write add_name };
+allow mysqld_safe_t var_lib_t:file { write ioctl setattr create open getattr append unlink };
+
+#============= mysqld_t ==============
+allow mysqld_t anon_inodefs_t:file write;
+allow mysqld_t tmp_t:sock_file { create unlink };
+allow mysqld_t tmpfs_t:dir { write search read remove_name open add_name };
+allow mysqld_t tmpfs_t:file { write getattr read create unlink open };
+allow mysqld_t fixed_disk_device_t:blk_file { read write open };
+allow mysqld_t ifconfig_exec_t:file { read execute open execute_no_trans getattr };
+
+#This rule allows connecting on 4444/4567/4568
+#allow mysqld_t kerberos_master_port_t:tcp_socket { name_bind name_connect };
+
+allow mysqld_t mysqld_safe_t:dir { getattr search };
+allow mysqld_t mysqld_safe_t:file { read open };
+allow mysqld_t self:unix_stream_socket connectto;
+allow mysqld_t port_t:tcp_socket { name_bind name_connect };
+allow mysqld_t proc_net_t:file { read getattr open };
+allow mysqld_t sysctl_net_t:dir search;
+allow mysqld_t var_lib_t:file { getattr open append };
+allow mysqld_t var_lib_t:sock_file { create unlink getattr };
+allow mysqld_t rsync_exec_t:file { read getattr open execute execute_no_trans };
+allow mysqld_t self:process getattr;
+allow mysqld_t hostname_exec_t:file { read getattr execute open execute_no_trans };
+allow mysqld_t user_tmp_t:dir { write add_name };
+allow mysqld_t user_tmp_t:file create;
+allow mysqld_t bin_t:lnk_file read;
+allow mysqld_t tmp_t:file { append create read write open getattr unlink setattr };
+
+# Allows too much leeway - the xtrabackup/wsrep rules in fc should fix it, but
+# keep for the moment.
+allow mysqld_t shell_exec_t:file { execute_no_trans getattr read execute open };
+allow mysqld_t bin_t:file { getattr read execute open execute_no_trans ioctl };
+
+# MariaDB additions
+allow mysqld_t self:process setpgid;
+# This rule allows port tcp/4444
+allow mysqld_t kerberos_port_t:tcp_socket { name_bind name_connect };
+# This rule allows port tcp/4567 (tram_port_t may not be available on
+# older versions)
+allow mysqld_t tram_port_t:tcp_socket name_bind;
+# This rule allows port udp/4567 (see README)
+allow mysqld_t mysqld_port_t:udp_socket name_bind;
+
+# Rules related to XtraBackup
+allow mysqld_t self:netlink_tcpdiag_socket { create nlmsg_read };
+allow mysqld_t sysctl_net_t:file { read getattr open };
+
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index 24b48e1920e..ee4ea0ce088 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -335,6 +335,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)
@@ -354,6 +363,7 @@ ELSE()
mysqldumpslow
mysqld_multi
mysqld_safe
+ ${WSREP_BINARIES}
)
FOREACH(file ${BIN_SCRIPTS})
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh)
@@ -376,6 +386,22 @@ ELSE()
COMPONENT ${${file}_COMPONENT}
)
ENDFOREACH()
+ SET (wsrep_sst_rsync_wan ${CMAKE_CURRENT_BINARY_DIR}/wsrep_sst_rsync_wan)
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${wsrep_sst_rsync_wan}
+ COMMAND ${CMAKE_COMMAND} ARGS -E create_symlink
+ wsrep_sst_rsync
+ wsrep_sst_rsync_wan
+ )
+ ADD_CUSTOM_TARGET(symlink_wsrep_sst_rsync
+ ALL
+ DEPENDS ${wsrep_sst_rsync_wan}
+ )
+ INSTALL(
+ FILES ${wsrep_sst_rsync_wan}
+ DESTINATION ${INSTALL_BINDIR}
+ COMPONENT Server
+ )
ENDIF()
# Install libgcc as mylibgcc.a
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index de8bc25afce..8b9bb02fa85 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -22,7 +22,7 @@ use Getopt::Long;
use POSIX qw(strftime getcwd);
$|=1;
-$VER="2.16";
+$VER="2.20";
my @defaults_options; # Leading --no-defaults, --defaults-file, etc.
@@ -122,6 +122,7 @@ sub main
print "will be disabled\nand some will be enabled.\n\n";
}
+ init_log() if (!defined($opt_log));
$groupids = $ARGV[1];
if ($opt_version)
{
@@ -147,7 +148,6 @@ sub main
!($ARGV[0] =~ m/^stop$/i) &&
!($ARGV[0] =~ m/^report$/i)));
- init_log() if (!defined($opt_log));
if (!$opt_no_log)
{
w2log("$my_progname log file version $VER; run: ",
@@ -190,9 +190,9 @@ sub main
}
}
-#
-# Quote word for shell
-#
+####
+#### Quote word for shell
+####
sub quote_shell_word
{
@@ -202,6 +202,10 @@ sub quote_shell_word
return $option;
}
+####
+#### get options for a group
+####
+
sub defaults_for_group
{
my ($group) = @_;
@@ -303,8 +307,12 @@ sub report_mysqlds
sub start_mysqlds()
{
- my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $info_sent);
+ my (@groups, $com, $com2, $tmp, $i, @options, $j, $mysqld_found,
+ $info_sent, $curdir, $mysql_install_db, $srcdir, $basedir,
+ $datadir);
+ $mysql_install_db= undef();
+ $srcdir= undef();
if (!$opt_no_log)
{
w2log("\nStarting MySQL servers\n","$opt_log",0,0);
@@ -318,8 +326,9 @@ sub start_mysqlds()
{
@options = defaults_for_group($groups[$i]);
- $basedir_found= 0; # The default
- $mysqld_found= 1; # The default
+ my $basedir_found= 0; # The default
+ my $datadir_found= 0; # The default
+ my $mysqld_found= 1; # The default
$mysqld_found= 0 if (!length($mysqld));
$com= "$mysqld";
for ($j = 0, $tmp= ""; defined($options[$j]); $j++)
@@ -334,6 +343,47 @@ sub start_mysqlds()
$com= $options[$j];
$mysqld_found= 1;
}
+ elsif ("--mysql-install-db=" eq substr($options[$j], 0, 19))
+ {
+ # mysql_install_db related option
+
+ $options[$j]=~ s/\-\-mysql\-install\-db\=//;
+ $mysql_install_db= $options[$j];
+ }
+ elsif ("--srcdir=" eq substr($options[$j], 0, 9))
+ {
+ # mysql_install_db related option
+
+ $options[$j]=~ s/\-\-srcdir\=//;
+ $srcdir= $options[$j];
+ }
+ elsif ("--include-config=" eq substr($options[$j], 0, 17))
+ {
+ $options[$j]=~ s/\-\-include\-config\=//;
+ $com2= "my_print_defaults --config-file=$options[$j] $groups[$i]";
+
+ # we need to reorder the array so that options in extra config file
+ # come in the middle. Needed if someone wants to overwrite an option
+
+ my ($k, @tmp_array);
+ for ($k= $j + 1; defined($options[$k]); $k++)
+ {
+ push (@tmp_array, $options[$k]);
+ undef($options[$k]);
+ }
+ pop(@options); # pop out last null array element
+ push (@options, `$com2`);
+ chomp(@options); # new lines away
+ push (@options, @tmp_array);
+ }
+ elsif ("--datadir=" eq substr($options[$j], 0, 10))
+ {
+ $datadir= $options[$j];
+ $datadir =~ s/^--datadir=//;
+ $datadir_found= 1;
+ $options[$j]= quote_shell_word($options[$j]);
+ $tmp.= " $options[$j]";
+ }
elsif ("--basedir=" eq substr($options[$j], 0, 10))
{
$basedir= $options[$j];
@@ -357,6 +407,25 @@ sub start_mysqlds()
print "wanted mysqld binary.\n\n";
$info_sent= 1;
}
+ if (defined($mysql_install_db))
+ {
+ $com2= "$mysql_install_db";
+ $com2.= " --srcdir=$srcdir" if (defined($srcdir));
+ $com2.= " --datadir=$datadir" if ($datadir_found);
+
+ if (-d "$datadir/mysql")
+ {
+ my $wstr= "WARNING: $datadir/mysql already exists. Not going to\n";
+ $wstr.= "run $mysql_install_db on $datadir\n";
+ print $wstr if ($opt_verbose);
+ w2log($wstr, 0, 0);
+ }
+ else
+ {
+ w2log("Installing databases on $datadir..\n", 0, 0);
+ `$com2`;
+ }
+ }
$com.= $tmp;
$com.= " >> $opt_log 2>&1" if (!$opt_no_log);
$com.= " &";
@@ -426,7 +495,7 @@ sub stop_mysqlds()
sub get_mysqladmin_options
{
my ($i, @groups)= @_;
- my ($mysqladmin_found, $com, $tmp, $j);
+ my ($mysqladmin_found, $com, $com2, $tmp, $j);
@options = defaults_for_group($groups[$i]);
@@ -449,6 +518,25 @@ sub get_mysqladmin_options
$com= $options[$j];
$mysqladmin_found= 1;
}
+ elsif ("--include-config=" eq substr($options[$j], 0, 17))
+ {
+ $options[$j]=~ s/\-\-include\-config\=//;
+ $com2= "my_print_defaults --config-file=$options[$j] $groups[$i]";
+
+ # we need to reorder the array so that options in extra config file
+ # come in the middle. Needed if someone wants to overwrite an option
+
+ my ($k, @tmp_array);
+ for ($k= $j + 1; defined($options[$k]); $k++)
+ {
+ push (@tmp_array, $options[$k]);
+ undef($options[$k]);
+ }
+ pop(@options); # pop out last null array element
+ push (@options, `$com2`);
+ chomp(@options); # new lines away
+ push (@options, @tmp_array);
+ }
elsif ((($options[$j] =~ m/^(\-\-socket\=)(.*)$/) && !$opt_tcp_ip) ||
($options[$j] =~ m/^(\-\-port\=)(.*)$/))
{
@@ -490,9 +578,11 @@ sub list_defaults_files
($ENV{HOME} ? "$ENV{HOME}/.my.cnf" : undef));
}
+####
+#### Takes a specification of GNRs (see --help), and returns a list of matching
+#### groups which actually are mentioned in a relevant config file
+####
-# Takes a specification of GNRs (see --help), and returns a list of matching
-# groups which actually are mentioned in a relevant config file
sub find_groups
{
my ($raw_gids) = @_;
@@ -820,6 +910,17 @@ Using: @{[join ' ', @defaults_options]}
question. This will be recognised as a special option and
will not be passed to the mysqld. This will allow one to
start different mysqld versions with mysqld_multi.
+--include-config= An optional config file inside a group [mysqld#] which
+ the program is currently reading. It will read any extra
+ options of that group from additional file and insert them
+ where this option was found. Note that the group name
+ [mysqld#] must be the same in order for options to be found.
+--mysql-install-db=...
+ mysql_install_db script to be used for creating internal
+ databases. Used when installing datadir for the first time.
+ This option will be skipped with info in the log file if
+ 'mysql' database already exists in the given datadir.
+--srcdir=... srcdir argument for mysql_install_db script. Optional.
--no-log Print to stdout instead of the log file. By default the log
file is turned on.
--password=... Password for mysqladmin user.
diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh
index c7280036a1e..4268c9fd9c6 100644
--- a/scripts/mysqld_safe.sh
+++ b/scripts/mysqld_safe.sh
@@ -168,7 +168,7 @@ log_notice () {
}
eval_log_error () {
- cmd="$1"
+ local cmd="$1"
case $logging in
file) cmd="$cmd 2>&1 | "`shell_quote_string "$helper"`" $user log "`shell_quote_string "$err_log"` ;;
syslog)
@@ -204,6 +204,89 @@ 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)
+
+ # safety checks
+ if [ -z $wr_logfile ]; then
+ log_error "WSREP: mktemp failed"
+ return 1
+ fi
+
+ if [ -f $wr_logfile ]; then
+ [ "$euid" = "0" ] && chown $user $wr_logfile
+ chmod 600 $wr_logfile
+ else
+ log_error "WSREP: mktemp failed"
+ return 1
+ fi
+
+ 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
+
+ [ $ret -eq 0 ] && rm $wr_logfile
+
+ return $ret
+}
+
check_executable_location() {
if test "$unsafe_my_cnf" = 1 -a "$unrecognized_handling" != collect; then
log_error "Cannot accept $1 from a config file, when my.cnf is in the datadir"
@@ -265,6 +348,14 @@ parse_arguments() {
--timezone=*) TZ="$val"; export TZ; ;;
--flush[-_]caches) flush_caches=1 ;;
--numa[-_]interleave) numa_interleave=1 ;;
+ --wsrep[-_]urls=*) wsrep_urls="$val"; ;;
+ --wsrep[-_]provider=*)
+ if test -n "$val" && test "$val" != "none"
+ then
+ wsrep_restart=1
+ fi
+ append_arg_to_args "$arg"
+ ;;
--help) usage ;;
@@ -858,7 +949,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"
@@ -878,13 +970,29 @@ else
exec 2>/dev/null
fi
+# maximum number of wsrep restarts
+max_wsrep_restarts=0
+
while true
do
rm -f "$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
+
end_time=`date +%M%S`
if test ! -f "$pid_file" # This is removed if normal shutdown
@@ -947,6 +1055,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"
if test -n "$crash_script"
then
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh
new file mode 100644
index 00000000000..9cafdb37023
--- /dev/null
+++ b/scripts/wsrep_sst_common.sh
@@ -0,0 +1,278 @@
+# Copyright (C) 2012-2015 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=${WSREP_SST_OPT_AUTH:-}
+WSREP_SST_OPT_USER=${WSREP_SST_OPT_USER:-}
+WSREP_SST_OPT_PSWD=${WSREP_SST_OPT_PSWD:-}
+WSREP_SST_OPT_DEFAULT=""
+WSREP_SST_OPT_EXTRA_DEFAULT=""
+WSREP_SST_OPT_SUFFIX_DEFAULT=""
+
+while [ $# -gt 0 ]; do
+case "$1" in
+ '--address')
+ readonly WSREP_SST_OPT_ADDR="$2"
+ #
+ # Break address string into host:port/path parts
+ #
+ case "${WSREP_SST_OPT_ADDR}" in
+ \[*)
+ # IPv6
+ addr_no_bracket=${WSREP_SST_OPT_ADDR#\[}
+ readonly WSREP_SST_OPT_HOST_UNESCAPED=${addr_no_bracket%%\]*}
+ readonly WSREP_SST_OPT_HOST="[${WSREP_SST_OPT_HOST_UNESCAPED}]"
+ ;;
+ *)
+ readonly WSREP_SST_OPT_HOST=${WSREP_SST_OPT_ADDR%%[:/]*}
+ readonly WSREP_SST_OPT_HOST_UNESCAPED=$WSREP_SST_OPT_HOST
+ ;;
+ esac
+ remain=${WSREP_SST_OPT_ADDR#${WSREP_SST_OPT_HOST}}
+ remain=${remain#:}
+ readonly WSREP_SST_OPT_ADDR_PORT=${remain%%/*}
+ remain=${remain#*/}
+ readonly WSREP_SST_OPT_MODULE=${remain%%/*}
+ readonly WSREP_SST_OPT_PATH=${WSREP_SST_OPT_ADDR#*/}
+ remain=${WSREP_SST_OPT_PATH#*/}
+ readonly WSREP_SST_OPT_LSN=${remain%%/*}
+ remain=${remain#*/}
+ readonly WSREP_SST_OPT_SST_VER=${remain%%/*}
+ shift
+ ;;
+ '--bypass')
+ WSREP_SST_OPT_BYPASS=1
+ ;;
+ '--datadir')
+ readonly WSREP_SST_OPT_DATA="$2"
+ shift
+ ;;
+ '--defaults-file')
+ readonly WSREP_SST_OPT_DEFAULT="$1=$2"
+ shift
+ ;;
+ '--defaults-extra-file')
+ readonly WSREP_SST_OPT_EXTRA_DEFAULT="$1=$2"
+ shift
+ ;;
+ '--defaults-group-suffix')
+ readonly WSREP_SST_OPT_SUFFIX_DEFAULT="$1=$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
+
+if [ -n "${WSREP_SST_OPT_ADDR_PORT:-}" ]; then
+ if [ -n "${WSREP_SST_OPT_PORT:-}" ]; then
+ if [ "$WSREP_SST_OPT_PORT" != "$WSREP_SST_OPT_ADDR_PORT" ]; then
+ echo "WSREP_SST: [ERROR] port in --port=$WSREP_SST_OPT_PORT differs from port in --address=$WSREP_SST_OPT_ADDR" >&2
+ exit 2
+ fi
+ else
+ readonly WSREP_SST_OPT_PORT="$WSREP_SST_OPT_ADDR_PORT"
+ fi
+fi
+
+# 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
+
+readonly WSREP_SST_OPT_CONF="$WSREP_SST_OPT_DEFAULT $WSREP_SST_OPT_EXTRA_DEFAULT $WSREP_SST_OPT_SUFFIX_DEFAULT"
+readonly MY_PRINT_DEFAULTS="${MY_PRINT_DEFAULTS} $WSREP_SST_OPT_CONF"
+
+wsrep_auth_not_set()
+{
+ [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ]
+}
+
+# State Snapshot Transfer authentication password was displayed in the ps output. Bug fixed #1200727.
+if $MY_PRINT_DEFAULTS sst | grep -q "wsrep_sst_auth"; then
+ if wsrep_auth_not_set; then
+ WSREP_SST_OPT_AUTH=$($MY_PRINT_DEFAULTS sst | grep -- "--wsrep_sst_auth" | cut -d= -f2)
+ fi
+fi
+readonly WSREP_SST_OPT_AUTH
+
+# Splitting AUTH into potential user:password pair
+if ! wsrep_auth_not_set
+then
+ readonly AUTH_VEC=(${WSREP_SST_OPT_AUTH//:/ })
+ WSREP_SST_OPT_USER="${AUTH_VEC[0]:-}"
+ WSREP_SST_OPT_PSWD="${AUTH_VEC[1]:-}"
+fi
+readonly WSREP_SST_OPT_USER
+readonly WSREP_SST_OPT_PSWD
+
+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_warning()
+{
+ wsrep_log "[WARNING] $*"
+}
+
+wsrep_log_info()
+{
+ wsrep_log "[INFO] $*"
+}
+
+wsrep_cleanup_progress_file()
+{
+ [ -n "${SST_PROGRESS_FILE:-}" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null || true
+}
+
+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
+}
+
+#
+# user can specify xtrabackup specific settings that will be used during sst
+# process like encryption, etc.....
+# parse such configuration option. (group for xb settings is [sst] in my.cnf
+#
+# 1st param: group (config file section like sst) or my_print_defaults argument (like --mysqld)
+# 2nd param: var : name of the variable in the section, e.g. server-id
+# 3rd param: - : default value for the param
+parse_cnf()
+{
+ local group=$1
+ local var=$2
+ local reval=""
+
+ # normalize the variable names specified in cnf file (user can use _ or - for example log-bin or log_bin)
+ # then search for needed variable
+ # finally get the variable value (if variables has been specified multiple time use the last value only)
+
+ reval=$($MY_PRINT_DEFAULTS "${group}" | awk -v var="${var}" 'BEGIN { OFS=FS="=" } { gsub(/_/,"-",$1); if ( $1=="--"var) lastval=substr($0,length($1)+2) } END { print lastval}')
+
+ # use default if we haven't found a value
+ if [ -z $reval ]; then
+ [ -n "$3" ] && reval=$3
+ fi
+ echo $reval
+}
diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh
new file mode 100644
index 00000000000..c2799aa3aa3
--- /dev/null
+++ b/scripts/wsrep_sst_mysqldump.sh
@@ -0,0 +1,168 @@
+#!/bin/bash -ue
+# Copyright (C) 2009-2015 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
+PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+
+EINVAL=22
+
+local_ip()
+{
+ [ "$1" = "127.0.0.1" ] && return 0
+ [ "$1" = "localhost" ] && return 0
+ [ "$1" = "[::1]" ] && 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_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
+if ! $MYSQL_CLIENT --version | grep 'Distrib 10.0' >/dev/null
+then
+ $MYSQL_CLIENT --version >&2
+ wsrep_log_error "this operation requires MySQL client version 10.0.x"
+ exit $EINVAL
+fi
+
+[ -n "$WSREP_SST_OPT_USER" ] && AUTH="-u$WSREP_SST_OPT_USER" || AUTH=
+
+# Refs https://github.com/codership/mysql-wsrep/issues/141
+# Passing password in MYSQL_PWD environment variable is considered
+# "extremely insecure" by MySQL Guidelines for Password Security
+# (https://dev.mysql.com/doc/refman/5.6/en/password-security-user.html)
+# that is even less secure than passing it on a command line! It is doubtful:
+# the whole command line is easily observable by any unprivileged user via ps,
+# whereas (at least on Linux) unprivileged user can't see process environment
+# that he does not own. So while it may be not secure in the NSA sense of the
+# word, it is arguably more secure than passing password on the command line.
+[ -n "$WSREP_SST_OPT_PSWD" ] && export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
+
+STOP_WSREP="SET wsrep_on=OFF;"
+
+# mysqldump cannot restore CSV tables, fix this issue
+CSV_TABLES_FIX="
+set sql_mode='';
+
+USE mysql;
+
+SET @cond = (SELECT (SUPPORT = 'YES' or SUPPORT = 'DEFAULT') FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'csv');
+
+SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS general_log ( event_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL, server_id int(10) unsigned NOT NULL, command_type varchar(64) NOT NULL, argument mediumtext NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"General log\"', 'SET @dummy = 0');
+
+PREPARE stmt FROM @stmt;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+SET @stmt = IF (@cond = '1', 'CREATE TABLE IF NOT EXISTS slow_log ( start_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host mediumtext NOT NULL, query_time time(6) NOT NULL, lock_time time(6) NOT NULL, rows_sent int(11) NOT NULL, rows_examined int(11) NOT NULL, db varchar(512) NOT NULL, last_insert_id int(11) NOT NULL, insert_id int(11) NOT NULL, server_id int(10) unsigned NOT NULL, sql_text mediumtext NOT NULL, thread_id bigint(21) unsigned NOT NULL) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT=\"Slow log\"', 'SET @dummy = 0');
+
+PREPARE stmt FROM @stmt;
+EXECUTE stmt;
+DROP PREPARE stmt;"
+
+SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';"
+
+# Retrieve the donor's @@global.gtid_binlog_state.
+GTID_BINLOG_STATE=$(echo "SHOW GLOBAL VARIABLES LIKE 'gtid_binlog_state'" |\
+$MYSQL_CLIENT $AUTH -S$WSREP_SST_OPT_SOCKET --disable-reconnect --connect_timeout=10 |\
+tail -1 | awk -F ' ' '{ print $2 }')
+
+MYSQL="$MYSQL_CLIENT $WSREP_SST_OPT_CONF "\
+"$AUTH -h${WSREP_SST_OPT_HOST_UNESCAPED} "\
+"-P$WSREP_SST_OPT_PORT --disable-reconnect --connect_timeout=10"
+
+# Check if binary logging is enabled on the joiner node.
+# Note: SELECT cannot be used at this point.
+LOG_BIN=$(echo "SHOW VARIABLES LIKE 'log_bin'" | $MYSQL |\
+tail -1 | awk -F ' ' '{ print $2 }')
+
+# Check the joiner node's server version.
+SERVER_VERSION=$(echo "SHOW VARIABLES LIKE 'version'" | $MYSQL |\
+tail -1 | awk -F ' ' '{ print $2 }')
+
+RESET_MASTER=""
+SET_GTID_BINLOG_STATE=""
+SQL_LOG_BIN_OFF=""
+
+# Safety check
+if [ ${SERVER_VERSION%%.*} != '5' ]
+then
+ # If binary logging is enabled on the joiner node, we need to copy donor's
+ # gtid_binlog_state to joiner. In order to do that, a RESET MASTER must be
+ # executed to erase binary logs (if any). Binary logging should also be
+ # turned off for the session so that gtid state does not get altered while
+ # the dump gets replayed on joiner.
+ if [[ "$LOG_BIN" == 'ON' ]]; then
+ RESET_MASTER="RESET MASTER;"
+ SET_GTID_BINLOG_STATE="SET @@global.gtid_binlog_state='$GTID_BINLOG_STATE';"
+ SQL_LOG_BIN_OFF="SET @@session.sql_log_bin=OFF;"
+ fi
+fi
+
+# 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"
+
+# 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;"
+
+
+if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
+then
+ (echo $STOP_WSREP && echo $RESET_MASTER && \
+ echo $SET_GTID_BINLOG_STATE && echo $SQL_LOG_BIN_OFF && \
+ echo $STOP_WSREP && $MYSQLDUMP && echo $CSV_TABLES_FIX && \
+ 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 00000000000..5617142ea99
--- /dev/null
+++ b/scripts/wsrep_sst_rsync.sh
@@ -0,0 +1,342 @@
+#!/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 pid file
+RSYNC_CONF= # rsync configuration file
+RSYNC_REAL_PID= # rsync process id
+
+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. rsync PID: $RSYNC_REAL_PID"
+ [ "0" != "$RSYNC_REAL_PID" ] && \
+ kill $RSYNC_REAL_PID && \
+ sleep 0.5 && \
+ kill -9 $RSYNC_REAL_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 whether rsync process is still running.
+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
+
+ if ! which lsof > /dev/null; then
+ wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed."
+ exit 2 # ENOENT
+ fi
+
+ if ! which lsof > /dev/null; then
+ wsrep_log_error "lsof tool not found in PATH! Make sure you have it installed."
+ exit 2 # ENOENT
+ fi
+
+ 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=$(parse_cnf --mysqld innodb-log-group-home-dir '')
+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 -not -name "lost+found" \
+ -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"
+
+ trap "exit 32" HUP PIPE
+ trap "exit 3" INT TERM ABRT
+ trap cleanup_joiner EXIT
+
+ RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf"
+
+ if [ -n "${MYSQL_TMP_DIR:-}" ] ; then
+ SILENT="log file = $MYSQL_TMP_DIR/rsyncd.log"
+ else
+ SILENT=""
+ fi
+
+cat << EOF > "$RSYNC_CONF"
+pid file = $RSYNC_PID
+use chroot = no
+read only = no
+timeout = 300
+$SILENT
+[$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)
+ readonly RSYNC_PORT=${WSREP_SST_OPT_PORT:-4444}
+ 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 $WSREP_SST_OPT_HOST:$RSYNC_PORT/$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 00000000000..f107cea6c74
--- /dev/null
+++ b/scripts/wsrep_sst_xtrabackup-v2.sh
@@ -0,0 +1,1189 @@
+#!/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
+ssyslog=""
+ssystag=""
+XTRABACKUP_PID=""
+tca=""
+tcert=""
+tkey=""
+sockopt=""
+progress=""
+ttime=0
+totime=0
+ecmd=""
+rlimit=""
+# Initially
+stagemsg="${WSREP_SST_OPT_ROLE}"
+cpat=""
+ib_home_dir=""
+ib_log_dir=""
+ib_undo_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=""
+ssl_dhparams=""
+
+ssl_cert=""
+ssl_ca=""
+ssl_key=""
+
+if which pv &>/dev/null && pv --help | grep -q FORMAT;then
+ pvopts+=$pvformat
+fi
+pcmd="pv $pvopts"
+declare -a RC
+
+INNOBACKUPEX_BIN=innobackupex
+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 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
+ wsrep_log_warning "Using the 'encrypt-key' option causes the encryption key"
+ wsrep_log_warning "to be set via the command-line and is considered insecure."
+ wsrep_log_warning "It is recommended to use the 'encrypt-key-file' option instead."
+
+ ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey"
+ fi
+
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ ecmd+=" -d"
+ fi
+
+ stagemsg+="-XB-Encrypted"
+}
+
+#
+# If the ssl_dhparams variable is already set, uses that as a source
+# of dh parameters for OpenSSL. Otherwise, looks for dhparams.pem in the
+# datadir, and creates it there if it can't find the file.
+# No input parameters
+#
+check_for_dhparams()
+{
+ if [[ -z "$ssl_dhparams" ]]; then
+ if ! [[ -r "$DATA/dhparams.pem" ]]; then
+ wsrep_check_programs openssl
+ wsrep_log_info "Could not find dhparams file, creating $DATA/dhparams.pem"
+
+ if ! openssl dhparam -out "$DATA/dhparams.pem" 2048 >/dev/null 2>&1
+ then
+ wsrep_log_error "******** FATAL ERROR ********************************* "
+ wsrep_log_error "* Could not create the dhparams.pem file with OpenSSL. "
+ wsrep_log_error "****************************************************** "
+ exit 22
+ fi
+ fi
+ ssl_dhparams="$DATA/dhparams.pem"
+ fi
+}
+
+#
+# verifies that the certificate matches the private key
+# doing this will save us having to wait for a timeout that would
+# otherwise occur.
+#
+# 1st param: path to the cert
+# 2nd param: path to the private key
+#
+verify_cert_matches_key()
+{
+ local cert_path=$1
+ local key_path=$2
+
+ wsrep_check_programs openssl diff
+
+ # generate the public key from the cert and the key
+ # they should match (otherwise we can't create an SSL connection)
+ if ! diff <(openssl x509 -in "$cert_path" -pubkey -noout) <(openssl rsa -in "$key_path" -pubout 2>/dev/null) >/dev/null 2>&1
+ then
+ wsrep_log_error "******** FATAL ERROR ************************* "
+ wsrep_log_error "* The certifcate and private key do not match. "
+ wsrep_log_error "* Please check your certificate and key files. "
+ wsrep_log_error "********************************************** "
+ exit 22
+ fi
+}
+
+# Checks to see if the file exists
+# If the file does not exist (or cannot be read), issues an error
+# and exits
+#
+# 1st param: file name to be checked (for read access)
+# 2nd param: 1st error message (header)
+# 3rd param: 2nd error message (footer, optional)
+#
+verify_file_exists()
+{
+ local file_path=$1
+ local error_message1=$2
+ local error_message2=$3
+
+ if ! [[ -r "$file_path" ]]; then
+ wsrep_log_error "******** FATAL ERROR ************************* "
+ wsrep_log_error "* $error_message1 "
+ wsrep_log_error "* Could not find/access : $file_path "
+
+ if ! [[ -z "$error_message2" ]]; then
+ wsrep_log_error "* $error_message2 "
+ fi
+
+ wsrep_log_error "********************************************** "
+ exit 22
+ fi
+}
+
+get_transfer()
+{
+ TSST_PORT=${WSREP_SST_OPT_PORT:-4444}
+
+ if [[ $tfmt == 'nc' ]];then
+ if [[ ! -x `which nc` ]];then
+ wsrep_log_error "nc(netcat) not found in path: $PATH"
+ exit 2
+ fi
+
+ if [[ $encrypt -eq 2 || $encrypt -eq 3 || $encrypt -eq 4 ]]; then
+ wsrep_log_error "******** FATAL ERROR *********************** "
+ wsrep_log_error "* Using SSL encryption (encrypt= 2, 3, or 4) "
+ wsrep_log_error "* is not supported when using nc(netcat). "
+ wsrep_log_error "******************************************** "
+ exit 22
+ fi
+
+ wsrep_log_info "Using netcat as streamer"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ if nc -h 2>&1 | grep -q ncat; then
+ tcmd="nc $sockopt -l ${TSST_PORT}"
+ else
+ tcmd="nc $sockopt -dl ${TSST_PORT}"
+ fi
+ else
+ # netcat doesn't understand [] around IPv6 address
+ tcmd="nc ${WSREP_SST_OPT_HOST_UNESCAPED} ${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
+
+ donor_extra=""
+ joiner_extra=""
+ if [[ $encrypt -eq 2 || $encrypt -eq 3 || $encrypt -eq 4 ]]; then
+ if ! socat -V | grep -q WITH_OPENSSL; then
+ wsrep_log_error "******** FATAL ERROR ****************** "
+ wsrep_log_error "* socat is not openssl enabled. "
+ wsrep_log_error "* Unable to encrypt SST communications. "
+ wsrep_log_error "*************************************** "
+ exit 2
+ fi
+
+ # Determine the socat version
+ SOCAT_VERSION=`socat -V 2>&1 | grep -oe '[0-9]\.[0-9][\.0-9]*' | head -n1`
+ if [[ -z "$SOCAT_VERSION" ]]; then
+ wsrep_log_error "******** FATAL ERROR **************** "
+ wsrep_log_error "* Cannot determine the socat version. "
+ wsrep_log_error "************************************* "
+ exit 2
+ fi
+
+ # socat versions < 1.7.3 will have 512-bit dhparams (too small)
+ # so create 2048-bit dhparams and send that as a parameter
+ # socat version >= 1.7.3, checks to see if the peername matches the hostname
+ # set commonname="" to disable the peername checks
+ #
+ if ! check_for_version "$SOCAT_VERSION" "1.7.3"; then
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]]; then
+ # dhparams check (will create ssl_dhparams if needed)
+ check_for_dhparams
+ joiner_extra=",dhparam=$ssl_dhparams"
+ fi
+ fi
+ if check_for_version "$SOCAT_VERSION" "1.7.3"; then
+ donor_extra=',commonname=""'
+ fi
+ fi
+
+ if [[ $encrypt -eq 2 ]]; then
+ wsrep_log_warning "**** WARNING **** encrypt=2 is deprecated and will be removed in a future release"
+ wsrep_log_info "Using openssl based encryption with socat: with crt and ca"
+
+ verify_file_exists "$tcert" "Both certificate and CA files are required." \
+ "Please check the 'tcert' option. "
+ verify_file_exists "$tca" "Both certificate and CA files are required." \
+ "Please check the 'tca' option. "
+
+ stagemsg+="-OpenSSL-Encrypted-2"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ wsrep_log_info "Decrypting with CERT: $tcert, CA: $tca"
+ tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=${tcert},cafile=${tca}${joiner_extra}${sockopt} stdio"
+ else
+ wsrep_log_info "Encrypting with CERT: $tcert, CA: $tca"
+ tcmd="socat -u stdio openssl-connect:${WSREP_SST_OPT_HOST}:${TSST_PORT},cert=${tcert},cafile=${tca}${donor_extra}${sockopt}"
+ fi
+ elif [[ $encrypt -eq 3 ]];then
+ wsrep_log_warning "**** WARNING **** encrypt=3 is deprecated and will be removed in a future release"
+ wsrep_log_info "Using openssl based encryption with socat: with key and crt"
+
+ verify_file_exists "$tcert" "Both certificate and key files are required." \
+ "Please check the 'tcert' option. "
+ verify_file_exists "$tkey" "Both certificate and key files are required." \
+ "Please check the 'tkey' option. "
+
+ stagemsg+="-OpenSSL-Encrypted-3"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ wsrep_log_info "Decrypting with CERT: $tcert, KEY: $tkey"
+ tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=${tcert},key=${tkey},verify=0${joiner_extra}${sockopt} stdio"
+ else
+ wsrep_log_info "Encrypting with CERT: $tcert, KEY: $tkey"
+ tcmd="socat -u stdio openssl-connect:${WSREP_SST_OPT_HOST}:${TSST_PORT},cert=${tcert},key=${tkey},verify=0${sockopt}"
+ fi
+ elif [[ $encrypt -eq 4 ]]; then
+ wsrep_log_info "Using openssl based encryption with socat: with key, crt, and ca"
+
+ verify_file_exists "$ssl_ca" "CA, certificate, and key files are required." \
+ "Please check the 'ssl-ca' option. "
+ verify_file_exists "$ssl_cert" "CA, certificate, and key files are required." \
+ "Please check the 'ssl-cert' option. "
+ verify_file_exists "$ssl_key" "CA, certificate, and key files are required." \
+ "Please check the 'ssl-key' option. "
+
+ # Check to see that the key matches the cert
+ verify_cert_matches_key $ssl_cert $ssl_key
+
+ stagemsg+="-OpenSSL-Encrypted-4"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]]; then
+ wsrep_log_info "Decrypting with CERT: $ssl_cert, KEY: $ssl_key, CA: $ssl_ca"
+ tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=${ssl_cert},key=${ssl_key},cafile=${ssl_ca},verify=1${joiner_extra}${sockopt} stdio"
+ else
+ wsrep_log_info "Encrypting with CERT: $ssl_cert, KEY: $ssl_key, CA: $ssl_ca"
+ tcmd="socat -u stdio openssl-connect:${WSREP_SST_OPT_HOST}:${TSST_PORT},cert=${ssl_cert},key=${ssl_key},cafile=${ssl_ca},verify=1${donor_extra}${sockopt}"
+ fi
+
+ else
+ if [[ $encrypt -eq 1 ]]; then
+ wsrep_log_warning "**** WARNING **** encrypt=1 is deprecated and will be removed in a future release"
+ fi
+
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]]; then
+ tcmd="socat -u TCP-LISTEN:${TSST_PORT},reuseaddr${sockopt} stdio"
+ else
+ tcmd="socat -u stdio TCP:${WSREP_SST_OPT_HOST}:${TSST_PORT}${sockopt}"
+ fi
+ fi
+ fi
+}
+
+get_footprint()
+{
+ pushd $WSREP_SST_OPT_DATA 1>/dev/null
+ payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c -s | awk 'END { print $1 }')
+ if $MY_PRINT_DEFAULTS 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 [[ ! -x `which pv` ]];then
+ wsrep_log_error "pv not found in path: $PATH"
+ wsrep_log_error "Disabling all progress/rate-limiting"
+ pcmd=""
+ rlimit=""
+ progress=""
+ return
+ fi
+
+ 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")
+ tca=$(parse_cnf sst tca "")
+ tcert=$(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 '.*\.pem$\|.*init\.ok$\|.*galera\.cache$\|.*sst_in_progress$\|.*\.sst$\|.*gvwstate\.dat$\|.*grastate\.dat$\|.*\.err$\|.*\.log$\|.*RPM_UPGRADE_MARKER$\|.*RPM_UPGRADE_HISTORY$')
+ 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
+
+ # Pull the parameters needed for encrypt=4
+ ssl_ca=$(parse_cnf sst ssl-ca "")
+ if [[ -z "$ssl_ca" ]]; then
+ ssl_ca=$(parse_cnf --mysqld ssl-ca "")
+ fi
+ ssl_cert=$(parse_cnf sst ssl-cert "")
+ if [[ -z "$ssl_cert" ]]; then
+ ssl_cert=$(parse_cnf --mysqld ssl-cert "")
+ fi
+ ssl_key=$(parse_cnf sst ssl-key "")
+ if [[ -z "$ssl_key" ]]; then
+ ssl_key=$(parse_cnf --mysqld ssl-key "")
+ fi
+
+ rlimit=$(parse_cnf sst rlimit "")
+ uextra=$(parse_cnf sst use-extra 0)
+ 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)
+ ssyslog=$(parse_cnf sst sst-syslog 0)
+ ssystag=$(parse_cnf mysqld_safe syslog-tag "${SST_SYSLOG_TAG:-}")
+ ssystag+="-"
+
+ if [[ $ssyslog -ne -1 ]];then
+ if $MY_PRINT_DEFAULTS mysqld_safe | grep -q -- "--syslog";then
+ ssyslog=1
+ fi
+ fi
+}
+
+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"
+ elif [ "${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
+
+ # Final cleanup
+ pgid=$(ps -o pgid= $$ | grep -o '[0-9]*')
+
+ # This means no setsid done in mysqld.
+ # We don't want to kill mysqld here otherwise.
+ if [[ $$ -eq $pgid ]];then
+
+ # This means a signal was delivered to the process.
+ # So, more cleanup.
+ if [[ $estatus -ge 128 ]];then
+ kill -KILL -$$ || true
+ fi
+
+ fi
+
+ exit $estatus
+}
+
+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
+
+ # Final cleanup
+ pgid=$(ps -o pgid= $$ | grep -o '[0-9]*')
+
+ # This means no setsid done in mysqld.
+ # We don't want to kill mysqld here otherwise.
+ if [[ $$ -eq $pgid ]];then
+
+ # This means a signal was delivered to the process.
+ # So, more cleanup.
+ if [[ $estatus -ge 128 ]];then
+ kill -KILL -$$ || true
+ fi
+
+ fi
+
+ exit $estatus
+
+}
+
+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
+}
+
+# waits ~1 minute for nc/socat to open the port and then reports ready
+# (regardless of timeout)
+wait_for_listen()
+{
+ local HOST=$1
+ local PORT=$2
+ local MODULE=$3
+
+ for i in {1..300}
+ do
+ ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break
+ sleep 0.2
+ done
+
+ echo "ready ${HOST}:${PORT}/${MODULE}//${WSREP_SST_OPT_SST_VER:-1}"
+}
+
+check_extra()
+{
+ local use_socket=1
+ if [[ $uextra -eq 1 ]];then
+ if [ $(parse_cnf --mysqld thread-handling) = 'pool-of-threads'];then
+ local eport=$(parse_cnf --mysqld extra-port)
+ 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 checkf=$4
+ local ltcmd
+
+ if [[ ! -d ${dir} ]];then
+ # This indicates that IST is in progress
+ return
+ fi
+
+ 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 -s9 $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 [[ $checkf -eq 1 && ! -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
+
+}
+
+# Returns the version string in a standardized format
+# Input "1.2.3" => echoes "010203"
+# Wrongly formatted values => echoes "000000"
+normalize_version()
+{
+ local major=0
+ local minor=0
+ local patch=0
+
+ # Only parses purely numeric version numbers, 1.2.3
+ # Everything after the first three values are ignored
+ if [[ $1 =~ ^([0-9]+)\.([0-9]+)\.?([0-9]*)([\.0-9])*$ ]]; then
+ major=${BASH_REMATCH[1]}
+ minor=${BASH_REMATCH[2]}
+ patch=${BASH_REMATCH[3]}
+ fi
+
+ printf %02d%02d%02d $major $minor $patch
+}
+
+# Compares two version strings
+# The first parameter is the version to be checked
+# The second parameter is the minimum version required
+# Returns 1 (failure) if $1 >= $2, 0 (success) otherwise
+check_for_version()
+{
+ local local_version_str="$( normalize_version $1 )"
+ local required_version_str="$( normalize_version $2 )"
+
+ if [[ "$local_version_str" < "$required_version_str" ]]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+
+if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then
+ wsrep_log_error "innobackupex not in path: $PATH"
+ exit 2
+fi
+
+# check the version, we require XB-2.4 to ensure that we can pass the
+# datadir via the command-line option
+XB_REQUIRED_VERSION="2.3.5"
+
+XB_VERSION=`$INNOBACKUPEX_BIN --version 2>&1 | grep -oe '[0-9]\.[0-9][\.0-9]*' | head -n1`
+if [[ -z $XB_VERSION ]]; then
+ wsrep_log_error "FATAL: Cannot determine the $INNOBACKUPEX_BIN version. Needs xtrabackup-$XB_REQUIRED_VERSION or higher to perform SST"
+ exit 2
+fi
+
+if ! check_for_version $XB_VERSION $XB_REQUIRED_VERSION; then
+ wsrep_log_error "FATAL: The $INNOBACKUPEX_BIN version is $XB_VERSION. Needs xtrabackup-$XB_REQUIRED_VERSION or higher to perform SST"
+ 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
+
+if ${INNOBACKUPEX_BIN} /tmp --help 2>/dev/null | grep -q -- '--version-check'; then
+ disver="--no-version-check"
+fi
+
+if [[ ${FORCE_FTWRL:-0} -eq 1 ]];then
+ wsrep_log_info "Forcing FTWRL due to environment variable FORCE_FTWRL equal to $FORCE_FTWRL"
+ iopts+=" --no-backup-locks "
+fi
+
+
+INNOEXTRA=""
+
+if [[ $ssyslog -eq 1 ]];then
+
+ if [[ ! -x `which logger` ]];then
+ wsrep_log_error "logger not in path: $PATH. Ignoring"
+ else
+
+ wsrep_log_info "Logging all stderr of SST/Innobackupex to syslog"
+
+ exec 2> >(logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE)
+
+ wsrep_log_error()
+ {
+ logger -p daemon.err -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@"
+ }
+
+ wsrep_log_info()
+ {
+ logger -p daemon.info -t ${ssystag}wsrep-sst-$WSREP_SST_OPT_ROLE "$@"
+ }
+
+ INNOAPPLY="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply "
+ INNOMOVE="2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move "
+ INNOBACKUP="2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)"
+ fi
+
+else
+ INNOAPPLY="&>\${DATA}/innobackup.prepare.log"
+ INNOMOVE="&>\${DATA}/innobackup.move.log"
+ INNOBACKUP="2>\${DATA}/innobackup.backup.log"
+fi
+
+get_stream
+get_transfer
+
+INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} ${INNOAPPLY}"
+INNOMOVE="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} ${INNOMOVE}"
+INNOBACKUP="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir ${INNOBACKUP}"
+
+if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
+then
+ trap cleanup_donor EXIT
+
+ if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
+ then
+ usrst=0
+ if [[ -z $WSREP_SST_OPT_SST_VER ]];then
+ wsrep_log_error "Upgrade joiner to 5.6.21 or higher for backup locks support"
+ wsrep_log_error "The joiner is not supported for this version of donor"
+ exit 93
+ fi
+
+ 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 [[ -n "${WSREP_SST_OPT_USER:-}" && "$WSREP_SST_OPT_USER" != "(null)" ]]; then
+ INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
+ usrst=1
+ fi
+
+ if [ -n "${WSREP_SST_OPT_PSWD:-}" ]; then
+ INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
+ elif [[ $usrst -eq 1 ]];then
+ # Empty password, used for testing, debugging etc.
+ INNOEXTRA+=" --password="
+ fi
+
+ get_keys
+ 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"
+
+ # Restore the transport commmand to its original state
+ 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 ${WSREP_SST_OPT_HOST} ${WSREP_SST_OPT_PORT:-4444}"
+
+ # Add compression to the head of the stream (if specified)
+ if [[ -n $scomp ]]; then
+ tcmd="$scomp | $tcmd"
+ fi
+
+ # Add encryption to the head of the stream (if specified)
+ if [[ $encrypt -eq 1 ]]; then
+ tcmd=" \$ecmd | $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
+
+ ib_home_dir=$(parse_cnf --mysqld innodb-data-home-dir "")
+ ib_log_dir=$(parse_cnf --mysqld innodb-log-group-home-dir "")
+ ib_undo_dir=$(parse_cnf --mysqld innodb-undo-directory "")
+
+ stagemsg="Joiner-Recv"
+
+ 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
+
+ wait_for_listen ${WSREP_SST_OPT_HOST} ${WSREP_SST_OPT_PORT:-4444} ${MODULE} &
+
+ trap sig_joiner_cleanup HUP PIPE INT TERM
+ trap cleanup_joiner EXIT
+
+ if [[ -n $progress ]];then
+ adjust_progress
+ tcmd+=" | $pcmd"
+ 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 1
+
+
+ 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
+
+ if [[ -d ${DATA}/.sst ]];then
+ wsrep_log_info "WARNING: Stale temporary SST directory: ${DATA}/.sst from previous state transfer. Removing"
+ rm -rf ${DATA}/.sst
+ fi
+ mkdir -p ${DATA}/.sst
+ (recv_joiner $DATA/.sst "${stagemsg}-SST" 0 0) &
+ jpid=$!
+ wsrep_log_info "Proceeding with SST"
+
+
+ wsrep_log_info "Cleaning the existing datadir and innodb-data/log directories"
+ find $ib_home_dir $ib_log_dir $ib_undo_dir $DATA -mindepth 1 -prune -regex $cpat -o -exec rm -rfv {} 1>&2 \+
+
+ 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 \+ || true
+ rm $binlog_dir/*.index || true
+ fi
+ fi
+
+
+
+ TDATA=${DATA}
+ DATA="${DATA}/.sst"
+
+
+ MAGIC_FILE="${DATA}/${INFO_FILE}"
+ wsrep_log_info "Waiting for SST streaming to complete!"
+ wait $jpid
+
+ get_proc
+
+ if [[ ! -s ${DATA}/xtrabackup_checkpoints ]];then
+ wsrep_log_error "xtrabackup_checkpoints missing, failed innobackupex/SST on donor"
+ exit 2
+ fi
+
+ # 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}.[0-9]*);do
+ echo ${BINLOG_DIRNAME}/${bfiles} >> ${BINLOG_FILENAME}.index
+ done
+ popd &> /dev/null
+
+ 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
+
+ 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"
+ 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
+ wsrep_log_info "Galera co-ords from recovery: $(cat ${MAGIC_FILE})"
+ 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 00000000000..eb059f8bb9d
--- /dev/null
+++ b/scripts/wsrep_sst_xtrabackup.sh
@@ -0,0 +1,686 @@
+#!/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=""
+tcert=""
+tpem=""
+sockopt=""
+progress=""
+ttime=0
+totime=0
+lsn="${WSREP_SST_OPT_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
+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 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()
+{
+ TSST_PORT=${WSREP_SST_OPT_PORT:-4444}
+
+ 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
+ if nc -h 2>&1 | grep -q ncat;then
+ tcmd="nc -l ${TSST_PORT}"
+ else
+ tcmd="nc -dl ${TSST_PORT}"
+ fi
+ else
+ tcmd="nc ${WSREP_SST_OPT_HOST_UNESCAPED} ${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:${WSREP_SST_OPT_HOST}:${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:${WSREP_SST_OPT_HOST}:${TSST_PORT}${sockopt}"
+ fi
+ fi
+ fi
+
+}
+
+get_footprint()
+{
+ pushd $WSREP_SST_OPT_DATA 1>/dev/null
+ payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c -s | awk 'END { print $1 }')
+ if $MY_PRINT_DEFAULTS 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"
+}
+
+# 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 [ $(parse_cnf --mysqld thread-handling) = 'pool-of-threads'];then
+ local eport=$(parse_cnf --mysqld extra-port)
+ 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
+get_stream
+get_transfer
+
+INNOEXTRA=""
+INNOAPPLY="${INNOBACKUPEX_BIN} ${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log"
+INNOBACKUP="${INNOBACKUPEX_BIN} ${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
+ usrst=0
+ TMPDIR="${TMPDIR:-/tmp}"
+
+ if [[ -n "${WSREP_SST_OPT_USER:-}" && "$WSREP_SST_OPT_USER" != "(null)" ]]; then
+ INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
+ usrst=1
+ fi
+
+ if [ -n "${WSREP_SST_OPT_PSWD:-}" ]; then
+ INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
+ elif [[ $usrst -eq 1 ]];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 ${WSREP_SST_OPT_HOST} ${WSREP_SST_OPT_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 $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_HOST}:${WSREP_SST_OPT_PORT:-4444}"
+
+ wait_for_listen ${WSREP_SST_OPT_PORT:-4444} ${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} ${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 8cd08d61e29..2bb68c7ec46 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -14,6 +14,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
@@ -21,6 +25,7 @@ ${PCRE_INCLUDES}
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}/sql
+${WSREP_INCLUDES}
)
SET(GEN_SOURCES
@@ -51,6 +56,23 @@ IF(SSL_DEFINES)
ADD_DEFINITIONS(${SSL_DEFINES})
ENDIF()
+IF(WITH_WSREP)
+ SET(WSREP_SOURCES
+ wsrep_utils.cc
+ wsrep_xid.cc
+ wsrep_check_opts.cc
+ wsrep_hton.cc
+ wsrep_mysqld.cc
+ wsrep_notify.cc
+ wsrep_sst.cc
+ wsrep_var.cc
+ wsrep_binlog.cc
+ wsrep_applier.cc
+ wsrep_thd.cc
+ )
+ SET(WSREP_LIB wsrep)
+ENDIF()
+
SET (SQL_SOURCE
../sql-common/client.c compat56.cc derror.cc des_key_file.cc
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
@@ -96,7 +118,6 @@ SET (SQL_SOURCE
sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc
transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
sql_reload.cc sql_cmd.h item_inetfunc.cc
-
# added in MariaDB:
sql_explain.h sql_explain.cc
sql_lifo_buffer.h sql_join_cache.h sql_join_cache.cc
@@ -108,6 +129,7 @@ SET (SQL_SOURCE
../sql-common/mysql_async.c
my_apc.cc my_apc.h
rpl_gtid.cc rpl_parallel.cc
+ ${WSREP_SOURCES}
table_cache.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${GEN_SOURCES}
@@ -135,6 +157,7 @@ DTRACE_INSTRUMENT(sql)
TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
mysys mysys_ssl dbug strings vio pcre ${LIBJEMALLOC}
${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT}
+ ${WSREP_LIB}
${SSL_LIBRARIES})
IF(WIN32)
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 09256a34853..aa85b570a84 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -1472,8 +1472,24 @@ end:
bool save_tx_read_only= thd->tx_read_only;
thd->tx_read_only= false;
+#ifdef WITH_WSREP
+ const bool sql_command_set= WSREP(thd);
+ const enum_sql_command sql_command_save= thd->lex->sql_command;
+
+ if (sql_command_set) {
+ thd->lex->sql_command = SQLCOM_DROP_EVENT;
+ }
+#endif
+
ret= Events::drop_event(thd, dbname, name, FALSE);
+#ifdef WITH_WSREP
+ if (sql_command_set)
+ {
+ WSREP_TO_ISOLATION_END;
+ thd->lex->sql_command = sql_command_save;
+ }
+#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 75e844a06c0..a30c1fadf75 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -332,6 +332,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
if (check_db_dir_existence(parse_data->dbname.str))
{
my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
@@ -409,6 +411,10 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
+#ifdef WITH_WSREP
+ error:
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
}
@@ -450,6 +456,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
if (new_dbname) /* It's a rename */
{
/* Check that the new and the old names differ. */
@@ -520,6 +528,10 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
+#ifdef WITH_WSREP
+ error:
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
}
@@ -560,6 +572,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
/*
Turn off row binlogging of this statement and use statement-based so
that all supporting tables are updated for DROP EVENT command.
@@ -581,6 +595,10 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
+#ifdef WITH_WSREP
+ error:
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
}
@@ -1146,7 +1164,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 != (longlong) thd->variables.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
@@ -1195,6 +1226,48 @@ end:
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: schema: %s, query: %s",
+ (thd->db ? thd->db : "(null)"), 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: schema: %s, query: %s",
+ (thd->db ? thd->db : "(null)"), 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 0488ebfb60f..7bffb68c6de 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -387,7 +387,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 71ae84b06a0..33a1a8ab43b 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1282,7 +1282,9 @@ public:
DBUG_ASSERT(h == m_file[i]->ht);
return h;
}
-
+#ifdef WITH_WSREP
+ virtual int wsrep_db_type() const;
+#endif /* WITH_WSREP */
friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2);
};
diff --git a/sql/handler.cc b/sql/handler.cc
index f38569a1458..d8df91c82ab 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -51,6 +51,10 @@
#include "../storage/maria/ha_maria.h"
#endif
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_xid.h"
+#endif
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
@@ -1171,10 +1175,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
@@ -1370,7 +1391,12 @@ int ha_commit_trans(THD *thd, bool all)
mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE,
MDL_EXPLICIT);
+#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);
@@ -1417,7 +1443,33 @@ int ha_commit_trans(THD *thd, bool all)
err= ht->prepare(ht, thd, all);
status_var_increment(thd->status_var.ha_prepare_count);
if (err)
- my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+#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 /* WITH_WSREP */
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
if (err)
goto err;
@@ -1428,6 +1480,13 @@ int ha_commit_trans(THD *thd, bool all)
DEBUG_SYNC(thd, "ha_commit_trans_after_prepare");
DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
+#ifdef WITH_WSREP
+ if (!error && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid))
+ {
+ // xid was rewritten by wsrep
+ xid= wsrep_xid_seqno(thd->transaction.xid_state.xid);
+ }
+#endif // WITH_WSREP
if (!is_real_trans)
{
error= commit_one_phase_2(thd, all, trans, is_real_trans);
@@ -1645,6 +1704,11 @@ int ha_rollback_trans(THD *thd, bool all)
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
+#ifdef WITH_WSREP
+ WSREP_WARN("handlerton rollback failed, thd %lu %lld conf %d SQL %s",
+ thd->thread_id, thd->query_id, thd->wsrep_conflict_state,
+ thd->query());
+#endif /* WITH_WSREP */
}
status_var_increment(thd->status_var.ha_rollback_count);
ha_info_next= ha_info->next();
@@ -1832,7 +1896,13 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
got, hton_name(hton)->str);
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
@@ -3160,7 +3230,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(thd) && wsrep_emulate_bin_log) || 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);
@@ -4379,6 +4454,8 @@ handler::ha_create_partitioning_metadata(const char *name, const char *old_name,
DBUG_ASSERT(m_lock_type == F_UNLCK ||
(!old_name && strcmp(name, table_share->path.str)));
+
+ mark_trx_read_write();
return create_partitioning_metadata(name, old_name, action_flag);
}
@@ -5772,7 +5849,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
}
@@ -5872,6 +5955,30 @@ static 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)))
+ {
+ return 0;
+ }
+
+ /* enforce wsrep_max_ws_rows */
+ if (table->s->tmp_table == NO_TMP_TABLE && WSREP(thd))
+ {
+ thd->wsrep_affected_rows++;
+ if (wsrep_max_ws_rows &&
+ thd->wsrep_exec_mode != REPL_RECV &&
+ thd->wsrep_affected_rows > wsrep_max_ws_rows)
+ {
+ trans_rollback_stmt(thd) || trans_rollback(thd);
+ my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
+ return ER_ERROR_DURING_COMMIT;
+ }
+ }
+#endif /* WITH_WSREP */
if (check_table_binlog_row_based(thd, table))
{
MY_BITMAP cols;
@@ -6203,6 +6310,69 @@ void handler::set_lock_type(enum thr_lock_type lock)
table->reginfo.lock_type= lock;
}
+#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) &&
+ !(bf_thd->variables.wsrep_OSU_method == 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;
+ }
+
+ if (thd->wsrep_ws_handle.trx_id != WSREP_UNDEFINED_TRX_ID)
+ {
+ WSREP_DEBUG("fake trx id skipped: %lu", thd->wsrep_ws_handle.trx_id);
+ 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 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 52396b84c0d..937a913eef0 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -441,6 +441,7 @@ enum legacy_db_type
DB_TYPE_BINLOG=21,
DB_TYPE_PBXT=23,
DB_TYPE_PERFORMANCE_SCHEMA=28,
+ DB_TYPE_WSREP=41,
DB_TYPE_ARIA=42,
DB_TYPE_TOKUDB=43,
DB_TYPE_FIRST_DYNAMIC=44,
@@ -1234,6 +1235,7 @@ struct handlerton
enum handler_create_iterator_result
(*create_iterator)(handlerton *hton, enum handler_iterator_type type,
struct handler_iterator *fill_this_in);
+
/*
Optional clauses in the CREATE/ALTER TABLE
*/
@@ -1346,6 +1348,14 @@ struct handlerton
*/
int (*discover_table_structure)(handlerton *hton, THD* thd,
TABLE_SHARE *share, HA_CREATE_INFO *info);
+
+#ifdef WITH_WSREP
+ 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);
+#endif /* WITH_WSREP */
};
@@ -4012,6 +4022,9 @@ bool key_uses_partial_cols(TABLE_SHARE *table, uint keyno);
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;
@@ -4131,6 +4144,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 */
/* these are called by storage engines */
void trans_register_ha(THD *thd, bool all, handlerton *ht);
@@ -4161,6 +4178,9 @@ int ha_binlog_end(THD *thd);
#define ha_binlog_wait(a) do {} while (0)
#define ha_binlog_end(a) do {} while (0)
#endif
+#ifdef WITH_WSREP
+void wsrep_brute_force_aborts();
+#endif
const char *get_canonical_filename(handler *file, const char *path,
char *tmp_path);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index dac45cc0928..914bfa47652 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2763,7 +2763,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 /* WITH_WSREP */
my_rnd_init(rand, (uint32) (tmp*0x10001L+55555555L),
(uint32) (tmp*0x10000001L));
}
diff --git a/sql/keycaches.cc b/sql/keycaches.cc
index 120aa7e1029..a559c99bbd8 100644
--- a/sql/keycaches.cc
+++ b/sql/keycaches.cc
@@ -223,6 +223,7 @@ Rpl_filter *get_or_create_rpl_filter(const char *name, uint length)
void free_rpl_filter(const char *name, Rpl_filter *filter)
{
delete filter;
+ filter= 0;
}
void free_all_rpl_filters()
diff --git a/sql/lock.cc b/sql/lock.cc
index 3354da2640b..965f7dcab99 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -83,6 +83,10 @@
#include "sql_acl.h" // SUPER_ACL
#include <hash.h>
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
+
/**
@defgroup Locking Locking
@{
@@ -313,6 +317,10 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
/* Copy the lock data array. thr_multi_lock() reorders its contents. */
memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
sql_lock->lock_count * sizeof(*sql_lock->locks));
+#ifdef WITH_WSREP
+ thd->lock_info.in_lock_tables= thd->in_lock_tables;
+#endif
+
/* 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,
@@ -323,6 +331,11 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
end:
THD_STAGE_INFO(thd, org_stage);
+#ifdef WITH_WSREP
+ thd_proc_info(thd, "mysql_lock_tables(): unlocking tables II");
+#else /* WITH_WSREP */
+ thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
if (thd->killed)
{
@@ -335,6 +348,9 @@ end:
my_error(rc, MYF(0));
thd->set_time_after_lock();
+#ifdef WITH_WSREP
+ thd_proc_info(thd, "exit mysqld_lock_tables()");
+#endif /* WITH_WSREP */
DBUG_RETURN(rc);
}
@@ -1024,11 +1040,29 @@ 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
+ if (WSREP(thd) || wsrep_node_is_donor())
+ {
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ wsrep->resume(wsrep);
+ /* resync here only if we did implicit desync earlier */
+ if (!wsrep_desync && wsrep_node_is_synced())
+ {
+ int ret = wsrep->resync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resync failed %d for FTWRL: db: %s, query: %s", ret,
+ (thd->db ? thd->db : "(null)"), thd->query());
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+#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;
}
@@ -1056,6 +1090,16 @@ 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 (WSREP(thd) && m_mdl_blocks_commits_lock)
+ {
+ WSREP_DEBUG("GRL was in block commit mode when entering "
+ "make_global_read_lock_block_commit");
+ DBUG_RETURN(FALSE);
+ }
+#endif /* WITH_WSREP */
+
if (m_state != GRL_ACQUIRED)
DBUG_RETURN(0);
@@ -1068,6 +1112,53 @@ 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
+ /* Native threads should bail out before wsrep oprations to follow.
+ Donor servicing thread is an exception, it should pause provider but not desync,
+ as it is already desynced in donor state
+ */
+ if (!WSREP(thd) && !wsrep_node_is_donor())
+ {
+ DBUG_RETURN(FALSE);
+ }
+
+ /* if already desynced or donor, avoid double desyncing
+ if not in PC and synced, desyncing is not possible either
+ */
+ if (wsrep_desync || !wsrep_node_is_synced())
+ {
+ WSREP_DEBUG("desync set upfont, skipping implicit desync for FTWRL: %d",
+ wsrep_desync);
+ }
+ else
+ {
+ int rcode;
+ WSREP_DEBUG("running implicit desync for node");
+ rcode = wsrep->desync(wsrep);
+ if (rcode != WSREP_OK)
+ {
+ WSREP_WARN("FTWRL desync failed %d for schema: %s, query: %s",
+ rcode, (thd->db ? thd->db : "(null)"), thd->query());
+ my_message(ER_LOCK_DEADLOCK, "wsrep desync failed for FTWRL", MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ }
+
+ 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 e82d001fefc..4cc3165377c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -52,6 +52,9 @@
#include "sql_plugin.h"
#include "rpl_handler.h"
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
#include "debug_sync.h"
#include "sql_show.h"
#include "my_pthread.h"
@@ -524,6 +527,9 @@ private:
};
handlerton *binlog_hton;
+#ifdef WITH_WSREP
+extern handlerton *wsrep_hton;
+#endif
bool LOGGER::is_log_table_enabled(uint log_table_type)
{
@@ -538,6 +544,66 @@ bool LOGGER::is_log_table_enabled(uint log_table_type)
}
}
+#ifdef WITH_WSREP
+IO_CACHE * get_trans_log(THD * thd)
+{
+ binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*)
+ thd_get_ha_data(thd, binlog_hton);
+ 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.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=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+ if (cache_mngr)
+ {
+ cache_mngr->reset(false, true);
+ if (!cache_mngr->stmt_cache.empty())
+ {
+ WSREP_DEBUG("pending events in stmt cache, sql: %s", thd->query());
+ cache_mngr->stmt_cache.reset();
+ }
+ }
+ }
+ thd->clear_binlog_table_maps();
+}
+
+void thd_binlog_rollback_stmt(THD * thd)
+{
+ WSREP_DEBUG("thd_binlog_rollback_stmt :%ld", thd->thread_id);
+ binlog_cache_mngr *const cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+ if (cache_mngr) cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
+}
+
+#endif
+
/**
Check if a given table is opened log table
@@ -1589,7 +1655,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->binlog_setup_trx_data();
+#ifdef WITH_WSREP
+ DBUG_ASSERT((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open());
+#else
DBUG_ASSERT(mysql_bin_log.is_open());
+#endif
*pos= cache_mngr->trx_cache.get_byte_position();
DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos));
DBUG_VOID_RETURN;
@@ -1637,7 +1707,8 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos)
int binlog_init(void *p)
{
binlog_hton= (handlerton *)p;
- binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
+ binlog_hton->state= (WSREP_ON || opt_bin_log) ? SHOW_OPTION_YES
+ : SHOW_OPTION_NO;
binlog_hton->db_type=DB_TYPE_BINLOG;
binlog_hton->savepoint_offset= sizeof(my_off_t);
binlog_hton->close_connection= binlog_close_connection;
@@ -1653,15 +1724,36 @@ 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=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+#ifdef WITH_WSREP
+ if (cache_mngr && !cache_mngr->trx_cache.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->trx_cache.empty() && cache_mngr->stmt_cache.empty());
thd_set_ha_data(thd, binlog_hton, NULL);
cache_mngr->~binlog_cache_mngr();
my_free(cache_mngr);
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -1757,6 +1849,14 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all,
binlog_cache_mngr *cache_mngr)
{
DBUG_ENTER("binlog_commit_flush_stmt_cache");
+#ifdef WITH_WSREP
+ if (thd->wsrep_mysql_replicated > 0)
+ {
+ WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", thd->wsrep_mysql_replicated);
+ return 0;
+ }
+#endif
+
Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
FALSE, TRUE, TRUE, 0);
DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE));
@@ -1912,12 +2012,12 @@ static bool trans_cannot_safely_rollback(THD *thd, bool all)
return ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
(trans_has_updated_non_trans_table(thd) &&
- thd->variables.binlog_format == BINLOG_FORMAT_STMT) ||
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT) ||
(cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
- thd->variables.binlog_format == BINLOG_FORMAT_MIXED) ||
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED) ||
(trans_has_updated_non_trans_table(thd) &&
ending_single_stmt_trans(thd,all) &&
- thd->variables.binlog_format == BINLOG_FORMAT_MIXED));
+ WSREP_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED));
}
@@ -1939,6 +2039,9 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
DBUG_ENTER("binlog_commit");
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+#ifdef WITH_WSREP
+ if (!cache_mngr) DBUG_RETURN(0);
+#endif /* WITH_WSREP */
DBUG_PRINT("debug",
("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
@@ -1995,6 +2098,9 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
int error= 0;
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+#ifdef WITH_WSREP
+ if (!cache_mngr) DBUG_RETURN(0);
+#endif /* WITH_WSREP */
DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
YESNO(all),
@@ -2023,8 +2129,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
cache_mngr->reset(false, true);
DBUG_RETURN(error);
}
-
+#ifdef WITH_WSREP
+ if (!wsrep_emulate_bin_log &&
+ mysql_bin_log.check_write_error(thd))
+#else
if (mysql_bin_log.check_write_error(thd))
+#endif
{
/*
"all == true" means that a "rollback statement" triggered the error and
@@ -2040,7 +2150,7 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
error |= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
else if (!error)
- {
+ {
if (ending_trans(thd, all) && trans_cannot_safely_rollback(thd, all))
error= binlog_rollback_flush_trx_cache(thd, all, cache_mngr);
/*
@@ -2055,9 +2165,9 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
else if (ending_trans(thd, all) ||
(!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
(!stmt_has_updated_non_trans_table(thd) ||
- thd->variables.binlog_format != BINLOG_FORMAT_STMT) &&
+ WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_STMT) &&
(!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
- thd->variables.binlog_format != BINLOG_FORMAT_MIXED)))
+ WSREP_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_MIXED)))
error= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
@@ -2164,8 +2274,15 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_set");
int error= 1;
-
char buf[1024];
+#ifdef WITH_WSREP
+ if (wsrep_emulate_bin_log) DBUG_RETURN(0);
+ /*
+ Clear table maps before writing SAVEPOINT event. This enforces
+ recreation of table map events for the following row event.
+ */
+ thd->clear_binlog_table_maps();
+#endif /* WITH_WSREP */
String log_query(buf, sizeof(buf), &my_charset_bin);
if (log_query.copy(STRING_WITH_LEN("SAVEPOINT "), &my_charset_bin) ||
append_identifier(thd, &log_query,
@@ -2202,7 +2319,12 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
+#ifdef WITH_WSREP
+ if (!wsrep_emulate_bin_log &&
+ unlikely(trans_has_updated_non_trans_table(thd) ||
+#else
if (unlikely(trans_has_updated_non_trans_table(thd) ||
+#endif
(thd->variables.option_bits & OPTION_KEEP_LOG)))
{
char buf[1024];
@@ -2216,7 +2338,10 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
TRUE, FALSE, TRUE, errcode);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
}
- binlog_trans_log_truncate(thd, *(my_off_t*)sv);
+#ifdef WITH_WSREP
+ if (!wsrep_emulate_bin_log)
+#endif
+ binlog_trans_log_truncate(thd, *(my_off_t*)sv);
DBUG_RETURN(0);
}
@@ -2498,7 +2623,7 @@ bool MYSQL_LOG::open(
File file= -1;
my_off_t seek_offset;
bool is_fifo = false;
- int open_flags= O_CREAT | O_BINARY;
+ int open_flags= O_CREAT | O_BINARY | O_CLOEXEC;
DBUG_ENTER("MYSQL_LOG::open");
DBUG_PRINT("enter", ("log_type: %d", (int) log_type_arg));
@@ -3183,7 +3308,7 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
".index", opt);
if ((index_file_nr= mysql_file_open(m_key_file_log_index,
index_file_name,
- O_RDWR | O_CREAT | O_BINARY,
+ O_RDWR | O_CREAT | O_BINARY | O_CLOEXEC,
MYF(MY_WME))) < 0 ||
mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
init_io_cache(&index_file, index_file_nr,
@@ -3553,7 +3678,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
new_xid_list_entry->binlog_id= current_binlog_id;
/* Remove any initial entries with no pending XIDs. */
while ((b= binlog_xid_count_list.head()) && b->xid_count == 0)
+ {
my_free(binlog_xid_count_list.get());
+ }
+ mysql_cond_broadcast(&COND_xid_list);
binlog_xid_count_list.push_back(new_xid_list_entry);
mysql_mutex_unlock(&LOCK_xid_list);
@@ -4074,6 +4202,7 @@ err:
DBUG_ASSERT(b->xid_count == 0);
my_free(binlog_xid_count_list.get());
}
+ mysql_cond_broadcast(&COND_xid_list);
reset_master_pending--;
mysql_mutex_unlock(&LOCK_xid_list);
}
@@ -4084,6 +4213,26 @@ err:
}
+void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
+{
+ mysql_mutex_lock(&LOCK_xid_list);
+ for (;;)
+ {
+ if (binlog_xid_count_list.is_last(binlog_xid_count_list.head()))
+ break;
+ mysql_cond_wait(&COND_xid_list, &LOCK_xid_list);
+ }
+ mysql_mutex_unlock(&LOCK_xid_list);
+
+ /*
+ LOCK_xid_list and LOCK_log are chained, so the LOCK_log will only be
+ obtained after mark_xid_done() has written the last checkpoint event.
+ */
+ mysql_mutex_lock(&LOCK_log);
+ mysql_mutex_unlock(&LOCK_log);
+}
+
+
/**
Delete relay log files prior to rli->group_relay_log_name
(i.e. all logs which are not involved in a non-finished group
@@ -5267,6 +5416,7 @@ binlog_cache_mngr *THD::binlog_setup_trx_data()
DBUG_RETURN(cache_mngr);
}
+
/*
Function to start a statement and optionally a transaction for the
binary log.
@@ -5387,7 +5537,12 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
is_transactional= 1;
/* 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
DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
Table_map_log_event
@@ -5527,7 +5682,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
DBUG_PRINT("enter", ("event: 0x%lx", (long) event));
int error= 0;
@@ -5822,11 +5981,23 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
binlog_cache_data *cache_data= 0;
bool is_trans_cache= FALSE;
bool using_trans= event_info->use_trans_cache();
- bool direct= event_info->use_direct_logging();
+ bool direct;
ulong prev_binlog_id;
DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
LINT_INIT(prev_binlog_id);
+#ifdef WITH_WSREP
+ /*
+ When binary logging is not enabled (--log-bin=0), wsrep-patch partially
+ enables it without opening the binlog file (MSQL_BIN_LOG::open().
+ So, avoid writing directly to binlog file.
+ */
+ if (wsrep_emulate_bin_log)
+ direct= false;
+ else
+#endif /* WITH_WSREP */
+ direct= event_info->use_direct_logging();
+
if (thd->variables.option_bits & OPTION_GTID_BEGIN)
{
DBUG_PRINT("info", ("OPTION_GTID_BEGIN was set"));
@@ -5861,7 +6032,13 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
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
{
my_off_t UNINIT_VAR(my_org_b_tell);
#ifdef HAVE_REPLICATION
@@ -6212,6 +6389,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
//todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log);
*check_purge= false;
@@ -6761,6 +6947,13 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
Ha_trx_info *ha_info;
DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_to_binlog");
+#ifdef WITH_WSREP
+ /*
+ Control should not be allowed beyond this point in wsrep_emulate_bin_log
+ mode.
+ */
+ if (wsrep_emulate_bin_log) DBUG_RETURN(0);
+#endif /* WITH_WSREP */
entry.thd= thd;
entry.cache_mngr= cache_mngr;
entry.error= 0;
@@ -6769,6 +6962,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
entry.using_trx_cache= using_trx_cache;
entry.need_unlog= false;
ha_info= all ? thd->transaction.all.ha_list : thd->transaction.stmt.ha_list;
+
for (; ha_info; ha_info= ha_info->next())
{
if (ha_info->is_started() && ha_info->ht() != binlog_hton &&
@@ -8374,7 +8568,7 @@ ulong tc_log_page_waits= 0;
static const uchar tc_log_magic[]={(uchar) 254, 0x23, 0x05, 0x74};
-ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
+ulong opt_tc_log_size;
ulong tc_log_max_pages_used=0, tc_log_page_size=0, tc_log_cur_pages_used=0;
int TC_LOG_MMAP::open(const char *opt_name)
@@ -8387,17 +8581,16 @@ int TC_LOG_MMAP::open(const char *opt_name)
DBUG_ASSERT(opt_name && opt_name[0]);
tc_log_page_size= my_getpagesize();
- DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
- if ((fd= mysql_file_open(key_file_tclog, logname, O_RDWR, MYF(0))) < 0)
+ if ((fd= mysql_file_open(key_file_tclog, logname, O_RDWR | O_CLOEXEC, MYF(0))) < 0)
{
if (my_errno != ENOENT)
goto err;
if (using_heuristic_recover())
return 1;
if ((fd= mysql_file_create(key_file_tclog, logname, CREATE_MODE,
- O_RDWR, MYF(MY_WME))) < 0)
+ O_RDWR | O_CLOEXEC, MYF(MY_WME))) < 0)
goto err;
inited=1;
file_length= opt_tc_log_size;
@@ -8726,6 +8919,7 @@ mmap_do_checkpoint_callback(void *data)
int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
{
pending_cookies *full_buffer= NULL;
+ uint32 ncookies= tc_log_page_size / sizeof(my_xid);
DBUG_ASSERT(*(my_xid *)(data+cookie) == xid);
/*
@@ -8739,7 +8933,7 @@ int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
mysql_mutex_lock(&LOCK_pending_checkpoint);
if (pending_checkpoint == NULL)
{
- uint32 size= sizeof(*pending_checkpoint);
+ uint32 size= sizeof(*pending_checkpoint) + sizeof(ulong) * (ncookies - 1);
if (!(pending_checkpoint=
(pending_cookies *)my_malloc(size, MYF(MY_ZEROFILL))))
{
@@ -8750,8 +8944,7 @@ int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
}
pending_checkpoint->cookies[pending_checkpoint->count++]= cookie;
- if (pending_checkpoint->count == sizeof(pending_checkpoint->cookies) /
- sizeof(pending_checkpoint->cookies[0]))
+ if (pending_checkpoint->count == ncookies)
{
full_buffer= pending_checkpoint;
pending_checkpoint= NULL;
@@ -8785,7 +8978,7 @@ TC_LOG_MMAP::commit_checkpoint_notify(void *cookie)
if (count == 0)
{
uint i;
- for (i= 0; i < sizeof(pending->cookies)/sizeof(pending->cookies[0]); ++i)
+ for (i= 0; i < tc_log_page_size / sizeof(my_xid); ++i)
delete_entry(pending->cookies[i]);
my_free(pending);
}
@@ -8992,7 +9185,14 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all,
binlog_cache_mngr *cache_mngr= thd->binlog_setup_trx_data();
if (!cache_mngr)
+#ifdef WITH_WSREP
+ {
+ WSREP_DEBUG("Skipping empty log_xid: %s", thd->query());
DBUG_RETURN(0);
+ }
+#else
+ DBUG_RETURN(0);
+#endif /* WITH_WSREP */
cache_mngr->using_xa= TRUE;
cache_mngr->xa_xid= xid;
@@ -9094,7 +9294,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
*/
if (unlikely(reset_master_pending))
{
- mysql_cond_signal(&COND_xid_list);
+ mysql_cond_broadcast(&COND_xid_list);
mysql_mutex_unlock(&LOCK_xid_list);
DBUG_VOID_RETURN;
}
@@ -9132,8 +9332,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
mysql_mutex_lock(&LOCK_log);
mysql_mutex_lock(&LOCK_xid_list);
--mark_xid_done_waiting;
- if (unlikely(reset_master_pending))
- mysql_cond_signal(&COND_xid_list);
+ mysql_cond_broadcast(&COND_xid_list);
/* We need to reload current_binlog_id due to release/re-take of lock. */
current= current_binlog_id;
diff --git a/sql/log.h b/sql/log.h
index 1c5e09c5c09..9eb9f88031d 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -105,7 +105,7 @@ public:
int log_and_order(THD *thd, my_xid xid, bool all,
bool need_prepare_ordered, bool need_commit_ordered)
{
- DBUG_ASSERT(0 /* Internal error - TC_LOG_DUMMY::log_and_order() called */);
+ //DBUG_ASSERT(0 /* Internal error - TC_LOG_DUMMY::log_and_order() called */);
return 1;
}
int unlog(ulong cookie, my_xid xid) { return 0; }
@@ -113,7 +113,6 @@ public:
};
#define TC_LOG_PAGE_SIZE 8192
-#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
#ifdef HAVE_MMAP
class TC_LOG_MMAP: public TC_LOG
@@ -128,7 +127,7 @@ class TC_LOG_MMAP: public TC_LOG
struct pending_cookies {
uint count;
uint pending_count;
- ulong cookies[TC_LOG_PAGE_SIZE/sizeof(my_xid)];
+ ulong cookies[1];
};
private:
@@ -775,6 +774,7 @@ public:
bool need_mutex);
bool reset_logs(THD* thd, bool create_new_log,
rpl_gtid *init_state, uint32 init_state_len);
+ void wait_for_last_checkpoint_event();
void close(uint exiting);
void clear_inuse_flag_when_closing(File file);
@@ -978,12 +978,29 @@ public:
};
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);
+void thd_binlog_rollback_stmt(THD * thd);
+
+#define WSREP_FORMAT(my_format) \
+ ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
+ wsrep_forced_binlog_format : my_format)
+#else
+#define WSREP_FORMAT(my_format) my_format
+#endif
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 3638269cbf5..e8c1115eafb 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -44,6 +44,9 @@
#include <strfunc.h>
#include "compat56.h"
+#if WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif
#endif /* MYSQL_CLIENT */
#include <base64.h>
@@ -3134,7 +3137,14 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
master_data_written(0)
{
time_t end_time;
-
+#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));
@@ -4137,7 +4147,11 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
uint64 sub_id= 0;
rpl_gtid gtid;
Relay_log_info const *rli= rgi->rli;
+#ifdef WITH_WSREP
+ Rpl_filter *rpl_filter= (rli->mi) ? rli->mi->rpl_filter: NULL;
+#else
Rpl_filter *rpl_filter= rli->mi->rpl_filter;
+#endif /* WITH_WSREP */
bool current_stmt_is_commit;
DBUG_ENTER("Query_log_event::do_apply_event");
@@ -4334,22 +4348,6 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
else
thd->variables.collation_database= thd->db_charset;
- {
- const CHARSET_INFO *cs= thd->charset();
- /*
- We cannot ask for parsing a statement using a character set
- without state_maps (parser internal data).
- */
- if (!cs->state_map)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "character_set cannot be parsed");
- thd->is_slave_error= true;
- goto end;
- }
- }
-
/*
Record any GTID in the same transaction, so slave state is
transactionally consistent.
@@ -4656,6 +4654,21 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi)
DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
}
}
+#ifdef WITH_WSREP
+ else if (wsrep_mysql_replication_bundle && WSREP_ON && thd->wsrep_mysql_replicated > 0 &&
+ (!strncasecmp(query , "BEGIN", 5) || !strncasecmp(query , "COMMIT", 6)))
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
DBUG_RETURN(Log_event::do_shall_skip(rgi));
}
@@ -7458,6 +7471,10 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
Record any GTID in the same transaction, so slave state is transactionally
consistent.
*/
+
+ /*Set wsrep_affected_rows = 0 */
+ thd->wsrep_affected_rows= 0;
+
if (rgi->gtid_pending)
{
sub_id= rgi->gtid_sub_id;
@@ -7518,6 +7535,20 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
}
+#ifdef WITH_WSREP
+ else if (wsrep_mysql_replication_bundle && WSREP_ON)
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
DBUG_RETURN(Log_event::do_shall_skip(rgi));
}
#endif /* !MYSQL_CLIENT */
@@ -7722,11 +7753,6 @@ User_var_log_event(const char* buf, uint event_len,
we keep the flags set to UNDEF_F.
*/
uint bytes_read= ((val + val_len) - buf_start);
- if (bytes_read > event_len)
- {
- error= true;
- goto err;
- }
if ((data_written - bytes_read) > 0)
{
flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
@@ -8563,6 +8589,14 @@ err:
end_io_cache(&file);
if (fd >= 0)
mysql_file_close(fd, MYF(0));
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ thd_proc_info(thd, "exit Create_file_log_event::do_apply_event()");
+ else
+ thd_proc_info(thd, 0);
+#else /* WITH_WSREP */
+ thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
return error != 0;
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -8734,6 +8768,14 @@ int Append_block_log_event::do_apply_event(rpl_group_info *rgi)
err:
if (fd >= 0)
mysql_file_close(fd, MYF(0));
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ thd_proc_info(thd, "exit Append_block_log_event::do_apply_event()");
+ else
+ thd_proc_info(thd, 0);
+#else /* WITH_WSREP */
+ thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
DBUG_RETURN(error);
}
#endif
@@ -9833,6 +9875,20 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
if (open_and_lock_tables(thd, rgi->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) &&
!is_parallel_retry_error(rgi, actual_error))
{
@@ -9967,7 +10023,18 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
}
#ifdef HAVE_QUERY_CACHE
+#ifdef WITH_WSREP
+ /*
+ Moved invalidation right before the call to rows_event_stmt_cleanup(),
+ to avoid query cache being polluted with stale entries.
+ */
+ if (! (WSREP(thd) && (thd->wsrep_exec_mode == REPL_RECV)))
+ {
+#endif /* WITH_WSREP */
query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
#endif
}
@@ -10155,6 +10222,14 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
/* remove trigger's tables */
if (slave_run_triggers_for_rbr)
restore_empty_query_table_list(thd->lex);
+
+#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
+ if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
+ {
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+ }
+#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
+
if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rgi, thd)))
slave_rows_error_report(ERROR_LEVEL,
thd->is_error() ? 0 : error,
@@ -11012,7 +11087,12 @@ check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list)
enum_tbl_map_status res= OK_TO_PROCESS;
Relay_log_info *rli= rgi->rli;
+#ifdef WITH_WSREP
+ if ((rgi->thd->slave_thread /* filtering is for slave only */ ||
+ (WSREP(rgi->thd) && rgi->thd->wsrep_applier)) &&
+#else
if (rgi->thd->slave_thread /* filtering is for slave only */ &&
+#endif /* WITH_WSREP */
(!rli->mi->rpl_filter->db_ok(table_list->db) ||
(rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list))))
res= FILTERED_OUT;
@@ -11769,8 +11849,23 @@ int
Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
{
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(rgi, 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);
@@ -12449,11 +12544,33 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
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, "Delete_rows_log_event::find_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,"Delete_rows_log_event::find_row()") : NULL;
+#endif /* WSREP_PROC_INFO */
+#endif /* WITH_WSREP */
if (!(error= find_row(rgi)))
{
/*
Delete the record found, located in record[0]
*/
+#ifdef WITH_WSREP
+#ifdef WSREP_PROC_INFO
+ snprintf(info, sizeof(info) - 1,
+ "Delete_rows_log_event::ha_delete_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ if (WSREP(thd)) thd_proc_info(thd, info);
+#else
+ if (WSREP(thd)) thd_proc_info(thd,"Delete_rows_log_event::ha_delete_row()");
+#endif /* WSREP_PROC_INFO */
+#endif /* WITH_WSREP */
if (invoke_triggers &&
process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE))
error= HA_ERR_GENERIC; // in case if error is not set yet
@@ -12464,6 +12581,9 @@ int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
error= HA_ERR_GENERIC; // in case if error is not set yet
m_table->file->ha_index_or_rnd_end();
}
+#ifdef WITH_WSREP
+ if (WSREP(thd)) thd_proc_info(thd, tmp);
+#endif /* WITH_WSREP */
return error;
}
@@ -12593,6 +12713,18 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
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, "Update_rows_log_event::find_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,"Update_rows_log_event::find_row()") : NULL;
+#endif /* WSREP_PROC_INFO */
+#endif /* WITH_WSREP */
int error= find_row(rgi);
if (error)
{
@@ -12619,6 +12751,17 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
store_record(m_table,record[1]);
m_curr_row= m_curr_row_end;
+#ifdef WITH_WSREP
+#ifdef WSREP_PROC_INFO
+ snprintf(info, sizeof(info) - 1,
+ "Update_rows_log_event::unpack_current_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ if (WSREP(thd)) thd_proc_info(thd, info);
+#else
+ if (WSREP(thd))
+ thd_proc_info(thd,"Update_rows_log_event::unpack_current_row()");
+#endif /* WSREP_PROC_INFO */
+#endif /* WITH_WSREP */
/* this also updates m_curr_row_end */
if ((error= unpack_current_row(rgi)))
goto err;
@@ -12637,6 +12780,17 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength);
#endif
+#ifdef WITH_WSREP
+#ifdef WSREP_PROC_INFO
+ snprintf(info, sizeof(info) - 1,
+ "Update_rows_log_event::ha_update_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ if (WSREP(thd)) thd_proc_info(thd, info);
+#else
+ if (WSREP(thd)) thd_proc_info(thd,"Update_rows_log_event::ha_update_row()");
+#endif /* WSREP_PROC_INFO */
+#endif /* WITH_WSREP */
+
if (invoke_triggers &&
process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE))
{
@@ -12652,6 +12806,9 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE))
error= HA_ERR_GENERIC; // in case if error is not set yet
+#ifdef WITH_WSREP
+ if (WSREP(thd)) thd_proc_info(thd, tmp);
+#endif /* WITH_WSREP */
err:
m_table->file->ha_index_or_rnd_end();
return error;
@@ -12752,6 +12909,47 @@ void Incident_log_event::pack_info(THD *thd, Protocol *protocol)
protocol->store(buf, bytes, &my_charset_bin);
}
#endif
+#if WITH_WSREP && !defined(MYSQL_CLIENT)
+/*
+ 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.
+*/
+#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max
+
+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_ALLOWED_PACKET)
+ {
+ error = "Event too big";
+ goto err;
+ }
+
+ res= Log_event::read_log_event(buf, data_len, &error, description_event, false);
+
+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);
+}
+#endif
#ifdef MYSQL_CLIENT
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 57d5d8e7283..0f1c961aa29 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -24,6 +24,20 @@
#include <mysql/service_thd_wait.h>
#include <mysql/psi/mysql_stage.h>
+#ifdef WITH_WSREP
+#include "debug_sync.h"
+#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,
+ const MDL_key *key);
+#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;
@@ -1435,6 +1449,22 @@ MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout,
while (!m_wait_status && !owner->is_killed() &&
wait_result != ETIMEDOUT && wait_result != ETIME)
{
+#ifdef WITH_WSREP
+ // Allow tests to block the applier thread using the DBUG facilities
+ DBUG_EXECUTE_IF("sync.wsrep_before_mdl_wait",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.wsrep_before_mdl_wait";
+ DBUG_ASSERT(!debug_sync_set_action((owner->get_thd()),
+ STRING_WITH_LEN(act)));
+ };);
+ if (wsrep_thd_is_BF(owner->get_thd(), false))
+ {
+ wait_result= mysql_cond_wait(&m_COND_wait_status, &m_LOCK_wait_status);
+ }
+ else
+#endif /* WITH_WSREP */
wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
abs_timeout);
}
@@ -1501,11 +1531,58 @@ 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()->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()->get_thd()), true))
+ {
+ WSREP_DEBUG("MDL add_ticket inserted before: %lu %s",
+ wsrep_thd_thread_id(waiting->get_ctx()->get_thd()),
+ wsrep_thd_query(waiting->get_ctx()->get_thd()));
+ /* Insert the ticket before the first non-BF waiting thd. */
+ m_list.insert_after(prev, ticket);
+ added= true;
+ }
+ prev= waiting;
+ }
+
+ /* Otherwise, insert the ticket at the back of the waiting list. */
+ 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,
+ &ticket->get_lock()->key))
+ {
+ 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());
}
@@ -1821,7 +1898,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.
@@ -1846,6 +1922,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:
@@ -1868,12 +1947,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->get_thd()),false) &&
+ key.mdl_namespace() == MDL_key::GLOBAL)
+ {
+ WSREP_DEBUG("global lock granted for BF: %lu %s",
+ wsrep_thd_thread_id(requestor_ctx->get_thd()),
+ wsrep_thd_query(requestor_ctx->get_thd()));
+ can_grant = true;
+ }
+ else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket, &key))
+ {
+ 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->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->get_thd()),
+ wsrep_thd_query(requestor_ctx->get_thd()));
+ can_grant = true;
+ }
+ }
+#endif /* WITH_WSREP */
return can_grant;
}
@@ -2980,7 +3106,12 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration,
DBUG_VOID_RETURN;
}
-
+#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.
@@ -3288,3 +3419,49 @@ 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)
+ {
+ const PSI_stage_info *psi_stage = m_lock->key.get_wait_state_name();
+
+ WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s (%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(),
+ psi_stage->m_name);
+ }
+}
+bool MDL_context::wsrep_has_explicit_locks()
+{
+ MDL_ticket *ticket = NULL;
+
+ Ticket_iterator it(m_tickets[MDL_EXPLICIT]);
+
+ while ((ticket = it++))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+#endif /* WITH_WSREP */
diff --git a/sql/mdl.h b/sql/mdl.h
index 13de60284da..86f681c90f0 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -457,6 +457,7 @@ public:
MDL_key key;
public:
+
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return alloc_root(mem_root, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
@@ -586,6 +587,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; }
@@ -774,6 +778,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(),
@@ -786,6 +797,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; }
@@ -918,6 +932,9 @@ private:
MDL_ticket **out_ticket);
public:
+#ifdef WITH_WSREP
+ bool wsrep_has_explicit_locks();
+#endif /* WITH_WSREP */
THD *get_thd() const { return m_owner->get_thd(); }
void find_deadlock();
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 75d6cca7fda..3cc87b02a4d 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -71,6 +71,13 @@
#include "scheduler.h"
#include <waiting_threads.h>
#include "debug_sync.h"
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_var.h"
+#include "wsrep_thd.h"
+#include "wsrep_sst.h"
+ulong wsrep_running_threads = 0; // # of currently running wsrep threads
+#endif
#include "sql_callback.h"
#include "threadpool.h"
@@ -357,7 +364,11 @@ static char *default_character_set_name;
static char *character_set_filesystem_name;
static char *lc_messages;
static char *lc_time_names_name;
+#ifndef WITH_WSREP
static char *my_bind_addr_str;
+#else
+char *my_bind_addr_str;
+#endif /* WITH_WSREP */
static char *default_collation_name;
char *default_storage_engine;
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
@@ -370,6 +381,10 @@ static DYNAMIC_ARRAY all_options;
/* Global variables */
+#ifdef WITH_WSREP
+ulong my_bind_addr;
+bool wsrep_new_cluster= false;
+#endif /* WITH_WSREP */
bool opt_bin_log, opt_bin_log_used=0, opt_ignore_builtin_innodb= 0;
my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0;
static my_bool opt_abort;
@@ -463,6 +478,10 @@ ulong opt_binlog_rows_event_max_size;
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 */
volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint mysqld_extra_port;
@@ -733,6 +752,23 @@ mysql_cond_t COND_server_started;
int mysqld_server_started=0, mysqld_server_initialized= 0;
File_parser_dummy_hook file_parser_dummy_hook;
+#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 */
/* replication parameters, if master_host is not NULL, we are a slave */
uint report_port= 0;
@@ -872,6 +908,12 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_error_messages, key_LOG_INFO_lock,
key_LOCK_thread_count, key_LOCK_thread_cache,
key_PARTITION_LOCK_auto_inc;
+#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_RELAYLOG_LOCK_index;
PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state,
key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry;
@@ -950,6 +992,18 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL},
{ &key_LOCK_slave_init, "LOCK_slave_init", PSI_FLAG_GLOBAL},
{ &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
+#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_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL},
{ &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL},
{ &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0},
@@ -996,6 +1050,11 @@ PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
key_TABLE_SHARE_cond, key_user_level_lock_cond,
key_COND_thread_count, key_COND_thread_cache, key_COND_flush_thread_cache,
key_BINLOG_COND_queue_busy;
+#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, key_COND_wakeup_ready,
key_COND_wait_commit;
PSI_cond_key key_RELAYLOG_COND_queue_busy;
@@ -1045,6 +1104,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_COND_rpl_thread, "COND_rpl_thread", 0},
{ &key_COND_rpl_thread_queue, "COND_rpl_thread_queue", 0},
@@ -1403,7 +1471,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;
@@ -1626,6 +1696,11 @@ static void close_connections(void)
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
tmp->killed= KILL_SERVER_HARD;
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
mysql_mutex_lock(&tmp->LOCK_thd_data);
@@ -1702,6 +1777,33 @@ static void close_connections(void)
close_connection(tmp,ER_SERVER_SHUTDOWN);
}
#endif
+#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= 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);
}
@@ -1856,8 +1958,16 @@ static void __cdecl kill_server(int sig_ptr)
}
}
#endif
+#ifdef WITH_WSREP
+ /* Stop wsrep threads in case they are running. */
+ wsrep_stop_replication(NULL);
+#endif
close_connections();
+#ifdef WITH_WSREP
+ if (wsrep_inited == 1)
+ wsrep_deinit(true);
+#endif
if (sig != MYSQL_KILL_SIGNAL &&
sig != 0)
unireg_abort(1); /* purecov: inspected */
@@ -1952,6 +2062,25 @@ 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.");
+
+ /* In bootstrap mode we deinitialize wsrep here. */
+ if (opt_bootstrap && wsrep_inited)
+ wsrep_deinit(true);
+ }
+#endif // WITH_WSREP
clean_up(!opt_abort && (exit_code || !opt_bootstrap)); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
mysqld_exit(exit_code);
@@ -2167,6 +2296,20 @@ static void clean_up_mutexes()
mysql_cond_destroy(&COND_thread_count);
mysql_cond_destroy(&COND_thread_cache);
mysql_cond_destroy(&COND_flush_thread_cache);
+#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
mysql_mutex_destroy(&LOCK_server_started);
mysql_cond_destroy(&COND_server_started);
mysql_mutex_destroy(&LOCK_prepare_ordered);
@@ -2642,9 +2785,19 @@ void thd_cleanup(THD *thd)
void dec_connection_count(THD *thd)
{
- mysql_mutex_lock(&LOCK_connection_count);
- (*thd->scheduler->connection_count)--;
- mysql_mutex_unlock(&LOCK_connection_count);
+#ifdef WITH_WSREP
+ /*
+ Do not decrement when its wsrep system thread. wsrep_applier is set for
+ applier as well as rollbacker threads.
+ */
+ if (!thd->wsrep_applier)
+#endif /* WITH_WSREP */
+ {
+ DBUG_ASSERT(*thd->scheduler->connection_count > 0);
+ mysql_mutex_lock(&LOCK_connection_count);
+ (*thd->scheduler->connection_count)--;
+ mysql_mutex_unlock(&LOCK_connection_count);
+ }
}
@@ -2814,10 +2967,19 @@ static bool cache_thread()
bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
{
DBUG_ENTER("one_thread_per_connection_end");
+#ifdef WITH_WSREP
+ const bool wsrep_applier(thd->wsrep_applier);
+#endif
+
unlink_thd(thd);
/* Mark that current_thd is not valid anymore */
set_current_thd(0);
+
+#ifdef WITH_WSREP
+ if (!wsrep_applier && put_in_cache && cache_thread())
+#else
if (put_in_cache && cache_thread())
+#endif /* WITH_WSREP */
DBUG_RETURN(0); // Thread is reused
signal_thd_deleted();
@@ -3251,8 +3413,8 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
should not be any other mysql_cond_signal() calls.
*/
mysql_mutex_lock(&LOCK_thread_count);
- mysql_mutex_unlock(&LOCK_thread_count);
mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
(void) pthread_sigmask(SIG_BLOCK,&set,NULL);
for (;;)
@@ -3930,7 +4092,6 @@ static int init_common_variables()
}
else
opt_log_basename= glob_hostname;
-
if (!*pidfile_name)
{
strmake(pidfile_name, opt_log_basename, sizeof(pidfile_name)-5);
@@ -3989,7 +4150,11 @@ static 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))
+ global_system_variables.wsrep_on= 0;
+#endif /* WITH_WSREP */
if (get_options(&remaining_argc, &remaining_argv))
return 1;
set_server_version();
@@ -4415,6 +4580,28 @@ static int init_thread_environment()
rpl_init_gtid_waiting();
#endif
+#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
+
DBUG_RETURN(0);
}
@@ -4667,10 +4854,18 @@ static int init_server_components()
/* need to configure logging before initializing storage engines */
if (!opt_bin_log_used)
{
+#ifdef WITH_WSREP
+ if (!WSREP_ON && opt_log_slave_updates)
+#else
if (opt_log_slave_updates)
+#endif
sql_print_warning("You need to use --log-bin to make "
"--log-slave-updates work.");
+#ifdef WITH_WSREP
+ if (!WSREP_ON && binlog_format_used)
+#else
if (binlog_format_used)
+#endif
sql_print_warning("You need to use --log-bin to make "
"--binlog-format work.");
}
@@ -4697,8 +4892,6 @@ static int init_server_components()
}
#endif
- DBUG_ASSERT(!opt_bin_log || opt_bin_logname);
-
if (opt_bin_log)
{
/* Reports an error and aborts, if the --log-bin's path
@@ -4747,10 +4940,72 @@ static int init_server_components()
{
opt_bin_logname= my_once_strdup(buf, MYF(MY_WME));
}
+#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 && !opt_help)
+ {
+ 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
+ /*
+ Plugin initialization (plugin_init()) hasn't happened yet, set
+ maria_hton to 0.
+ */
+ maria_hton= 0;
+ 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 */
}
/* call ha_init_key_cache() on all key caches to init them */
@@ -4774,6 +5029,49 @@ static int init_server_components()
}
plugins_are_initialized= TRUE; /* Don't separate from init function */
+#ifdef WITH_WSREP
+ /* Wait for wsrep threads to get created. */
+ if (wsrep_creating_startup_threads == 1) {
+ mysql_mutex_lock(&LOCK_thread_count);
+ while (wsrep_running_threads < 2)
+ {
+ mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
+ }
+
+ /* Now is the time to initialize threads for queries. */
+ THD *tmp;
+ I_List_iterator<THD> it(threads);
+ while ((tmp= it++))
+ {
+ if (tmp->wsrep_applier == true)
+ {
+ /*
+ Save/restore server_status and variables.option_bits and they get
+ altered during init_for_queries().
+ */
+ unsigned int server_status_saved= tmp->server_status;
+ ulonglong option_bits_saved= tmp->variables.option_bits;
+
+ /*
+ Set THR_THD to temporarily point to this THD to register all the
+ variables that allocates memory for this THD.
+ */
+ THD *current_thd_saved= current_thd;
+ set_current_thd(tmp);
+
+ tmp->init_for_queries();
+
+ /* Restore current_thd. */
+ set_current_thd(current_thd_saved);
+
+ tmp->server_status= server_status_saved;
+ tmp->variables.option_bits= option_bits_saved;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_thread_count);
+ }
+#endif
+
/* we do want to exit if there are any other unknown options */
if (remaining_argc > 1)
{
@@ -4900,8 +5198,33 @@ static int init_server_components()
internal_tmp_table_max_key_segments= myisam_max_key_segments();
#endif
+#ifdef WITH_WSREP
+ if (!opt_bin_log)
+ {
+ wsrep_emulate_bin_log= 1;
+ }
+#endif
+
tc_log= get_tc_log_implementation();
+#ifdef WITH_WSREP
+ if (tc_log == &tc_log_mmap)
+ {
+ /*
+ wsrep hton raises total_ha_2pc count to 2, even in native mysql mode.
+ Have to force using tc_log_dummy here, as tc_log_mmap segfaults.
+ */
+ if (WSREP_ON || total_ha_2pc <= 2)
+ tc_log= &tc_log_dummy;
+ }
+
+ 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");
@@ -4992,6 +5315,437 @@ 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() || (!(thd= new THD(true))))
+ {
+ goto error;
+ }
+
+ mysql_mutex_lock(&LOCK_thread_count);
+ thd->thread_id=thread_id++;
+
+ thd->real_id=pthread_self(); // Keep purify happy
+ thread_count++;
+ thread_created++;
+ threads.append(thd);
+
+ my_net_init(&thd->net,(st_vio*) 0, MYF(0));
+
+ DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id));
+ thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer();
+ (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= microsecond_interval_timer();
+
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
+ {
+ close_connection(thd, ER_OUT_OF_RESOURCES);
+ statistic_increment(aborted_connects,&LOCK_status);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+ goto error;
+ }
+
+// </5.1.17>
+ /*
+ handle_one_connection() is normally the only way a thread would
+ start and would always be on the very high end of the stack ,
+ therefore, the thread stack always starts at the address of the
+ first local variable of handle_one_connection, which is thd. We
+ need to know the start of the stack so that we could check for
+ stack overruns.
+ */
+ DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n",
+ (long long)thd->thread_id));
+ /* 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);
+ statistic_increment(aborted_connects,&LOCK_status);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+ delete thd;
+ goto error;
+ }
+
+ 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);
+
+ if (wsrep_creating_startup_threads == 0)
+ {
+ thd->init_for_queries();
+ }
+
+ mysql_mutex_lock(&LOCK_thread_count);
+ wsrep_running_threads++;
+ mysql_cond_broadcast(&COND_thread_count);
+
+ if (wsrep_running_threads > 2)
+ {
+ wsrep_creating_startup_threads= 0;
+ }
+
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ processor(thd);
+
+ close_connection(thd, 0);
+
+ mysql_mutex_lock(&LOCK_thread_count);
+ wsrep_running_threads--;
+ WSREP_DEBUG("wsrep running threads now: %lu", wsrep_running_threads);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ // 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
+ }
+
+ my_thread_end();
+ if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION)
+ {
+ mysql_mutex_lock(&LOCK_thread_count);
+ delete thd;
+ thread_count--;
+ mysql_mutex_unlock(&LOCK_thread_count);
+ }
+ return(NULL);
+
+error:
+ WSREP_ERROR("Failed to create/initialize system thread");
+
+ /* Abort if its the first applier/rollbacker thread. */
+ if (wsrep_creating_startup_threads == 1)
+ unireg_abort(1);
+ else
+ return NULL;
+}
+
+/**/
+static bool abort_replicated(THD *thd)
+{
+ bool ret_code= false;
+ if (thd->wsrep_query_state== QUERY_COMMITTING)
+ {
+ WSREP_DEBUG("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()
+{
+ THD *tmp;
+
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++))
+ {
+ DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
+ tmp->thread_id));
+ if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION)
+ {
+ (void)abort_replicated(tmp);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void wsrep_close_thread(THD *thd)
+{
+ thd->killed= 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()
+{
+ THD *tmp;
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
+
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++))
+ {
+ if (!is_client_connection(tmp))
+ continue;
+
+ if (is_committing_connection(tmp))
+ {
+ return TRUE;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_thread_count);
+ 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
+ */
+
+ THD *tmp;
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
+
+ bool kill_cached_threads_saved= kill_cached_threads;
+ kill_cached_threads= true; // prevent future threads caching
+ mysql_cond_broadcast(&COND_thread_cache); // tell cached threads to die
+
+ I_List_iterator<THD> it(threads);
+ while ((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= 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 (thread_count)
+ 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
+ */
+
+ I_List_iterator<THD> it2(threads);
+ while ((tmp=it2++))
+ {
+#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);
+ }
+#endif
+ }
+
+ DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
+ WSREP_DEBUG("waiting for client connections to close: %u", 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)", thread_count));
+ }
+
+ kill_cached_threads= kill_cached_threads_saved;
+
+ 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)
+{
+ THD *tmp;
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
+
+ I_List_iterator<THD> it(threads);
+ while ((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_wait_appliers_close(THD *thd)
+{
+ /* Wait for wsrep appliers to gracefully exit */
+ mysql_mutex_lock(&LOCK_thread_count);
+ while (wsrep_running_threads > 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.
+ {
+ if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION)
+ {
+ mysql_mutex_unlock(&LOCK_thread_count);
+ my_sleep(100);
+ mysql_mutex_lock(&LOCK_thread_count);
+ }
+ else
+ mysql_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ DBUG_PRINT("quit",("One applier died (count=%u)",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 (wsrep_running_threads > 0)
+ {
+ if (thread_handling > SCHEDULER_ONE_THREAD_PER_CONNECTION)
+ {
+ mysql_mutex_unlock(&LOCK_thread_count);
+ my_sleep(100);
+ mysql_mutex_lock(&LOCK_thread_count);
+ }
+ else
+ mysql_cond_wait(&COND_thread_count,&LOCK_thread_count);
+ DBUG_PRINT("quit",("One thread died (count=%u)",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()
@@ -5395,6 +6149,15 @@ int mysqld_main(int argc, char **argv)
}
#endif
+#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
@@ -5453,8 +6216,33 @@ int mysqld_main(int argc, char **argv)
if (Events::init((THD*) 0, 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
bootstrap(mysql_stdin);
if (!kill_in_progress)
@@ -5529,6 +6317,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
@@ -5794,6 +6585,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, MYF(0));
thd->max_client_packet_length= thd->net.max_packet;
@@ -6195,6 +6989,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
{
@@ -6938,12 +7735,6 @@ struct my_option my_long_options[]=
"more than one storage engine, when binary log is disabled).",
&opt_tc_log_file, &opt_tc_log_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#ifdef HAVE_MMAP
- {"log-tc-size", 0, "Size of transaction coordinator log.",
- &opt_tc_log_size, &opt_tc_log_size, 0, GET_ULONG,
- REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, (ulonglong) ULONG_MAX, 0,
- TC_LOG_PAGE_SIZE, 0},
-#endif
{"master-info-file", 0,
"The location and name of the file that remembers the master and where "
"the I/O replication thread is in the master's binlogs. Defaults to "
@@ -7127,6 +7918,13 @@ struct my_option my_long_options[]=
{"table_cache", 0, "Deprecated; use --table-open-cache instead.",
&tc_size, &tc_size, 0, GET_ULONG,
REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
+#ifdef WITH_WSREP
+ {"wsrep-new-cluster", 0, "Bootstrap a cluster. It works by overriding the "
+ "current value of wsrep_cluster_address. It is recommended not to add this "
+ "option to the config file as this will trigger bootstrap on every server "
+ "start.", &wsrep_new_cluster, &wsrep_new_cluster, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+#endif
/* The following options exist in 5.6 but not in 10.0 */
MYSQL_TO_BE_IMPLEMENTED_OPTION("default-tmp-storage-engine"),
@@ -7978,6 +8776,21 @@ SHOW_VAR status_vars[]= {
#ifdef ENABLED_PROFILING
{"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_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_SIMPLE_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_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH},
+ {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC},
+#endif
{NullS, NullS, SHOW_LONG}
};
@@ -8319,6 +9132,10 @@ static int mysql_init_variables(void)
tmpenv = DEFAULT_MYSQL_HOME;
strmake_buf(mysql_home, tmpenv);
#endif
+#ifdef WITH_WSREP
+ if (wsrep_init_vars())
+ return 1;
+#endif
return 0;
}
@@ -8569,6 +9386,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:
/*
@@ -8869,6 +9694,40 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
else
global_system_variables.option_bits&= ~OPTION_BIG_SELECTS;
+#ifdef WITH_WSREP
+ if (!opt_bootstrap && WSREP_PROVIDER_EXISTS &&
+ global_system_variables.binlog_format != BINLOG_FORMAT_ROW) {
+
+ WSREP_ERROR ("Only binlog_format = 'ROW' is currently supported. "
+ "Configured value: '%s'. Please adjust your configuration.",
+ binlog_format_names[global_system_variables.binlog_format]);
+ return 1;
+ }
+
+ if (global_system_variables.wsrep_causal_reads) {
+ WSREP_WARN("option --wsrep-causal-reads is deprecated");
+ if (!(global_system_variables.wsrep_sync_wait &
+ WSREP_SYNC_WAIT_BEFORE_READ)) {
+ WSREP_WARN("--wsrep-causal-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 both turned on.
+ }
+ } 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 both turned off.
+ }
+ }
+#endif // WITH_WSREP
+
// Synchronize @@global.autocommit on --autocommit
const ulonglong turn_bit_on= opt_autocommit ?
OPTION_AUTOCOMMIT : OPTION_NOT_AUTOCOMMIT;
@@ -9034,6 +9893,9 @@ void set_server_version(void)
#ifdef EMBEDDED_LIBRARY
end= strnmov(end, "-embedded", (version_end-end));
#endif
+#ifdef WITH_WSREP
+ end= strmov(end, "-wsrep");
+#endif
#ifndef DBUG_OFF
if (!strstr(MYSQL_SERVER_SUFFIX_STR, "-debug"))
end= strnmov(end, "-debug", (version_end-end));
@@ -9262,8 +10124,6 @@ static int test_if_case_insensitive(const char *dir_name)
DBUG_PRINT("exit", ("result: %d", result));
DBUG_RETURN(result);
}
-
-
#ifndef EMBEDDED_LIBRARY
/**
@@ -9327,6 +10187,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, 0);
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 188ac0449c8..73718abd582 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -248,6 +248,11 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
key_LOCK_pool, key_LOCK_pending_checkpoint;
#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;
#endif
@@ -604,6 +609,15 @@ enum options_mysqld
OPT_WANT_CORE,
OPT_MYSQL_COMPATIBILITY,
OPT_MYSQL_TO_BE_IMPLEMENTED,
+#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_which_is_always_the_last
};
#endif
@@ -767,4 +781,9 @@ extern uint internal_tmp_table_max_key_segments;
extern uint volatile global_disable_checkpoint;
extern my_bool opt_help;
+#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 777f124f502..67fb8924764 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -497,6 +497,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.cc b/sql/rpl_gtid.cc
index 683f2492097..52cec9f0a85 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -560,6 +560,14 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
if ((err= gtid_check_rpl_slave_state_table(table)))
goto end;
+#ifdef WITH_WSREP
+ /*
+ Updates in slave state table should not be appended to galera transaction
+ writeset.
+ */
+ thd->wsrep_skip_append_keys= true;
+#endif
+
if (!in_transaction)
{
DBUG_PRINT("info", ("resetting OPTION_BEGIN"));
@@ -673,6 +681,10 @@ IF_DBUG(dbug_break:, )
end:
+#ifdef WITH_WSREP
+ thd->wsrep_skip_append_keys= false;
+#endif
+
if (table_opened)
{
if (err || (err= ha_commit_trans(thd, FALSE)))
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index c810e030bf2..c23190cda2b 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -111,7 +111,13 @@ void Master_info::wait_until_free()
Master_info::~Master_info()
{
- wait_until_free();
+#ifdef WITH_WSREP
+ /*
+ Do not free "wsrep" rpl_filter. It will eventually be freed by
+ free_all_rpl_filters() when server terminates.
+ */
+ if (strncmp(connection_name.str, STRING_WITH_LEN("wsrep")))
+#endif
rpl_filters.delete_element(connection_name.str, connection_name.length,
(void (*)(const char*, uchar*)) free_rpl_filter);
my_free(connection_name.str);
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index 5e48cfb02e5..21b8a8028a6 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -308,7 +308,11 @@ unpack_row(rpl_group_info *rgi,
uint16 const metadata= tabledef->field_metadata(i);
#ifndef DBUG_OFF
uchar const *const old_pack_ptr= pack_ptr;
-#endif
+#else
+#ifdef WITH_WSREP
+ uchar const *const old_pack_ptr= pack_ptr;
+#endif /* WITH_WSREP */
+#endif /* !DBUF_OFF */
pack_ptr= f->unpack(f->ptr, pack_ptr, row_end, metadata);
DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;"
" pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d",
@@ -317,6 +321,20 @@ unpack_row(rpl_group_info *rgi,
(int) (pack_ptr - old_pack_ptr)));
if (!pack_ptr)
{
+#ifdef WITH_WSREP
+ /*
+ Debug message to troubleshoot bug:
+ https://mariadb.atlassian.net/browse/MDEV-4404
+ */
+ WSREP_WARN("ROW event unpack field: %s metadata: 0x%x;"
+ " pack_ptr: 0x%lx; conv_table %p conv_field %p table %s"
+ " row_end: 0x%lx",
+ f->field_name, metadata,
+ (ulong) old_pack_ptr, conv_table, conv_field,
+ (table_found) ? "found" : "not found", (ulong)row_end
+ );
+#endif /* WITH_WSREP */
+
rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT,
rgi->gtid_info(),
"Could not read field '%s' of table '%s.%s'",
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 0b9699e39f7..7ad528f0eae 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -556,7 +556,11 @@ int mysql_del_sys_var_chain(sys_var *first)
static int show_cmp(SHOW_VAR *a, SHOW_VAR *b)
{
+#ifdef WITH_WSREP
+ return my_strcasecmp(system_charset_info, a->name, b->name);
+#else
return strcmp(a->name, b->name);
+#endif /* WITH_WSREP */
}
diff --git a/sql/set_var.h b/sql/set_var.h
index 83ba662b76c..064da1404fa 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -247,6 +247,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
};
@@ -341,6 +344,9 @@ extern sys_var *Sys_autocommit_ptr;
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(DYNAMIC_ARRAY *long_options, int parse_flags);
void sys_var_end(void);
diff --git a/sql/slave.cc b/sql/slave.cc
index eb2dbd291f6..3dee39ad65f 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -53,6 +53,9 @@
// Create_file_log_event,
// Format_description_log_event
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif
#ifdef HAVE_REPLICATION
#include "rpl_tblmap.h"
@@ -1029,8 +1032,7 @@ static bool io_slave_killed(Master_info* mi)
In the event of deffering decision @rli->last_event_start_time waiting
timer is set to force the killed status be accepted upon its expiration.
- @param thd pointer to a THD instance
- @param rli pointer to Relay_log_info instance
+ @param rgi pointer to relay_group_info instance
@return TRUE the killed status is recognized, FALSE a possible killed
status is deferred.
@@ -1367,6 +1369,10 @@ bool is_network_error(uint errorno)
errorno == ER_NET_READ_INTERRUPTED ||
errorno == ER_SERVER_SHUTDOWN)
return TRUE;
+#ifdef WITH_WSREP
+ if (errorno == ER_UNKNOWN_COM_ERROR)
+ return TRUE;
+#endif
return FALSE;
}
@@ -3309,6 +3315,17 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd,
if (reason == Log_event::EVENT_SKIP_NOT)
exec_res= ev->apply_event(rgi);
+#ifdef WITH_WSREP
+ if (exec_res && thd->wsrep_conflict_state != NO_CONFLICT)
+ {
+ WSREP_DEBUG("SQL apply failed, res %d conflict state: %d",
+ exec_res, thd->wsrep_conflict_state);
+ rli->abort_slave= 1;
+ rli->report(ERROR_LEVEL, ER_UNKNOWN_COM_ERROR, rgi->gtid_info(),
+ "Node has dropped from cluster");
+ }
+#endif
+
#ifndef DBUG_OFF
/*
This only prints information to the debug trace.
@@ -3640,6 +3657,10 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
serial_rgi->event_relay_log_pos= rli->event_relay_log_pos;
exec_res= apply_event_and_update_pos(ev, thd, serial_rgi, NULL);
+#ifdef WITH_WSREP
+ WSREP_DEBUG("apply_event_and_update_pos() result: %d", exec_res);
+#endif /* WITH_WSREP */
+
delete_or_keep_event_post_apply(serial_rgi, typ, ev);
/*
@@ -3649,6 +3670,12 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
if (exec_res == 2)
DBUG_RETURN(1);
+#ifdef WITH_WSREP
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state == NO_CONFLICT)
+ {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+#endif /* WITH_WSREP */
if (slave_trans_retries)
{
int temp_err;
@@ -3722,6 +3749,12 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
serial_rgi->trans_retries));
}
}
+#ifdef WITH_WSREP
+ } else {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+#endif /* WITH_WSREP */
+
thread_safe_increment64(&rli->executed_entries,
&slave_executed_entries_lock);
DBUG_RETURN(exec_res);
@@ -4464,6 +4497,9 @@ pthread_handler_t handle_slave_sql(void *arg)
my_off_t saved_skip= 0;
Master_info *mi= ((Master_info*)arg);
Relay_log_info* rli = &mi->rli;
+#ifdef WITH_WSREP
+ my_bool wsrep_node_dropped= FALSE;
+#endif /* WITH_WSREP */
const char *errmsg;
rpl_group_info *serial_rgi;
rpl_sql_thread_info sql_info(mi->rpl_filter);
@@ -4471,6 +4507,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 */
LINT_INIT(saved_master_log_pos);
LINT_INIT(saved_log_pos);
@@ -4628,6 +4667,11 @@ 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) wsrep_ready_wait();
+#endif
DBUG_PRINT("master_info",("log_file_name: %s position: %s",
rli->group_master_log_name,
llstr(rli->group_master_log_pos,llbuff)));
@@ -4751,10 +4795,27 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME,
if (exec_relay_log_event(thd, rli, serial_rgi))
{
+#ifdef WITH_WSREP
+ if (thd->wsrep_conflict_state != NO_CONFLICT)
+ {
+ wsrep_node_dropped= TRUE;
+ rli->abort_slave= TRUE;
+ }
+#endif /* WITH_WSREP */
+
DBUG_PRINT("info", ("exec_relay_log_event() failed"));
// do not scare the user if SQL thread was simply killed or stopped
if (!sql_slave_killed(serial_rgi))
+ {
slave_output_error_info(serial_rgi, thd);
+#ifdef WITH_WSREP
+ uint32 const last_errno= rli->last_error().number;
+ if (WSREP_ON && last_errno == ER_UNKNOWN_COM_ERROR)
+ {
+ wsrep_node_dropped= TRUE;
+ }
+#endif /* WITH_WSREP */
+ }
goto err;
}
}
@@ -4881,6 +4942,33 @@ err_during_init:
thd->rgi_fake= thd->rgi_slave= NULL;
delete serial_rgi;
mysql_mutex_unlock(&LOCK_thread_count);
+
+#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_get())
+ {
+ WSREP_INFO("Slave error due to node temporarily non-primary"
+ "SQL slave will continue");
+ wsrep_node_dropped= FALSE;
+ mysql_mutex_unlock(&rli->run_lock);
+ WSREP_DEBUG("wsrep_conflict_state now: %d", thd->wsrep_conflict_state);
+ WSREP_INFO("slave restart: %d", thd->wsrep_conflict_state);
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ 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/sp.cc b/sql/sp.cc
index 6d75f551357..ccdc53429bf 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -2274,3 +2274,38 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db,
thd->lex= old_lex;
return sp;
}
+#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: schema: %s, query: %s",
+ (thd->db ? thd->db : "(null)"), 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 fa0f4ad1563..cbca413a93d 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2558,8 +2558,15 @@ int check_change_password(THD *thd, const char *host, const char *user,
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
return(1);
}
+
+#ifdef WITH_WSREP
+ if ((!WSREP(thd) || !thd->wsrep_applier) &&
+ !thd->slave_thread && !thd->security_ctx->priv_user[0] &&
+ !in_bootstrap)
+#else
if (!thd->slave_thread && !thd->security_ctx->priv_user[0] &&
!in_bootstrap)
+#endif /* WITH_WSREP */
{
my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
MYF(0));
@@ -2570,7 +2577,11 @@ int check_change_password(THD *thd, const char *host, const char *user,
my_error(ER_PASSWORD_NO_MATCH, MYF(0));
return 1;
}
+
if (!thd->slave_thread &&
+#ifdef WITH_WSREP
+ (!WSREP(thd) || !thd->wsrep_applier) &&
+#endif /* WITH_WSREP */
(strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, host,
thd->security_ctx->priv_host)))
@@ -2609,11 +2620,14 @@ bool change_password(THD *thd, const char *host, const char *user,
Rpl_filter *rpl_filter;
/* Buffer should be extended when password length is extended. */
char buff[512];
- ulong query_length;
+ ulong query_length=0;
enum_binlog_format save_binlog_format;
uint new_password_len= (uint) strlen(new_password);
bool result= 1;
bool use_salt= 0;
+#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));
@@ -2621,6 +2635,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);
@@ -2702,9 +2728,23 @@ bool change_password(THD *thd, const char *host, const char *user,
}
end:
close_mysql_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 */
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(result);
+#ifdef WITH_WSREP
+ error:
+ WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff);
+ DBUG_RETURN(result);
+#endif /* WITH_WSREP */
}
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 10fcbd56e18..a053d7efc19 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1195,6 +1195,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
FALSE, UINT_MAX, FALSE))
goto error;
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
thd->enable_slow_log= opt_log_slow_admin_statements;
res= mysql_admin_table(thd, first_table, &m_lex->check_opt,
"analyze", lock_type, 1, 0, 0, 0,
@@ -1250,6 +1251,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_WRTCHK(NULL, NULL, first_table);
thd->enable_slow_log= opt_log_slow_admin_statements;
res= (specialflag & SPECIAL_NO_NEW_FUNC) ?
mysql_recreate_table(thd, first_table, true) :
@@ -1283,6 +1285,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_WRTCHK(NULL, NULL, first_table);
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair",
TL_WRITE, 1,
MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM),
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 97b9c127c22..a39f07ae35d 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -18,7 +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)
:drop_list(rhs.drop_list, mem_root),
alter_list(rhs.alter_list, mem_root),
@@ -303,6 +305,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,
@@ -312,6 +325,12 @@ 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 */
}
bool Sql_cmd_discard_import_tablespace::execute(THD *thd)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1ed57a051d8..07540d3c96d 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -62,6 +62,10 @@
#include <io.h>
#endif
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
+#endif // WITH_WSREP
bool
No_such_table_error_handler::handle_condition(THD *,
@@ -3690,7 +3694,7 @@ thr_lock_type read_lock_type_for_table(THD *thd,
*/
bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
ulong binlog_format= thd->variables.binlog_format;
- if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) ||
+ if ((log_on == FALSE) || (WSREP_FORMAT(binlog_format) == BINLOG_FORMAT_ROW) ||
(table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
(table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
!(is_update_query(prelocking_ctx->sql_command) ||
@@ -4738,9 +4742,38 @@ restart:
tbl->reginfo.lock_type= tables->lock_type;
}
}
+#ifdef WITH_WSREP
+ if (wsrep_replicate_myisam &&
+ (*start) &&
+ (*start)->table &&
+ (*start)->table->file->ht->db_type == DB_TYPE_MYISAM &&
+ thd->get_command() != COM_STMT_PREPARE &&
+ ((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_TO_ISOLATION_BEGIN(NULL, NULL, (*start));
+ }
+ error:
+#endif
err:
THD_STAGE_INFO(thd, stage_after_opening_tables);
+
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ thd_proc_info(thd, "exit open_tables()");
+ else
+ thd_proc_info(thd, 0);
+#else /* WITH_WSREP */
+ thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
+
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
if (error && *table_to_open)
@@ -5206,7 +5239,18 @@ end:
trans_rollback_stmt(thd);
close_thread_tables(thd);
}
+
THD_STAGE_INFO(thd, stage_after_opening_tables);
+
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ thd_proc_info(thd, "End opening table");
+ else
+ thd_proc_info(thd, 0);
+#else /* WITH_WSREP */
+ thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
+
DBUG_RETURN(table);
}
@@ -9084,7 +9128,19 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
(e.g. see partitioning code).
*/
if (!thd_table->needs_reopen())
+#ifdef WITH_WSREP
+ {
+ signalled|= mysql_lock_abort_for_thread(thd, thd_table);
+ if (thd && WSREP(thd) && wsrep_thd_is_BF((void *)thd, true))
+ {
+ WSREP_DEBUG("remove_table_from_cache: %llu",
+ (unsigned long long) thd->real_id);
+ wsrep_abort_thd((void *)thd, (void *)in_use, FALSE);
+ }
+ }
+#else
signalled|= mysql_lock_abort_for_thread(thd, thd_table);
+#endif
}
mysql_mutex_unlock(&in_use->LOCK_thd_data);
}
diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
index 63850650ac9..2de475b0a76 100644
--- a/sql/sql_builtin.cc.in
+++ b/sql/sql_builtin.cc.in
@@ -25,7 +25,11 @@ extern
#endif
builtin_maria_plugin
@mysql_mandatory_plugins@ @mysql_optional_plugins@
- builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin;
+ builtin_maria_binlog_plugin,
+#ifdef WITH_WSREP
+ builtin_wsrep_plugin@mysql_plugin_defs@,
+#endif /* WITH_WSREP */
+ builtin_maria_mysql_password_plugin;
struct st_maria_plugin *mysql_optional_plugins[]=
{
@@ -35,5 +39,8 @@ struct st_maria_plugin *mysql_optional_plugins[]=
struct st_maria_plugin *mysql_mandatory_plugins[]=
{
builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin,
+#ifdef WITH_WSREP
+ builtin_wsrep_plugin@mysql_plugin_defs@,
+#endif /* WITH_WSREP */
@mysql_mandatory_plugins@ 0
};
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index a70e2ac46fd..2c9eadf48c8 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1951,6 +1951,13 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
(int)flags.autocommit));
memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
(uchar*) &flags, QUERY_CACHE_FLAGS_SIZE);
+
+#ifdef WITH_WSREP
+ bool once_more;
+ once_more= true;
+lookup:
+#endif /* WITH_WSREP */
+
query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql,
tot_length);
/* Quick abort on unlocked data */
@@ -1963,6 +1970,19 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block));
+#ifdef WITH_WSREP
+ if (once_more && WSREP_CLIENT(thd) && wsrep_must_sync_wait(thd))
+ {
+ unlock();
+ if (wsrep_sync_wait(thd))
+ goto err;
+ if (try_lock(thd, Query_cache::TIMEOUT))
+ goto err;
+ once_more= false;
+ goto lookup;
+ }
+#endif /* WITH_WSREP */
+
/* Now lock and test that nothing changed while blocks was unlocked */
BLOCK_LOCK_RD(query_block);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 3b293935048..385ced114c8 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -63,6 +63,10 @@
#include "sql_parse.h" // is_update_query
#include "sql_callback.h"
#include "lock.h"
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
+#endif
#include "sql_connect.h"
/*
@@ -717,6 +721,180 @@ extern "C"
}
+#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)
+{
+ if (WSREP(thd)) 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(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 "C" bool wsrep_thd_skip_append_keys(THD *thd)
+{
+ return thd->wsrep_skip_append_keys;
+}
+
+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
#if MARIA_PLUGIN_INTERFACE_VERSION < 0x0200
/**
TODO: This function is for API compatibility, remove it eventually.
@@ -759,7 +937,11 @@ bool Drop_table_error_handler::handle_condition(THD *thd,
}
+#ifdef WITH_WSREP
+THD::THD(bool is_applier)
+#else
THD::THD()
+#endif
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
rli_fake(0), rgi_fake(0), rgi_slave(NULL),
@@ -795,8 +977,20 @@ THD::THD()
debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
wait_for_commit_ptr(0),
- main_da(0, false, false),
+ main_da(0, false, false),
m_stmt_da(&main_da)
+#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),
+ wsrep_skip_append_keys(false)
+#endif
{
ulong tmp;
@@ -906,6 +1100,26 @@ THD::THD()
m_command=COM_CONNECT;
*scramble= '\0';
+#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;
+ wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
+ wsrep_affected_rows = 0;
+ wsrep_replicate_GTID = false;
+ wsrep_skip_wsrep_GTID = false;
+#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -945,6 +1159,13 @@ THD::THD()
my_rnd_init(&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_token_array= NULL;
if (max_digest_length > 0)
@@ -1299,6 +1520,27 @@ void THD::init(void)
last_commit_gtid.seq_no= 0;
status_in_global= 0;
+#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_rgi= 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;
+ wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
+ wsrep_affected_rows = 0;
+ wsrep_replicate_GTID = false;
+ wsrep_skip_wsrep_GTID = false;
+#endif /* WITH_WSREP */
+
if (variables.sql_log_bin)
variables.option_bits|= OPTION_BIN_LOG;
else
@@ -1494,6 +1736,13 @@ THD::~THD()
mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_unlock(&LOCK_thd_data);
+#ifdef WITH_WSREP
+ mysql_mutex_lock(&LOCK_wsrep_thd);
+ mysql_mutex_unlock(&LOCK_wsrep_thd);
+ mysql_mutex_destroy(&LOCK_wsrep_thd);
+ if (wsrep_rgi) delete wsrep_rgi;
+ wsrep_free_status(this);
+#endif
/* Close connection */
#ifndef EMBEDDED_LIBRARY
if (net.vio)
@@ -1675,6 +1924,9 @@ void THD::awake(killed_state state_to_set)
/* Interrupt target waiting inside a storage engine. */
if (state_to_set != NOT_KILLED)
+#ifdef WITH_WSREP
+ /* TODO: prevent applier close here */
+#endif /* WITH_WSREP */
ha_kill_query(this, thd_kill_level(this));
/* Broadcast a condition to kick the target if it is waiting on it. */
@@ -1823,7 +2075,19 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
thread can see those instances (e.g. see partitioning code).
*/
if (!thd_table->needs_reopen())
+#ifdef WITH_WSREP
+ {
signalled|= mysql_lock_abort_for_thread(this, thd_table);
+ if (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);
@@ -2006,12 +2270,25 @@ void THD::cleanup_after_query()
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= INVOKER_NONE;
+#ifdef WITH_WSREP
+ if (TOTAL_ORDER == wsrep_exec_mode)
+ {
+ wsrep_exec_mode = LOCAL_STATE;
+ }
+ //wsrep_trx_seqno = 0;
+#endif /* WITH_WSREP */
#ifndef EMBEDDED_LIBRARY
if (rgi_slave)
rgi_slave->cleanup_after_query();
#endif
+#ifdef WITH_WSREP
+ wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+ if (!in_active_multi_stmt_transaction())
+ wsrep_affected_rows= 0;
+#endif /* WITH_WSREP */
+
DBUG_VOID_RETURN;
}
@@ -2422,6 +2699,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;
@@ -4399,10 +4683,17 @@ 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))
+ {
+ /* for wsrep binlog format is meaningful also when binlogging is off */
+ return (int) WSREP_FORMAT(thd->variables.binlog_format);
+ }
+#endif /* WITH_WSREP */
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
return (int) thd->variables.binlog_format;
else
- return BINLOG_FORMAT_UNSPEC;
+ return BINLOG_FORMAT_UNSPEC;
}
extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all)
@@ -4879,7 +5170,11 @@ void THD::get_definer(LEX_USER *definer, bool role)
{
binlog_invoker(role);
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+#ifdef WITH_WSREP
+ if ((wsrep_applier || slave_thread) && has_invoker())
+#else
if (slave_thread && has_invoker())
+#endif
{
definer->user = invoker_user;
definer->host= invoker_host;
@@ -5229,7 +5524,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
binlog by filtering rules.
*/
if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
- !(variables.binlog_format == BINLOG_FORMAT_STMT &&
+ !(WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT &&
!binlog_filter->db_ok(db)))
{
/*
@@ -5466,7 +5761,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_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW &&
sqlcom_can_generate_row_events(this))
{
/*
@@ -5495,7 +5790,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
else
{
/* binlog_format = STATEMENT */
- if (variables.binlog_format == BINLOG_FORMAT_STMT)
+ if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT)
{
if (lex->is_stmt_row_injection())
{
@@ -5512,7 +5807,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)
{
@@ -5624,7 +5926,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_FORMAT(variables.binlog_format),
binlog_filter->db_ok(db)));
#endif
@@ -5861,7 +6163,13 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
MY_BITMAP const* cols, size_t colcnt,
uchar const *record)
{
+#ifdef WITH_WSREP
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
+ ((WSREP(this) && wsrep_emulate_bin_log) ||
+ mysql_bin_log.is_open()));
+#else
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
+#endif
/*
Pack records into format for transfer. We are allocating more
@@ -5895,7 +6203,13 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
const uchar *before_record,
const uchar *after_record)
{
+#ifdef WITH_WSREP
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
+ ((WSREP(this) && wsrep_emulate_bin_log)
+ || mysql_bin_log.is_open()));
+#else
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
+#endif
size_t const before_maxlen = max_row_length(table, before_record);
size_t const after_maxlen = max_row_length(table, after_record);
@@ -5944,7 +6258,13 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
MY_BITMAP const* cols, size_t colcnt,
uchar const *record)
{
+#ifdef WITH_WSREP
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
+ ((WSREP(this) && wsrep_emulate_bin_log)
+ || mysql_bin_log.is_open()));
+#else
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
+#endif
/*
Pack records into format for transfer. We are allocating more
@@ -5979,7 +6299,11 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps,
{
DBUG_ENTER("THD::binlog_remove_pending_rows_event");
+#ifdef WITH_WSREP
+ if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()))
+#else
if (!mysql_bin_log.is_open())
+#endif
DBUG_RETURN(0);
/* Ensure that all events in a GTID group are in the same cache */
@@ -6002,7 +6326,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).
*/
+#ifdef WITH_WSREP
+ if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()))
+#else
if (!mysql_bin_log.is_open())
+#endif
DBUG_RETURN(0);
/* Ensure that all events in a GTID group are in the same cache */
@@ -6264,7 +6592,13 @@ 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), (int) query_len, 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
/* If this is withing a BEGIN ... COMMIT group, don't log it */
if (variables.option_bits & OPTION_GTID_BEGIN)
@@ -6282,7 +6616,6 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
*/
DBUG_RETURN(0);
}
-
/*
If we are not in prelocked mode, mysql_unlock_tables() will be
called after this binlog_query(), so we have to flush the pending
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 9428f6f6ce5..b6fde5f6875 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -58,6 +58,20 @@ void set_thd_stage_info(void *thd,
#include "my_apc.h"
#include "rpl_gtid.h"
+#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;
+ my_hrtime_t user_time;
+ longlong row_count_func;
+};
+#endif
class Reprepare_observer;
class Relay_log_info;
struct rpl_group_info;
@@ -640,6 +654,14 @@ typedef struct system_variables
ulong wt_timeout_short, wt_deadlock_search_depth_short;
ulong wt_timeout_long, wt_deadlock_search_depth_long;
+#ifdef WITH_WSREP
+ my_bool wsrep_on;
+ my_bool wsrep_causal_reads;
+ my_bool wsrep_dirty_reads;
+ uint wsrep_sync_wait;
+ ulong wsrep_retry_autocommit;
+ ulong wsrep_OSU_method;
+#endif
double long_query_time_double;
my_bool pseudo_slave_mode;
@@ -2832,6 +2854,7 @@ public:
query_id_t first_query_id;
} binlog_evt_union;
+ mysql_cond_t COND_wsrep_thd;
/**
Internal parser state.
Note that since the parser is not re-entrant, we keep only one parser
@@ -2863,7 +2886,11 @@ public:
/* Debug Sync facility. See debug_sync.cc. */
struct st_debug_sync_control *debug_sync_control;
#endif /* defined(ENABLED_DEBUG_SYNC) */
+#ifdef WITH_WSREP
+ THD(bool is_applier = false);
+#else
THD();
+#endif
~THD();
void init(void);
@@ -3396,7 +3423,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_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED) &&
(in_sub_stmt == 0))
set_current_stmt_binlog_format_row();
@@ -3448,7 +3475,7 @@ public:
show_system_thread(system_thread)));
if (in_sub_stmt == 0)
{
- if (variables.binlog_format == BINLOG_FORMAT_ROW)
+ if (WSREP_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
else if (temporary_tables == NULL)
set_current_stmt_binlog_format_stmt();
@@ -3849,6 +3876,52 @@ public:
return (temporary_tables ||
(rgi_slave && unlikely(rgi_have_temporary_tables())));
}
+
+#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;
+ // 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;
+ rpl_group_info* wsrep_rgi;
+ 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;
+#ifdef GTID_SUPPORT
+ rpl_sid wsrep_po_sid;
+#endif /* GTID_SUPPORT */
+ void* wsrep_apply_format;
+ bool wsrep_apply_toi; /* applier processing in TOI */
+ bool wsrep_skip_append_keys;
+ wsrep_gtid_t wsrep_sync_wait_gtid;
+ ulong wsrep_affected_rows;
+ bool wsrep_replicate_GTID;
+ bool wsrep_skip_wsrep_GTID;
+#endif /* WITH_WSREP */
};
@@ -4164,6 +4237,8 @@ class select_insert :public select_result_interceptor {
virtual int send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
virtual bool can_rollback_data() { return 0; }
+ bool prepare_eof();
+ bool send_ok_packet();
bool send_eof();
virtual void abort_result_set();
/* not implemented: select_insert is never re-used in prepared statements */
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 63f9bfae47a..695d1095125 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -43,6 +43,9 @@ HASH global_index_stats;
extern mysql_mutex_t LOCK_global_user_client_stats;
extern mysql_mutex_t LOCK_global_table_stats;
extern mysql_mutex_t LOCK_global_index_stats;
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif
/*
Get structure for logging connection data for the current user
@@ -1170,6 +1173,17 @@ exit:
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);
if (thd->user_connect)
@@ -1305,6 +1319,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;
}
@@ -1378,7 +1395,15 @@ 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:
close_connection(thd);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 609e5472ba6..bc87e69a606 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -643,7 +643,11 @@ cleanup:
/* See similar binlogging code in sql_update.cc, for comments */
if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
+#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)
@@ -1094,7 +1098,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 == NOT_KILLED);
/* possible error of writing binary log is ignored deliberately */
@@ -1270,7 +1278,11 @@ bool multi_delete::send_eof()
}
if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
{
+#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 8b03c722898..18eb42734e3 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1018,7 +1018,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->transaction.stmt.modified_non_trans_table ||
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)
@@ -3246,6 +3250,12 @@ bool Delayed_insert::handle_inserts(void)
mysql_cond_broadcast(&cond_client); // If waiting clients
}
}
+#ifdef WITH_WSREP
+ if (WSREP((&thd)))
+ thd_proc_info(&thd, "insert done");
+ else
+#endif /* WITH_WSREP */
+ thd_proc_info(&thd, 0);
mysql_mutex_unlock(&mutex);
/*
@@ -3688,19 +3698,26 @@ void select_insert::store_values(List<Item> &values)
TRG_EVENT_INSERT);
}
-bool select_insert::send_eof()
+bool select_insert::prepare_eof()
{
int error;
bool const trans_table= table->file->has_transactions();
- ulonglong id, row_count;
bool changed;
killed_state killed_status= thd->killed;
- DBUG_ENTER("select_insert::send_eof");
+
+ DBUG_ENTER("select_insert::prepare_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 :
+ (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
+ table->file->ha_end_bulk_insert() : 0);
+#else
error= (thd->locked_tables_mode <= LTM_LOCK_TABLES ?
table->file->ha_end_bulk_insert() : 0);
+#endif /* WITH_WSREP */
if (!error && thd->is_error())
error= thd->get_stmt_da()->sql_errno();
@@ -3728,7 +3745,11 @@ 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()) &&
+#else
if (mysql_bin_log.is_open() &&
+#endif
(!error || thd->transaction.stmt.modified_non_trans_table))
{
int errcode= 0;
@@ -3741,7 +3762,7 @@ bool select_insert::send_eof()
trans_table, FALSE, FALSE, errcode))
{
table->file->ha_release_auto_increment();
- DBUG_RETURN(1);
+ DBUG_RETURN(true);
}
}
table->file->ha_release_auto_increment();
@@ -3749,27 +3770,49 @@ bool select_insert::send_eof()
if (error)
{
table->file->print_error(error,MYF(0));
- DBUG_RETURN(1);
+ DBUG_RETURN(true);
}
- char buff[160];
+
+ DBUG_RETURN(false);
+}
+
+bool select_insert::send_ok_packet() {
+ char message[160]; /* status message */
+ ulong row_count; /* rows affected */
+ ulong id; /* last insert-id */
+
+ DBUG_ENTER("select_insert::send_ok_packet");
+
if (info.ignore)
- sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.records - info.copied),
- (long) thd->get_stmt_da()->current_statement_warn_count());
+ my_snprintf(message, sizeof(message), ER(ER_INSERT_INFO),
+ (ulong) info.records, (ulong) (info.records - info.copied),
+ (long) thd->get_stmt_da()->current_statement_warn_count());
else
- sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.deleted+info.updated),
- (long) thd->get_stmt_da()->current_statement_warn_count());
+ my_snprintf(message, sizeof(message), ER(ER_INSERT_INFO),
+ (ulong) info.records, (ulong) (info.deleted + info.updated),
+ (long) thd->get_stmt_da()->current_statement_warn_count());
+
row_count= info.copied + info.deleted +
- ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
- info.touched : info.updated);
+ ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
+ info.touched : info.updated);
+
id= (thd->first_successful_insert_id_in_cur_stmt > 0) ?
thd->first_successful_insert_id_in_cur_stmt :
(thd->arg_of_last_insert_id_function ?
thd->first_successful_insert_id_in_prev_stmt :
(info.copied ? autoinc_value_of_last_inserted_row : 0));
- ::my_ok(thd, row_count, id, buff);
- DBUG_RETURN(0);
+
+ ::my_ok(thd, row_count, id, message);
+
+ DBUG_RETURN(false);
+}
+
+bool select_insert::send_eof()
+{
+ bool res;
+ DBUG_ENTER("select_insert::send_eof");
+ res= (prepare_eof() || send_ok_packet());
+ DBUG_RETURN(res);
}
void select_insert::abort_result_set() {
@@ -3813,7 +3856,11 @@ void select_insert::abort_result_set() {
if (!can_rollback_data())
thd->transaction.all.modified_non_trans_table= TRUE;
+#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 == NOT_KILLED);
/* error of writing binary log is ignored */
@@ -4243,7 +4290,11 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
WITH_DB_NAME);
DBUG_ASSERT(result == 0); /* show_create_table() 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 == NOT_KILLED);
result= thd->binlog_query(THD::STMT_QUERY_TYPE,
@@ -4253,6 +4304,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;
}
@@ -4265,13 +4319,13 @@ void select_create::store_values(List<Item> &values)
bool select_create::send_eof()
{
- if (select_insert::send_eof())
+ DBUG_ENTER("select_create::send_eof");
+ if (prepare_eof())
{
abort_result_set();
- return 1;
+ DBUG_RETURN(true);
}
- exit_done= 1; // Avoid double calls
/*
Do an implicit commit at end of statement for non-temporary
tables. This can fail, but we should unlock the table
@@ -4279,16 +4333,71 @@ bool select_create::send_eof()
*/
if (!table->s->tmp_table)
{
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ {
+ /*
+ append table level exclusive key for CTAS
+ */
+ wsrep_key_arr_t key_arr= {0, 0};
+ wsrep_prepare_keys_for_isolation(thd,
+ create_table->db,
+ create_table->table_name,
+ table_list,
+ &key_arr);
+ int rcode = wsrep->append_key(
+ wsrep,
+ &thd->wsrep_ws_handle,
+ key_arr.keys, //&wkey,
+ key_arr.keys_len,
+ WSREP_KEY_EXCLUSIVE,
+ false);
+ wsrep_keys_free(&key_arr);
+ if (rcode) {
+ DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
+ WSREP_ERROR("Appending table key for CTAS failed: %s, %d",
+ (wsrep_thd_query(thd)) ?
+ wsrep_thd_query(thd) : "void", rcode);
+ return true;
+ }
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->get_stmt_da()->set_overwrite_status(TRUE);
+ }
+#endif /* WITH_WSREP */
trans_commit_stmt(thd);
if (!(thd->variables.option_bits & OPTION_GTID_BEGIN))
trans_commit_implicit(thd);
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ {
+ thd->get_stmt_da()->set_overwrite_status(FALSE);
+ 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();
+ DBUG_RETURN(true);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+#endif /* WITH_WSREP */
}
else if (!thd->is_current_stmt_binlog_format_row())
table->s->table_creation_was_logged= 1;
+ /*
+ exit_done must only be set after last potential call to
+ abort_result_set().
+ */
+ exit_done= 1; // Avoid double calls
+
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
+ send_ok_packet();
+
if (m_plock)
{
MYSQL_LOCK *lock= *m_plock;
@@ -4309,12 +4418,12 @@ bool select_create::send_eof()
create_info->
pos_in_locked_tables,
table, lock))
- return 0; // ok
+ DBUG_RETURN(false); // ok
/* Fail. Continue without locking the table */
}
mysql_unlock_tables(thd, lock);
}
- return 0;
+ DBUG_RETURN(false);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 6c7e57aa730..e0b14e536c0 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1622,6 +1622,17 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
}
else
{
+#ifdef WITH_WSREP
+ if (version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE)
+ {
+ WSREP_DEBUG("consistency check: %s", thd->query());
+ thd->wsrep_consistency_check= CONSISTENCY_CHECK_DECLARED;
+ lip->yySkipn(5);
+ lip->set_echo(TRUE);
+ state=MY_LEX_START;
+ break; /* Do not treat contents as a comment. */
+ }
+#endif /* WITH_WSREP */
/*
Patch and skip the conditional comment to avoid it
being propagated infinitely (eg. to a slave).
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a9849c7248d..7e3590bcc83 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -50,7 +50,7 @@
#include "sql_connect.h" // decrease_user_connections,
// check_mqh,
// reset_mqh
-#include "sql_rename.h" // mysql_rename_table
+#include "sql_rename.h" // mysql_rename_tables
#include "sql_tablespace.h" // mysql_alter_tablespace
#include "hostname.h" // hostname_cache_refresh
#include "sql_acl.h" // *_ACL, check_grant, is_acl_user,
@@ -104,6 +104,13 @@
#include "../storage/maria/ha_maria.h"
#endif
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
+#include "wsrep_binlog.h"
+static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
+ Parser_state *parser_state);
+#endif /* WITH_WSREP */
/**
@defgroup Runtime_Environment Runtime Environment
@{
@@ -883,11 +890,26 @@ bool do_command(THD *thd)
{
bool return_value;
char *packet= 0;
+#ifdef WITH_WSREP
+ ulong packet_length= 0; // just to avoid (false positive) compiler warning
+#else
ulong packet_length;
+#endif /* WITH_WSREP */
NET *net= &thd->net;
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)
@@ -934,12 +956,46 @@ bool do_command(THD *thd)
packet_length= my_net_read_packet(net, 1);
+#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].
@@ -995,12 +1051,79 @@ 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_get() &&
+ 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_STMT_PREPARE &&
+ command != COM_STMT_SEND_LONG_DATA &&
+ command != COM_STMT_EXECUTE &&
+ command != COM_STMT_RESET &&
+ command != COM_STMT_CLOSE &&
+ command != COM_END
+ ) {
+ my_message(ER_UNKNOWN_COM_ERROR,
+ "WSREP has not yet prepared node for application use",
+ MYF(0));
+ thd->protocol->end_statement();
+
+ /* Performance Schema Interface instrumentation end */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+
+ return_value= FALSE;
+ goto out;
+ }
+ }
+#endif /* WITH_WSREP */
/* Restore read timeout value */
my_net_set_read_timeout(net, thd->variables.net_read_timeout);
DBUG_ASSERT(packet_length);
DBUG_ASSERT(!thd->apc_target.is_enabled());
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)
+ {
+ WSREP_DEBUG("Retry autocommit for: %s\n", thd->wsrep_retry_query);
+ CHARSET_INFO *current_charset = thd->variables.character_set_client;
+ if (!is_supported_parser_charset(current_charset))
+ {
+ /* Do not use non-supported parser character sets */
+ WSREP_WARN("Current client character set is non-supported parser "
+ "character set: %s", current_charset->csname);
+ thd->variables.character_set_client = &my_charset_latin1;
+ WSREP_WARN("For retry temporally setting character set to : %s",
+ my_charset_latin1.csname);
+ }
+ return_value= dispatch_command(command, thd, thd->wsrep_retry_query,
+ thd->wsrep_retry_query_len);
+ thd->variables.character_set_client = current_charset;
+ }
+ }
+ 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 */
DBUG_ASSERT(!thd->apc_target.is_enabled());
out:
@@ -1066,6 +1189,21 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
DBUG_RETURN(some_non_temp_table_to_be_updated(thd, all_tables));
}
+#ifdef WITH_WSREP
+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.
@@ -1095,6 +1233,42 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_ENTER("dispatch_command");
DBUG_PRINT("info", ("command: %d", 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 = 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 */
#if defined(ENABLED_PROFILING)
thd->profiling.start_new_query();
#endif
@@ -1297,7 +1471,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())
@@ -1374,10 +1552,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"));
@@ -1717,6 +1904,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 */
DBUG_ASSERT(thd->derived_tables == NULL &&
(thd->open_tables == NULL ||
(thd->locked_tables_mode == LTM_LOCK_TABLES)));
@@ -1726,6 +1933,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->update_server_status();
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);
@@ -2179,6 +2389,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.
@@ -2384,7 +2601,52 @@ mysql_execute_command(THD *thd)
#ifdef HAVE_REPLICATION
} /* endif unlikely slave */
#endif
+#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. SET and SHOW commands,
+ however, are always allowed.
+ We additionally allow all other commands that do not change data in
+ case wsrep_dirty_reads is enabled.
+ */
+ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready_get() &&
+ lex->sql_command != SQLCOM_SET_OPTION &&
+ !(thd->variables.wsrep_dirty_reads &&
+ !is_update_query(lex->sql_command)) &&
+ !wsrep_is_show_query(lex->sql_command))
+ {
+ my_message(ER_UNKNOWN_COM_ERROR,
+ "WSREP has not yet prepared node for application use",
+ MYF(0));
+ goto error;
+ }
+ }
+#endif /* WITH_WSREP */
status_var_increment(thd->status_var.com_stat[lex->sql_command]);
thd->progress.report_to_client= MY_TEST(sql_command_flags[lex->sql_command] &
CF_REPORT_PROGRESS);
@@ -2426,7 +2688,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();
}
@@ -2484,7 +2752,9 @@ mysql_execute_command(THD *thd)
#endif
case SQLCOM_SHOW_STATUS:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
execute_show_status(thd, all_tables);
+
break;
}
case SQLCOM_SHOW_EXPLAIN:
@@ -2524,17 +2794,24 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_PLUGINS:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_SHOW_KEYS:
+ case SQLCOM_SHOW_CLIENT_STATS:
+ case SQLCOM_SHOW_USER_STATS:
+ case SQLCOM_SHOW_TABLE_STATS:
+ case SQLCOM_SHOW_INDEX_STATS:
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_CHARSETS:
case SQLCOM_SHOW_COLLATIONS:
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
- case SQLCOM_SHOW_CLIENT_STATS:
- case SQLCOM_SHOW_USER_STATS:
- case SQLCOM_SHOW_TABLE_STATS:
- case SQLCOM_SHOW_INDEX_STATS:
case SQLCOM_SELECT:
- {
+ {
+#ifdef WITH_WSREP
+ if (lex->sql_command == SQLCOM_SELECT)
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ)
+ else
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW)
+#endif /* WITH_WSREP */
+
thd->status_var.last_query_cost= 0.0;
/*
@@ -2657,6 +2934,7 @@ case SQLCOM_PREPARE:
case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
case SQLCOM_SHOW_BINLOG_EVENTS:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
res = mysql_show_binlog_events(thd);
@@ -2911,7 +3189,7 @@ case SQLCOM_PREPARE:
*/
if (thd->query_name_consts &&
mysql_bin_log.is_open() &&
- thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
+ WSREP_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);
@@ -2996,6 +3274,7 @@ case SQLCOM_PREPARE:
/*
select_create is currently not re-execution friendly and
needs to be created for every execution of a PS/SP.
+ Note: In wsrep-patch, CTAS is handled like a regular transaction.
*/
if ((result= new select_create(create_table,
&create_info,
@@ -3030,6 +3309,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);
@@ -3067,6 +3355,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
@@ -3203,6 +3492,7 @@ end_with_restore_list:
{
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
res = show_binlogs(thd);
break;
}
@@ -3216,6 +3506,8 @@ end_with_restore_list:
goto error;
#else
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
+
/*
Access check:
SHOW CREATE TABLE require any privileges on the table level (ie
@@ -3278,6 +3570,8 @@ end_with_restore_list:
case SQLCOM_CHECKSUM:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ);
+
if (check_table_access(thd, SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
@@ -3287,6 +3581,7 @@ end_with_restore_list:
}
case SQLCOM_UPDATE:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
ha_rows found= 0, updated= 0;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (update_precheck(thd, all_tables))
@@ -3325,6 +3620,7 @@ end_with_restore_list:
/* if we switched from normal update, rights are checked */
if (up_result != 2)
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
if ((res= multi_update_precheck(thd, all_tables)))
break;
}
@@ -3431,6 +3727,7 @@ end_with_restore_list:
/* fall through */
case SQLCOM_INSERT:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/*
@@ -3484,11 +3781,20 @@ end_with_restore_list:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- select_result *sel_result;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
+ select_insert *sel_result;
bool explain= MY_TEST(lex->describe);
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
@@ -3590,6 +3896,7 @@ end_with_restore_list:
}
case SQLCOM_DELETE:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
select_result *sel_result=lex->result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= delete_precheck(thd, all_tables)))
@@ -3610,6 +3917,7 @@ end_with_restore_list:
}
case SQLCOM_DELETE_MULTI:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
bool explain= MY_TEST(lex->describe);
@@ -3694,6 +4002,19 @@ end_with_restore_list:
slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
lex->check_exists= 1;
+#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->check_exists,
lex->drop_temporary);
@@ -3737,7 +4058,6 @@ end_with_restore_list:
if (!mysql_change_db(thd, &db_str, FALSE))
my_ok(thd);
-
break;
}
@@ -3888,6 +4208,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, lex->name.str, &create_info, 0);
break;
}
@@ -3919,6 +4240,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->check_exists, 0);
break;
}
@@ -3950,6 +4272,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);
@@ -3985,6 +4308,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;
}
@@ -3998,6 +4322,9 @@ end_with_restore_list:
db_name.str= db_name_buff;
db_name.length= lex->name.length;
strmov(db_name.str, lex->name.str);
+
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
+
if (check_db_name(&db_name))
{
my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
@@ -4053,6 +4380,7 @@ end_with_restore_list:
/* lex->unit.cleanup() is called outside, no need to call it here */
break;
case SQLCOM_SHOW_CREATE_EVENT:
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
res= Events::show_create_event(thd, lex->spname->m_db,
lex->spname->m_name);
break;
@@ -4071,6 +4399,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
@@ -4086,6 +4415,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,
lex->sql_command == SQLCOM_CREATE_ROLE)))
@@ -4099,6 +4429,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,
lex->sql_command == SQLCOM_DROP_ROLE)))
my_ok(thd);
@@ -4110,6 +4441,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;
@@ -4121,6 +4453,7 @@ end_with_restore_list:
break;
/* 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;
@@ -4203,6 +4536,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,
@@ -4216,6 +4550,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);
@@ -4231,6 +4566,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,
@@ -4256,6 +4592,7 @@ end_with_restore_list:
case SQLCOM_REVOKE_ROLE:
case SQLCOM_GRANT_ROLE:
{
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res= mysql_grant_role(thd, lex->users_list,
lex->sql_command != SQLCOM_GRANT_ROLE)))
my_ok(thd);
@@ -4289,6 +4626,38 @@ end_with_restore_list:
break;
}
+#ifdef WITH_WSREP
+ if (lex->type & (
+ REFRESH_GRANT |
+ REFRESH_HOSTS |
+#ifdef HAVE_OPENSSL
+ REFRESH_DES_KEY_FILE |
+#endif
+ /*
+ Write all flush log statements except
+ FLUSH LOGS
+ FLUSH BINARY LOGS
+ Check reload_acl_and_cache for why.
+ */
+ REFRESH_RELAY_LOG |
+ REFRESH_SLOW_LOG |
+ REFRESH_GENERAL_LOG |
+ REFRESH_ENGINE_LOG |
+ REFRESH_ERROR_LOG |
+#ifdef HAVE_QUERY_CACHE
+ REFRESH_QUERY_CACHE_FREE |
+#endif /* HAVE_QUERY_CACHE */
+ REFRESH_STATUS |
+ REFRESH_USER_RESOURCES |
+ REFRESH_TABLE_STATS |
+ REFRESH_INDEX_STATS |
+ REFRESH_USER_STATS |
+ REFRESH_CLIENT_STATS))
+ {
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL)
+ }
+#endif /* WITH_WSREP*/
+
#ifdef HAVE_REPLICATION
if (lex->type & REFRESH_READ_LOCK)
{
@@ -4302,12 +4671,32 @@ end_with_restore_list:
goto error;
}
#endif
+
/*
reload_acl_and_cache() will tell us if we are allowed to write to the
binlog or not.
*/
if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog))
{
+#ifdef WITH_WSREP
+ if ((lex->type & REFRESH_TABLES) && !(lex->type & (REFRESH_FOR_EXPORT|REFRESH_READ_LOCK)))
+ {
+ /*
+ This is done after reload_acl_and_cache is because
+ LOCK TABLES is not replicated in galera, the upgrade of which
+ is checked in reload_acl_and_cache.
+ Hence, done after/if we are able to upgrade locks.
+ */
+ if (first_table)
+ {
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
+ }
+ else
+ {
+ WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL);
+ }
+ }
+#endif /* WITH_WSREP */
/*
We WANT to write and we CAN write.
! we write after unlocking the table.
@@ -4384,6 +4773,7 @@ end_with_restore_list:
if (!grant_user)
goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
res = mysql_show_grants(thd, grant_user);
break;
}
@@ -4409,15 +4799,29 @@ end_with_restore_list:
able to open it (with SQLCOM_HA_OPEN) in the first place.
*/
unit->set_limit(select_lex);
+#ifdef WITH_WSREP
+ { char* tmp_info= NULL;
+ if (WSREP(thd)) tmp_info = (char *)thd_proc_info(thd, "mysql_ha_read()");
+#endif /* WITH_WSREP */
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
unit->select_limit_cnt, unit->offset_limit_cnt);
+#ifdef WITH_WSREP
+ if (WSREP(thd)) thd_proc_info(thd, tmp_info);
+ }
+#endif /* WITH_WSREP */
break;
case SQLCOM_BEGIN:
DBUG_PRINT("info", ("Executing SQLCOM_BEGIN thd: %p", thd));
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:
@@ -4431,7 +4835,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)
@@ -4451,7 +4861,20 @@ end_with_restore_list:
thd->killed= KILL_CONNECTION;
thd->print_aborted_warning(3, "RELEASE");
}
+#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:
@@ -4466,7 +4889,13 @@ end_with_restore_list:
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)
@@ -4483,8 +4912,18 @@ end_with_restore_list:
/* Disconnect the current client connection. */
if (tx_release)
thd->killed= KILL_CONNECTION;
- my_ok(thd);
- break;
+#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:
if (trans_release_savepoint(thd, lex->ident))
@@ -4552,6 +4991,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->m_type, lex->sphead));
switch (sp_result) {
case SP_OK: {
@@ -4762,6 +5202,7 @@ create_sp_error:
already puts on CREATE FUNCTION.
*/
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
sp_result= sp_update_routine(thd, type, lex->spname, &lex->sp_chistics);
switch (sp_result)
{
@@ -4833,6 +5274,7 @@ create_sp_error:
if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
goto error;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
sp_result= sp_drop_routine(thd, type, lex->spname);
@@ -4897,12 +5339,14 @@ create_sp_error:
}
case SQLCOM_SHOW_CREATE_PROC:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
if (sp_show_create_routine(thd, TYPE_ENUM_PROCEDURE, lex->spname))
goto error;
break;
}
case SQLCOM_SHOW_CREATE_FUNC:
{
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
if (sp_show_create_routine(thd, TYPE_ENUM_FUNCTION, lex->spname))
goto error;
break;
@@ -4915,6 +5359,7 @@ create_sp_error:
stored_procedure_type type= (lex->sql_command == SQLCOM_SHOW_PROC_CODE ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION);
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
if (sp_cache_routine(thd, type, lex->spname, FALSE, &sp))
goto error;
if (!sp || sp->show_routine_code(thd))
@@ -4936,6 +5381,7 @@ create_sp_error:
if (check_ident_length(&lex->spname->m_name))
goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
if (show_create_trigger(thd, lex->spname))
goto error; /* Error has been already logged. */
@@ -4955,6 +5401,7 @@ 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;
}
@@ -4988,7 +5435,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
@@ -5000,7 +5453,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
@@ -5159,6 +5618,25 @@ finish:
}
if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
trans_rollback_stmt(thd);
+#ifdef WITH_WSREP
+ else if (thd->spcont &&
+ (thd->wsrep_conflict_state == MUST_ABORT ||
+ thd->wsrep_conflict_state == ABORTED ||
+ thd->wsrep_conflict_state == CERT_FAILURE))
+ {
+ /*
+ The error was cleared, but THD was aborted by wsrep and
+ wsrep_conflict_state is still set accordingly. This
+ situation is expected if we are running a stored procedure
+ that declares a handler that catches ER_LOCK_DEADLOCK error.
+ In which case the error may have been cleared in method
+ sp_rcontext::handle_sql_condition().
+ */
+ trans_rollback_stmt(thd);
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ thd->killed= NOT_KILLED;
+ }
+#endif /* WITH_WSREP */
else
{
/* If commit fails, we should be able to reset the OK status. */
@@ -5173,6 +5651,9 @@ finish:
/* Free 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)
@@ -5226,6 +5707,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());
}
@@ -5308,6 +5805,9 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
status_var_increment(thd->status_var.empty_queries);
else
status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count());
+#ifdef WITH_WSREP
+ if (lex->sql_command == SQLCOM_SHOW_STATUS) wsrep_free_status(thd);
+#endif /* WITH_WSREP */
return res;
}
@@ -5320,6 +5820,7 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
+
/* Don't log SHOW STATUS commands to slow query log */
thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED);
@@ -5390,7 +5891,6 @@ static TABLE *find_temporary_table_for_rename(THD *thd,
DBUG_RETURN(res);
}
-
static bool execute_rename_table(THD *thd, TABLE_LIST *first_table,
TABLE_LIST *all_tables)
{
@@ -5406,7 +5906,7 @@ static bool execute_rename_table(THD *thd, TABLE_LIST *first_table,
&table->next_local->grant.privilege,
&table->next_local->grant.m_internal,
0, 0))
- return 1;
+ return true;
/* check if these are refering to temporary tables */
table->table= find_temporary_table_for_rename(thd, first_table, table);
@@ -5425,10 +5925,17 @@ static bool execute_rename_table(THD *thd, TABLE_LIST *first_table,
INSERT_ACL | CREATE_ACL) &&
check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, FALSE, 1,
FALSE)))
- return 1;
+ return true;
}
+ WSREP_TO_ISOLATION_BEGIN(0, 0, first_table)
+
return mysql_rename_tables(thd, first_table, 0);
+
+#ifdef WITH_WSREP
+error:
+ return true;
+#endif
}
@@ -6334,6 +6841,24 @@ 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 and
+ mysql slave may be processing STATEMENT format events, but he should
+ use autoinc values passed in binlog events, not the values forced by
+ the cluster.
+ */
+ if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE &&
+ !thd->slave_thread && wsrep_auto_increment_control)
+ {
+ thd->variables.auto_increment_offset=
+ global_system_variables.auto_increment_offset;
+ thd->variables.auto_increment_increment=
+ global_system_variables.auto_increment_increment;
+ }
+#endif /* WITH_WSREP */
thd->query_start_used= 0;
thd->query_start_sec_part_used= 0;
thd->is_fatal_error= thd->time_zone_used= 0;
@@ -6539,6 +7064,120 @@ 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;
+
+ do
+ {
+ if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
+ {
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ /* Performance Schema Interface instrumentation, begin */
+ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
+ com_statement_info[thd->get_command()].m_key);
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(),
+ thd->query_length());
+ WSREP_DEBUG("Retry autocommit query: %s", thd->query());
+ }
+
+ 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");
+ }
+
+ if (thd->wsrep_conflict_state == MUST_REPLAY)
+ {
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (thd->lex->explain)
+ delete_explain_query(thd->lex);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ 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= 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");
+
+ /* Performance Schema Interface instrumentation, end */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+ 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);
+ }
+ 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->wsrep_conflict_state= NO_CONFLICT;
+ if (thd->wsrep_conflict_state != REPLAYING)
+ thd->wsrep_retry_counter= 0; // reset
+ }
+
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ thd->reset_killed();
+ }
+ else
+ {
+ set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ }
+
+ /* If retry is requested clean up explain structure */
+ if ((thd->wsrep_conflict_state == RETRY_AUTOCOMMIT ||
+ thd->wsrep_conflict_state == MUST_REPLAY )
+ && thd->lex->explain)
+ delete_explain_query(thd->lex);
+
+ } 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 modify
@@ -6593,6 +7232,7 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
sql_statement_info[thd->lex->sql_command].
m_key);
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect &&
check_mqh(thd, lex->sql_command))
@@ -6667,6 +7307,12 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
sql_statement_info[SQLCOM_SELECT].m_key);
status_var_increment(thd->status_var.com_stat[SQLCOM_SELECT]);
thd->update_stats();
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd))
+ {
+ thd->wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+ }
+#endif /* WITH_WSREP */
}
DBUG_VOID_RETURN;
}
@@ -7565,8 +8211,14 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
faster and do a harder kill than KILL_SYSTEM_THREAD;
*/
+#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 */
{
tmp->awake(kill_signal);
error=0;
@@ -8443,7 +9095,6 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
return definer;
}
-
/**
Check that byte length of a string does not exceed some limit.
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 39d92e656c8..fea13085917 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -209,6 +209,34 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs)
{
return MY_TEST(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);
+
+/* Checks if lex->no_write_to_binlog is set for statements that use
+ LOCAL or NO_WRITE_TO_BINLOG
+*/
+#define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_) \
+ if (WSREP(thd) && !thd->lex->no_write_to_binlog \
+ && wsrep_to_isolation_begin(thd, db_, table_, table_list_)) goto error;
+
+#define WSREP_SYNC_WAIT(thd_, before_) \
+ { if (WSREP_CLIENT(thd_) && \
+ wsrep_sync_wait(thd_, before_)) goto error; }
+
+#else
+
+#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_)
+#define WSREP_TO_ISOLATION_END
+#define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_)
+#define WSREP_SYNC_WAIT(thd_, before_)
+
+#endif /* WITH_WSREP */
#endif /* SQL_PARSE_INCLUDED */
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 39b7f4c49f6..e067f584960 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -530,6 +530,21 @@ bool Sql_cmd_alter_table_exchange_partition::
&alter_prelocking_strategy))
DBUG_RETURN(true);
+#ifdef WITH_WSREP
+ /* Forward declaration */
+ TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
+
+ if ((!thd->is_current_stmt_binlog_format_row() ||
+ /* TODO: Do we really need to check for temp tables in this case? */
+ !find_temporary_table(thd, table_list)) &&
+ wsrep_to_isolation_begin(thd, table_list->db, table_list->table_name,
+ NULL))
+ {
+ WSREP_WARN("ALTER TABLE EXCHANGE PARTITION isolation failure");
+ DBUG_RETURN(TRUE);
+ }
+#endif /* WITH_WSREP */
+
part_table= table_list->table;
swap_table= swap_table_list->table;
@@ -763,6 +778,20 @@ 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
+ /* Forward declaration */
+ TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
+
+ if (WSREP(thd) && (!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 TRUNCATE PARTITION 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 2e0b35f610f..bd0877b3def 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2082,11 +2082,14 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
bool error;
int argc=orig_argc;
char **argv=orig_argv;
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
+ { MYSQL_AUDIT_GENERAL_CLASSMASK };
DBUG_ENTER("mysql_install_plugin");
tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
if (!opt_noacl && check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table = open_ltable(thd, &tables, TL_WRITE,
@@ -2120,8 +2123,7 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
See also mysql_uninstall_plugin() and initialize_audit_plugin()
*/
- unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
- { MYSQL_AUDIT_GENERAL_CLASSMASK };
+
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
@@ -2152,6 +2154,10 @@ err:
if (argv)
free_defaults(argv);
DBUG_RETURN(error);
+#ifdef WITH_WSREP
+ error:
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
}
@@ -2218,12 +2224,15 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
TABLE_LIST tables;
LEX_STRING dl= *dl_arg;
bool error= false;
+ unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
+ { MYSQL_AUDIT_GENERAL_CLASSMASK };
DBUG_ENTER("mysql_uninstall_plugin");
tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
@@ -2260,8 +2269,6 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
See also mysql_install_plugin() and initialize_audit_plugin()
*/
- unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
- { MYSQL_AUDIT_GENERAL_CLASSMASK };
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
@@ -2291,6 +2298,10 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(error);
+#ifdef WITH_WSREP
+ error:
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
}
@@ -3009,11 +3020,17 @@ void plugin_thdvar_init(THD *thd)
thd->variables.dynamic_variables_size= 0;
thd->variables.dynamic_variables_ptr= 0;
+#ifdef WITH_WSREP
+ if (!WSREP(thd) || !thd->wsrep_applier) {
+#endif
mysql_mutex_lock(&LOCK_plugin);
thd->variables.table_plugin=
intern_plugin_lock(NULL, global_system_variables.table_plugin);
intern_plugin_unlock(NULL, old_table_plugin);
mysql_mutex_unlock(&LOCK_plugin);
+#ifdef WITH_WSREP
+ }
+#endif
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 18f95490a82..f12d982c925 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -3550,6 +3550,10 @@ Prepared_statement::set_parameters(String *expanded_query,
return res;
}
+#ifdef WITH_WSREP
+/* forward declaration */
+void wsrep_replay_transaction(THD *thd);
+#endif /* WITH_WSREP */
/**
Execute a prepared statement. Re-prepare it a limited number
@@ -3629,6 +3633,24 @@ reexecute:
error= execute(expanded_query, open_cursor) || thd->is_error();
thd->m_reprepare_observer= NULL;
+#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);
+ /* fallthrough */
+
+ default: break;
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+#endif /* WITH_WSREP */
if ((sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) &&
error && !thd->is_fatal_error && !thd->killed &&
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index f9c5757f721..704e2f84437 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -30,6 +30,7 @@
#include "debug_sync.h"
#include "des_key_file.h"
+
static void disable_checkpoints(THD *thd);
/**
@@ -154,6 +155,12 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
{
if (mysql_bin_log.rotate_and_purge(true))
*write_to_binlog= -1;
+
+ if (WSREP_ON)
+ {
+ /* Wait for last binlog checkpoint event to be logged. */
+ mysql_bin_log.wait_for_last_checkpoint_event();
+ }
}
}
if (options & REFRESH_RELAY_LOG)
@@ -253,7 +260,18 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
}
if (options & REFRESH_CHECKPOINT)
disable_checkpoints(thd);
- }
+#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)
@@ -297,6 +315,16 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
}
}
+#ifdef WITH_WSREP
+ if (thd && thd->wsrep_applier)
+ {
+ /*
+ In case of applier thread, do not wait for table share(s) to be
+ removed from table definition cache.
+ */
+ options|= REFRESH_FAST;
+ }
+#endif
if (close_cached_tables(thd, tables,
((options & REFRESH_FAST) ? FALSE : TRUE),
(thd ? thd->variables.lock_wait_timeout :
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index a2acf52d44e..f1bbe58a8b8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -2996,6 +2996,15 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
err:
mi->unlock_slave_threads();
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ thd_proc_info(thd, "exit stop_slave()");
+ else
+ thd_proc_info(thd, 0);
+#else /* WITH_WSREP */
+ thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
+
if (slave_errno)
{
if (net_report)
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index af02c74c58b..f107028104f 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -59,6 +59,10 @@
#include "debug_sync.h"
#include "keycaches.h"
+#if !defined(MYSQL_MAX_VARIABLE_VALUE_LEN)
+#define MYSQL_MAX_VARIABLE_VALUE_LEN 1024
+#endif // !defined(MYSQL_MAX_VARIABLE_VALUE_LEN)
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
#endif
@@ -118,8 +122,6 @@ static void get_cs_converted_string_value(THD *thd,
static int show_create_view(THD *thd, TABLE_LIST *table, String *buff);
-static void append_algorithm(TABLE_LIST *table, String *buff);
-
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
/**
@@ -2099,32 +2101,30 @@ static void store_key_options(THD *thd, String *packet, TABLE *table,
}
}
-
-void
-view_store_options(THD *thd, TABLE_LIST *table, String *buff)
-{
- append_algorithm(table, buff);
- append_definer(thd, buff, &table->definer.user, &table->definer.host);
- if (table->view_suid)
- buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
- else
- buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER "));
-}
-
-
/*
- Append DEFINER clause to the given buffer.
+ Append ALGORITHM clause to the given buffer.
SYNOPSIS
- append_definer()
- thd [in] thread handle
- buffer [inout] buffer to hold DEFINER clause
- definer_user [in] user name part of definer
- definer_host [in] host name part of definer
+ append_algorithm()
+ table [in] table list
+ buff [inout] buffer to hold the ALGORITHM clause
+ check_inherit [in] if true, do nothing if algorithm is INHERIT
*/
-static void append_algorithm(TABLE_LIST *table, String *buff)
+static void append_algorithm(TABLE_LIST *table, String *buff,
+ bool check_inherit)
{
+ int16 algorithm= (int16) table->algorithm;
+
+ DBUG_ENTER("append_algorithm");
+
+ /*
+ Handle a special case when ALGORITHM is not specified, in which case we
+ simply return.
+ */
+ if (check_inherit && (algorithm == VIEW_ALGORITHM_INHERIT))
+ DBUG_VOID_RETURN;
+
buff->append(STRING_WITH_LEN("ALGORITHM="));
switch ((int16)table->algorithm) {
case VIEW_ALGORITHM_UNDEFINED:
@@ -2139,6 +2139,8 @@ static void append_algorithm(TABLE_LIST *table, String *buff)
default:
DBUG_ASSERT(0); // never should happen
}
+
+ DBUG_VOID_RETURN;
}
/*
@@ -2157,7 +2159,7 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
{
buffer->append(STRING_WITH_LEN("DEFINER="));
append_identifier(thd, buffer, definer_user->str, definer_user->length);
- if (definer_host->str[0])
+ if (definer_host->str && definer_host->str[0])
{
buffer->append('@');
append_identifier(thd, buffer, definer_host->str, definer_host->length);
@@ -2165,6 +2167,23 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
buffer->append(' ');
}
+void
+view_store_options4(THD *thd, TABLE_LIST *table, String *buff,
+ bool check_inherit)
+{
+ append_algorithm(table, buff, check_inherit);
+ append_definer(thd, buff, &table->definer.user, &table->definer.host);
+ if (table->view_suid)
+ buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
+ else
+ buff->append(STRING_WITH_LEN("SQL SECURITY INVOKER "));
+}
+
+void
+view_store_options(THD *thd, TABLE_LIST *table, String *buff)
+{
+ view_store_options4(thd, table, buff, false);
+}
static int show_create_view(THD *thd, TABLE_LIST *table, String *buff)
{
@@ -3019,11 +3038,39 @@ static bool show_status_array(THD *thd, const char *wild,
*prefix_end++= '_';
len=name_buffer + sizeof(name_buffer) - prefix_end;
+#ifdef WITH_WSREP
+ bool is_wsrep_var= FALSE;
+ /*
+ This is a workaround for lp:1306875 (PBX) to skip switching of wsrep
+ status variable name's first letter to uppercase. This is an optimization
+ for status variables defined under wsrep plugin.
+ TODO: remove once lp:1306875 has been addressed.
+ */
+ if (*prefix && !my_strcasecmp(system_charset_info, prefix, "wsrep"))
+ {
+ is_wsrep_var= TRUE;
+ }
+#endif /* WITH_WSREP */
+
for (; variables->name; variables++)
{
bool wild_checked= 0;
strnmov(prefix_end, variables->name, len);
name_buffer[sizeof(name_buffer)-1]=0; /* Safety */
+
+#ifdef WITH_WSREP
+ /*
+ If the prefix is NULL, that means we are looking into the status variables
+ defined directly under mysqld.cc. Do not capitalize wsrep status variable
+ names until lp:1306875 has been fixed.
+ TODO: remove once lp:1306875 has been addressed.
+ */
+ if (!(*prefix) && !strncasecmp(name_buffer, "wsrep", strlen("wsrep")))
+ {
+ is_wsrep_var= TRUE;
+ }
+#endif /* WITH_WSREP */
+
if (ucase_names)
my_caseup_str(system_charset_info, name_buffer);
else
@@ -3032,8 +3079,13 @@ static bool show_status_array(THD *thd, const char *wild,
DBUG_ASSERT(name_buffer[0] >= 'a');
DBUG_ASSERT(name_buffer[0] <= 'z');
+#ifdef WITH_WSREP
+ // TODO: remove once lp:1306875 has been addressed.
+ if (status_var && (is_wsrep_var == FALSE))
+#else
/* traditionally status variables have a first letter uppercased */
if (status_var)
+#endif /* WITH_WSREP */
name_buffer[0]-= 'a' - 'A';
}
@@ -8940,7 +8992,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_show.h b/sql/sql_show.h
index 9ca60557cc0..c1c6388216d 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -109,6 +109,8 @@ void free_status_vars();
void reset_status_vars();
bool show_create_trigger(THD *thd, const sp_name *trg_name);
void view_store_options(THD *thd, TABLE_LIST *table, String *buff);
+void view_store_options4(THD *thd, TABLE_LIST *table, String *buff,
+ bool check_inherit);
void init_fill_schema_files_row(TABLE* table);
bool schema_table_store_record(THD *thd, TABLE *table);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9a2b4901d4e..d9e00602dfc 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2111,6 +2111,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
DBUG_RETURN(TRUE);
my_ok(thd);
DBUG_RETURN(FALSE);
+
}
@@ -2157,7 +2158,6 @@ static uint32 comment_length(THD *thd, uint32 comment_pos,
return 0;
}
-
/**
Execute the drop of a normal or temporary table.
@@ -2592,6 +2592,9 @@ err:
/* Chop of the last comma */
built_non_trans_tmp_query.chop();
built_non_trans_tmp_query.append(" /* generated by server */");
+#ifdef WITH_WSREP
+ thd->wsrep_skip_wsrep_GTID = true;
+#endif /* WITH_WSREP */
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_non_trans_tmp_query.ptr(),
built_non_trans_tmp_query.length(),
@@ -2604,6 +2607,9 @@ err:
/* Chop of the last comma */
built_trans_tmp_query.chop();
built_trans_tmp_query.append(" /* generated by server */");
+#ifdef WITH_WSREP
+ thd->wsrep_skip_wsrep_GTID = true;
+#endif /* WITH_WSREP */
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_trans_tmp_query.ptr(),
built_trans_tmp_query.length(),
@@ -2618,6 +2624,9 @@ err:
built_query.append(" /* generated by server */");
int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno()
: 0;
+#ifdef WITH_WSREP
+ thd->wsrep_skip_wsrep_GTID = false;
+#endif /* WITH_WSREP */
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_query.ptr(),
built_query.length(),
@@ -2666,6 +2675,9 @@ err:
}
end:
+#ifdef WITH_WSREP
+ thd->wsrep_skip_wsrep_GTID = false;
+#endif /* WITH_WSREP */
DBUG_RETURN(error);
}
@@ -5310,8 +5322,64 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
bool do_logging= FALSE;
uint not_used;
int create_res;
+ uint save_thd_create_info_options;
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;
+ bzero((void*) &tbl, 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) show_create_table(thd, &tbl, &query, NULL, WITH_DB_NAME);
+ 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
and Alter_info objects. This also acquires a shared metadata lock
@@ -5325,7 +5393,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
*/
/* Copy temporarily the statement flags to thd for lock_table_names() */
- uint save_thd_create_info_options= thd->lex->create_info.options;
+ save_thd_create_info_options= thd->lex->create_info.options;
thd->lex->create_info.options|= create_info->options;
res= open_tables(thd, &thd->lex->query_tables, &not_used, 0);
thd->lex->create_info.options= save_thd_create_info_options;
@@ -5599,6 +5667,13 @@ err:
res= 1;
}
DBUG_RETURN(res);
+
+#ifdef WITH_WSREP
+ error:
+ thd->wsrep_TOI_pre_query= NULL;
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
+
}
@@ -8232,6 +8307,10 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
: HA_EXTRA_FORCE_REOPEN;
DBUG_ENTER("simple_rename_or_index_change");
+#ifdef WITH_WSREP
+ bool do_log_write(true);
+#endif /* WITH_WSREP */
+
if (keys_onoff != Alter_info::LEAVE_AS_IS)
{
if (wait_while_table_is_used(thd, table, extra_func))
@@ -8291,7 +8370,14 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
if (!error)
{
- error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+#ifdef WITH_WSREP
+ if (!WSREP(thd) || do_log_write) {
+#endif /* WITH_WSREP */
+ error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
+#ifdef WITH_WSREP
+ }
+#endif /* !WITH_WSREP */
+
if (!error)
my_ok(thd);
}
@@ -8418,6 +8504,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 2f3145b9aaf..784464110cf 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -435,8 +435,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);
@@ -503,6 +509,9 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
goto end;
}
+ if (thd->wsrep_exec_mode == LOCAL_STATE)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+
/* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0);
@@ -606,6 +615,10 @@ end:
my_ok(thd);
DBUG_RETURN(result);
+#ifdef WITH_WSREP
+ error:
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
}
@@ -2441,3 +2454,59 @@ 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, false)))
+ return 1;
+ }
+ }
+
+ if (lex->definer)
+ {
+ /* SUID trigger. */
+ LEX_USER *d= get_current_user(thd, lex->definer);
+
+ if (!d)
+ return 1;
+
+ definer_user= d->user;
+ definer_host= d->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 f5161c09b2c..18c2e3dffed 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -24,6 +24,9 @@
#include "sql_acl.h" // DROP_ACL
#include "sql_parse.h" // check_one_table_access()
#include "sql_truncate.h"
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
#include "sql_show.h" //append_identifier()
@@ -484,6 +487,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);
@@ -566,6 +575,5 @@ 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 94fbe0924b6..4a1d72d0ed7 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -985,7 +985,11 @@ int mysql_update(THD *thd,
*/
if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
+#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)
@@ -2257,7 +2261,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
@@ -2529,7 +2537,11 @@ bool multi_update::send_eof()
if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table)
{
+#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_view.cc b/sql/sql_view.cc
index 9fe4dd4849d..8fdd86535d1 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -429,6 +429,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
lex->link_first_table_back(view, link_to_local);
view->open_type= OT_BASE_ONLY;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/*
ignore lock specs for CREATE statement
@@ -686,6 +687,10 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
lex->link_first_table_back(view, link_to_local);
DBUG_RETURN(0);
+#ifdef WITH_WSREP
+ error:
+ res= TRUE;
+#endif /* WITH_WSREP */
err:
THD_STAGE_INFO(thd, stage_end);
lex->link_first_table_back(view, link_to_local);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 321e6ffc9cd..0e222bf3504 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -7135,7 +7135,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
@@ -7147,9 +7147,12 @@ alter:
if (!(Lex->event_parse_data= Event_parse_data::new_instance(thd)))
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
@@ -7157,7 +7160,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;
@@ -7167,6 +7170,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 a21fe5df247..2348cb4d45d 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -446,6 +446,27 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var)
if (check_has_super(self, thd, var))
return true;
+#ifdef WITH_WSREP
+ /*
+ MariaDB Galera does not support STATEMENT or MIXED binlog format currently.
+ */
+ if (WSREP(thd) &&
+ var->save_result.ulonglong_value != BINLOG_FORMAT_ROW)
+ {
+ // Push a warning to the error log.
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+ "MariaDB Galera does not support binlog format: %s",
+ binlog_format_names[var->save_result.ulonglong_value]);
+
+ if (var->type == OPT_GLOBAL)
+ {
+ WSREP_ERROR("MariaDB Galera does not support binlog format: %s",
+ binlog_format_names[var->save_result.ulonglong_value]);
+ return true;
+ }
+ }
+#endif
+
if (var->type == OPT_GLOBAL)
return false;
@@ -3363,6 +3384,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;
}
/*
@@ -4474,6 +4499,278 @@ static Sys_var_tz Sys_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_NONE),
+ 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(""), 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(mysql_real_data_home),
+ 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(""),
+ &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(glob_hostname), NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ wsrep_node_name_check, wsrep_node_name_update);
+
+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(""),
+ 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_AUTO),
+ 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(NULL),
+ 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_DEFAULT), 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_ADDRESS_AUTO), 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(NULL), 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(check_has_super),
+ 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_ZERO),
+ 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),
+ VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(WSREP_MAX_WS_SIZE),
+ BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(wsrep_max_ws_size_update));
+
+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(0, 1048576), DEFAULT(0), 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 and BEGIN/START TRANSACTION); 2 - UPDATE and DELETE; 4 - "
+ "INSERT and REPLACE; 8 - SHOW",
+ 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",
+ SESSION_VAR(wsrep_OSU_method), 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_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 checks",
+ 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));
+
+static Sys_var_mybool Sys_wsrep_dirty_reads(
+ "wsrep_dirty_reads",
+ "Allow reads even when the node is not in the primary component.",
+ SESSION_VAR(wsrep_dirty_reads), CMD_LINE(OPT_ARG),
+ DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG);
+
+#endif /* WITH_WSREP */
+
static bool fix_host_cache_size(sys_var *, THD *, enum_var_type)
{
hostname_cache_resize((uint) host_cache_size);
@@ -4830,3 +5127,13 @@ static Sys_var_mybool Sys_pseudo_slave_mode(
SESSION_ONLY(pseudo_slave_mode), NO_CMD_LINE, DEFAULT(FALSE),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_pseudo_slave_mode));
+#ifdef HAVE_MMAP
+static Sys_var_ulong Sys_log_tc_size(
+ "log_tc_size",
+ "Size of transaction coordinator log.",
+ READ_ONLY GLOBAL_VAR(opt_tc_log_size),
+ CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(my_getpagesize() * 3, ULONG_MAX),
+ DEFAULT(my_getpagesize() * 6),
+ BLOCK_SIZE(my_getpagesize()));
+#endif
diff --git a/sql/table.cc b/sql/table.cc
index 5ea5d8cf3c5..757e1fa444e 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -39,6 +39,9 @@
#include "sql_statistics.h"
#include "discover.h"
#include "mdl.h" // MDL_wait_for_graph_visitor
+#ifdef WITH_WSREP
+#include "ha_partition.h"
+#endif /* WITH_WSREP */
/* INFORMATION_SCHEMA name */
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 1d5ad9aa1b0..1a98b54edef 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -98,6 +98,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));
@@ -136,10 +139,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 | OPTION_KEEP_LOG);
@@ -184,6 +193,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)
@@ -215,10 +230,16 @@ bool trans_commit(THD *thd)
if (trans_check(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);
+#ifdef WITH_WSREP
+ wsrep_post_commit(thd, TRUE);
+#endif /* WITH_WSREP */
/*
if res is non-zero, then ha_commit_trans has rolled back the
transaction, so the hooks for rollback will be called.
@@ -264,10 +285,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;
+#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 | OPTION_KEEP_LOG);
@@ -300,9 +327,15 @@ bool trans_rollback(THD *thd)
int res;
DBUG_ENTER("trans_rollback");
+#ifdef WITH_WSREP
+ thd->wsrep_PA_safe= true;
+#endif /* WITH_WSREP */
if (trans_check(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"));
@@ -393,11 +426,17 @@ 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())
{
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 */
}
}
@@ -438,6 +477,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())
{
@@ -807,9 +849,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)
{
@@ -828,6 +876,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/tztime.cc b/sql/tztime.cc
index 9933c1e6364..d07d87e7b2f 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2705,6 +2705,12 @@ main(int argc, char **argv)
free_defaults(default_argv);
return 1;
}
+
+#ifdef WITH_WSREP
+ // Replicate MyISAM DDL for this session, cf. lp:1161432
+ printf("SET GLOBAL wsrep_replicate_myisam= ON;\n");
+#endif /* WITH_WSREP */
+
if (argc == 1 && !opt_leap)
{
/* Argument is timezonedir */
@@ -2752,6 +2758,11 @@ main(int argc, char **argv)
free_root(&tz_storage, MYF(0));
}
+#ifdef WITH_WSREP
+ // Reset wsrep_replicate_myisam. lp:1161432
+ printf("SET GLOBAL wsrep_replicate_myisam= OFF;\n");
+#endif /* WITH_WSREP */
+
free_defaults(default_argv);
my_end(0);
return 0;
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
new file mode 100644
index 00000000000..db92878dbe5
--- /dev/null
+++ b/sql/wsrep_applier.cc
@@ -0,0 +1,403 @@
+/* Copyright (C) 2013-2015 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_applier.h"
+#include "wsrep_priv.h"
+#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
+#include "wsrep_xid.h"
+
+#include "log_event.h" // class THD, EVENT_LEN_OFFSET, etc.
+#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;
+
+ res= Log_event::read_log_event(buf, data_len, &error, description_event,
+ true);
+
+ 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_rgi->rli->relay_log.description_event_for_exec;
+}
+
+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;
+ Log_event_type typ;
+
+ DBUG_ENTER("wsrep_apply_events");
+
+ if (thd->killed == 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;
+ }
+
+ typ= ev->get_type_code();
+
+ switch (typ) {
+ case FORMAT_DESCRIPTION_EVENT:
+ wsrep_set_apply_format(thd, (Format_description_log_event*)ev);
+ continue;
+#ifdef GTID_SUPPORT
+ 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;
+ }
+ }
+#endif /* GTID_SUPPORT */
+ default:
+ break;
+ }
+
+ /* Use the original server id for logging. */
+ thd->set_server_id(ev->server_id);
+ 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)
+ {
+ my_hrtime_t hrtime= my_hrtime();
+ ev->when= hrtime_to_my_time(hrtime);
+ ev->when_sec_part= hrtime_sec_part(hrtime);
+ }
+
+ thd->variables.option_bits=
+ (thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) |
+ (ev->flags & LOG_EVENT_SKIP_REPLICATION_F ? OPTION_SKIP_REPLICATION : 0);
+
+ ev->thd = thd;
+ exec_res = ev->apply_event(thd->wsrep_rgi);
+ 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_or_keep_event_post_apply(thd->wsrep_rgi, typ, 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 == 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);
+
+ assert(thd->wsrep_apply_toi == false);
+
+ // Allow tests to block the applier thread using the DBUG facilities.
+ DBUG_EXECUTE_IF("sync.wsrep_apply_cb",
+ {
+ const char act[]=
+ "now "
+ "SIGNAL sync.wsrep_apply_cb_reached "
+ "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)
+{
+#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);
+
+ if (WSREP_CB_SUCCESS == rcode)
+ {
+ thd->wsrep_rgi->cleanup_context(thd, false);
+#ifdef GTID_SUPPORT
+ thd->variables.gtid_next.set_automatic();
+#endif /* GTID_SUPPORT */
+ if (thd->wsrep_apply_toi)
+ {
+ wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ }
+ }
+
+#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 */
+
+ return rcode;
+}
+
+static wsrep_cb_status_t wsrep_rollback(THD* const thd)
+{
+#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 */
+
+ 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);
+ else
+ rcode = wsrep_rollback(thd);
+
+ 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 (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 00000000000..424db466e53
--- /dev/null
+++ b/sql/wsrep_applier.h
@@ -0,0 +1,39 @@
+/* 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 <my_config.h>
+#include "../wsrep/wsrep_api.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 00000000000..5c5ebb9f780
--- /dev/null
+++ b/sql/wsrep_binlog.cc
@@ -0,0 +1,412 @@
+/* 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(MY_ALLOW_ZERO_PTR));
+ 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;
+ }
+
+ 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(MY_ALLOW_ZERO_PTR));
+ 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)
+ {
+ if (fwrite(rbr_buf, buf_len, 1, of) == 0)
+ WSREP_ERROR("Failed to write buffer of length %llu to '%s'",
+ (unsigned long long)buf_len, filename);
+
+ fclose(of);
+ }
+ else
+ {
+ WSREP_ERROR("Failed to open file '%s': %d (%s)",
+ filename, errno, strerror(errno));
+ }
+}
+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;
+}
+
+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);
+}
diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h
new file mode 100644
index 00000000000..c29d51caf2c
--- /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 2147483647 /* 2GB */
+
+/*
+ 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 00000000000..188f0696bff
--- /dev/null
+++ b/sql/wsrep_check_opts.cc
@@ -0,0 +1,396 @@
+/* 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
+#if 0
+ { "query_cache_type", "0" }, // mysqld.cc
+ { "query_cache_size", "0" }, // mysqld.cc
+#endif
+ { "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,
+#if 0
+ QUERY_CACHE_TYPE,
+ QUERY_CACHE_SIZE,
+#endif
+ 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;
+
+ /*
+ We're interested only in long options, ensure that the arg is of
+ sufficient length.
+ */
+ if (strlen(a.argv_[i]) > 2)
+ {
+ ptr= a.argv_[i] + 2;
+ }
+ else
+ {
+ continue;
+ }
+
+ 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 00000000000..734a0686a6d
--- /dev/null
+++ b/sql/wsrep_hton.cc
@@ -0,0 +1,638 @@
+/* Copyright 2008-2015 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 "rpl_filter.h"
+#include <sql_class.h>
+#include "wsrep_mysqld.h"
+#include "wsrep_binlog.h"
+#include "wsrep_xid.h"
+#include <cstdio>
+#include <cstdlib>
+#include "debug_sync.h"
+
+extern handlerton *binlog_hton;
+extern int binlog_close_connection(handlerton *hton, THD *thd);
+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(thd)) return;
+
+ 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;
+ thd->wsrep_affected_rows= 0;
+ thd->wsrep_skip_wsrep_GTID= false;
+ 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)
+ {
+ if (thd->wsrep_exec_mode == LOCAL_STATE &&
+ (thd_sql_command(thd) == SQLCOM_OPTIMIZE ||
+ thd_sql_command(thd) == SQLCOM_ANALYZE ||
+ thd_sql_command(thd) == SQLCOM_REPAIR) &&
+ thd->lex->no_write_to_binlog == 1)
+ {
+ WSREP_DEBUG("Skipping wsrep_register_hton for LOCAL sql admin command : %s",
+ thd->query());
+ return;
+ }
+
+ 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) ||
+ (i->ht()->db_type == DB_TYPE_TOKUDB))
+ {
+ 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)
+{
+ if (!WSREP(thd)) return;
+
+ switch (thd->wsrep_exec_mode)
+ {
+ case LOCAL_COMMIT:
+ {
+ DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
+ if (wsrep && 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");
+ /*
+ Run post-rollback hook to clean up in the case if
+ some keys were populated for the transaction in provider
+ but during commit time there was no write set to replicate.
+ This may happen when client sets the SAVEPOINT and immediately
+ rolls back to savepoint after first operation.
+ */
+ if (all && thd->wsrep_conflict_state != MUST_REPLAY &&
+ wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
+ {
+ WSREP_WARN("post_rollback fail: %llu %d",
+ (long long)thd->thread_id, thd->get_stmt_da()->status());
+ }
+ 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);
+ }
+
+ if (wsrep_emulate_bin_log && thd_get_ha_data(thd, binlog_hton) != NULL)
+ binlog_hton->close_connection (binlog_hton, thd);
+ DBUG_RETURN(0);
+}
+
+/*
+ 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 && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
+ {
+ DBUG_PRINT("wsrep", ("setting rollback fail"));
+ WSREP_ERROR("settting rollback fail: thd: %llu, schema: %s, SQL: %s",
+ (long long)thd->real_id, (thd->db ? thd->db : "(null)"),
+ 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_PROVIDER_EXISTS) {
+ if (wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
+ {
+ DBUG_PRINT("wsrep", ("setting rollback fail"));
+ WSREP_ERROR("settting rollback fail: thd: %llu, schema: %s, SQL: %s",
+ (long long)thd->real_id, (thd->db ? thd->db : "(null)"),
+ 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_DEBUG("commit issue, error: %d %s",
+ thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
+ }
+
+ DBUG_ENTER("wsrep_run_wsrep_commit");
+
+ DEBUG_SYNC(thd, "wsrep_before_replication");
+
+ 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 == 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"
+ "schema: %s \n"
+ "QUERY: %s\n"
+ " => Skipping replication",
+ thd->thread_id, data_len,
+ (thd->db ? thd->db : "(null)"), 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, schema: %s, SQL: %s",
+ thd->thread_id, (thd->db ? thd->db : "(null)"), 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);
+
+ DEBUG_SYNC(thd, "wsrep_after_replication");
+
+ 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 00000000000..5b6575e7166
--- /dev/null
+++ b/sql/wsrep_mysqld.cc
@@ -0,0 +1,1742 @@
+/* Copyright 2008-2015 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.x1
+
+ 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 <sql_plugin.h> // SHOW_MY_BOOL
+#include <mysqld.h>
+#include <sql_class.h>
+#include <sql_parse.h>
+#include <sql_base.h> /* find_temporary_table() */
+#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 "wsrep_xid.h"
+#include <cstdio>
+#include <cstdlib>
+#include "log_event.h"
+#include <slave.h>
+
+wsrep_t *wsrep = NULL;
+my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
+#ifdef GTID_SUPPORT
+/* Sidno in global_sid_map corresponding to group uuid */
+rpl_sidno wsrep_sidno= -1;
+#endif /* GTID_SUPPORT */
+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
+// Allow reads even if the node is not in the primary component.
+bool wsrep_dirty_reads = false;
+
+/*
+ Set during the creation of first wsrep applier and rollback threads.
+ Since these threads are critical, abort if the thread creation fails.
+*/
+my_bool wsrep_creating_startup_threads = 0;
+
+/*
+ * End configuration options
+ */
+
+/*
+ * Other wsrep global variables.
+ */
+my_bool wsrep_inited = 0; // initialized ?
+
+static 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);
+}
+
+#ifdef GTID_SUPPORT
+void wsrep_init_sidno(const wsrep_uuid_t& wsrep_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] = ~wsrep_uuid.data[i];
+ }
+
+ sid.copy_from(ltid_uuid.data);
+ global_sid_lock->wrlock();
+ wsrep_sidno= global_sid_map->add_sid(sid);
+ WSREP_INFO("Initialized wsrep sidno %d", wsrep_sidno);
+ global_sid_lock->unlock();
+}
+#endif /* GTID_SUPPORT */
+
+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(&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)
+ {
+#ifdef HAVE_QUERY_CACHE
+ // query cache must be initialised by now
+ query_cache.flush();
+#endif /* HAVE_QUERY_CACHE */
+
+ 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_get();
+ 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 */
+ wsrep_set_SE_checkpoint(local_uuid, local_seqno);
+#ifdef GTID_SUPPORT
+ wsrep_init_sidno(local_uuid);
+#endif /* GTID_SUPPORT */
+ new_status= WSREP_MEMBER_JOINED;
+ }
+
+ // 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;
+}
+
+my_bool wsrep_ready_set (my_bool x)
+{
+ WSREP_DEBUG("Setting wsrep_ready to %d", x);
+ if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
+ my_bool ret= (wsrep_ready != x);
+ if (ret)
+ {
+ wsrep_ready= x;
+ mysql_cond_signal (&COND_wsrep_ready);
+ }
+ mysql_mutex_unlock (&LOCK_wsrep_ready);
+ return ret;
+}
+
+my_bool wsrep_ready_get (void)
+{
+ if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
+ my_bool ret= wsrep_ready;
+ mysql_mutex_unlock (&LOCK_wsrep_ready);
+ return ret;
+}
+
+int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type= SHOW_MY_BOOL;
+ var->value= buff;
+ *((my_bool *)buff)= wsrep_ready_get();
+ return 0;
+}
+
+// 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");
+ my_bool signal_main= wsrep_ready_set(TRUE);
+ local_status.set(WSREP_MEMBER_SYNCED);
+
+ 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,
+ master_info_file,
+ relay_log_info_file,
+ 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 */
+ wsrep_uuid_t uuid;
+ wsrep_seqno_t seqno;
+ wsrep_get_SE_checkpoint(uuid, seqno);
+
+ if (!memcmp(&uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)))
+ {
+ WSREP_INFO("Read nil XID from storage engines, skipping position init");
+ return;
+ }
+
+ 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");
+ }
+}
+
+extern char* my_bind_addr_str;
+
+int wsrep_init()
+{
+ int rcode= -1;
+ DBUG_ASSERT(wsrep_inited == 0);
+
+ 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
+ return wsrep_init();
+ }
+ 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 (!WSREP_PROVIDER_EXISTS)
+ {
+ // enable normal operation in case no provider is specified
+ wsrep_ready_set(TRUE);
+ wsrep_inited= 1;
+ 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);
+ }
+
+ 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)
+ {
+ size_t const ip_len= wsrep_host_len(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';
+ }
+ }
+
+ 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;
+ } else {
+ wsrep_inited= 1;
+ }
+
+ 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 dummy wsrep provider is loaded */
+ if (!strcmp(wsrep_provider, WSREP_NONE)) return;
+
+ /* 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_creating_startup_threads= 1;
+ wsrep_create_rollbacker();
+ wsrep_create_appliers(1);
+
+ if (first && !wsrep_sst_wait()) unireg_abort(1);// wait until SST is completed
+}
+
+
+void wsrep_deinit(bool free_options)
+{
+ DBUG_ASSERT(wsrep_inited == 1);
+ wsrep_unload(wsrep);
+ wsrep= 0;
+ provider_name[0]= '\0';
+ provider_version[0]= '\0';
+ provider_vendor[0]= '\0';
+
+ wsrep_inited= 0;
+
+ if (free_options)
+ {
+ wsrep_sst_auth_free();
+ }
+}
+
+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;
+ }
+ wsrep_uuid_t uuid;
+ wsrep_seqno_t seqno;
+ wsrep_get_SE_checkpoint(uuid, seqno);
+ char uuid_str[40];
+ wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str));
+ WSREP_INFO("Recovered position: %s:%lld", uuid_str, (long long)seqno);
+}
+
+
+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;
+}
+
+
+bool wsrep_start_replication()
+{
+ wsrep_status_t rcode;
+
+ /*
+ if provider is trivial, don't even try to connect,
+ but resume local node operation
+ */
+ if (!WSREP_PROVIDER_EXISTS)
+ {
+ // 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= wsrep_new_cluster;
+
+ WSREP_INFO("Start replication");
+
+ if (wsrep_new_cluster)
+ {
+ WSREP_INFO("'wsrep-new-cluster' option used, bootstrapping the cluster");
+ wsrep_new_cluster= false;
+ }
+
+ if ((rcode = wsrep->connect(wsrep,
+ wsrep_cluster_name,
+ wsrep_cluster_address,
+ wsrep_sst_donor,
+ bootstrap)))
+ {
+ DBUG_PRINT("wsrep",("wsrep->connect(%s) failed: %d",
+ wsrep_cluster_address, rcode));
+ WSREP_ERROR("wsrep::connect(%s) failed: %d",
+ wsrep_cluster_address, 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_must_sync_wait (THD* thd, uint mask)
+{
+ return (thd->variables.wsrep_sync_wait & mask) &&
+ thd->variables.wsrep_on &&
+ !(thd->variables.wsrep_dirty_reads &&
+ !is_update_query(thd->lex->sql_command)) &&
+ !thd->in_active_multi_stmt_transaction() &&
+ thd->wsrep_conflict_state != REPLAYING &&
+ thd->wsrep_sync_wait_gtid.seqno == WSREP_SEQNO_UNDEFINED;
+}
+
+bool wsrep_sync_wait (THD* thd, uint mask)
+{
+ if (wsrep_must_sync_wait(thd, mask))
+ {
+ 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_status_t ret= wsrep->causal_read (wsrep, &thd->wsrep_sync_wait_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;
+}
+
+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 */
+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;
+
+ if (db || 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 (1)");
+ goto err;
+ }
+ }
+
+ for (const TABLE_LIST* table= table_list; table; table= table->next_global)
+ {
+ wsrep_key_t* tmp;
+ if (ka->keys)
+ tmp= (wsrep_key_t*)my_realloc(ka->keys,
+ (ka->keys_len + 1) * sizeof(wsrep_key_t),
+ MYF(0));
+ else
+ tmp= (wsrep_key_t*)my_malloc((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 (2)");
+ goto err;
+ }
+ }
+ return 0;
+err:
+ wsrep_keys_free(ka);
+ return 1;
+}
+
+
+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);
+
+ Format_description_log_event *tmp_fd= new Format_description_log_event(4);
+ tmp_fd->checksum_alg= binlog_checksum_options;
+ tmp_fd->write(&tmp_io_cache);
+ delete tmp_fd;
+
+#ifdef GTID_SUPPORT
+ 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;
+ }
+#endif /* GTID_SUPPORT */
+
+ /* 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);
+
+ LEX_USER *definer;
+
+ if (lex->definer)
+ {
+ definer= get_current_user(thd, lex->definer);
+ }
+ else
+ {
+ /*
+ 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.
+ */
+ definer= create_default_definer(thd, false);
+ }
+
+ if (definer)
+ {
+ views->definer.user = definer->user;
+ views->definer.host = definer->host;
+ } else {
+ WSREP_ERROR("Failed to get DEFINER for VIEW.");
+ return 1;
+ }
+
+ views->algorithm = lex->create_view_algorithm;
+ views->view_suid = lex->create_view_suid;
+ views->with_check = lex->create_view_check;
+
+ view_store_options4(thd, views, &buff, true);
+ 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);
+}
+
+/*
+ Rewrite DROP TABLE for TOI. Temporary tables are eliminated from
+ the query as they are visible only to client connection.
+
+ TODO: See comments for sql_base.cc:drop_temporary_table() and refine
+ the function to deal with transactional locked tables.
+ */
+static int wsrep_drop_table_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;
+ String buff;
+
+ DBUG_ASSERT(!lex->drop_temporary);
+
+ bool found_temp_table= false;
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (find_temporary_table(thd, table->db, table->table_name))
+ {
+ found_temp_table= true;
+ break;
+ }
+ }
+
+ if (found_temp_table)
+ {
+ buff.append("DROP TABLE ");
+ if (lex->check_exists)
+ buff.append("IF EXISTS ");
+
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (!find_temporary_table(thd, table->db, table->table_name))
+ {
+ append_identifier(thd, &buff, table->db, strlen(table->db));
+ buff.append(".");
+ append_identifier(thd, &buff, table->table_name,
+ strlen(table->table_name));
+ buff.append(",");
+ }
+ }
+
+ /* Chop the last comma */
+ buff.chop();
+ buff.append(" /* generated by wsrep */");
+
+ WSREP_DEBUG("Rewrote '%s' as '%s'", thd->query(), buff.ptr());
+
+ return wsrep_to_buf_helper(thd, buff.ptr(), buff.length(), buf, buf_len);
+ }
+ else
+ {
+ return wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
+ buf, buf_len);
+ }
+}
+
+/*
+ Decide if statement should run in TOI.
+
+ Look if table or table_list contain temporary tables. If the
+ statement affects only temporary tables, statement should not run
+ in TOI. If the table list contains mix of regular and temporary tables
+ (DROP TABLE, OPTIMIZE, ANALYZE), statement should be run in TOI but
+ should be rewritten at later time for replication to contain only
+ non-temporary tables.
+ */
+static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
+ const TABLE_LIST *table_list)
+{
+ DBUG_ASSERT(!table || db);
+ DBUG_ASSERT(table_list || db);
+
+ LEX* lex= thd->lex;
+ SELECT_LEX* select_lex= &lex->select_lex;
+ TABLE_LIST* first_table= select_lex->table_list.first;
+
+ switch (lex->sql_command)
+ {
+ case SQLCOM_CREATE_TABLE:
+ DBUG_ASSERT(!table_list);
+ if (thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ return false;
+ }
+ return true;
+
+ case SQLCOM_CREATE_VIEW:
+
+ DBUG_ASSERT(!table_list);
+ DBUG_ASSERT(first_table); /* First table is view name */
+ /*
+ If any of the remaining tables refer to temporary table error
+ is returned to client, so TOI can be skipped
+ */
+ for (TABLE_LIST* it= first_table->next_global; it; it= it->next_global)
+ {
+ if (find_temporary_table(thd, it))
+ {
+ return false;
+ }
+ }
+ return true;
+
+ case SQLCOM_CREATE_TRIGGER:
+
+ DBUG_ASSERT(!table_list);
+ DBUG_ASSERT(first_table);
+
+ if (find_temporary_table(thd, first_table))
+ {
+ return false;
+ }
+ return true;
+
+ default:
+ if (table && !find_temporary_table(thd, db, table))
+ {
+ return true;
+ }
+
+ if (table_list)
+ {
+ for (TABLE_LIST* table= first_table; table; table= table->next_global)
+ {
+ if (!find_temporary_table(thd, table->db, table->table_name))
+ {
+ return true;
+ }
+ }
+ }
+ return !(table || table_list);
+ }
+}
+
+static const char* wsrep_get_query_or_msg(const THD* thd)
+{
+ switch(thd->lex->sql_command)
+ {
+ case SQLCOM_CREATE_USER:
+ return "CREATE USER";
+ case SQLCOM_GRANT:
+ return "GRANT";
+ case SQLCOM_REVOKE:
+ return "REVOKE";
+ case SQLCOM_SET_OPTION:
+ if (thd->lex->definer)
+ return "SET PASSWORD";
+ /* fallthrough */
+ default:
+ return thd->query();
+ }
+}
+
+/*
+ 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;
+ int rc= 0;
+
+ if (wsrep_can_run_in_toi(thd, db_, table_, table_list) == false)
+ {
+ WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
+ return 1;
+ }
+
+ WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
+
+ 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;
+ case SQLCOM_CREATE_ROLE:
+ if (sp_process_definer(thd))
+ {
+ WSREP_WARN("Failed to set CREATE ROLE definer for TOI.");
+ }
+ /* fallthrough */
+ 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++;
+ 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, schema: %s, sql: %s. Check wsrep "
+ "connection state and retry the query.",
+ ret,
+ (thd->db ? thd->db : "(null)"),
+ (thd->query()) ? thd->query() : "void");
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
+ "your wsrep connection state and retry the query.");
+ wsrep_keys_free(&key_arr);
+ rc= -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");
+ rc= 1;
+ }
+ if (buf) my_free(buf);
+ return rc;
+}
+
+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, wsrep_get_query_or_msg(thd));
+
+ wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ 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, schema: %s, sql: %s",
+ ret,
+ (thd->db ? thd->db : "(null)"),
+ (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 schema: %s, query: %s",
+ ret, (thd->db ? thd->db : "(null)"), 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, schema: %s, query %s",
+ (thd->db ? thd->db : "(null)"),
+ 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 schema: %s, query: %s",
+ ret, (thd->db ? thd->db : "(null)"), 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 schema: %s, query: %s", (long long)seqno,
+ (thd->db ? thd->db : "(null)"),
+ 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 schema: %s, query: %s", ret,
+ (thd->db ? thd->db : "(null)"),
+ thd->query());
+ }
+
+ ret = wsrep->resync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resync failed %d for schema: %s, query: %s", ret,
+ (thd->db ? thd->db : "(null)"), 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, schema: %s, query: %s has been aborted due to multi-master conflict",
+ thd->thread_id,
+ (thd->db ? thd->db : "(null)"),
+ 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 (thd->variables.wsrep_OSU_method) {
+ 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;
+ default:
+ WSREP_ERROR("Unsupported OSU method: %lu",
+ thd->variables.wsrep_OSU_method);
+ ret= -1;
+ 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(thd->variables.wsrep_OSU_method)
+ {
+ case WSREP_OSU_TOI: wsrep_TOI_end(thd); break;
+ case WSREP_OSU_RSU: wsrep_RSU_end(thd); break;
+ default:
+ WSREP_WARN("Unsupported wsrep OSU method at isolation end: %lu",
+ thd->variables.wsrep_OSU_method);
+ break;
+ }
+ wsrep_cleanup_transaction(thd);
+ }
+}
+
+#define WSREP_MDL_LOG(severity, msg, schema, schema_len, req, gra) \
+ WSREP_##severity( \
+ "%s\n" \
+ "schema: %.*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, schema_len, schema, \
+ 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());
+
+/**
+ Check if request for the metadata lock should be granted to the requester.
+
+ @param requestor_ctx The MDL context of the requestor
+ @param ticket MDL ticket for the requested lock
+
+ @retval TRUE Lock request can be granted
+ @retval FALSE Lock request cannot be granted
+*/
+
+bool
+wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
+ MDL_ticket *ticket,
+ const MDL_key *key
+) {
+ /* Fallback to the non-wsrep behaviour */
+ if (!WSREP_ON) return FALSE;
+
+ THD *request_thd = requestor_ctx->get_thd();
+ THD *granted_thd = ticket->get_ctx()->get_thd();
+ bool ret = FALSE;
+
+ const char* schema= key->db_name();
+ int schema_len= key->db_name_length();
+
+ 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 ", schema, schema_len,
+ 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", schema, schema_len,
+ 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 ||
+ granted_thd->mdl_context.wsrep_has_explicit_locks())
+ {
+ WSREP_DEBUG("BF thread waiting for FLUSH");
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ ret = FALSE;
+ }
+ else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
+ {
+ WSREP_DEBUG("DROP caused BF abort, conf %d", granted_thd->wsrep_conflict_state);
+ 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", schema, schema_len,
+ 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;
+}
+
+bool wsrep_node_is_donor()
+{
+ return (WSREP_ON) ? (local_status.get() == 2) : false;
+}
+bool wsrep_node_is_synced()
+{
+ return (WSREP_ON) ? (local_status.get() == 4) : false;
+}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
new file mode 100644
index 00000000000..ee96a304f7b
--- /dev/null
+++ b/sql/wsrep_mysqld.h
@@ -0,0 +1,358 @@
+/* Copyright 2008-2015 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 {
+ /* Transaction processing before replication. */
+ LOCAL_STATE,
+ /* Slave thread applying write sets from other nodes or replaying thread. */
+ REPL_RECV,
+ /* Total-order-isolation mode */
+ TOTAL_ORDER,
+ /*
+ Transaction procession after it has been replicated in prepare stage and
+ has passed certification
+ */
+ 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 bool wsrep_dirty_reads;
+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 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;
+extern bool wsrep_new_cluster; // bootstrap the cluster ?
+extern my_bool wsrep_creating_startup_threads;
+
+enum enum_wsrep_OSU_method {
+ WSREP_OSU_TOI,
+ WSREP_OSU_RSU,
+ WSREP_OSU_NONE,
+};
+
+enum enum_wsrep_sync_wait {
+ WSREP_SYNC_WAIT_NONE = 0x0,
+ // 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_BEFORE_SHOW = 0x8,
+ WSREP_SYNC_WAIT_MAX = 0xF
+};
+
+// 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);
+int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff);
+void wsrep_free_status(THD *thd);
+
+int wsrep_init();
+void wsrep_deinit(bool free_options);
+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);
+
+// Other wsrep global variables
+extern my_bool wsrep_inited; // whether wsrep is initialized ?
+
+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 "C" bool wsrep_thd_skip_append_keys(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_must_sync_wait (THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ);
+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);
+
+/* Other global variables */
+extern wsrep_seqno_t wsrep_locked_seqno;
+
+#define WSREP_ON \
+ (global_system_variables.wsrep_on)
+
+#define WSREP_ON_NEW \
+ ((global_system_variables.wsrep_on) && \
+ wsrep_provider && \
+ strcmp(wsrep_provider, WSREP_NONE))
+
+#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 != NULL) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
+ if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \
+ }
+
+#define WSREP_PROVIDER_EXISTS \
+ (wsrep_provider && strncasecmp(wsrep_provider, WSREP_NONE, FN_REFLEN))
+
+#define WSREP_QUERY(thd) (thd->query())
+
+extern my_bool wsrep_ready_get();
+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;
+#ifdef GTID_SUPPORT
+extern rpl_sidno wsrep_sidno;
+#endif /* GTID_SUPPORT */
+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);
+
+#ifdef GTID_SUPPORT
+void wsrep_init_sidno(const wsrep_uuid_t&);
+#endif /* GTID_SUPPORT */
+
+bool wsrep_node_is_donor();
+bool wsrep_node_is_synced();
+
+typedef struct wsrep_key_arr
+{
+ wsrep_key_t* keys;
+ size_t keys_len;
+} wsrep_key_arr_t;
+bool wsrep_prepare_keys_for_isolation(THD* thd,
+ const char* db,
+ const char* table,
+ const TABLE_LIST* table_list,
+ wsrep_key_arr_t* ka);
+void wsrep_keys_free(wsrep_key_arr_t* key_arr);
+#endif /* WSREP_MYSQLD_H */
diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc
new file mode 100644
index 00000000000..e7d30d5a9c1
--- /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", NULL);
+
+ 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 00000000000..58d8cc4f86d
--- /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>
+
+my_bool 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 00000000000..097c1ba8b41
--- /dev/null
+++ b/sql/wsrep_sst.cc
@@ -0,0 +1,1232 @@
+/* Copyright 2008-2015 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 <m_ctype.h>
+#include <my_sys.h>
+#include <strfunc.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 "wsrep_xid.h"
+#include <cstdio>
+#include <cstdlib>
+
+static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 +
+ sizeof(WSREP_SST_OPT_CONF) +
+ sizeof(WSREP_SST_OPT_CONF_SUFFIX) +
+ sizeof(WSREP_SST_OPT_CONF_EXTRA)] = {0};
+
+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)
+{
+ if ((! var->save_result.string_value.str) ||
+ (var->save_result.string_value.length == 0 ))
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ var->save_result.string_value.str ?
+ var->save_result.string_value.str : "NULL");
+ return 1;
+ }
+
+ return 0;
+}
+
+bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ return 0;
+}
+
+
+static void make_wsrep_defaults_file()
+{
+ if (!wsrep_defaults_file[0])
+ {
+ char *ptr= wsrep_defaults_file;
+ char *end= ptr + sizeof(wsrep_defaults_file);
+ if (my_defaults_file)
+ ptr= strxnmov(ptr, end - ptr,
+ WSREP_SST_OPT_CONF, " '", my_defaults_file, "' ", NULL);
+
+ if (my_defaults_extra_file)
+ ptr= strxnmov(ptr, end - ptr,
+ WSREP_SST_OPT_CONF_EXTRA, " '", my_defaults_extra_file, "' ", NULL);
+
+ if (my_defaults_group_suffix)
+ ptr= strxnmov(ptr, end - ptr,
+ WSREP_SST_OPT_CONF_SUFFIX, " '", my_defaults_group_suffix, "' ", NULL);
+ }
+}
+
+
+// TODO: Improve address verification.
+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)
+{
+ char addr_buf[FN_REFLEN];
+
+ if ((! var->save_result.string_value.str) ||
+ (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety
+ {
+ goto err;
+ }
+
+ memcpy(addr_buf, var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ addr_buf[var->save_result.string_value.length]= 0;
+
+ if (sst_receive_address_check(addr_buf))
+ {
+ goto err;
+ }
+
+ return 0;
+
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ var->save_result.string_value.str ?
+ var->save_result.string_value.str : "NULL");
+ return 1;
+}
+
+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= NULL;
+
+ if (value)
+ {
+ v= my_strdup(value, MYF(0));
+ }
+ else // its NULL
+ {
+ wsrep_sst_auth_free();
+ return 0;
+ }
+
+ if (v)
+ {
+ // set sst_auth_real
+ if (sst_auth_real) { my_free((void *) sst_auth_real); }
+ sst_auth_real = v;
+
+ // mask wsrep_sst_auth
+ 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));
+ }
+ return 0;
+ }
+ return 1;
+}
+
+void wsrep_sst_auth_free()
+{
+ if (wsrep_sst_auth) { my_free((void *) wsrep_sst_auth); }
+ if (sst_auth_real) { my_free((void *) sst_auth_real); }
+ wsrep_sst_auth= NULL;
+ sst_auth_real= NULL;
+}
+
+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& uuid,
+ wsrep_seqno_t const seqno,
+ const void* const state,
+ size_t const state_len)
+{
+ wsrep_get_SE_checkpoint(local_uuid, local_seqno);
+
+ if (memcmp(&local_uuid, &uuid, sizeof(wsrep_uuid_t)) ||
+ local_seqno < seqno || seqno < 0)
+ {
+ wsrep_set_SE_checkpoint(uuid, seqno);
+ local_uuid = uuid;
+ local_seqno = seqno;
+ }
+ else if (local_seqno > seqno)
+ {
+ WSREP_WARN("SST postion is in the past: %lld, current: %lld. "
+ "Can't continue.",
+ (long long)seqno, (long long)local_seqno);
+ unireg_abort(1);
+ }
+
+#ifdef GTID_SUPPORT
+ wsrep_init_sidno(uuid);
+#endif /* GTID_SUPPORT */
+
+ if (wsrep)
+ {
+ int const rcode(seqno < 0 ? seqno : 0);
+ wsrep_gtid_t const state_id = {
+ uuid, (rcode ? WSREP_SEQNO_UNDEFINED : seqno)
+ };
+
+ 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;
+ char** env;
+ char* ret_str;
+ int err;
+ mysql_mutex_t lock;
+ mysql_cond_t cond;
+
+ sst_thread_arg (const char* c, char** e)
+ : cmd(c), env(e), ret_str(0), err(-1)
+ {
+ 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)
+ {
+ 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", arg->env);
+
+ 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;
+}
+
+#define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH"
+
+static int sst_append_auth_env(wsp::env& env, const char* sst_auth)
+{
+ int const sst_auth_size= strlen(WSREP_SST_AUTH_ENV) + 1 /* = */
+ + (sst_auth ? strlen(sst_auth) : 0) + 1 /* \0 */;
+
+ wsp::string sst_auth_str(sst_auth_size); // for automatic cleanup on return
+ if (!sst_auth_str()) return -ENOMEM;
+
+ int ret= snprintf(sst_auth_str(), sst_auth_size, "%s=%s",
+ WSREP_SST_AUTH_ENV, sst_auth ? sst_auth : "");
+
+ if (ret < 0 || ret >= sst_auth_size)
+ {
+ WSREP_ERROR("sst_append_auth_env(): snprintf() failed: %d", ret);
+ return (ret < 0 ? ret : -EMSGSIZE);
+ }
+
+ env.append(sst_auth_str());
+ return -env.error();
+}
+
+static ssize_t sst_prepare_other (const char* method,
+ const char* sst_auth,
+ const char* addr_in,
+ const char** addr_out)
+{
+ int const cmd_len= 4096;
+ wsp::string cmd_str(cmd_len);
+
+ if (!cmd_str())
+ {
+ WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %d bytes",
+ cmd_len);
+ return -ENOMEM;
+ }
+
+ 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;
+
+ make_wsrep_defaults_file();
+
+ ret= snprintf (cmd_str(), cmd_len,
+ "wsrep_sst_%s "
+ WSREP_SST_OPT_ROLE" 'joiner' "
+ WSREP_SST_OPT_ADDR" '%s' "
+ WSREP_SST_OPT_DATA" '%s' "
+ " %s "
+ WSREP_SST_OPT_PARENT" '%d'"
+ " %s '%s' ",
+ method, addr_in, mysql_real_data_home,
+ wsrep_defaults_file,
+ (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);
+ }
+
+ wsp::env env(NULL);
+ if (env.error())
+ {
+ WSREP_ERROR("sst_prepare_other(): env. var ctor failed: %d", -env.error());
+ return -env.error();
+ }
+
+ if ((ret= sst_append_auth_env(env, sst_auth)))
+ {
+ WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret);
+ return ret;
+ }
+
+ pthread_t tmp;
+ sst_thread_arg arg(cmd_str(), env());
+ 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))
+ {
+ size_t const addr_len= strlen(wsrep_node_address);
+ size_t const host_len= wsrep_host_len(wsrep_node_address, addr_len);
+
+ if (host_len < addr_len)
+ {
+ strncpy (ip_buf, wsrep_node_address, host_len);
+ ip_buf[host_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, sst_auth_real,
+ 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, char** env, int max_tries)
+{
+ int ret = 0;
+
+ for (int tries=1; tries <= max_tries; tries++)
+ {
+ wsp::process proc (cmd_str, "r", env);
+
+ 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_donate_mysqldump (const char* addr,
+ const wsrep_uuid_t* uuid,
+ const char* uuid_str,
+ wsrep_seqno_t seqno,
+ bool bypass,
+ char** env) // carries auth info
+{
+ int const cmd_len= 4096;
+ wsp::string cmd_str(cmd_len);
+
+ if (!cmd_str())
+ {
+ WSREP_ERROR("sst_donate_mysqldump(): "
+ "could not allocate cmd buffer of %d bytes", cmd_len);
+ return -ENOMEM;
+ }
+
+ if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
+
+ make_wsrep_defaults_file();
+
+ int ret= snprintf (cmd_str(), cmd_len,
+ "wsrep_sst_mysqldump "
+ WSREP_SST_OPT_ADDR" '%s' "
+ WSREP_SST_OPT_LPORT" '%u' "
+ WSREP_SST_OPT_SOCKET" '%s' "
+ " '%s' "
+ WSREP_SST_OPT_GTID" '%s:%lld'"
+ "%s",
+ addr, mysqld_port, mysqld_unix_port,
+ wsrep_defaults_file, uuid_str,
+ (long long)seqno, bypass ? " " WSREP_SST_OPT_BYPASS : "");
+
+ if (ret < 0 || ret >= cmd_len)
+ {
+ WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret);
+ return (ret < 0 ? ret : -EMSGSIZE);
+ }
+
+ WSREP_DEBUG("Running: '%s'", cmd_str());
+
+ ret= sst_run_shell (cmd_str(), env, 3);
+
+ wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)};
+
+ wsrep->sst_sent (wsrep, &state_id, ret);
+
+ 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;
+ CHARSET_INFO *current_charset;
+
+ current_charset = thd->variables.character_set_client;
+
+ if (!is_supported_parser_charset(current_charset))
+ {
+ /* Do not use non-supported parser character sets */
+ WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname);
+ thd->variables.character_set_client = &my_charset_latin1;
+ WSREP_WARN("For SST temporally setting character set to : %s",
+ my_charset_latin1.csname);
+ }
+
+ 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);
+ }
+
+ thd->variables.character_set_client = current_charset;
+
+
+ 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 *) alloca(full_len);
+ snprintf(real_name, (size_t) full_len, "%s/%s", mysql_real_data_home,
+ base_name);
+ char *tmp_name= (char *) alloca(full_len + 4);
+ snprintf(tmp_name, (size_t) full_len + 4, "%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));
+ }
+ }
+ }
+
+ 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;
+ CHARSET_INFO *current_charset;
+
+ current_charset = thd->variables.character_set_client;
+
+ if (!is_supported_parser_charset(current_charset))
+ {
+ /* Do not use non-supported parser character sets */
+ WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname);
+ thd->variables.character_set_client = &my_charset_latin1;
+ WSREP_WARN("For SST temporally setting character set to : %s",
+ my_charset_latin1.csname);
+ }
+
+ 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");
+ }
+ thd->variables.character_set_client = current_charset;
+}
+
+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", arg->env);
+
+ 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);
+ /*
+ Lets also keep statements that modify binary logs (like RESET LOGS,
+ RESET MASTER) from proceeding until the files have been transferred
+ to the joiner node.
+ */
+ if (mysql_bin_log.is_open())
+ {
+ mysql_mutex_lock(mysql_bin_log.get_log_lock());
+ }
+
+ locked= true;
+ goto wait_signal;
+ }
+ }
+ else if (!strcasecmp (out, magic_cont))
+ {
+ if (locked)
+ {
+ if (mysql_bin_log.is_open())
+ {
+ mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
+ mysql_mutex_unlock(mysql_bin_log.get_log_lock());
+ }
+ 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
+ {
+ if (mysql_bin_log.is_open())
+ {
+ mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
+ mysql_mutex_unlock(mysql_bin_log.get_log_lock());
+ }
+ 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,
+ char** env) // carries auth info
+{
+ int const cmd_len= 4096;
+ wsp::string cmd_str(cmd_len);
+
+ if (!cmd_str())
+ {
+ WSREP_ERROR("sst_donate_other(): "
+ "could not allocate cmd buffer of %d bytes", cmd_len);
+ return -ENOMEM;
+ }
+
+ 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;
+
+ make_wsrep_defaults_file();
+
+ ret= snprintf (cmd_str(), cmd_len,
+ "wsrep_sst_%s "
+ WSREP_SST_OPT_ROLE" 'donor' "
+ WSREP_SST_OPT_ADDR" '%s' "
+ WSREP_SST_OPT_SOCKET" '%s' "
+ WSREP_SST_OPT_DATA" '%s' "
+ " %s "
+ " %s '%s' "
+ WSREP_SST_OPT_GTID" '%s:%lld'"
+ "%s",
+ method, addr, mysqld_unix_port, mysql_real_data_home,
+ wsrep_defaults_file,
+ 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(), env);
+ 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? */
+ 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));
+
+ wsp::env env(NULL);
+ if (env.error())
+ {
+ WSREP_ERROR("wsrep_sst_donate_cb(): env var ctor failed: %d", -env.error());
+ return WSREP_CB_FAILURE;
+ }
+
+ int ret;
+ if ((ret= sst_append_auth_env(env, sst_auth_real)))
+ {
+ WSREP_ERROR("wsrep_sst_donate_cb(): appending auth env failed: %d", ret);
+ return WSREP_CB_FAILURE;
+ }
+
+ if (!strcmp (WSREP_SST_MYSQLDUMP, method))
+ {
+ ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str,
+ current_gtid->seqno, bypass, env());
+ }
+ else
+ {
+ ret = sst_donate_other(method, data, uuid_str,
+ current_gtid->seqno, bypass, env());
+ }
+
+ 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 00000000000..631480e7986
--- /dev/null
+++ b/sql/wsrep_sst.h
@@ -0,0 +1,71 @@
+/* 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 <my_config.h>
+#include <mysql.h> // my_bool
+
+#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_CONF_EXTRA "--defaults-extra-file"
+#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_DEFAULT WSREP_SST_RSYNC
+#define WSREP_SST_ADDRESS_AUTO "AUTO"
+#define WSREP_SST_AUTH_MASK "********"
+
+/* 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_sst_auth_free();
+
+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 00000000000..328bcbd6be6
--- /dev/null
+++ b/sql/wsrep_thd.cc
@@ -0,0 +1,666 @@
+/* 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();
+
+#include "slave.h" // opt_log_slave_updates
+#include "rpl_filter.h"
+#include "rpl_rli.h"
+#include "rpl_mi.h"
+
+#if (__LP64__)
+static volatile int64 wsrep_bf_aborts_counter(0);
+#define WSREP_ATOMIC_LOAD_LONG my_atomic_load64
+#define WSREP_ATOMIC_ADD_LONG my_atomic_add64
+#else
+static volatile int32 wsrep_bf_aborts_counter(0);
+#define WSREP_ATOMIC_LOAD_LONG my_atomic_load32
+#define WSREP_ATOMIC_ADD_LONG my_atomic_add32
+#endif
+
+int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff)
+{
+ wsrep_local_bf_aborts = WSREP_ATOMIC_LOAD_LONG(&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());
+
+ WSREP_ATOMIC_ADD_LONG(&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
+
+static rpl_group_info* wsrep_relay_group_init(const char* log_fname)
+{
+ Relay_log_info* rli= new Relay_log_info(false);
+
+ rli->no_storage= true;
+ if (!rli->relay_log.description_event_for_exec)
+ {
+ rli->relay_log.description_event_for_exec=
+ new Format_description_log_event(4);
+ }
+
+ static LEX_STRING connection_name= { C_STRING_WITH_LEN("wsrep") };
+
+ /*
+ Master_info's constructor initializes rpl_filter by either an already
+ constructed Rpl_filter object from global 'rpl_filters' list if the
+ specified connection name is same, or it constructs a new Rpl_filter
+ object and adds it to rpl_filters. This object is later destructed by
+ Mater_info's destructor by looking it up based on connection name in
+ rpl_filters list.
+
+ However, since all Master_info objects created here would share same
+ connection name ("wsrep"), destruction of any of the existing Master_info
+ objects (in wsrep_return_from_bf_mode()) would free rpl_filter referenced
+ by any/all existing Master_info objects.
+
+ In order to avoid that, we have added a check in Master_info's destructor
+ to not free the "wsrep" rpl_filter. It will eventually be freed by
+ free_all_rpl_filters() when server terminates.
+ */
+ rli->mi = new Master_info(&connection_name, false);
+
+ struct rpl_group_info *rgi= new rpl_group_info(rli);
+ rgi->thd= rli->sql_driver_thd= current_thd;
+
+ if ((rgi->deferred_events_collecting= rli->mi->rpl_filter->is_on()))
+ {
+ rgi->deferred_events= new Deferred_log_events(rli);
+ }
+
+ return rgi;
+}
+
+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;
+
+ // Disable general logging on applier threads
+ thd->variables.option_bits |= OPTION_LOG_OFF;
+ // Enable binlogging if opt_log_slave_updates is set
+ if (opt_log_slave_updates)
+ thd->variables.option_bits|= OPTION_BIN_LOG;
+ else
+ thd->variables.option_bits&= ~(OPTION_BIN_LOG);
+
+ if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init("wsrep_relay");
+
+ /* thd->system_thread_info.rpl_sql_info isn't initialized. */
+ thd->system_thread_info.rpl_sql_info=
+ new rpl_sql_thread_info(thd->wsrep_rgi->rli->mi->rpl_filter);
+
+ 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;
+ shadow->user_time = thd->user_time;
+ shadow->row_count_func= thd->get_row_count_func();
+ 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->user_time = shadow->user_time;
+ thd->reset_db(shadow->db, shadow->db_length);
+
+ delete thd->system_thread_info.rpl_sql_info;
+ delete thd->wsrep_rgi->rli->mi;
+ delete thd->wsrep_rgi->rli;
+
+ thd->wsrep_rgi->cleanup_after_session();
+ delete thd->wsrep_rgi;
+ thd->wsrep_rgi = NULL;
+ thd->set_row_count_func(shadow->row_count_func);
+}
+
+void wsrep_replay_transaction(THD *thd)
+{
+ DBUG_ENTER("wsrep_replay_transaction");
+ /* 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");
+ }
+
+
+ /*
+ PS reprepare observer should have been removed already.
+ open_table() will fail if we have dangling observer here.
+ */
+ DBUG_ASSERT(thd->m_reprepare_observer == NULL);
+
+ struct da_shadow
+ {
+ enum Diagnostics_area::enum_diagnostics_status status;
+ ulonglong affected_rows;
+ ulonglong last_insert_id;
+ char message[MYSQL_ERRMSG_SIZE];
+ };
+ struct da_shadow da_status;
+ da_status.status= thd->get_stmt_da()->status();
+ if (da_status.status == Diagnostics_area::DA_OK)
+ {
+ da_status.affected_rows= thd->get_stmt_da()->affected_rows();
+ da_status.last_insert_id= thd->get_stmt_da()->last_insert_id();
+ strmake(da_status.message,
+ thd->get_stmt_da()->message(),
+ sizeof(da_status.message)-1);
+ }
+
+ 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= 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->m_digest= 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
+ {
+ if (da_status.status == Diagnostics_area::DA_OK)
+ {
+ my_ok(thd,
+ da_status.affected_rows,
+ da_status.last_insert_id,
+ da_status.message);
+ }
+ 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, schema: %s, query: %s",
+ rcode,
+ (thd->db ? thd->db : "(null)"),
+ thd->query() ? thd->query() : "void");
+ /* we're now in inconsistent state, must abort */
+
+ /* http://bazaar.launchpad.net/~codership/codership-mysql/5.6/revision/3962#sql/wsrep_thd.cc */
+ 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);
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+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 */
+ 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 != 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 == 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);
+
+ set_current_thd(aborting);
+ 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);
+
+ set_current_thd(thd);
+ thd->store_globals();
+
+ 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_wsrep(void *thd_ptr)
+{
+ my_bool status = FALSE;
+ if (thd_ptr)
+ {
+ THD* thd = (THD*)thd_ptr;
+
+ status = (WSREP(thd) && WSREP_PROVIDER_EXISTS);
+ }
+ return status;
+}
+
+my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync)
+{
+ my_bool status = FALSE;
+ if (thd_ptr)
+ {
+ THD* thd = (THD*)thd_ptr;
+ // THD can be BF only if provider exists
+ if (wsrep_thd_is_wsrep(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 || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) &&
+ bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) &&
+ victim_thd)
+ {
+ if ((victim_thd->wsrep_conflict_state == MUST_ABORT) ||
+ (victim_thd->wsrep_conflict_state == ABORTED) ||
+ (victim_thd->wsrep_conflict_state == ABORTING))
+ {
+ WSREP_DEBUG("wsrep_abort_thd called by %llu with victim %llu already "
+ "aborted. Ignoring.",
+ (bf_thd) ? (long long)bf_thd->real_id : 0,
+ (long long)victim_thd->real_id);
+ DBUG_RETURN(1);
+ }
+
+ 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);
+}
+
+extern "C"
+int wsrep_thd_in_locking_session(void *thd_ptr)
+{
+ if (thd_ptr && ((THD *)thd_ptr)->in_lock_tables) {
+ return 1;
+ }
+ return 0;
+}
+
+bool wsrep_thd_has_explicit_locks(THD *thd)
+{
+ assert(thd);
+ return (thd->mdl_context.wsrep_has_explicit_locks());
+}
diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h
new file mode 100644
index 00000000000..700e0f1cc56
--- /dev/null
+++ b/sql/wsrep_thd.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_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 my_bool wsrep_thd_is_wsrep(void *thd_ptr);
+
+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);
+extern "C" 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 00000000000..6b46fca33f5
--- /dev/null
+++ b/sql/wsrep_utils.cc
@@ -0,0 +1,570 @@
+/* Copyright 2010-2015 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 (static_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
+{
+
+bool
+env::ctor_common(char** e)
+{
+ env_ = static_cast<char**>(malloc((len_ + 1) * sizeof(char*)));
+
+ if (env_)
+ {
+ for (size_t i(0); i < len_; ++i)
+ {
+ assert(e[i]); // caller should make sure about len_
+ env_[i] = strdup(e[i]);
+ if (!env_[i])
+ {
+ errno_ = errno;
+ WSREP_ERROR("Failed to allocate env. var: %s", e[i]);
+ return true;
+ }
+ }
+
+ env_[len_] = NULL;
+ return false;
+ }
+ else
+ {
+ errno_ = errno;
+ WSREP_ERROR("Failed to allocate env. var vector of length: %zu", len_);
+ return true;
+ }
+}
+
+void
+env::dtor()
+{
+ if (env_)
+ {
+ /* don't need to go beyond the first NULL */
+ for (size_t i(0); env_[i] != NULL; ++i) { free(env_[i]); }
+ free(env_);
+ env_ = NULL;
+ }
+ len_ = 0;
+}
+
+env::env(char** e)
+ : len_(0), env_(NULL), errno_(0)
+{
+ if (!e) { e = environ; }
+ /* count the size of the vector */
+ while (e[len_]) { ++len_; }
+
+ if (ctor_common(e)) dtor();
+}
+
+env::env(const env& e)
+ : len_(e.len_), env_(0), errno_(0)
+{
+ if (ctor_common(e.env_)) dtor();
+}
+
+env::~env() { dtor(); }
+
+int
+env::append(const char* val)
+{
+ char** tmp = static_cast<char**>(realloc(env_, (len_ + 2)*sizeof(char*)));
+
+ if (tmp)
+ {
+ env_ = tmp;
+ env_[len_] = strdup(val);
+
+ if (env_[len_])
+ {
+ ++len_;
+ env_[len_] = NULL;
+ }
+ else errno_ = errno;
+ }
+ else errno_ = errno;
+
+ return errno_;
+}
+
+
+#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, char** env)
+ : 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;
+ }
+
+ if (NULL == env) { env = environ; } // default to global environment
+
+ 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 |
+ 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, env);
+ 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 */
+ case 143: err_ = EINTR; break; /* Subprocess killed */
+ }
+ 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)
+{
+ 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;
+}
+
+extern char* my_bind_addr_str;
+
+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 OSX, 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;
+}
+
+/* returns the length of the host part of the address string */
+size_t wsrep_host_len(const char* const addr, size_t const addr_len)
+{
+ // check for IPv6 notation first
+ const char* const bracket= ('[' == addr[0] ? strchr(addr, ']') : NULL);
+
+ if (bracket) { // IPv6
+ return (bracket - addr + 1);
+ }
+ else { // host part ends at ':' or end of string
+ const char* const colon= strchr(addr, ':');
+ return (colon ? colon - addr : addr_len);
+ }
+}
diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
new file mode 100644
index 00000000000..0ae5c68df21
--- /dev/null
+++ b/sql/wsrep_utils.h
@@ -0,0 +1,232 @@
+/* Copyright (C) 2013-2015 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);
+
+/* returns the length of the host part of the address string */
+size_t wsrep_host_len(const char* addr, size_t addr_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 class to manage env vars array */
+class env
+{
+private:
+ size_t len_;
+ char** env_;
+ int errno_;
+ bool ctor_common(char** e);
+ void dtor();
+ env& operator =(env);
+public:
+ explicit env(char** env);
+ explicit env(const env&);
+ ~env();
+ int append(const char* var); /* add a new env. var */
+ int error() const { return errno_; }
+ char** operator()() { return env_; }
+};
+
+/* 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.
+ @arg env optional null-terminated vector of environment variables
+ */
+ process (const char* cmd, const char* type, char** env);
+ ~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) {}
+ explicit string(size_t s) : string_(static_cast<char*>(malloc(s))) {}
+ char* operator()() { return string_; }
+ 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 00000000000..8cb80a7c13a
--- /dev/null
+++ b/sql/wsrep_var.cc
@@ -0,0 +1,681 @@
+/* Copyright 2008-2015 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 "wsrep_xid.h"
+#include <my_dir.h>
+#include <cstdio>
+#include <cstdlib>
+
+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;
+
+static long wsrep_prev_slave_threads = wsrep_slave_threads;
+
+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 start_pos_buf[FN_REFLEN];
+
+ if ((! var->save_result.string_value.str) ||
+ (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety
+ goto err;
+
+ memcpy(start_pos_buf, var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ start_pos_buf[var->save_result.string_value.length]= 0;
+
+ if (!wsrep_start_position_verify(start_pos_buf)) return 0;
+
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ var->save_result.string_value.str ?
+ var->save_result.string_value.str : "NULL");
+ return 1;
+}
+
+static
+void wsrep_set_local_position(const char* const value, bool const sst)
+{
+ size_t const value_len = strlen(value);
+ wsrep_uuid_t uuid;
+ size_t const uuid_len = wsrep_uuid_scan(value, value_len, &uuid);
+ wsrep_seqno_t const seqno = strtoll(value + uuid_len + 1, NULL, 10);
+
+ if (sst) {
+ wsrep_sst_received (wsrep, uuid, seqno, NULL, 0);
+ } else {
+ // initialization
+ local_uuid = uuid;
+ local_seqno = seqno;
+ }
+}
+
+bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ WSREP_INFO ("wsrep_start_position var submitted: '%s'",
+ wsrep_start_position);
+ // since this value passed wsrep_start_position_check, don't check anything
+ // here
+ wsrep_set_local_position (wsrep_start_position, true);
+ 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, false);
+}
+
+static int get_provider_option_value(const char* opts,
+ const char* opt_name,
+ ulong* opt_value)
+{
+ int ret= 1;
+ ulong opt_value_tmp;
+ char *opt_value_str, *s, *opts_copy= my_strdup(opts, MYF(MY_WME));
+
+ if ((opt_value_str= strstr(opts_copy, opt_name)) == NULL)
+ goto end;
+ opt_value_str= strtok_r(opt_value_str, "=", &s);
+ if (opt_value_str == NULL) goto end;
+ opt_value_str= strtok_r(NULL, ";", &s);
+ if (opt_value_str == NULL) goto end;
+
+ opt_value_tmp= strtoul(opt_value_str, NULL, 10);
+ if (errno == ERANGE) goto end;
+
+ *opt_value= opt_value_tmp;
+ ret= 0;
+
+end:
+ my_free(opts_copy);
+ return ret;
+}
+
+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)
+ {
+ wsrep_provider_options_init(opts);
+ get_provider_option_value(wsrep_provider_options,
+ (char*)"repl.max_ws_size",
+ &wsrep_max_ws_size);
+ free(opts);
+ }
+ 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 wsrep_provider_buf[FN_REFLEN];
+
+ if ((! var->save_result.string_value.str) ||
+ (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety
+ goto err;
+
+ memcpy(wsrep_provider_buf, var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ wsrep_provider_buf[var->save_result.string_value.length]= 0;
+
+ if (!wsrep_provider_verify(wsrep_provider_buf)) return 0;
+
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ var->save_result.string_value.str ?
+ var->save_result.string_value.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);
+
+ if (wsrep_inited == 1)
+ wsrep_deinit(false);
+
+ char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider
+ //when fails
+
+ /* provider status variables are allocated in provider library
+ and need to freed here, otherwise a dangling reference to
+ wsrep_status_vars would remain in THD
+ */
+ wsrep_free_status(thd);
+
+ 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 addr_buf[FN_REFLEN];
+
+ if ((! var->save_result.string_value.str) ||
+ (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety
+ goto err;
+
+ memcpy(addr_buf, var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ addr_buf[var->save_result.string_value.length]= 0;
+
+ if (!wsrep_cluster_address_verify(addr_buf)) return 0;
+
+ err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ var->save_result.string_value.str ?
+ var->save_result.string_value.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);
+
+ /*
+ Unlock and lock LOCK_wsrep_slave_threads to maintain lock order & avoid
+ any potential deadlock.
+ */
+ mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_wsrep_slave_threads);
+
+ 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;
+}
+
+/* wsrep_cluster_name cannot be NULL or an empty string. */
+bool wsrep_cluster_name_check (sys_var *self, THD* thd, set_var* var)
+{
+ if (!var->save_result.string_value.str ||
+ (var->save_result.string_value.length == 0))
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ (var->save_result.string_value.str ?
+ var->save_result.string_value.str : "NULL"));
+ return 1;
+ }
+ return 0;
+}
+
+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)
+{
+ // TODO: for now 'allow' 0-length string to be valid (default)
+ if (!var->save_result.string_value.str)
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ (var->save_result.string_value.str ?
+ var->save_result.string_value.str : "NULL"));
+ return 1;
+ }
+ return 0;
+}
+
+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 addr_buf[FN_REFLEN];
+
+ if ((! var->save_result.string_value.str) ||
+ (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety
+ goto err;
+
+ memcpy(addr_buf, var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ addr_buf[var->save_result.string_value.length]= 0;
+
+ // TODO: for now 'allow' 0-length string to be valid (default)
+ return 0;
+
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
+ var->save_result.string_value.str ?
+ var->save_result.string_value.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;
+}
+
+static void wsrep_slave_count_change_update ()
+{
+ wsrep_slave_count_change += (wsrep_slave_threads - wsrep_prev_slave_threads);
+ wsrep_prev_slave_threads = wsrep_slave_threads;
+}
+
+bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ wsrep_slave_count_change_update();
+ 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= (bool) var->save_result.ulonglong_value;
+ 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 false;
+ }
+ wsrep_status_t ret(WSREP_WARNING);
+ if (new_wsrep_desync) {
+ ret = wsrep->desync (wsrep);
+ if (ret != WSREP_OK) {
+ WSREP_WARN ("SET desync failed %d for schema: %s, query: %s", ret,
+ (thd->db ? thd->db : "(null)"),
+ 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 schema: %s, query: %s", ret,
+ (thd->db ? thd->db : "(null)"),
+ thd->query());
+ my_error (ER_CANNOT_USER, MYF(0), "'resync'", thd->query());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ return false;
+}
+
+bool wsrep_max_ws_size_update (sys_var *self, THD *thd, enum_var_type)
+{
+ char max_ws_size_opt[128];
+ my_snprintf(max_ws_size_opt, sizeof(max_ws_size_opt),
+ "repl.max_ws_size=%d", wsrep_max_ws_size);
+ wsrep_status_t ret= wsrep->options_set(wsrep, max_ws_size_opt);
+ if (ret != WSREP_OK)
+ {
+ WSREP_ERROR("Set options returned %d", ret);
+ refresh_provider_options();
+ return true;
+ }
+ return refresh_provider_options();
+}
+
+/*
+ * 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;
+
+ wsrep_free_status(thd);
+
+ 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 00000000000..f72df9d098a
--- /dev/null
+++ b/sql/wsrep_var.h
@@ -0,0 +1,88 @@
+/* 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_CLUSTER_NAME "my_wsrep_cluster"
+#define WSREP_NODE_INCOMING_AUTO "AUTO"
+#define WSREP_START_POSITION_ZERO "00000000-0000-0000-0000-000000000000:-1"
+
+// 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;
+
+extern bool wsrep_max_ws_size_update UPDATE_ARGS;
+
+#endif /* WSREP_VAR_H */
diff --git a/sql/wsrep_xid.cc b/sql/wsrep_xid.cc
new file mode 100644
index 00000000000..056da5748b9
--- /dev/null
+++ b/sql/wsrep_xid.cc
@@ -0,0 +1,150 @@
+/* Copyright 2015 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
+
+#include "wsrep_xid.h"
+#include "sql_class.h"
+#include "wsrep_mysqld.h" // for logging macros
+
+/*
+ * 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));
+}
+
+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));
+}
+
+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;
+ }
+}
+
+static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
+{
+ XID* xid= static_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);
+}
+
+void wsrep_set_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
+{
+ XID xid;
+ wsrep_xid_init(&xid, uuid, seqno);
+ wsrep_set_SE_checkpoint(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_get_SE_checkpoint(wsrep_uuid_t& uuid, wsrep_seqno_t& seqno)
+{
+ uuid= WSREP_UUID_UNDEFINED;
+ seqno= WSREP_SEQNO_UNDEFINED;
+
+ XID xid;
+ memset(&xid, 0, sizeof(xid));
+ xid.formatID= -1;
+
+ wsrep_get_SE_checkpoint(xid);
+
+ if (xid.formatID == -1) return; // nil XID
+
+ if (!wsrep_is_wsrep_xid(&xid))
+ {
+ WSREP_WARN("Read non-wsrep XID from storage engines.");
+ return;
+ }
+
+ uuid= *wsrep_xid_uuid(xid);
+ seqno= wsrep_xid_seqno(xid);
+}
diff --git a/sql/wsrep_xid.h b/sql/wsrep_xid.h
new file mode 100644
index 00000000000..8a43e49c733
--- /dev/null
+++ b/sql/wsrep_xid.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2015 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_XID_H
+#define WSREP_XID_H
+
+#include <my_config.h>
+#include "../wsrep/wsrep_api.h"
+#include "handler.h" // XID typedef
+
+void wsrep_xid_init(xid_t*, const wsrep_uuid_t&, wsrep_seqno_t);
+int wsrep_is_wsrep_xid(const void* xid);
+const wsrep_uuid_t* wsrep_xid_uuid(const XID&);
+wsrep_seqno_t wsrep_xid_seqno(const XID&);
+
+//void wsrep_get_SE_checkpoint(XID&); /* uncomment if needed */
+void wsrep_get_SE_checkpoint(wsrep_uuid_t&, wsrep_seqno_t&);
+//void wsrep_set_SE_checkpoint(XID&); /* uncomment if needed */
+void wsrep_set_SE_checkpoint(const wsrep_uuid_t&, wsrep_seqno_t);
+
+#endif /* WSREP_UTILS_H */
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index 18efa58b2a3..2d7247ea4bd 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -323,7 +323,28 @@ ENDIF()
# Include directories under innobase
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include
- ${CMAKE_SOURCE_DIR}/storage/innobase/handler)
+ ${CMAKE_SOURCE_DIR}/storage/innobase/handler)
+
+IF(WITH_WSREP)
+ # ssl include directory
+ INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS}
+ ${CMAKE_SOURCE_DIR}/storage/innobase/wsrep)
+
+ IF(SSL_DEFINES)
+ ADD_DEFINITIONS(${SSL_DEFINES})
+ ENDIF()
+
+ LINK_LIBRARIES(${SSL_LIBRARIES})
+
+ # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere.
+ # In order to get correct symbol visibility, these files
+ # must be compiled with "-fvisibility=hidden"
+ IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
+ SET_SOURCE_FILES_PROPERTIES(
+ {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc
+ PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
+ ENDIF()
+ENDIF()
# Sun Studio bug with -xO2
IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro"
@@ -469,6 +490,10 @@ SET(INNOBASE_SOURCES
ut/ut0vec.cc
ut/ut0wqueue.cc)
+IF(WITH_WSREP)
+ SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc)
+ENDIF()
+
IF(WITH_INNODB)
# Legacy option
SET(WITH_INNOBASE_STORAGE_ENGINE TRUE)
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 9642fc86018..e3c7d972532 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -41,6 +41,7 @@ Created April 08, 2011 Vasil Dimov
#include "sync0rw.h" /* rw_lock_s_lock() */
#include "ut0byte.h" /* ut_ull_create() */
#include "ut0sort.h" /* UT_SORT_FUNCTION_BODY */
+#include "wsrep_mysqld.h" /* wsrep_recovery */
enum status_severity {
STATUS_INFO,
@@ -219,7 +220,20 @@ buf_dump(
buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
full_filename);
- f = fopen(tmp_filename, "w");
+#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
+ f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
+#else
+ {
+ int fd;
+ fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
+ if (fd >= 0) {
+ f = fdopen(fd, "w");
+ }
+ else {
+ f = NULL;
+ }
+ }
+#endif
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",
@@ -690,7 +704,14 @@ DECLARE_THREAD(buf_dump_thread)(
buf_load_status(STATUS_INFO, "not started");
if (srv_buffer_pool_load_at_startup) {
- buf_load();
+
+#ifdef WITH_WSREP
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
+ buf_load();
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
}
while (!SHUTTING_DOWN()) {
@@ -714,8 +735,15 @@ DECLARE_THREAD(buf_dump_thread)(
}
if (srv_buffer_pool_dump_at_shutdown && srv_fast_shutdown != 2) {
+#ifdef WITH_WSREP
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
+
buf_dump(FALSE /* ignore shutdown down flag,
keep going even if we are in a shutdown state */);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
}
srv_buf_dump_thread_active = FALSE;
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 7575a4aed62..0485f0470df 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -3383,7 +3383,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,
+ NULL, NULL, NULL);
+}
+#endif /* WITH_WSREP */
/**********************************************************************//**
Report an error in a foreign key definition. */
static
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 3959b49b600..7d1911889bd 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -126,6 +126,45 @@ MYSQL_PLUGIN_IMPORT extern char mysql_unpacked_real_data_home[];
# define MYSQL_PLUGIN_IMPORT /* nothing */
# endif /* MYSQL_PLUGIN_IMPORT */
+#ifdef WITH_WSREP
+#include "dict0priv.h"
+#include "../storage/innobase/include/ut0byte.h"
+#include <wsrep_mysqld.h>
+#include <wsrep_md5.h>
+
+extern my_bool wsrep_certify_nonPK;
+class binlog_trx_data;
+extern handlerton *binlog_hton;
+
+extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
+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);
+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 /* WITH_WSREP */
/** to protect innobase_open_files */
static mysql_mutex_t innobase_share_mutex;
/** to force correct commit order in binlog */
@@ -1356,6 +1395,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) {
@@ -1390,6 +1433,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
@@ -1530,6 +1577,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 /* WITH_WSREP */
/********************************************************************//**
Call this function when mysqld passes control to the client. That is to
@@ -2025,6 +2081,9 @@ int
innobase_mysql_tmpfile(
const char* path)
{
+#ifdef WITH_INNODB_DISALLOW_WRITES
+ os_event_wait(srv_allow_writes_event);
+#endif /* WITH_INNODB_DISALLOW_WRITES */
int fd2 = -1;
File fd;
@@ -2069,8 +2128,12 @@ innobase_mysql_tmpfile(
}
}
#else
+#ifdef F_DUPFD_CLOEXEC
+ fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+#else
fd2 = dup(fd);
#endif
+#endif
if (fd2 < 0) {
DBUG_PRINT("error",("Got error %d on dup",fd2));
my_errno=errno;
@@ -3104,6 +3167,12 @@ innobase_init(
innobase_hton->release_temporary_latches =
innobase_release_temporary_latches;
+#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 */
innobase_hton->kill_query = innobase_kill_query;
if (srv_file_per_table)
@@ -3713,10 +3782,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 */
}
/*****************************************************************//**
@@ -4438,25 +4527,66 @@ innobase_kill_query(
enum thd_kill_levels level) /*!< in: kill level */
{
trx_t* trx;
+
DBUG_ENTER("innobase_kill_query");
DBUG_ASSERT(hton == innodb_hton_ptr);
+#ifdef WITH_WSREP
+ wsrep_thd_LOCK(thd);
+ if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) {
+ /* if victim has been signaled by BF thread and/or aborting
+ is already progressing, following query aborting is not necessary
+ any more.
+ Also, BF thread should own trx mutex for the victim, which would
+ conflict with trx_mutex_enter() below
+ */
+ wsrep_thd_UNLOCK(thd);
+ DBUG_VOID_RETURN;
+ }
+ wsrep_thd_UNLOCK(thd);
+#endif /* WITH_WSREP */
trx = thd_to_trx(thd);
- if (trx) {
- THD *cur = current_thd;
- THD *owner = trx->current_lock_mutex_owner;
-
- /* Cancel a pending lock request. */
- if (owner != cur) {
+ if (trx && trx->lock.wait_lock) {
+ /* In wsrep BF we have already took lock_sys and trx
+ mutex either on wsrep_abort_transaction() or
+ before wsrep_kill_victim(). In replication we
+ could own lock_sys mutex taken in
+ lock_deadlock_check_and_resolve(). */
+
+ WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " TRX_ID_FMT " ABORT %d thd %p"
+ " current_thd %p BF %d wait_lock_modes: %s\n",
+ trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE),
+ wsrep_thd_is_BF(thd, FALSE),
+ trx->id, trx->abort_type,
+ trx->mysql_thd,
+ current_thd,
+ wsrep_thd_is_BF(current_thd, FALSE),
+ lock_get_info(trx->lock.wait_lock).c_str());
+
+ if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
+ trx->abort_type == TRX_SERVER_ABORT) {
+ ut_ad(!lock_mutex_own());
lock_mutex_enter();
}
- trx_mutex_enter(trx);
+
+ if (trx->abort_type != TRX_WSREP_ABORT) {
+ trx_mutex_enter(trx);
+ }
+
+ ut_ad(lock_mutex_own());
+ ut_ad(trx_mutex_own(trx));
+
if (trx->lock.wait_lock) {
lock_cancel_waiting_and_release(trx->lock.wait_lock);
}
- trx_mutex_exit(trx);
- if (owner != cur) {
+
+ if (trx->abort_type != TRX_WSREP_ABORT) {
+ trx_mutex_exit(trx);
+ }
+
+ if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
+ trx->abort_type == TRX_SERVER_ABORT) {
lock_mutex_exit();
}
}
@@ -4615,7 +4745,11 @@ ha_innobase::max_supported_key_length() const
case 8192:
return(1536);
default:
+#ifdef WITH_WSREP
+ return(3500);
+#else
return(3500);
+#endif
}
}
@@ -5702,6 +5836,117 @@ 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);
+
+ tmp_length = charset->coll->strnxfrm(charset, str, str_length,
+ str_length, tmp_str,
+ tmp_length, 0);
+ DBUG_ASSERT(tmp_length <= 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
is such that we must use MySQL code to compare them. NOTE that the prototype
@@ -6200,6 +6445,312 @@ innobase_read_from_2_little_endian(
return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))));
}
+#ifdef WITH_WSREP
+/*******************************************************************//**
+Stores a key value for a row to a buffer.
+@return key value length as stored in buff */
+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 */
+
/*******************************************************************//**
Stores a key value for a row to a buffer.
@return key value length as stored in buff */
@@ -7112,6 +7663,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);
@@ -7145,8 +7699,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
@@ -7180,6 +7746,28 @@ 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 (binlog_hton->commit(binlog_hton, 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. */
@@ -7190,6 +7778,28 @@ 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 (binlog_hton->commit(binlog_hton, 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. */
@@ -7219,6 +7829,10 @@ 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. */
@@ -7297,6 +7911,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 /* WITH_WSREP */
+
default:
break;
}
@@ -7356,6 +8004,21 @@ report_error:
prebuilt->table->flags,
user_thd);
+#ifdef WITH_WSREP
+ if (!error_result
+ && wsrep_on(user_thd)
+ && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE
+ && !wsrep_consistency_check(user_thd)
+ && !wsrep_thd_skip_append_keys(user_thd)) {
+ 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 /* WITH_WSREP */
+
if (error_result == HA_FTS_INVALID_DOCID) {
my_error(HA_FTS_INVALID_DOCID, MYF(0));
}
@@ -7643,6 +8306,87 @@ calc_row_difference(
return(DB_SUCCESS);
}
+#ifdef WITH_WSREP
+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->null_ptr &&
+ field_in_record_is_null(table, field, (char*) row)) {
+ */
+
+ 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 */
/**********************************************************************//**
Updates a row given as a parameter to a new value. Note that we are given
whole rows, not just the fields which are updated: this incurs some
@@ -7780,6 +8524,25 @@ func_exit:
innobase_active_small();
+#ifdef WITH_WSREP
+ if (error == DB_SUCCESS &&
+ wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd) &&
+ !wsrep_thd_skip_append_keys(user_thd))
+ {
+ DBUG_PRINT("wsrep", ("update row key"));
+
+ if (wsrep_append_keys(user_thd, false, old_row, new_row)) {
+ WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED");
+ DBUG_PRINT("wsrep", ("row key failed"));
+ err = HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif /* WITH_WSREP */
+
+
DBUG_RETURN(err);
}
@@ -7827,6 +8590,20 @@ 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) &&
+ !wsrep_thd_skip_append_keys(user_thd))
+ {
+ if (wsrep_append_keys(user_thd, false, record, NULL)) {
+ DBUG_PRINT("wsrep", ("delete fail"));
+ error = (dberr_t)HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif
DBUG_RETURN(convert_error_code_to_mysql(
error, prebuilt->table->flags, user_thd));
}
@@ -9049,6 +9826,415 @@ ha_innobase::ft_end()
rnd_end();
}
+#ifdef WITH_WSREP
+extern 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 */
+{
+ ut_a(trx);
+ THD* thd = (THD*)trx->mysql_thd;
+ ulint rcode = DB_SUCCESS;
+ char cache_key[513] = {'\0'};
+ int cache_key_len;
+ bool const copy = true;
+
+ 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: %lu (%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);
+#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,
+ (size_t*)&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 = (int)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: %lu", rcode));
+ WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu",
+ (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 Query: %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,
+ (size_t*)&wkey.key_parts_num)) {
+ WSREP_WARN("key prepare failed for: %s",
+ (wsrep_thd_query(thd)) ?
+ wsrep_thd_query(thd) : "void");
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ }
+
+ int rcode = (int)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(HA_ERR_INTERNAL_ERROR);
+ }
+ DBUG_RETURN(0);
+}
+
+extern void compute_md5_hash(char *digest, const char *buf, int len);
+#define MD5_HASH compute_md5_hash
+
+static bool
+referenced_by_foreign_key2(dict_table_t* table,
+ dict_index_t* index) {
+ ut_ad(table != NULL);
+ ut_ad(index != NULL);
+
+ const dict_foreign_set* fks = &table->referenced_set;
+ for (dict_foreign_set::const_iterator it = fks->begin();
+ it != fks->end();
+ ++it)
+ {
+ dict_foreign_t* foreign = *it;
+ if (foreign->referenced_index != index) {
+ continue;
+ }
+ ut_ad(table == foreign->referenced_table);
+ return true;
+ }
+ return false;
+}
+
+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 &&
+ referenced_by_foreign_key2(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 /* WITH_WSREP */
/*********************************************************************//**
Stores a reference to the current row to 'ref' field of the handle. Note
@@ -12911,11 +14097,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 */
}
}
@@ -14033,7 +15226,20 @@ ha_innobase::get_auto_increment(
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, offset, col_max_value);
@@ -14395,6 +15601,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);
}
@@ -16466,6 +17675,327 @@ 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();
+}
+/*******************************************************************//**
+This function is used to kill one transaction in BF. */
+UNIV_INTERN
+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: %lu", 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: %lu", (bf_trx) ? bf_trx->id : 0);
+ DBUG_RETURN(1);
+ }
+
+ WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
+
+ WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu",
+ signal, (long long)bf_seqno,
+ wsrep_thd_thread_id(thd),
+ victim_trx->id);
+
+ WSREP_DEBUG("Aborting query: %s conf %d trx: %lu",
+ (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void",
+ wsrep_thd_conflict_state(thd),
+ wsrep_thd_ws_handle(thd)->trx_id);
+
+ wsrep_thd_LOCK(thd);
+ DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.wsrep_after_BF_victim_lock";
+ DBUG_ASSERT(!debug_sync_set_action(bf_thd,
+ STRING_WITH_LEN(act)));
+ };);
+
+
+ if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
+ WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ DBUG_RETURN(0);
+ }
+
+ if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
+ WSREP_DEBUG("withdraw for BF trx: %lu, state: %d",
+ 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 %lu in MUST ABORT state",
+ 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 %lu in state %d",
+ 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 query for: %ld",
+ wsrep_thd_thread_id(thd));
+ WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu",
+ victim_trx->id);
+
+ 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)wsrep_thd_ws_handle(thd)->trx_id
+ );
+
+ switch (rcode) {
+ case WSREP_WARNING:
+ WSREP_DEBUG("cancel commit warning: %lu",
+ victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ wsrep_thd_awake(thd, signal);
+ DBUG_RETURN(1);
+ break;
+ case WSREP_OK:
+ break;
+ default:
+ WSREP_ERROR(
+ "cancel commit bad exit: %d %lu",
+ rcode,
+ victim_trx->id);
+ /* unable to interrupt, must abort */
+ /* note: kill_mysql() will block, if we cannot.
+ * kill the lock holder first.
+ */
+ abort();
+ break;
+ }
+ }
+ wsrep_thd_UNLOCK(thd);
+ wsrep_thd_awake(thd, signal);
+ 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 %lu", 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_UNLOCK(thd);
+ 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));
+ /* Note that innobase_kill_connection will take lock_mutex
+ and trx_mutex */
+ wsrep_thd_UNLOCK(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 %lu", 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);
+ wsrep_thd_UNLOCK(thd);
+
+ break;
+ }
+ default:
+ WSREP_WARN("bad wsrep query state: %d",
+ wsrep_thd_query_state(thd));
+ wsrep_thd_UNLOCK(thd);
+ break;
+ }
+
+ 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 victim conf: %d",
+ wsrep_thd_query(bf_thd),
+ wsrep_thd_query(victim_thd),
+ wsrep_thd_conflict_state(victim_thd));
+
+ if (victim_trx) {
+ lock_mutex_enter();
+ trx_mutex_enter(victim_trx);
+ victim_trx->abort_type = TRX_WSREP_ABORT;
+ int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
+ victim_trx, signal);
+ trx_mutex_exit(victim_trx);
+ lock_mutex_exit();
+ victim_trx->abort_type = TRX_SERVER_ABORT;
+ 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 */
+{
+ mutex_enter(&trx_sys->mutex);
+ trx_id_t trx_id = trx_sys_get_new_trx_id();
+ mutex_exit(&trx_sys->mutex);
+ WSREP_DEBUG("innodb fake trx id: %lu thd: %s", trx_id, wsrep_thd_query(thd));
+ (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,
@@ -17219,6 +18749,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.",
@@ -17448,6 +19012,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 f9e98d5dfe6..8fd60046650 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -96,6 +96,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);
@@ -445,7 +449,40 @@ MY_ATTRIBUTE((nonnull));
*/
extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file);
-struct trx_t;
+#ifdef WITH_WSREP
+#include <wsrep_mysqld.h>
+//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2);
+
+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
extern const struct _ft_vft ft_vft_result;
@@ -483,6 +520,9 @@ innobase_index_name_is_reserved(
MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/*****************************************************************//**
+#ifdef WITH_WSREP
+extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
+#endif
Determines InnoDB table flags.
@retval true if successful, false if error */
UNIV_INTERN
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 6a3e9575eb1..9764f4b841a 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -51,6 +51,10 @@ Smart ALTER TABLE
#include "pars0pars.h"
#include "row0sel.h"
#include "ha_innodb.h"
+#ifdef WITH_WSREP
+//#include "wsrep_api.h"
+#include <sql_acl.h> // PROCESS_ACL
+#endif
/** Operations for creating secondary indexes (no rebuild needed) */
static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 394106235ef..650dd5d6e81 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -493,6 +493,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{
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 488ed0257a7..fee145dbdf3 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -274,6 +274,22 @@ 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);
+my_bool wsrep_thd_is_wsrep(void *thd_ptr);
+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);
+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 6f9a628df5d..9a4077befb1 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 7fbc19086d5..2547097a14b 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -654,6 +654,16 @@ lock_get_type(
const lock_t* lock); /*!< in: lock */
/*******************************************************************//**
+Gets the trx of the lock. Non-inline version for using outside of the
+lock module.
+@return trx_t* */
+UNIV_INTERN
+trx_t*
+lock_get_trx(
+/*=========*/
+ const lock_t* lock); /*!< in: lock */
+
+/*******************************************************************//**
Gets the id of the transaction owning a lock.
@return transaction id */
UNIV_INTERN
@@ -978,6 +988,24 @@ 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 */
+
+/*******************************************************************//**
+Get lock mode and table/index name
+@return string containing lock info */
+std::string
+lock_get_info(
+ const lock_t*);
+
+#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 742d2cc87d9..330718bae9b 100644
--- a/storage/innobase/include/rem0rec.h
+++ b/storage/innobase/include/rem0rec.h
@@ -984,6 +984,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
+int 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 190397595ee..bc45b4f15c5 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -277,6 +277,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 */
@@ -918,5 +922,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 84a9be971b9..f4b874bdc84 100644
--- a/storage/innobase/include/sync0sync.ic
+++ b/storage/innobase/include/sync0sync.ic
@@ -206,7 +206,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 4a88ef241a1..f70c53b57e6 100644
--- a/storage/innobase/include/trx0sys.h
+++ b/storage/innobase/include/trx0sys.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
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
@@ -42,6 +43,9 @@ Created 3/26/1996 Heikki Tuuri
#include "read0types.h"
#include "page0types.h"
#include "ut0bh.h"
+#ifdef WITH_WSREP
+#include "trx0xa.h"
+#endif /* WITH_WSREP */
typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t;
@@ -293,6 +297,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 +308,29 @@ UNIV_INTERN
void
trx_sys_print_mysql_binlog_offset(void);
/*===================================*/
+
+#ifdef WITH_WSREP
+
+/** Update WSREP XID info in sys_header of TRX_SYS_PAGE_NO = 5.
+@param[in] xid Transaction XID
+@param[in,out] sys_header sys_header
+@param[in] mtr minitransaction */
+UNIV_INTERN
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid,
+ trx_sysf_t* sys_header,
+ mtr_t* mtr);
+
+/** Read WSREP XID from sys_header of TRX_SYS_PAGE_NO = 5.
+@param[out] xid Transaction XID
+@return true on success, false on error. */
+UNIV_INTERN
+bool
+trx_sys_read_wsrep_checkpoint(XID* 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 +559,78 @@ 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 */
+/** Memory map TRX_SYS_PAGE_NO = 5 when UNIV_PAGE_SIZE = 4096
+
+0...37 FIL_HEADER
+38...45 TRX_SYS_TRX_ID_STORE
+46...55 TRX_SYS_FSEG_HEADER (FSEG_HEADER_SIZE == 10)
+56 TRX_SYS_RSEGS
+ 56...59 TRX_SYS_RSEG_SPACE for slot 0
+ 60...63 TRX_SYS_RSEG_PAGE_NO for slot 0
+ 64...67 TRX_SYS_RSEG_SPACE for slot 1
+ 68...71 TRX_SYS_RSEG_PAGE_NO for slot 1
+....
+ 594..597 TRX_SYS_RSEG_SPACE for slot 72
+ 598..601 TRX_SYS_RSEG_PAGE_NO for slot 72
+...
+ ...1063 TRX_SYS_RSEG_PAGE_NO for slot 126
+
+(UNIV_PAGE_SIZE-3500 WSREP ::: FAIL would overwrite undo tablespace
+space_id, page_no pairs :::)
+596 TRX_SYS_WSREP_XID_INFO TRX_SYS_WSREP_XID_MAGIC_N_FLD
+600 TRX_SYS_WSREP_XID_FORMAT
+604 TRX_SYS_WSREP_XID_GTRID_LEN
+608 TRX_SYS_WSREP_XID_BQUAL_LEN
+612 TRX_SYS_WSREP_XID_DATA (len = 128)
+739 TRX_SYS_WSREP_XID_DATA_END
+
+FIXED WSREP XID info offsets for 4k page size 10.0.32-galera
+(UNIV_PAGE_SIZE-2500)
+1596 TRX_SYS_WSREP_XID_INFO TRX_SYS_WSREP_XID_MAGIC_N_FLD
+1600 TRX_SYS_WSREP_XID_FORMAT
+1604 TRX_SYS_WSREP_XID_GTRID_LEN
+1608 TRX_SYS_WSREP_XID_BQUAL_LEN
+1612 TRX_SYS_WSREP_XID_DATA (len = 128)
+1739 TRX_SYS_WSREP_XID_DATA_END
+
+(UNIV_PAGE_SIZE - 2000 MYSQL MASTER LOG)
+2096 TRX_SYS_MYSQL_MASTER_LOG_INFO TRX_SYS_MYSQL_LOG_MAGIC_N_FLD
+2100 TRX_SYS_MYSQL_LOG_OFFSET_HIGH
+2104 TRX_SYS_MYSQL_LOG_OFFSET_LOW
+2108 TRX_SYS_MYSQL_LOG_NAME
+
+(UNIV_PAGE_SIZE - 1000 MYSQL LOG)
+3096 TRX_SYS_MYSQL_LOG_INFO TRX_SYS_MYSQL_LOG_MAGIC_N_FLD
+3100 TRX_SYS_MYSQL_LOG_OFFSET_HIGH
+3104 TRX_SYS_MYSQL_LOG_OFFSET_LOW
+3108 TRX_SYS_MYSQL_LOG_NAME
+
+(UNIV_PAGE_SIZE - 200 DOUBLEWRITE)
+3896 TRX_SYS_DOUBLEWRITE TRX_SYS_DOUBLEWRITE_FSEG
+3906 TRX_SYS_DOUBLEWRITE_MAGIC
+3910 TRX_SYS_DOUBLEWRITE_BLOCK1
+3914 TRX_SYS_DOUBLEWRITE_BLOCK2
+3918 TRX_SYS_DOUBLEWRITE_REPEAT
+3930 TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N
+
+(UNIV_PAGE_SIZE - 8, TAILER)
+4088..4096 FIL_TAILER
+
+*/
+#ifdef WITH_WSREP
+/** The offset to WSREP XID headers */
+#define TRX_SYS_WSREP_XID_INFO (ut_max(UNIV_PAGE_SIZE - 3500, 1596))
+#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 e097e29b551..7265a97ae25 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 aed70afef65..6db87efaf91 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, 2017, MariaDB Corporation.
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
@@ -333,6 +334,23 @@ trx_print_latched(
or 0 to use the default max length */
MY_ATTRIBUTE((nonnull));
+#ifdef WITH_WSREP
+/**********************************************************************//**
+Prints info about a transaction.
+Transaction information may be retrieved without having trx_sys->mutex acquired
+so it may not be completely accurate. The caller must own lock_sys->mutex
+and the trx must have some locks to make sure that it does not escape
+without locking lock_sys->mutex. */
+UNIV_INTERN
+void
+wsrep_trx_print_locking(
+/*==============*/
+ FILE* f, /*!< in: output stream */
+ const trx_t* trx, /*!< in: transaction */
+ ulint max_query_len) /*!< in: max query length to print,
+ or 0 to use the default max length */
+ MY_ATTRIBUTE((nonnull));
+#endif /* WITH_WSREP */
/**********************************************************************//**
Prints info about a transaction.
Acquires and releases lock_sys->mutex and trx_sys->mutex. */
@@ -673,6 +691,12 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
+typedef enum {
+ TRX_SERVER_ABORT = 0,
+ TRX_WSREP_ABORT = 1,
+ TRX_REPLICATION_ABORT = 2
+} trx_abort_t;
+
struct trx_t{
ulint magic_n;
@@ -848,6 +872,8 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
+ trx_abort_t abort_type; /*!< Transaction abort type*/
+
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file
@@ -992,11 +1018,6 @@ struct trx_t{
count of tables being flushed. */
/*------------------------------*/
- THD* current_lock_mutex_owner;
- /*!< If this is equal to current_thd,
- then in innobase_kill_query() we know we
- already hold the lock_sys->mutex. */
- /*------------------------------*/
#ifdef UNIV_DEBUG
ulint start_line; /*!< Track where it was started from */
const char* start_file; /*!< Filename where it was started */
@@ -1022,6 +1043,9 @@ struct trx_t{
ulint total_table_lock_wait_time;
/*!< Total table lock wait time
up to this moment. */
+#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 1e91ce45633..fb861bbec56 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -52,6 +52,15 @@ Created 5/7/1996 Heikki Tuuri
#include <set>
#include "mysql/plugin.h"
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+extern my_bool wsrep_log_conflicts;
+#include "ha_prototypes.h"
+#endif
+
+#include <string>
+#include <sstream>
+
/* Restricts the length of search we will do in the waits-for
graph of transactions */
#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
@@ -962,6 +971,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
@@ -1058,9 +1070,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);
}
@@ -1088,7 +1150,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)));
@@ -1557,6 +1623,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.
@@ -1605,6 +1676,72 @@ 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));
+
+ /* quit for native mysql */
+ if (!wsrep_on(trx->mysql_thd)) return;
+
+ 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) {
+ if (bf_this) {
+ fputs("\n*** Priority TRANSACTION:\n",
+ stderr);
+ } else {
+ fputs("\n*** Victim TRANSACTION:\n",
+ stderr);
+ }
+
+ wsrep_trx_print_locking(stderr, trx, 3000);
+
+ if (bf_other) {
+ fputs("\n*** Priority TRANSACTION:\n",
+ stderr);
+ } else {
+ fputs("\n*** Victim TRANSACTION:\n",
+ stderr);
+ }
+
+ wsrep_trx_print_locking(stderr, lock->trx, 3000);
+
+ 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);
+ }
+ }
+
+ lock->trx->abort_type = TRX_WSREP_ABORT;
+ wsrep_innobase_kill_one_trx(trx->mysql_thd,
+ (const trx_t*) trx, lock->trx, TRUE);
+ lock->trx->abort_type = TRX_SERVER_ABORT;
+ }
+ }
+}
+#endif
/*********************************************************************//**
Checks if some other transaction has a conflicting explicit lock request
in the queue, so that we have to wait.
@@ -1633,7 +1770,17 @@ lock_rec_other_has_conflicting(
lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) {
- if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) {
+#ifdef WITH_WSREP
+ if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) {
+ if (wsrep_on(trx->mysql_thd)) {
+ 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);
}
}
@@ -1814,6 +1961,28 @@ 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
for deadlocks or lock compatibility!
@@ -1822,6 +1991,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 */
@@ -1896,8 +2069,90 @@ lock_rec_create(
ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted);
+#ifdef WITH_WSREP
+ if (c_lock &&
+ wsrep_on(trx->mysql_thd) &&
+ 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);
@@ -1905,7 +2160,6 @@ lock_rec_create(
ut_ad(trx_mutex_own(trx));
if (type_mode & LOCK_WAIT) {
-
lock_set_lock_and_trx_wait(lock, trx);
}
@@ -1917,7 +2171,6 @@ lock_rec_create(
MONITOR_INC(MONITOR_RECLOCK_CREATED);
MONITOR_INC(MONITOR_NUM_RECLOCK);
-
return(lock);
}
@@ -1932,6 +2185,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
@@ -1989,6 +2245,9 @@ lock_rec_enqueue_waiting(
/* Enqueue the lock request that will wait to be granted, note that
we already own the trx mutex. */
lock = lock_rec_create(
+#ifdef WITH_WSREP
+ c_lock, thr,
+#endif /* WITH_WSREP */
type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
/* Release the mutex to obey the latching order.
@@ -2092,7 +2351,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_thd_is_wsrep(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 */
@@ -2120,7 +2391,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;
}
}
@@ -2143,9 +2423,15 @@ lock_rec_add_to_queue(
}
somebody_waits:
- return(lock_rec_create(
+#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 /* WITH_WSREP */
}
/** Record locking request status */
@@ -2208,9 +2494,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 /* WITH_WSREP */
}
status = LOCK_REC_SUCCESS_CREATED;
} else {
@@ -2263,6 +2553,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());
@@ -2286,18 +2579,31 @@ lock_rec_lock_slow(
/* The trx already has a strong enough lock on rec: do
nothing */
-
+#ifdef WITH_WSREP
+ } else if ((c_lock = (ib_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
@@ -2349,6 +2655,7 @@ lock_rec_lock(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0);
+
ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index));
/* We try a simplified and faster subroutine for the most
@@ -2403,7 +2710,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);
}
}
@@ -3800,10 +4113,22 @@ lock_deadlock_select_victim(
/* The joining transaction is 'smaller',
choose it as the victim and roll it back. */
- return(ctx->start);
+#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);
}
- return(ctx->wait_lock->trx);
+#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);
}
/********************************************************************//**
@@ -3933,8 +4258,14 @@ lock_deadlock_search(
ctx->too_deep = TRUE;
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) {
+ return(ctx->wait_lock->trx->id);
+ }
+ else
+#endif /* WITH_WSREP */
/* Select the joining transaction as the victim. */
- return(ctx->start->id);
+ return(ctx->start->id);
} else {
/* We do not need to report autoinc locks to the upper
@@ -4080,9 +4411,9 @@ lock_report_waiters_to_mysql(
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
- w_trx->current_lock_mutex_owner = mysql_thd;
+ w_trx->abort_type = TRX_REPLICATION_ABORT;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
- w_trx->current_lock_mutex_owner = NULL;
+ w_trx->abort_type = TRX_SERVER_ABORT;
}
++i;
}
@@ -4159,9 +4490,18 @@ lock_deadlock_check_and_resolve(
ut_a(trx == ctx.start);
ut_a(victim_trx_id == trx->id);
- if (!srv_read_only_mode) {
- lock_deadlock_joining_trx_print(trx, lock);
+#ifdef WITH_WSREP
+ if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE))
+ {
+#endif /* WITH_WSREP */
+ 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);
@@ -4199,6 +4539,9 @@ UNIV_INLINE
lock_t*
lock_table_create(
/*==============*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /*!< in: conflicting lock */
+#endif
dict_table_t* table, /*!< in/out: database table
in dictionary cache */
ulint type_mode,/*!< in: lock mode possibly ORed with
@@ -4244,7 +4587,59 @@ 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 (wsrep_thd_is_wsrep(trx->mysql_thd)) {
+ 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);
+ wsrep_print_wait_locks(c_lock->trx->lock.wait_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 {
+#endif /* WITH_WSREP */
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
@@ -4401,6 +4796,9 @@ static
dberr_t
lock_table_enqueue_waiting(
/*=======================*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /*!< in: conflicting lock */
+#endif
ulint mode, /*!< in: lock mode this transaction is
requesting */
dict_table_t* table, /*!< in/out: table */
@@ -4445,7 +4843,14 @@ lock_table_enqueue_waiting(
/* Enqueue the lock request that will wait to be granted */
- lock = lock_table_create(table, mode | LOCK_WAIT, trx);
+#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 /* WITH_WSREP */
/* Release the mutex to obey the latching order.
This is safe, because lock_deadlock_check_and_resolve()
@@ -4518,6 +4923,18 @@ lock_table_other_has_incompatible(
&& !lock_mode_compatible(lock_get_mode(lock), mode)
&& (wait || !lock_get_wait(lock))) {
+#ifdef WITH_WSREP
+ if(wsrep_thd_is_wsrep(trx->mysql_thd)) {
+ if (wsrep_debug) {
+ fprintf(stderr, "WSREP: trx %ld table lock abort\n",
+ trx->id);
+ }
+ trx_mutex_enter(lock->trx);
+ wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
+ trx_mutex_exit(lock->trx);
+ }
+#endif
+
return(lock);
}
}
@@ -4540,6 +4957,9 @@ lock_table(
enum lock_mode mode, /*!< in: lock mode */
que_thr_t* thr) /*!< in: query thread */
{
+#ifdef WITH_WSREP
+ lock_t *c_lock = NULL;
+#endif
trx_t* trx;
dberr_t err;
const lock_t* wait_for;
@@ -4571,8 +4991,13 @@ lock_table(
/* We have to check if the new lock is compatible with any locks
other transactions have in the table lock queue. */
+#ifdef WITH_WSREP
+ wait_for = lock_table_other_has_incompatible(
+ trx, LOCK_WAIT, table, mode);
+#else
wait_for = lock_table_other_has_incompatible(
trx, LOCK_WAIT, table, mode);
+#endif
trx_mutex_enter(trx);
@@ -4580,9 +5005,17 @@ lock_table(
mode: this trx may have to wait */
if (wait_for != NULL) {
+#ifdef WITH_WSREP
+ err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr);
+#else
err = lock_table_enqueue_waiting(mode | flags, table, thr);
+#endif
} else {
+#ifdef WITH_WSREP
+ lock_table_create(c_lock, table, mode | flags, trx);
+#else
lock_table_create(table, mode | flags, trx);
+#endif
ut_a(!flags || mode == LOCK_S || mode == LOCK_X);
@@ -4620,7 +5053,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
lock_mutex_exit();
trx_mutex_exit(trx);
}
@@ -5786,6 +6223,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) {
@@ -5794,7 +6232,9 @@ lock_rec_queue_validate(
mode = LOCK_S;
}
ut_a(!lock_rec_other_has_expl_req(
- mode, 0, 0, block, heap_no, lock->trx));
+ mode, 0, 0, block, heap_no, lock->trx));
+ }
+#endif /* WITH_WSREP */
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
@@ -6099,6 +6539,9 @@ lock_rec_insert_check_and_lock(
dberr_t err;
ulint next_rec_heap_no;
ibool inherit_in = *inherit;
+#ifdef WITH_WSREP
+ lock_t* c_lock=NULL;
+#endif
ut_ad(block->frame == page_align(rec));
ut_ad(!dict_index_is_online_ddl(index)
@@ -6155,17 +6598,30 @@ 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 = (ib_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 {
@@ -6320,8 +6776,9 @@ lock_clust_rec_modify_check_and_lock(
lock_rec_convert_impl_to_expl(block, rec, index, offsets);
lock_mutex_enter();
+ trx_t* trx = thr_get_trx(thr);
- ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ ut_ad(lock_table_has(trx, index->table, LOCK_IX));
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, index, thr);
@@ -6379,9 +6836,10 @@ lock_sec_rec_modify_check_and_lock(
index record, and this would not have been possible if another active
transaction had modified this secondary index record. */
+ trx_t* trx = thr_get_trx(thr);
lock_mutex_enter();
- ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ ut_ad(lock_table_has(trx, index->table, LOCK_IX));
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, index, thr);
@@ -6478,12 +6936,13 @@ lock_sec_rec_read_check_and_lock(
lock_rec_convert_impl_to_expl(block, rec, index, offsets);
}
+ trx_t* trx = thr_get_trx(thr);
lock_mutex_enter();
ut_ad(mode != LOCK_X
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ || lock_table_has(trx, index->table, LOCK_IX));
ut_ad(mode != LOCK_S
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
+ || lock_table_has(trx, index->table, LOCK_IS));
err = lock_rec_lock(FALSE, mode | gap_mode,
block, heap_no, index, thr);
@@ -6551,11 +7010,12 @@ lock_clust_rec_read_check_and_lock(
}
lock_mutex_enter();
+ trx_t* trx = thr_get_trx(thr);
ut_ad(mode != LOCK_X
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ || lock_table_has(trx, index->table, LOCK_IX));
ut_ad(mode != LOCK_S
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
+ || lock_table_has(trx, index->table, LOCK_IS));
err = lock_rec_lock(FALSE, mode | gap_mode,
block, heap_no, index, thr);
@@ -6708,6 +7168,19 @@ lock_get_type(
}
/*******************************************************************//**
+Gets the trx of the lock. Non-inline version for using outside of the
+lock module.
+@return trx_t* */
+UNIV_INTERN
+trx_t*
+lock_get_trx(
+/*=========*/
+ const lock_t* lock) /*!< in: lock */
+{
+ return (lock->trx);
+}
+
+/*******************************************************************//**
Gets the id of the transaction owning a lock.
@return transaction id */
UNIV_INTERN
@@ -7279,3 +7752,32 @@ lock_trx_has_rec_x_lock(
return(true);
}
#endif /* UNIV_DEBUG */
+
+/*******************************************************************//**
+Get lock mode and table/index name
+@return string containing lock info */
+std::string
+lock_get_info(
+ const lock_t* lock)
+{
+ std::string info;
+ std::string mode("mode ");
+ std::string index("index ");
+ std::string table("table ");
+ std::string n_uniq(" n_uniq");
+ std::string n_user(" n_user");
+ std::string lock_mode((lock_get_mode_str(lock)));
+ std::string iname(lock->index->name);
+ std::string tname(lock->index->table_name);
+
+#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \
+ ( std::ostringstream() << std::dec << x ) ).str()
+
+ info = mode + lock_mode
+ + index + iname
+ + table + tname
+ + n_uniq + SSTR(lock->index->n_uniq)
+ + n_user + SSTR(lock->index->n_user_defined_cols);
+
+ return info;
+}
diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc
index 5b67fbe72b7..92be74d1412 100644
--- a/storage/innobase/lock/lock0wait.cc
+++ b/storage/innobase/lock/lock0wait.cc
@@ -185,6 +185,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
@@ -377,9 +399,17 @@ lock_wait_suspend_thread(
if (lock_wait_timeout < 100000000
&& wait_time > (double) lock_wait_timeout) {
+#ifdef WITH_WSREP
+ if (!wsrep_on(trx->mysql_thd) ||
+ (!wsrep_is_BF_lock_timeout(trx) &&
+ trx->error_state != DB_DEADLOCK)) {
+#endif /* WITH_WSREP */
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
MONITOR_INC(MONITOR_TIMEOUT);
}
@@ -463,8 +493,13 @@ 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 038d59c2170..d1b6eadbaf7 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -88,6 +88,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:
@@ -754,6 +760,7 @@ os_file_create_tmpfile(
const char* path)
{
FILE* file = NULL;
+ WAIT_ALLOW_WRITES();
int fd = innobase_mysql_tmpfile(path);
ut_ad(!srv_read_only_mode);
@@ -1080,6 +1087,7 @@ os_file_create_directory(
return(TRUE);
#else
int rcode;
+ WAIT_ALLOW_WRITES();
rcode = mkdir(pathname, 0770);
@@ -1207,6 +1215,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));
@@ -1256,7 +1266,7 @@ os_file_create_simple_func(
}
do {
- file = ::open(name, create_flag, os_innodb_umask);
+ file = ::open(name, create_flag | O_CLOEXEC, os_innodb_umask);
if (file == -1) {
*success = FALSE;
@@ -1373,6 +1383,8 @@ os_file_create_simple_no_error_handling_func(
int create_flag;
const char* mode_str = NULL;
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));
@@ -1417,7 +1429,7 @@ os_file_create_simple_no_error_handling_func(
return(file);
}
- file.m_file = ::open(name, create_flag, os_innodb_umask);
+ file.m_file = ::open(name, create_flag | O_CLOEXEC, os_innodb_umask);
*success = file.m_file == -1 ? FALSE : TRUE;
@@ -1683,6 +1695,9 @@ 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;
on_error_silent = create_mode & OS_FILE_ON_ERROR_SILENT
@@ -1741,7 +1756,7 @@ os_file_create_func(
#endif /* O_SYNC */
do {
- file.m_file = ::open(name, create_flag, os_innodb_umask);
+ file.m_file = ::open(name, create_flag | O_CLOEXEC, os_innodb_umask);
if (file.m_file == -1) {
const char* operation;
@@ -1862,6 +1877,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -1926,6 +1942,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -1996,6 +2013,7 @@ os_file_rename_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = rename(oldpath, newpath);
@@ -2202,6 +2220,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__ */
}
@@ -2294,6 +2313,7 @@ os_file_flush_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
#if defined(HAVE_DARWIN_THREADS)
# ifndef F_FULLFSYNC
@@ -2910,6 +2930,7 @@ retry:
return(FALSE);
#else
ssize_t ret;
+ WAIT_ALLOW_WRITES();
ret = os_file_pwrite(file, buf, n, offset);
@@ -3145,7 +3166,7 @@ os_file_get_status(
access = !srv_read_only_mode ? O_RDWR : O_RDONLY;
- fh = ::open(path, access, os_innodb_umask);
+ fh = ::open(path, access | O_CLOEXEC, os_innodb_umask);
if (fh == -1) {
stat_info->rw_perm = false;
@@ -3574,7 +3595,7 @@ os_aio_native_aio_supported(void)
strcpy(name + dirnamelen, "ib_logfile0");
- fd = ::open(name, O_RDONLY);
+ fd = ::open(name, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc
index 6ad87ab9f46..79c39801abc 100644
--- a/storage/innobase/rem/rem0rec.cc
+++ b/storage/innobase/rem/rem0rec.cc
@@ -34,6 +34,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)
===========================
@@ -1959,3 +1962,133 @@ rec_get_trx_id(
}
# endif /* UNIV_DEBUG */
#endif /* !UNIV_HOTBACKUP */
+#ifdef WITH_WSREP
+int
+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 dbf43cca058..f196ba790df 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -931,6 +931,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
@@ -1282,7 +1290,19 @@ row_ins_foreign_check_on_constraint(
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
- err = row_update_cascade_for_mysql(thr, cascade,
+#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 /* WITH_WSREP */
+ err = row_update_cascade_for_mysql(thr, cascade,
foreign->foreign_table);
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
@@ -1437,6 +1457,9 @@ row_ins_check_foreign_constraint(
ulint* offsets = offsets_;
rec_offs_init(offsets_);
+#ifdef WITH_WSREP
+ upd_node= NULL;
+#endif /* WITH_WSREP */
run_again:
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
@@ -1616,7 +1639,15 @@ 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,
+ (upd_node) ? TRUE : FALSE);
+#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 4f1ce9a69ce..b81100d0520 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -54,6 +54,10 @@ Created 12/27/1996 Heikki Tuuri
#include "buf0lru.h"
#include <algorithm>
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+#endif
+
/* What kind of latch and lock can we assume when the control comes to
-------------------------------------------------------------------
an update node?
@@ -163,6 +167,50 @@ 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;
+ dict_foreign_t* foreign;
+ 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;
+ }
+
+ for (dict_foreign_set::iterator it= table->foreign_set.begin();
+ it != table->foreign_set.end();
+ ++ it)
+ {
+ foreign= *it;
+
+ if (foreign->foreign_index == index)
+ {
+ is_referenced= TRUE;
+ goto func_exit;
+ }
+ }
+
+func_exit:
+ 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.
@@ -282,7 +330,123 @@ run_again:
}
err = DB_SUCCESS;
+func_exit:
+ if (got_s_lock) {
+ row_mysql_unfreeze_data_dictionary(trx);
+ }
+
+ mem_heap_free(heap);
+
+ 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);
+ }
+
+ 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 = (foreign->referenced_table) ? TRUE : FALSE;
+ }
+
+ 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, FALSE, FALSE);
+ opened = FALSE;
+ }
+ }
+
+ if (err != DB_SUCCESS) {
+ goto func_exit;
+ }
+ }
+ }
+
+ err = DB_SUCCESS;
func_exit:
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
@@ -294,6 +458,7 @@ func_exit:
return(err);
}
+#endif /* WITH_WSREP */
/*********************************************************************//**
Creates an update node for a query graph.
@@ -1664,6 +1829,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);
@@ -1791,6 +1959,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);
@@ -1808,6 +1979,39 @@ row_upd_sec_index_entry(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ err == DB_SUCCESS && !referenced &&
+ !wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
+ !(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;
}
@@ -1962,6 +2166,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;
@@ -1975,6 +2182,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));
@@ -2057,6 +2267,34 @@ err_exit:
goto err_exit;
}
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) && !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);
@@ -2249,11 +2487,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));
@@ -2270,8 +2515,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 ! */
@@ -2279,6 +2532,33 @@ row_upd_del_mark_clust_rec(
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
+#ifdef WITH_WSREP
+ trx_t* trx = thr_get_trx(thr) ;
+
+ if (err == DB_SUCCESS && !referenced && trx && wsrep_on(trx->mysql_thd) &&
+ !(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, 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);
@@ -2311,6 +2591,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;
@@ -2405,7 +2689,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;
@@ -2450,7 +2738,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 3eda0700a15..f236f9eb9cc 100644
--- a/storage/innobase/srv/srv0conc.cc
+++ b/storage/innobase/srv/srv0conc.cc
@@ -43,6 +43,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. */
@@ -89,6 +93,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 */
@@ -148,6 +155,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 */
}
@@ -205,6 +215,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;
@@ -322,6 +342,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 */
@@ -332,6 +355,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;
@@ -387,6 +423,13 @@ retry:
return;
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_thd_is_brute_force(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 */
@@ -453,6 +496,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);
@@ -460,6 +506,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
@@ -475,6 +533,9 @@ retry:
os_event_wait(slot->event);
thd_wait_end(trx->mysql_thd);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
trx->op_info = "";
@@ -486,6 +547,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);
@@ -596,5 +660,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 e8e77c1376a..2874d74b860 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -72,6 +72,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;
@@ -212,6 +216,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;
@@ -1017,6 +1025,14 @@ srv_init(void)
dict_ind_init();
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);
@@ -1818,7 +1834,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/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 789fe50d337..c62c848c705 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -67,6 +67,8 @@ Created 2/16/1996 Heikki Tuuri
#include "ibuf0ibuf.h"
#include "srv0start.h"
#include "srv0srv.h"
+#include "wsrep_mysqld.h" /* wsrep_recovery */
+
#ifndef UNIV_HOTBACKUP
# include "trx0rseg.h"
# include "os0proc.h"
@@ -2895,9 +2897,23 @@ files_checked:
}
if (!srv_read_only_mode) {
+#ifdef WITH_WSREP
+ /* Create the dump/load thread only when not running with
+ --wsrep-recover */
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
+
/* Create the buffer pool dump/load thread */
buf_dump_thread_handle = os_thread_create(buf_dump_thread, NULL, NULL);
buf_dump_thread_started = true;
+#ifdef WITH_WSREP
+ } else {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Skipping buffer pool dump/restore during wsrep "
+ "recovery.");
+ }
+#endif /* WITH_WSREP */
+
}
srv_was_started = TRUE;
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index a9f3da0dc89..87b6f2ade35 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -46,6 +46,9 @@ Created 3/26/1996 Heikki Tuuri
#include "pars0pars.h"
#include "srv0mon.h"
#include "trx0sys.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h"
+#endif /* WITH_WSREP */
/** This many pages must be undone before a truncate is tried within
rollback */
@@ -368,6 +371,13 @@ trx_rollback_to_savepoint_for_mysql_low(
trx->op_info = "";
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->lock.was_chosen_as_deadlock_victim) {
+ trx->lock.was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
+
return(err);
}
@@ -1055,6 +1065,12 @@ 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 924141bdba0..68fc0e54351 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
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
@@ -47,6 +48,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 */
@@ -177,7 +182,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);
@@ -205,9 +215,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) {
@@ -216,7 +231,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)
@@ -303,6 +320,136 @@ 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];
+
+/** Read WSREP XID seqno */
+static inline long long read_wsrep_xid_seqno(const XID* xid)
+{
+ long long seqno;
+ memcpy(&seqno, xid->data + 24, sizeof(long long));
+ return seqno;
+}
+
+/** Read WSREP XID UUID */
+static inline void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
+{
+ memcpy(buf, xid->data + 8, 16);
+}
+
+#endif /* UNIV_DEBUG */
+
+/** Update WSREP XID info in sys_header of TRX_SYS_PAGE_NO = 5.
+@param[in] xid Transaction XID
+@param[in,out] sys_header sys_header
+@param[in] mtr minitransaction */
+UNIV_INTERN
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid,
+ trx_sysf_t* sys_header,
+ mtr_t* mtr)
+{
+#ifdef UNIV_DEBUG
+ if (xid->formatID != -1
+ && mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
+ == TRX_SYS_WSREP_XID_MAGIC_N) {
+ /* 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);
+ ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid((const void *)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);
+}
+
+/** Read WSREP XID from sys_header of TRX_SYS_PAGE_NO = 5.
+@param[out] xid Transaction XID
+@return true on success, false on error. */
+UNIV_INTERN
+bool
+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 false;
+ }
+
+ 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);
+ return true;
+}
+
+#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 2401783648a..312f5e73ac8 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -163,6 +163,9 @@ trx_create(void)
trx->lock.table_locks = ib_vector_create(
heap_alloc, sizeof(void**), 32);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
return(trx);
}
@@ -845,6 +848,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: */
@@ -959,6 +967,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;
@@ -1005,6 +1016,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((const void *)&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 */
@@ -1015,7 +1035,11 @@ trx_write_serialisation_history(
trx_sys_update_mysql_binlog_offset(
trx->mysql_log_file_name,
trx->mysql_log_offset,
- TRX_SYS_MYSQL_LOG_INFO, mtr);
+ TRX_SYS_MYSQL_LOG_INFO,
+#ifdef WITH_WSREP
+ sys_header,
+#endif /* WITH_WSREP */
+ mtr);
trx->mysql_log_file_name = NULL;
}
@@ -1311,6 +1335,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;
@@ -1495,6 +1524,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:
@@ -1834,6 +1867,118 @@ trx_print_latched(
mem_heap_get_size(trx->lock.lock_heap));
}
+#ifdef WITH_WSREP
+/**********************************************************************//**
+Prints info about a transaction.
+Transaction information may be retrieved without having trx_sys->mutex acquired
+so it may not be completely accurate. The caller must own lock_sys->mutex
+and the trx must have some locks to make sure that it does not escape
+without locking lock_sys->mutex. */
+UNIV_INTERN
+void
+wsrep_trx_print_locking(
+/*==========*/
+ FILE* f,
+ /*!< in: output stream */
+ const trx_t* trx,
+ /*!< in: transaction */
+ ulint max_query_len)
+ /*!< in: max query length to print,
+ or 0 to use the default max length */
+{
+ ibool newline;
+ const char* op_info;
+
+ ut_ad(lock_mutex_own());
+ ut_ad(trx->lock.trx_locks.count > 0);
+
+ fprintf(f, "TRANSACTION " TRX_ID_FMT, trx->id);
+
+ /* trx->state may change since trx_sys->mutex is not required */
+ switch (trx->state) {
+ case TRX_STATE_NOT_STARTED:
+ fputs(", not started", f);
+ goto state_ok;
+ case TRX_STATE_ACTIVE:
+ fprintf(f, ", ACTIVE %lu sec",
+ (ulong) difftime(time(NULL), trx->start_time));
+ goto state_ok;
+ case TRX_STATE_PREPARED:
+ fprintf(f, ", ACTIVE (PREPARED) %lu sec",
+ (ulong) difftime(time(NULL), trx->start_time));
+ goto state_ok;
+ case TRX_STATE_COMMITTED_IN_MEMORY:
+ fputs(", COMMITTED IN MEMORY", f);
+ goto state_ok;
+ }
+ fprintf(f, ", state %lu", (ulong) trx->state);
+ ut_ad(0);
+state_ok:
+
+ /* prevent a race condition */
+ op_info = trx->op_info;
+
+ if (*op_info) {
+ putc(' ', f);
+ fputs(op_info, f);
+ }
+
+ if (trx->is_recovered) {
+ fputs(" recovered trx", f);
+ }
+
+ if (trx->declared_to_be_inside_innodb) {
+ fprintf(f, ", thread declared inside InnoDB %lu",
+ (ulong) trx->n_tickets_to_enter_innodb);
+ }
+
+ putc('\n', f);
+
+ if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
+ fprintf(f, "mysql tables in use %lu, locked %lu\n",
+ (ulong) trx->n_mysql_tables_in_use,
+ (ulong) trx->mysql_n_tables_locked);
+ }
+
+ newline = TRUE;
+
+ /* trx->lock.que_state of an ACTIVE transaction may change
+ while we are not holding trx->mutex. We perform a dirty read
+ for performance reasons. */
+
+ switch (trx->lock.que_state) {
+ case TRX_QUE_RUNNING:
+ newline = FALSE; break;
+ case TRX_QUE_LOCK_WAIT:
+ fputs("LOCK WAIT ", f); break;
+ case TRX_QUE_ROLLING_BACK:
+ fputs("ROLLING BACK ", f); break;
+ case TRX_QUE_COMMITTING:
+ fputs("COMMITTING ", f); break;
+ default:
+ fprintf(f, "que state %lu ", (ulong) trx->lock.que_state);
+ }
+
+ if (trx->has_search_latch) {
+ newline = TRUE;
+ fputs(", holds adaptive hash latch", f);
+ }
+
+ if (trx->undo_no != 0) {
+ newline = TRUE;
+ fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no);
+ }
+
+ if (newline) {
+ putc('\n', f);
+ }
+
+ if (trx->mysql_thd != NULL) {
+ innobase_mysql_print_thd(
+ f, trx->mysql_thd, static_cast<uint>(max_query_len));
+ }
+}
+#endif /* WITH_WSREP */
/**********************************************************************//**
Prints info about a transaction.
Acquires and releases lock_sys->mutex and trx_sys->mutex. */
@@ -2213,7 +2358,7 @@ trx_start_if_not_started_xa_low(
transaction, doesn't. */
trx->support_xa = thd_supports_xa(trx->mysql_thd);
- trx_start_low(trx);
+ trx_start_if_not_started(trx);
/* fall through */
case TRX_STATE_ACTIVE:
return;
diff --git a/storage/innobase/wsrep/md5.cc b/storage/innobase/wsrep/md5.cc
new file mode 100644
index 00000000000..30be6ab7dd3
--- /dev/null
+++ b/storage/innobase/wsrep/md5.cc
@@ -0,0 +1,74 @@
+/*
+ Copyright (c) 2014 SkySQL AB.
+
+ 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
+*/
+
+#ifdef WITH_WSREP
+
+#if defined(HAVE_YASSL)
+#include "my_config.h"
+#include "md5.hpp"
+#elif defined(HAVE_OPENSSL)
+#include <openssl/md5.h>
+#endif /* HAVE_YASSL */
+
+/* Initialize md5 object. */
+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 */
+}
+
+/**
+ Supply message to be hashed.
+
+ @param ctx [IN] Pointer to MD5 context
+ @param buf [IN] Message to be computed.
+ @param len [IN] Length of the message.
+*/
+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 */
+}
+
+/**
+ Place computed MD5 digest into the given buffer.
+
+ @param digest [OUT] Computed MD5 digest
+ @param ctx [IN] Pointer to MD5 context
+*/
+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 /* WITH_WSREP */
+
diff --git a/storage/innobase/wsrep/wsrep_md5.h b/storage/innobase/wsrep/wsrep_md5.h
new file mode 100644
index 00000000000..1339f7f4b86
--- /dev/null
+++ b/storage/innobase/wsrep/wsrep_md5.h
@@ -0,0 +1,26 @@
+#ifndef WSREP_MD5_INCLUDED
+#define WSREP_MD5_INCLUDED
+
+/* Copyright (c) 2014 SkySQL AB.
+
+ 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
+*/
+
+#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 /* WITH_WSREP */
+
+#endif /* WSREP_MD5_INCLUDED */
diff --git a/storage/maria/ma_control_file.c b/storage/maria/ma_control_file.c
index 2fa3e6ed18e..11cb4c5fd24 100644
--- a/storage/maria/ma_control_file.c
+++ b/storage/maria/ma_control_file.c
@@ -273,7 +273,7 @@ CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
" file is probably in use by another process";
uint new_cf_create_time_size, new_cf_changeable_size, new_block_size;
my_off_t file_size;
- int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR;
+ int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR | O_CLOEXEC;
int error= CONTROL_FILE_UNKNOWN_ERROR;
DBUG_ENTER("ma_control_file_open");
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c
index 878b30e926e..9f31879879c 100644
--- a/storage/maria/ma_loghandler.c
+++ b/storage/maria/ma_loghandler.c
@@ -990,7 +990,7 @@ static File create_logfile_by_number_no_cache(uint32 file_no)
/* TODO: add O_DIRECT to open flags (when buffer is aligned) */
if ((file= mysql_file_create(key_file_translog,
translog_filename_by_fileno(file_no, path),
- 0, O_BINARY | O_RDWR, MYF(MY_WME))) < 0)
+ 0, O_BINARY | O_RDWR | O_CLOEXEC, MYF(MY_WME))) < 0)
{
DBUG_PRINT("error", ("Error %d during creating file '%s'", errno, path));
translog_stop_writing();
@@ -1028,7 +1028,7 @@ static File open_logfile_by_number_no_cache(uint32 file_no)
/* TODO: use mysql_file_create() */
if ((file= mysql_file_open(key_file_translog,
translog_filename_by_fileno(file_no, path),
- log_descriptor.open_flags,
+ log_descriptor.open_flags | O_CLOEXEC,
MYF(MY_WME))) < 0)
{
DBUG_PRINT("error", ("Error %d during opening file '%s'", errno, path));
@@ -3310,7 +3310,7 @@ static my_bool translog_get_last_page_addr(TRANSLOG_ADDRESS *addr,
File fd;
if ((fd= mysql_file_open(key_file_translog,
translog_filename_by_fileno(file_no, path),
- O_RDONLY, (no_errors ? MYF(0) : MYF(MY_WME)))) < 0)
+ O_RDONLY | O_CLOEXEC, (no_errors ? MYF(0) : MYF(MY_WME)))) < 0)
{
my_errno= errno;
DBUG_PRINT("error", ("Error %d during opening file #%d",
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index 8fda846172b..30d0ab00140 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -333,13 +333,13 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
});
DEBUG_SYNC_C("mi_open_kfile");
if ((kfile=mysql_file_open(key_file_kfile, name_buff,
- (open_mode=O_RDWR) | O_SHARE | O_NOFOLLOW,
+ (open_mode=O_RDWR) | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
MYF(MY_NOSYMLINKS))) < 0)
{
if ((errno != EROFS && errno != EACCES) ||
mode != O_RDONLY ||
(kfile=mysql_file_open(key_file_kfile, name_buff,
- (open_mode=O_RDONLY) | O_SHARE | O_NOFOLLOW,
+ (open_mode=O_RDONLY) | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
MYF(MY_NOSYMLINKS))) < 0)
goto err;
}
@@ -1907,7 +1907,7 @@ int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share)
DEBUG_SYNC_C("mi_open_datafile");
info->dfile.file= share->bitmap.file.file=
mysql_file_open(key_file_dfile, share->data_file_name.str,
- share->mode | O_SHARE, MYF(flags));
+ share->mode | O_SHARE | O_CLOEXEC, MYF(flags));
return info->dfile.file >= 0 ? 0 : 1;
}
@@ -1921,7 +1921,7 @@ int _ma_open_keyfile(MARIA_SHARE *share)
mysql_mutex_lock(&share->intern_lock);
share->kfile.file= mysql_file_open(key_file_kfile,
share->unique_file_name.str,
- share->mode | O_SHARE | O_NOFOLLOW,
+ share->mode | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
MYF(MY_WME | MY_NOSYMLINKS));
mysql_mutex_unlock(&share->intern_lock);
return (share->kfile.file < 0);
diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c
index 7e846fc262c..c7ff84d514e 100644
--- a/storage/myisam/mi_open.c
+++ b/storage/myisam/mi_open.c
@@ -139,13 +139,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
DEBUG_SYNC_C("mi_open_kfile");
if ((kfile= mysql_file_open(mi_key_file_kfile, name_buff,
- (open_mode= O_RDWR) | O_SHARE | O_NOFOLLOW,
+ (open_mode= O_RDWR) | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
MYF(MY_NOSYMLINKS))) < 0)
{
if ((errno != EROFS && errno != EACCES) ||
mode != O_RDONLY ||
(kfile= mysql_file_open(mi_key_file_kfile, name_buff,
- (open_mode= O_RDONLY) | O_SHARE| O_NOFOLLOW,
+ (open_mode= O_RDONLY) | O_SHARE| O_NOFOLLOW | O_CLOEXEC,
MYF(MY_NOSYMLINKS))) < 0)
goto err;
}
@@ -1275,7 +1275,7 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share)
myf flags= MY_WME | (share->mode & O_NOFOLLOW ? MY_NOSYMLINKS: 0);
DEBUG_SYNC_C("mi_open_datafile");
info->dfile= mysql_file_open(mi_key_file_dfile, share->data_file_name,
- share->mode | O_SHARE, MYF(flags));
+ share->mode | O_SHARE | O_CLOEXEC, MYF(flags));
return info->dfile >= 0 ? 0 : 1;
}
@@ -1284,7 +1284,7 @@ int mi_open_keyfile(MYISAM_SHARE *share)
{
if ((share->kfile= mysql_file_open(mi_key_file_kfile,
share->unique_file_name,
- share->mode | O_SHARE | O_NOFOLLOW,
+ share->mode | O_SHARE | O_NOFOLLOW | O_CLOEXEC,
MYF(MY_NOSYMLINKS | MY_WME))) < 0)
return 1;
return 0;
diff --git a/storage/tokudb/ha_tokudb.cc b/storage/tokudb/ha_tokudb.cc
index 7a328e31261..c0c1c5031a6 100644
--- a/storage/tokudb/ha_tokudb.cc
+++ b/storage/tokudb/ha_tokudb.cc
@@ -55,6 +55,38 @@ static const char* ha_tokudb_exts[] = {
NullS
};
+#ifdef WITH_WSREP
+#include <wsrep_mysqld.h>
+#include <my_md5.h>
+#include <openssl/md5.h>
+
+extern my_bool wsrep_certify_nonPK;
+class binlog_trx_data;
+extern handlerton *binlog_hton;
+extern "C" int thd_binlog_format(const MYSQL_THD thd);
+
+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;
+
+static inline wsrep_ws_handle_t*
+//wsrep_ws_handle_t*
+//ha_tokudb::wsrep_ws_handle_t*
+wsrep_ws_handle(THD* thd) {
+ tokudb_trx_data* trx = (tokudb_trx_data *) thd_get_ha_data(thd, tokudb_hton);
+ DB_TXN* txn = (trx->all) ? trx->all : trx->stmt;
+ assert(txn);
+ WSREP_DEBUG("txn->id: %lu", txn->id64(txn));
+ return wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd),
+ (wsrep_trx_id_t)txn->id64(txn));
+}
+
+#endif /* WITH_WSREP */
//
// This offset is calculated starting from AFTER the NULL bytes
//
@@ -4108,6 +4140,19 @@ int ha_tokudb::write_row(uchar * record) {
added_rows++;
trx->stmt_progress.inserted++;
track_progress(thd);
+#ifdef WITH_WSREP
+ if (wsrep_thd_exec_mode(thd) == LOCAL_STATE &&
+ WSREP(thd) && !wsrep_consistency_check(thd) &&
+ (thd_sql_command(thd) != SQLCOM_LOAD ||
+ thd_binlog_format(thd) == BINLOG_FORMAT_ROW)) {
+
+ if (wsrep_append_keys(thd, false, record, NULL)) {
+ DBUG_PRINT("wsrep", ("row key failed"));
+ error = HA_ERR_INTERNAL_ERROR;
+ }
+ }
+
+#endif
}
cleanup:
if (num_DBs_locked) {
@@ -8999,3 +9044,256 @@ namespace tokudb {
template size_t vlq_encode_ui(uint64_t n, void *p, size_t s);
template size_t vlq_decode_ui(uint64_t *np, void *p, size_t s);
};
+#ifdef WITH_WSREP
+static
+int
+wsrep_calc_row_hash(
+/*================*/
+ uchar* digest, /*!< in/out: md5 sum */
+ const uchar* row, /*!< in: row in MySQL format */
+ TABLE* table, /*!< in: table in MySQL data
+ dictionary */
+ THD* thd) /*!< in: user thread */
+{
+ Field* field;
+ enum_field_types field_mysql_type;
+ uint n_fields;
+ unsigned long int len;
+ const uchar* ptr;
+ unsigned long int col_type;
+ uint i;
+
+ *digest = rand();
+#ifdef REMOVED
+ MD5_CTX ctx;
+ MD5_Init (&ctx);
+
+ n_fields = table->s->fields;
+
+ for (i = 0; i < n_fields; i++) {
+ uchar null_byte=0;
+ uchar true_byte=1;
+ ptr = (const byte*) row + get_field_offset(table, field);
+
+ field = table->field[i];
+ ptr = (const uchar*) row + get_field_offset(table, field);
+ len = field->pack_length();
+
+ field_mysql_type = field->type();
+
+ col_type = 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->null_ptr &&
+ field_in_record_is_null(table, field, (char*) row)) {
+ */
+
+ if( field->real_maybe_null() && field->is_null_in_record(row)) {
+ MD5_Update (&ctx, &null_byte, 1);
+ } else {
+ MD5_Update (&ctx, &true_byte, 1);
+ MD5_Update (&ctx, ptr, len);
+ }
+ }
+
+ MD5_Final (digest, &ctx);
+#endif
+ return(0);
+}
+#endif /* WITH_WSREP */
+#ifdef WITH_WSREP
+int
+wsrep_append_key(
+/*==================*/
+ THD *thd,
+ TABLE_SHARE *table_share,
+ TABLE *table,
+ const char* key,
+ uint16_t key_len,
+ bool shared
+)
+{
+ DBUG_ENTER("wsrep_append_key");
+ tokudb_trx_data* trx = (tokudb_trx_data *) thd_get_ha_data(thd, tokudb_hton);
+ bool const copy = true;
+#ifdef WSREP_DEBUG_PRINT
+ fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s ",
+ (shared) ? "Shared" : "Exclusive",
+ wsrep_thd_thread_id(thd), trx->id, key_len,
+ table_share->table_name.str);
+ 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,
+ (size_t*)&wkey.key_parts_num)) {
+ WSREP_WARN("key prepare failed for: %s",
+ (wsrep_thd_query(thd)) ?
+ wsrep_thd_query(thd) : "void");
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ }
+
+ int rcode = (int)wsrep->append_key(
+ wsrep,
+ wsrep_ws_handle(thd),
+ &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(HA_ERR_INTERNAL_ERROR);
+ }
+ DBUG_RETURN(0);
+}
+
+
+int
+ha_tokudb::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;
+#ifdef REMOVED
+ 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);
+ }
+
+
+ ut_a(table->s->keys <= 256);
+ uint i;
+ 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);
+ }
+ if (key_info->flags & HA_NOSAME ||
+ ((tab &&
+ dict_table_get_referenced_constraint(tab, idx)) ||
+ (!tab && referenced_by_foreign_key()))) {
+
+ if (key_info->flags & HA_NOSAME || shared)
+ key_appended = true;
+
+ len = wsrep_store_key_val_for_row(
+ table, i, key0, key_info->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);
+ }
+ else
+ {
+ WSREP_DEBUG("NULL key skipped: %s",
+ wsrep_thd_query(thd));
+ }
+ if (record1) {
+ len = wsrep_store_key_val_for_row(
+ table, i, key1, key_info->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);
+ }
+ }
+ }
+ }
+
+#endif
+ /* 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, thd);
+ if ((rcode = wsrep_append_key(thd, table_share, table,
+ (const char*) digest, 16,
+ shared))) {
+ DBUG_RETURN(rcode);
+ }
+
+ if (record1) {
+ wsrep_calc_row_hash(
+ digest, record1, table, thd);
+ if ((rcode = wsrep_append_key(thd, table_share,
+ table,
+ (const char*) digest,
+ 16, shared))) {
+ DBUG_RETURN(rcode);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+
+ DBUG_RETURN(0);
+}
+#endif
diff --git a/storage/tokudb/ha_tokudb.h b/storage/tokudb/ha_tokudb.h
index a2fd747bb92..9cf0c10e836 100644
--- a/storage/tokudb/ha_tokudb.h
+++ b/storage/tokudb/ha_tokudb.h
@@ -1046,6 +1046,11 @@ private:
bool check_upsert(THD *thd, List<Item> &update_fields, List<Item> &update_values);
int send_upsert_message(THD *thd, List<Item> &update_fields, List<Item> &update_values, DB_TXN *txn);
#endif
+#ifdef WITH_WSREP
+ int wsrep_append_keys(THD *thd, bool shared,
+ const uchar* record0, const uchar* record1);
+#endif
+
public:
// mysql sometimes retires a txn before a cursor that references the txn is closed.
// for example, commit is sometimes called before index_end. the following methods
diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt
index 76cd2e3f83f..0b98eb5c2cc 100644
--- a/storage/xtradb/CMakeLists.txt
+++ b/storage/xtradb/CMakeLists.txt
@@ -332,7 +332,28 @@ ENDIF()
# Include directories under xtradb
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/xtradb/include
- ${CMAKE_SOURCE_DIR}/storage/xtradb/handler)
+ ${CMAKE_SOURCE_DIR}/storage/xtradb/handler)
+
+IF(WITH_WSREP)
+ # ssl include directory
+ INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS}
+ ${CMAKE_SOURCE_DIR}/storage/xtradb/wsrep)
+
+ IF(SSL_DEFINES)
+ ADD_DEFINITIONS(${SSL_DEFINES})
+ ENDIF()
+
+ LINK_LIBRARIES(${SSL_LIBRARIES})
+
+ # We do RESTRICT_SYMBOL_EXPORTS(yassl) elsewhere.
+ # In order to get correct symbol visibility, these files
+ # must be compiled with "-fvisibility=hidden"
+ IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
+ SET_SOURCE_FILES_PROPERTIES(
+ {CMAKE_CURRENT_SOURCE_DIR}/wsrep/md5.cc
+ PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
+ ENDIF()
+ENDIF()
# Sun Studio bug with -xO2
IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro"
@@ -471,6 +492,10 @@ SET(INNOBASE_SOURCES
ut/ut0vec.cc
ut/ut0wqueue.cc)
+IF(WITH_WSREP)
+ SET(INNOBASE_SOURCES ${INNOBASE_SOURCES} wsrep/md5.cc)
+ENDIF()
+
# These files have unused result errors, so we skip Werror
CHECK_C_COMPILER_FLAG("-Werror" HAVE_WERROR)
IF(HAVE_WERROR)
diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc
index d5f07250f05..3d2c810c358 100644
--- a/storage/xtradb/buf/buf0dump.cc
+++ b/storage/xtradb/buf/buf0dump.cc
@@ -41,6 +41,7 @@ Created April 08, 2011 Vasil Dimov
#include "sync0rw.h" /* rw_lock_s_lock() */
#include "ut0byte.h" /* ut_ull_create() */
#include "ut0sort.h" /* UT_SORT_FUNCTION_BODY */
+#include "wsrep_mysqld.h" /* wsrep_recovery */
enum status_severity {
STATUS_INFO,
@@ -219,7 +220,20 @@ buf_dump(
buf_dump_status(STATUS_NOTICE, "Dumping buffer pool(s) to %s",
full_filename);
- f = fopen(tmp_filename, "w");
+#if defined(__GLIBC__) || defined(__WIN__) || O_CLOEXEC == 0
+ f = fopen(tmp_filename, "w" STR_O_CLOEXEC);
+#else
+ {
+ int fd;
+ fd = open(tmp_filename, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, 0640);
+ if (fd >= 0) {
+ f = fdopen(fd, "w");
+ }
+ else {
+ f = NULL;
+ }
+ }
+#endif
if (f == NULL) {
buf_dump_status(STATUS_ERR,
"Cannot open '%s' for writing: %s",
@@ -690,7 +704,13 @@ DECLARE_THREAD(buf_dump_thread)(
buf_load_status(STATUS_INFO, "not started");
if (srv_buffer_pool_load_at_startup) {
+#ifdef WITH_WSREP
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
buf_load();
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
}
while (!SHUTTING_DOWN()) {
@@ -714,8 +734,14 @@ DECLARE_THREAD(buf_dump_thread)(
}
if (srv_buffer_pool_dump_at_shutdown && srv_fast_shutdown != 2) {
+#ifdef WITH_WSREP
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
buf_dump(FALSE /* ignore shutdown down flag,
keep going even if we are in a shutdown state */);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
}
srv_buf_dump_thread_active = FALSE;
diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index b76414eeea4..b055374c23b 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -3400,7 +3400,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,
+ NULL, NULL, NULL);
+}
+#endif /* WITH_WSREP */
/**********************************************************************//**
Report an error in a foreign key definition. */
static
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 3553674040a..ca14617acff 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -4,7 +4,7 @@ Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2017, MariaDB Corporation.
+Copyright (c) 2013, 2018, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -123,6 +123,44 @@ this program; if not, write to the Free Software Foundation, Inc.,
# define MYSQL_PLUGIN_IMPORT /* nothing */
# endif /* MYSQL_PLUGIN_IMPORT */
+#ifdef WITH_WSREP
+#include "dict0priv.h"
+#include "../storage/innobase/include/ut0byte.h"
+#include <wsrep_mysqld.h>
+#include <wsrep_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);
+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 /* WITH_WSREP */
/** to protect innobase_open_files */
static mysql_mutex_t innobase_share_mutex;
/** to force correct commit order in binlog */
@@ -1653,6 +1691,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) {
@@ -1687,6 +1729,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
@@ -1852,6 +1898,16 @@ 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 /* WITH_WSREP */
+
my_bool
ha_innobase::is_fake_change_enabled(THD* thd)
{
@@ -2362,6 +2418,9 @@ int
innobase_mysql_tmpfile(
const char* path)
{
+#ifdef WITH_INNODB_DISALLOW_WRITES
+ os_event_wait(srv_allow_writes_event);
+#endif /* WITH_INNODB_DISALLOW_WRITES */
int fd2 = -1;
File fd;
@@ -2406,8 +2465,12 @@ innobase_mysql_tmpfile(
}
}
#else
+#ifdef F_DUPFD_CLOEXEC
+ fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+#else
fd2 = dup(fd);
#endif
+#endif
if (fd2 < 0) {
DBUG_PRINT("error",("Got error %d on dup",fd2));
my_errno=errno;
@@ -3550,6 +3613,13 @@ innobase_init(
if (srv_file_per_table)
innobase_hton->tablefile_extensions = ha_innobase_exts;
+#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);
#ifndef DBUG_OFF
@@ -4242,10 +4312,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 */
}
#if NOT_USED
@@ -5161,23 +5251,63 @@ innobase_kill_connection(
DBUG_ENTER("innobase_kill_connection");
DBUG_ASSERT(hton == innodb_hton_ptr);
- trx = thd_to_trx(thd);
+#ifdef WITH_WSREP
+ wsrep_thd_LOCK(thd);
+ if (wsrep_thd_conflict_state(thd) != NO_CONFLICT) {
+ /* if victim has been signaled by BF thread and/or aborting
+ is already progressing, following query aborting is not necessary
+ any more.
+ Also, BF thread should own trx mutex for the victim, which would
+ conflict with trx_mutex_enter() below
+ */
+ wsrep_thd_UNLOCK(thd);
+ DBUG_VOID_RETURN;
+ }
+ wsrep_thd_UNLOCK(thd);
+#endif /* WITH_WSREP */
- if (trx) {
- THD *cur = current_thd;
- THD *owner = trx->current_lock_mutex_owner;
+ trx = thd_to_trx(thd);
- if (owner != cur) {
+ if (trx && trx->lock.wait_lock) {
+ /* In wsrep BF we have already took lock_sys and trx
+ mutex either on wsrep_abort_transaction() or
+ before wsrep_kill_victim(). In replication we
+ could own lock_sys mutex taken in
+ lock_deadlock_check_and_resolve().*/
+
+ WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " TRX_ID_FMT " ABORT %d thd %p"
+ " current_thd %p BF %d wait_lock_modes: %s\n",
+ trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE),
+ wsrep_thd_is_BF(thd, FALSE),
+ trx->id, trx->abort_type,
+ trx->mysql_thd,
+ current_thd,
+ wsrep_thd_is_BF(current_thd, FALSE),
+ lock_get_info(trx->lock.wait_lock).c_str());
+
+ if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
+ trx->abort_type == TRX_SERVER_ABORT) {
+ ut_ad(!lock_mutex_own());
lock_mutex_enter();
}
- trx_mutex_enter(trx);
- /* Cancel a pending lock request. */
- if (trx->lock.wait_lock)
+ if (trx->abort_type != TRX_WSREP_ABORT) {
+ trx_mutex_enter(trx);
+ }
+
+ ut_ad(lock_mutex_own());
+ ut_ad(trx_mutex_own(trx));
+
+ if (trx->lock.wait_lock) {
lock_cancel_waiting_and_release(trx->lock.wait_lock);
+ }
+
+ if (trx->abort_type != TRX_WSREP_ABORT) {
+ trx_mutex_exit(trx);
+ }
- trx_mutex_exit(trx);
- if (owner != cur) {
+ if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
+ trx->abort_type == TRX_SERVER_ABORT) {
lock_mutex_exit();
}
}
@@ -5290,7 +5420,11 @@ ha_innobase::max_supported_key_length() const
case 8192:
return(1536);
default:
+#ifdef WITH_WSREP
+ return(3500);
+#else
return(3500);
+#endif
}
}
@@ -6390,6 +6524,117 @@ 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);
+
+ tmp_length = charset->coll->strnxfrm(charset, str, str_length,
+ str_length, tmp_str,
+ tmp_length, 0);
+ DBUG_ASSERT(tmp_length <= 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
is such that we must use MySQL code to compare them. NOTE that the prototype
@@ -6888,6 +7133,313 @@ innobase_read_from_2_little_endian(
return((uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))));
}
+#ifdef WITH_WSREP
+/*******************************************************************//**
+Stores a key value for a row to a buffer.
+@return key value length as stored in buff */
+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,
+ row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
+ 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 */
+
/*******************************************************************//**
Stores a key value for a row to a buffer.
@return key value length as stored in buff */
@@ -7823,6 +8375,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);
@@ -7866,8 +8421,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
@@ -7901,6 +8468,28 @@ 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 (binlog_hton->commit(binlog_hton, 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. */
@@ -7911,6 +8500,28 @@ 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 (binlog_hton->commit(binlog_hton, 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. */
@@ -7940,6 +8551,10 @@ 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. */
@@ -8021,6 +8636,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 /* WITH_WSREP */
+
default:
break;
}
@@ -8080,6 +8729,21 @@ report_error:
prebuilt->table->flags,
user_thd);
+#ifdef WITH_WSREP
+ if (!error_result
+ && wsrep_on(user_thd)
+ && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE
+ && !wsrep_consistency_check(user_thd)
+ && !wsrep_thd_skip_append_keys(user_thd)) {
+ 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 /* WITH_WSREP */
+
if (error_result == HA_FTS_INVALID_DOCID) {
my_error(HA_FTS_INVALID_DOCID, MYF(0));
}
@@ -8377,6 +9041,86 @@ calc_row_difference(
return(DB_SUCCESS);
}
+#ifdef WITH_WSREP
+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->null_ptr &&
+ field_in_record_is_null(table, field, (char*) row)) {
+ */
+
+ 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 */
/**********************************************************************//**
Updates a row given as a parameter to a new value. Note that we are given
whole rows, not just the fields which are updated: this incurs some
@@ -8523,6 +9267,24 @@ func_exit:
innobase_active_small();
+#ifdef WITH_WSREP
+ if (error == DB_SUCCESS &&
+ wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd) &&
+ !wsrep_thd_skip_append_keys(user_thd))
+ {
+ DBUG_PRINT("wsrep", ("update row key"));
+
+ if (wsrep_append_keys(user_thd, false, old_row, new_row)) {
+ WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED");
+ DBUG_PRINT("wsrep", ("row key failed"));
+ err = HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif /* WITH_WSREP */
+
if (share->ib_table != prebuilt->table) {
fprintf(stderr,
"InnoDB: Warning: share->ib_table %p prebuilt->table %p table %s is_corrupt %lu.",
@@ -8585,6 +9347,21 @@ 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) &&
+ !wsrep_thd_skip_append_keys(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 /* WITH_WSREP */
+
if (UNIV_UNLIKELY(share && share->ib_table
&& share->ib_table->is_corrupt)) {
DBUG_RETURN(HA_ERR_CRASHED);
@@ -9820,6 +10597,415 @@ ha_innobase::ft_end()
rnd_end();
}
+#ifdef WITH_WSREP
+extern 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 */
+{
+ ut_a(trx);
+ THD* thd = (THD*)trx->mysql_thd;
+ ulint rcode = DB_SUCCESS;
+ char cache_key[513] = {'\0'};
+ int cache_key_len;
+ bool const copy = true;
+
+ 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: %lu (%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);
+#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,
+ (size_t*)&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 = (int)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: %lu", rcode));
+ WSREP_ERROR("Appending cascaded fk row key failed: %s, %lu",
+ (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 Query: %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,
+ (size_t*)&wkey.key_parts_num)) {
+ WSREP_WARN("key prepare failed for: %s",
+ (wsrep_thd_query(thd)) ?
+ wsrep_thd_query(thd) : "void");
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ }
+
+ int rcode = (int)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(HA_ERR_INTERNAL_ERROR);
+ }
+ DBUG_RETURN(0);
+}
+
+extern void compute_md5_hash(char *digest, const char *buf, int len);
+#define MD5_HASH compute_md5_hash
+
+static bool
+referenced_by_foreign_key2(dict_table_t* table,
+ dict_index_t* index) {
+ ut_ad(table != NULL);
+ ut_ad(index != NULL);
+
+ const dict_foreign_set* fks = &table->referenced_set;
+ for (dict_foreign_set::const_iterator it = fks->begin();
+ it != fks->end();
+ ++it)
+ {
+ dict_foreign_t* foreign = *it;
+ if (foreign->referenced_index != index) {
+ continue;
+ }
+ ut_ad(table == foreign->referenced_table);
+ return true;
+ }
+ return false;
+}
+
+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, prebuilt, &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 &&
+ referenced_by_foreign_key2(tab, idx)) ||
+ (!tab && referenced_by_foreign_key()))) {
+
+ len = wsrep_store_key_val_for_row(
+ thd, table, i, key0,
+ WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record0, prebuilt, &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, prebuilt, &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 /* WITH_WSREP */
/*********************************************************************//**
Stores a reference to the current row to 'ref' field of the handle. Note
@@ -13832,11 +15018,18 @@ ha_innobase::external_lock(
/* used by test case */
DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;);
if (!skip) {
- 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
+ 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 */
}
}
@@ -14981,7 +16174,20 @@ ha_innobase::get_auto_increment(
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, offset, col_max_value);
@@ -15342,6 +16548,9 @@ innobase_xa_prepare(
time, not the current session variable value. Any possible changes
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);
}
@@ -17806,6 +19015,319 @@ 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();
+}
+/*******************************************************************//**
+This function is used to kill one transaction in BF. */
+UNIV_INTERN
+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: %lu", 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: %lu", (bf_trx) ? bf_trx->id : 0);
+ DBUG_RETURN(1);
+ }
+
+ WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
+
+ WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %lu",
+ signal, (long long)bf_seqno,
+ wsrep_thd_thread_id(thd),
+ victim_trx->id);
+
+ WSREP_DEBUG("Aborting query: %s",
+ (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void");
+
+ wsrep_thd_LOCK(thd);
+ DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.wsrep_after_BF_victim_lock";
+ DBUG_ASSERT(!debug_sync_set_action(bf_thd,
+ STRING_WITH_LEN(act)));
+ };);
+
+
+ if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
+ WSREP_DEBUG("kill trx EXITING for %lu", victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ DBUG_RETURN(0);
+ }
+
+ if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
+ WSREP_DEBUG("withdraw for BF trx: %lu, state: %d",
+ 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 %lu in MUST ABORT state",
+ 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 %lu in state %d",
+ 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 query for: %ld",
+ wsrep_thd_thread_id(thd));
+ WSREP_DEBUG("kill trx QUERY_COMMITTING for %lu",
+ victim_trx->id);
+
+ 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: %lu",
+ victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ wsrep_thd_awake(thd, signal);
+ DBUG_RETURN(1);
+ break;
+ case WSREP_OK:
+ break;
+ default:
+ WSREP_ERROR(
+ "cancel commit bad exit: %d %lu",
+ rcode,
+ victim_trx->id);
+ /* unable to interrupt, must abort */
+ /* note: kill_mysql() will block, if we cannot.
+ * kill the lock holder first.
+ */
+ abort();
+ break;
+ }
+ }
+ wsrep_thd_UNLOCK(thd);
+ wsrep_thd_awake(thd, signal);
+ 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 %lu", 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_UNLOCK(thd);
+ 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));
+ /* Note that innobase_kill_connection will take lock_mutex
+ and trx_mutex */
+ wsrep_thd_UNLOCK(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 %lu", 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);
+ wsrep_thd_UNLOCK(thd);
+
+ break;
+ }
+ default:
+ WSREP_WARN("bad wsrep query state: %d",
+ wsrep_thd_query_state(thd));
+ wsrep_thd_UNLOCK(thd);
+ break;
+ }
+
+ 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);
+ victim_trx->abort_type = TRX_WSREP_ABORT;
+ int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
+ victim_trx, signal);
+ trx_mutex_exit(victim_trx);
+ lock_mutex_exit();
+ victim_trx->abort_type = TRX_SERVER_ABORT;
+ 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((const void *)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 */
+{
+ mutex_enter(&trx_sys->mutex);
+ trx_id_t trx_id = trx_sys_get_new_trx_id();
+ mutex_exit(&trx_sys->mutex);
+ WSREP_DEBUG("innodb fake trx id: %lu thd: %s", trx_id, wsrep_thd_query(thd));
+ (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,
@@ -18775,6 +20297,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.",
@@ -19055,6 +20611,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/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h
index 24fb04093ac..54df3bef8f1 100644
--- a/storage/xtradb/handler/ha_innodb.h
+++ b/storage/xtradb/handler/ha_innodb.h
@@ -97,6 +97,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);
@@ -454,6 +458,40 @@ MY_ATTRIBUTE((nonnull));
extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file);
struct trx_t;
+#ifdef WITH_WSREP
+#include <wsrep_mysqld.h>
+//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2);
+
+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
extern const struct _ft_vft ft_vft_result;
@@ -491,6 +529,9 @@ innobase_index_name_is_reserved(
MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/*****************************************************************//**
+#ifdef WITH_WSREP
+extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
+#endif
Determines InnoDB table flags.
@retval true if successful, false if error */
UNIV_INTERN
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index bc6a6dd68d4..f86d6763315 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -51,6 +51,10 @@ Smart ALTER TABLE
#include "pars0pars.h"
#include "row0sel.h"
#include "ha_innodb.h"
+#ifdef WITH_WSREP
+//#include "wsrep_api.h"
+#include <sql_acl.h> // PROCESS_ACL
+#endif
/** Operations for creating secondary indexes (no rebuild needed) */
static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index a4f810652e0..d38243e3275 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -500,6 +500,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{
diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h
index 1dfbfe7c8fb..43399c8e218 100644
--- a/storage/xtradb/include/ha_prototypes.h
+++ b/storage/xtradb/include/ha_prototypes.h
@@ -293,6 +293,22 @@ 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);
+my_bool wsrep_thd_is_wsrep(void *thd_ptr);
+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);
+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/xtradb/include/hash0hash.h b/storage/xtradb/include/hash0hash.h
index a6fe4e680a1..68d3c6ace4e 100644
--- a/storage/xtradb/include/hash0hash.h
+++ b/storage/xtradb/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/xtradb/include/lock0lock.h b/storage/xtradb/include/lock0lock.h
index 20c7ac888a4..698780a9a9e 100644
--- a/storage/xtradb/include/lock0lock.h
+++ b/storage/xtradb/include/lock0lock.h
@@ -39,6 +39,8 @@ Created 5/7/1996 Heikki Tuuri
#include "srv0srv.h"
#include "ut0vec.h"
+#include <string>
+
#ifdef UNIV_DEBUG
extern ibool lock_print_waits;
#endif /* UNIV_DEBUG */
@@ -666,6 +668,16 @@ lock_get_type(
const lock_t* lock); /*!< in: lock */
/*******************************************************************//**
+Gets the trx of the lock. Non-inline version for using outside of the
+lock module.
+@return trx_t* */
+UNIV_INTERN
+trx_t*
+lock_get_trx(
+/*=========*/
+ const lock_t* lock); /*!< in: lock */
+
+/*******************************************************************//**
Gets the id of the transaction owning a lock.
@return transaction id */
UNIV_INTERN
@@ -991,6 +1003,13 @@ extern lock_sys_t* lock_sys;
mutex_exit(&lock_sys->wait_mutex); \
} while (0)
+/*******************************************************************//**
+Get lock mode and table/index name
+@return string containing lock info */
+std::string
+lock_get_info(
+ const lock_t*);
+
#ifndef UNIV_NONINL
#include "lock0lock.ic"
#endif
diff --git a/storage/xtradb/include/rem0rec.h b/storage/xtradb/include/rem0rec.h
index cddc7ef63f9..3d147e3d5fb 100644
--- a/storage/xtradb/include/rem0rec.h
+++ b/storage/xtradb/include/rem0rec.h
@@ -980,6 +980,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
+int 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/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index bab9a90c563..8cf1c67e268 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -316,6 +316,10 @@ extern uint srv_flush_log_at_timeout;
extern char srv_use_global_flush_log_at_trx_commit;
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 */
@@ -1172,6 +1176,15 @@ struct srv_slot_t{
# 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 */
+
#ifndef DBUG_OFF
/** false before InnoDB monitor has been printed at least once, true
afterwards */
diff --git a/storage/xtradb/include/sync0sync.ic b/storage/xtradb/include/sync0sync.ic
index 823389d4cbe..82547470d4b 100644
--- a/storage/xtradb/include/sync0sync.ic
+++ b/storage/xtradb/include/sync0sync.ic
@@ -257,7 +257,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/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h
index 7fcdf71e1cc..3d7cb983eeb 100644
--- a/storage/xtradb/include/trx0sys.h
+++ b/storage/xtradb/include/trx0sys.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
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
@@ -42,6 +43,9 @@ Created 3/26/1996 Heikki Tuuri
#include "read0types.h"
#include "page0types.h"
#include "ut0bh.h"
+#ifdef WITH_WSREP
+#include "trx0xa.h"
+#endif /* WITH_WSREP */
typedef UT_LIST_BASE_NODE_T(trx_t) trx_list_t;
@@ -314,6 +318,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
@@ -322,6 +329,28 @@ UNIV_INTERN
void
trx_sys_print_mysql_binlog_offset(void);
/*===================================*/
+
+#ifdef WITH_WSREP
+
+/** Update WSREP XID info in sys_header of TRX_SYS_PAGE_NO = 5.
+@param[in] xid Transaction XID
+@param[in,out] sys_header sys_header
+@param[in] mtr minitransaction */
+UNIV_INTERN
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid,
+ trx_sysf_t* sys_header,
+ mtr_t* mtr);
+
+/** Read WSREP checkpoint XID from sys header.
+@param[out] xid Transaction XID
+@return true on success, false on error. */
+UNIV_INTERN
+bool
+trx_sys_read_wsrep_checkpoint(XID* 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. */
@@ -550,6 +579,78 @@ 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 */
+/** Memory map TRX_SYS_PAGE_NO = 5 when UNIV_PAGE_SIZE = 4096
+
+0...37 FIL_HEADER
+38...45 TRX_SYS_TRX_ID_STORE
+46...55 TRX_SYS_FSEG_HEADER (FSEG_HEADER_SIZE == 10)
+56 TRX_SYS_RSEGS
+ 56...59 TRX_SYS_RSEG_SPACE for slot 0
+ 60...63 TRX_SYS_RSEG_PAGE_NO for slot 0
+ 64...67 TRX_SYS_RSEG_SPACE for slot 1
+ 68...71 TRX_SYS_RSEG_PAGE_NO for slot 1
+....
+ 594..597 TRX_SYS_RSEG_SPACE for slot 72
+ 598..601 TRX_SYS_RSEG_PAGE_NO for slot 72
+...
+ ...1063 TRX_SYS_RSEG_PAGE_NO for slot 126
+
+(UNIV_PAGE_SIZE-3500 WSREP ::: FAIL would overwrite undo tablespace
+space_id, page_no pairs :::)
+596 TRX_SYS_WSREP_XID_INFO TRX_SYS_WSREP_XID_MAGIC_N_FLD
+600 TRX_SYS_WSREP_XID_FORMAT
+604 TRX_SYS_WSREP_XID_GTRID_LEN
+608 TRX_SYS_WSREP_XID_BQUAL_LEN
+612 TRX_SYS_WSREP_XID_DATA (len = 128)
+739 TRX_SYS_WSREP_XID_DATA_END
+
+FIXED WSREP XID info offsets for 4k page size 10.0.32-galera
+(UNIV_PAGE_SIZE-2500)
+1596 TRX_SYS_WSREP_XID_INFO TRX_SYS_WSREP_XID_MAGIC_N_FLD
+1600 TRX_SYS_WSREP_XID_FORMAT
+1604 TRX_SYS_WSREP_XID_GTRID_LEN
+1608 TRX_SYS_WSREP_XID_BQUAL_LEN
+1612 TRX_SYS_WSREP_XID_DATA (len = 128)
+1739 TRX_SYS_WSREP_XID_DATA_END
+
+(UNIV_PAGE_SIZE - 2000 MYSQL MASTER LOG)
+2096 TRX_SYS_MYSQL_MASTER_LOG_INFO TRX_SYS_MYSQL_LOG_MAGIC_N_FLD
+2100 TRX_SYS_MYSQL_LOG_OFFSET_HIGH
+2104 TRX_SYS_MYSQL_LOG_OFFSET_LOW
+2108 TRX_SYS_MYSQL_LOG_NAME
+
+(UNIV_PAGE_SIZE - 1000 MYSQL LOG)
+3096 TRX_SYS_MYSQL_LOG_INFO TRX_SYS_MYSQL_LOG_MAGIC_N_FLD
+3100 TRX_SYS_MYSQL_LOG_OFFSET_HIGH
+3104 TRX_SYS_MYSQL_LOG_OFFSET_LOW
+3108 TRX_SYS_MYSQL_LOG_NAME
+
+(UNIV_PAGE_SIZE - 200 DOUBLEWRITE)
+3896 TRX_SYS_DOUBLEWRITE TRX_SYS_DOUBLEWRITE_FSEG
+3906 TRX_SYS_DOUBLEWRITE_MAGIC
+3910 TRX_SYS_DOUBLEWRITE_BLOCK1
+3914 TRX_SYS_DOUBLEWRITE_BLOCK2
+3918 TRX_SYS_DOUBLEWRITE_REPEAT
+3930 TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N
+
+(UNIV_PAGE_SIZE - 8, TAILER)
+4088..4096 FIL_TAILER
+
+*/
+#ifdef WITH_WSREP
+/** The offset to WSREP XID headers */
+#define TRX_SYS_WSREP_XID_INFO (ut_max(UNIV_PAGE_SIZE - 3500, 1596))
+#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/xtradb/include/trx0sys.ic b/storage/xtradb/include/trx0sys.ic
index 699148cff6d..6024c1dc94e 100644
--- a/storage/xtradb/include/trx0sys.ic
+++ b/storage/xtradb/include/trx0sys.ic
@@ -474,7 +474,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/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 44f49d47b4d..1bc1e07f547 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, MariaDB Corporation
+Copyright (c) 2015, 2017, MariaDB Corporation
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
@@ -333,6 +333,24 @@ trx_print_low(
/*!< in: mem_heap_get_size(trx->lock.lock_heap) */
MY_ATTRIBUTE((nonnull));
+#ifdef WITH_WSREP
+/**********************************************************************//**
+Prints info about a transaction.
+Transaction information may be retrieved without having trx_sys->mutex acquired
+so it may not be completely accurate. The caller must own lock_sys->mutex
+and the trx must have some locks to make sure that it does not escape
+without locking lock_sys->mutex. */
+UNIV_INTERN
+void
+wsrep_trx_print_locking(
+/*==============*/
+ FILE* f, /*!< in: output stream */
+ const trx_t* trx, /*!< in: transaction */
+ ulint max_query_len) /*!< in: max query length to print,
+ or 0 to use the default max length */
+ MY_ATTRIBUTE((nonnull));
+#endif /* WITH_WSREP */
+
/**********************************************************************//**
Prints info about a transaction.
The caller must hold lock_sys->mutex and trx_sys->mutex.
@@ -705,6 +723,12 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
+typedef enum {
+ TRX_SERVER_ABORT = 0,
+ TRX_WSREP_ABORT = 1,
+ TRX_REPLICATION_ABORT = 2
+} trx_abort_t;
+
struct trx_t{
ulint magic_n;
@@ -881,6 +905,8 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
+ trx_abort_t abort_type; /*!< Transaction abort type */
+
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file
@@ -1031,11 +1057,6 @@ struct trx_t{
count of tables being flushed. */
/*------------------------------*/
- THD* current_lock_mutex_owner;
- /*!< If this is equal to current_thd,
- then in innobase_kill_query() we know we
- already hold the lock_sys->mutex. */
- /*------------------------------*/
#ifdef UNIV_DEBUG
ulint start_line; /*!< Track where it was started from */
const char* start_file; /*!< Filename where it was started */
@@ -1048,6 +1069,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 */
/*------------------------------*/
ulint io_reads;
ib_uint64_t io_read;
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index 9dc82daecf8..bb83ac47553 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -52,6 +52,15 @@ Created 5/7/1996 Heikki Tuuri
#include <set>
#include "mysql/plugin.h"
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+extern my_bool wsrep_log_conflicts;
+#include "ha_prototypes.h"
+#endif
+
+#include <string>
+#include <sstream>
+
/* Restricts the length of search we will do in the waits-for
graph of transactions */
#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
@@ -974,6 +983,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
@@ -1070,6 +1082,56 @@ 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);
}
@@ -1100,7 +1162,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)));
@@ -1569,6 +1635,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.
@@ -1615,6 +1686,72 @@ 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));
+
+ /* quit for native mysql */
+ if (!wsrep_on(trx->mysql_thd)) return;
+
+ 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) {
+ if (bf_this) {
+ fputs("\n*** Priority TRANSACTION:\n",
+ stderr);
+ } else {
+ fputs("\n*** Victim TRANSACTION:\n",
+ stderr);
+ }
+
+ wsrep_trx_print_locking(stderr, trx, 3000);
+
+ if (bf_other) {
+ fputs("\n*** Priority TRANSACTION:\n",
+ stderr);
+ } else {
+ fputs("\n*** Victim TRANSACTION:\n",
+ stderr);
+ }
+
+ wsrep_trx_print_locking(stderr, lock->trx, 3000);
+
+ 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);
+ }
+ }
+
+ lock->trx->abort_type = TRX_WSREP_ABORT;
+ wsrep_innobase_kill_one_trx(trx->mysql_thd,
+ (const trx_t*) trx, lock->trx, TRUE);
+ lock->trx->abort_type = TRX_SERVER_ABORT;
+ }
+ }
+}
+#endif
/*********************************************************************//**
Checks if some other transaction has a conflicting explicit lock request
in the queue, so that we have to wait.
@@ -1643,7 +1780,17 @@ lock_rec_other_has_conflicting(
lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) {
- if (lock_rec_has_to_wait(trx, mode, lock, is_supremum)) {
+#ifdef WITH_WSREP
+ if (lock_rec_has_to_wait(TRUE, trx, mode, lock, is_supremum)) {
+ if (wsrep_on(trx->mysql_thd)) {
+ 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);
}
}
@@ -1836,6 +1983,28 @@ 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
for deadlocks or lock compatibility!
@@ -1844,6 +2013,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 */
@@ -1918,8 +2091,90 @@ lock_rec_create(
ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted);
+#ifdef WITH_WSREP
+ if (c_lock &&
+ wsrep_on(trx->mysql_thd) &&
+ 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 */
lock_sys->rec_num++;
@@ -1929,7 +2184,6 @@ lock_rec_create(
ut_ad(trx_mutex_own(trx));
if (type_mode & LOCK_WAIT) {
-
lock_set_lock_and_trx_wait(lock, trx);
}
@@ -1941,7 +2195,6 @@ lock_rec_create(
MONITOR_INC(MONITOR_RECLOCK_CREATED);
MONITOR_INC(MONITOR_NUM_RECLOCK);
-
return(lock);
}
@@ -1956,6 +2209,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
@@ -2016,7 +2272,10 @@ lock_rec_enqueue_waiting(
/* Enqueue the lock request that will wait to be granted, note that
we already own the trx mutex. */
lock = lock_rec_create(
- type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
+#ifdef WITH_WSREP
+ c_lock, thr,
+#endif /* WITH_WSREP */
+ type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
/* Release the mutex to obey the latching order.
This is safe, because lock_deadlock_check_and_resolve()
@@ -2124,7 +2383,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->id);
+#ifdef WITH_WSREP
+ /* this can potentionally assert with wsrep */
+ if (wsrep_thd_is_wsrep(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 */
@@ -2152,7 +2423,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;
}
}
@@ -2175,9 +2455,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 /* WITH_WSREP */
}
/** Record locking request status */
@@ -2240,8 +2526,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;
@@ -2295,6 +2586,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());
@@ -2319,17 +2613,31 @@ 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
@@ -2381,6 +2689,7 @@ lock_rec_lock(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0);
+
ut_ad(dict_index_is_clust(index) || !dict_index_is_online_ddl(index));
/* We try a simplified and faster subroutine for the most
@@ -2435,7 +2744,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);
}
}
@@ -3834,10 +4149,22 @@ lock_deadlock_select_victim(
/* The joining transaction is 'smaller',
choose it as the victim and roll it back. */
- return(ctx->start);
+#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);
}
- return(ctx->wait_lock->trx);
+#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);
}
/********************************************************************//**
@@ -3967,8 +4294,14 @@ lock_deadlock_search(
ctx->too_deep = TRUE;
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_BF(ctx->start->mysql_thd, TRUE)) {
+ return(ctx->wait_lock->trx->id);
+ }
+ else
+#endif /* WITH_WSREP */
/* Select the joining transaction as the victim. */
- return(ctx->start->id);
+ return(ctx->start->id);
} else {
/* We do not need to report autoinc locks to the upper
@@ -4114,9 +4447,9 @@ lock_report_waiters_to_mysql(
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
- w_trx->current_lock_mutex_owner = mysql_thd;
+ w_trx->abort_type = TRX_REPLICATION_ABORT;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
- w_trx->current_lock_mutex_owner = NULL;
+ w_trx->abort_type = TRX_SERVER_ABORT;
}
++i;
}
@@ -4193,9 +4526,18 @@ lock_deadlock_check_and_resolve(
ut_a(trx == ctx.start);
ut_a(victim_trx_id == trx->id);
- if (!srv_read_only_mode) {
- lock_deadlock_joining_trx_print(trx, lock);
+#ifdef WITH_WSREP
+ if (!wsrep_thd_is_BF(ctx.start->mysql_thd, TRUE))
+ {
+#endif /* WITH_WSREP */
+ if (!srv_read_only_mode) {
+ lock_deadlock_joining_trx_print(trx, lock);
+ }
+#ifdef WITH_WSREP
+ } else {
+ /* BF processor */;
}
+#endif /* WITH_WSREP */
} else if (victim_trx_id != 0 && victim_trx_id != trx->id) {
@@ -4234,6 +4576,9 @@ UNIV_INLINE
lock_t*
lock_table_create(
/*==============*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /*!< in: conflicting lock */
+#endif
dict_table_t* table, /*!< in/out: database table
in dictionary cache */
ulint type_mode,/*!< in: lock mode possibly ORed with
@@ -4279,7 +4624,59 @@ 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 (wsrep_thd_is_wsrep(trx->mysql_thd)) {
+ 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);
+ wsrep_print_wait_locks(c_lock->trx->lock.wait_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 {
+#endif /* WITH_WSREP */
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
@@ -4436,6 +4833,9 @@ static
dberr_t
lock_table_enqueue_waiting(
/*=======================*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /*!< in: conflicting lock */
+#endif
ulint mode, /*!< in: lock mode this transaction is
requesting */
dict_table_t* table, /*!< in/out: table */
@@ -4482,7 +4882,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 /* WITH_WSREP */
/* Release the mutex to obey the latching order.
This is safe, because lock_deadlock_check_and_resolve()
@@ -4560,6 +4967,18 @@ lock_table_other_has_incompatible(
&& !lock_mode_compatible(lock_get_mode(lock), mode)
&& (wait || !lock_get_wait(lock))) {
+#ifdef WITH_WSREP
+ if(wsrep_thd_is_wsrep(trx->mysql_thd)) {
+ if (wsrep_debug) {
+ fprintf(stderr, "WSREP: trx %ld table lock abort\n",
+ trx->id);
+ }
+ trx_mutex_enter(lock->trx);
+ wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
+ trx_mutex_exit(lock->trx);
+ }
+#endif
+
return(lock);
}
}
@@ -4582,6 +5001,9 @@ lock_table(
enum lock_mode mode, /*!< in: lock mode */
que_thr_t* thr) /*!< in: query thread */
{
+#ifdef WITH_WSREP
+ lock_t *c_lock = NULL;
+#endif
trx_t* trx;
dberr_t err;
const lock_t* wait_for;
@@ -4617,8 +5039,13 @@ lock_table(
/* We have to check if the new lock is compatible with any locks
other transactions have in the table lock queue. */
+#ifdef WITH_WSREP
+ wait_for = lock_table_other_has_incompatible(
+ trx, LOCK_WAIT, table, mode);
+#else
wait_for = lock_table_other_has_incompatible(
trx, LOCK_WAIT, table, mode);
+#endif
trx_mutex_enter(trx);
@@ -4626,9 +5053,17 @@ lock_table(
mode: this trx may have to wait */
if (wait_for != NULL) {
+#ifdef WITH_WSREP
+ err = lock_table_enqueue_waiting((ib_lock_t*)wait_for, mode | flags, table, thr);
+#else
err = lock_table_enqueue_waiting(mode | flags, table, thr);
+#endif
} else {
+#ifdef WITH_WSREP
+ lock_table_create(c_lock, table, mode | flags, trx);
+#else
lock_table_create(table, mode | flags, trx);
+#endif
ut_a(!flags || mode == LOCK_S || mode == LOCK_X);
@@ -4666,7 +5101,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
lock_mutex_exit();
trx_mutex_exit(trx);
}
@@ -5842,6 +6281,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) {
@@ -5850,9 +6290,8 @@ lock_rec_queue_validate(
mode = LOCK_S;
}
ut_a(!lock_rec_other_has_expl_req(
- mode, 0, 0, block, heap_no,
- lock->trx->id));
-
+ mode, 0, 0, block, heap_no, lock->trx));
+#endif /* WITH_WSREP */
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
ut_a(lock_rec_has_to_wait_in_queue(lock));
@@ -6156,6 +6595,9 @@ lock_rec_insert_check_and_lock(
dberr_t err;
ulint next_rec_heap_no;
ibool inherit_in = *inherit;
+#ifdef WITH_WSREP
+ lock_t* c_lock=NULL;
+#endif
ut_ad(block->frame == page_align(rec));
ut_ad(!dict_index_is_online_ddl(index)
@@ -6218,17 +6660,30 @@ 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 = (ib_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 {
@@ -6397,8 +6852,9 @@ lock_clust_rec_modify_check_and_lock(
lock_rec_convert_impl_to_expl(block, rec, index, offsets);
lock_mutex_enter();
+ trx_t* trx = thr_get_trx(thr);
- ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ ut_ad(lock_table_has(trx, index->table, LOCK_IX));
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, index, thr);
@@ -6460,9 +6916,10 @@ lock_sec_rec_modify_check_and_lock(
index record, and this would not have been possible if another active
transaction had modified this secondary index record. */
+ trx_t* trx = thr_get_trx(thr);
lock_mutex_enter();
- ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ ut_ad(lock_table_has(trx, index->table, LOCK_IX));
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, index, thr);
@@ -6568,12 +7025,13 @@ lock_sec_rec_read_check_and_lock(
lock_rec_convert_impl_to_expl(block, rec, index, offsets);
}
+ trx_t* trx = thr_get_trx(thr);
lock_mutex_enter();
ut_ad(mode != LOCK_X
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ || lock_table_has(trx, index->table, LOCK_IX));
ut_ad(mode != LOCK_S
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
+ || lock_table_has(trx, index->table, LOCK_IS));
err = lock_rec_lock(FALSE, mode | gap_mode,
block, heap_no, index, thr);
@@ -6650,11 +7108,12 @@ lock_clust_rec_read_check_and_lock(
}
lock_mutex_enter();
+ trx_t* trx = thr_get_trx(thr);
ut_ad(mode != LOCK_X
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
+ || lock_table_has(trx, index->table, LOCK_IX));
ut_ad(mode != LOCK_S
- || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
+ || lock_table_has(trx, index->table, LOCK_IS));
err = lock_rec_lock(FALSE, mode | gap_mode,
block, heap_no, index, thr);
@@ -6807,6 +7266,19 @@ lock_get_type(
}
/*******************************************************************//**
+Gets the trx of the lock. Non-inline version for using outside of the
+lock module.
+@return trx_t* */
+UNIV_INTERN
+trx_t*
+lock_get_trx(
+/*=========*/
+ const lock_t* lock) /*!< in: lock */
+{
+ return (lock->trx);
+}
+
+/*******************************************************************//**
Gets the id of the transaction owning a lock.
@return transaction id */
UNIV_INTERN
@@ -7400,3 +7872,32 @@ lock_trx_has_rec_x_lock(
return(true);
}
#endif /* UNIV_DEBUG */
+
+/*******************************************************************//**
+Get lock mode and table/index name
+@return string containing lock info */
+std::string
+lock_get_info(
+ const lock_t* lock)
+{
+ std::string info;
+ std::string mode("mode ");
+ std::string index("index ");
+ std::string table("table ");
+ std::string n_uniq(" n_uniq");
+ std::string n_user(" n_user");
+ std::string lock_mode((lock_get_mode_str(lock)));
+ std::string iname(lock->index->name);
+ std::string tname(lock->index->table_name);
+
+#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \
+ ( std::ostringstream() << std::dec << x ) ).str()
+
+ info = mode + lock_mode
+ + index + iname
+ + table + tname
+ + n_uniq + SSTR(lock->index->n_uniq)
+ + n_user + SSTR(lock->index->n_user_defined_cols);
+
+ return info;
+}
diff --git a/storage/xtradb/lock/lock0wait.cc b/storage/xtradb/lock/lock0wait.cc
index 3ccd23c0496..f31e658bc81 100644
--- a/storage/xtradb/lock/lock0wait.cc
+++ b/storage/xtradb/lock/lock0wait.cc
@@ -199,6 +199,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 */
+
/** Print lock wait timeout info to stderr. It's supposed this function
is executed in trx's THD thread as it calls some non-thread-safe
functions to get some info from THD.
@@ -433,11 +455,19 @@ lock_wait_suspend_thread(
if (lock_wait_timeout < 100000000
&& wait_time > (double) lock_wait_timeout) {
+#ifdef WITH_WSREP
+ if (!wsrep_on(trx->mysql_thd) ||
+ (!wsrep_is_BF_lock_timeout(trx) &&
+ trx->error_state != DB_DEADLOCK)) {
+#endif /* WITH_WSREP */
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
if (srv_print_lock_wait_timeout_info)
print_lock_wait_timeout(*trx, blocking, blocking_count);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
MONITOR_INC(MONITOR_TIMEOUT);
}
@@ -521,8 +551,13 @@ 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/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc
index 4246bfbff70..c46f9eec95d 100644
--- a/storage/xtradb/os/os0file.cc
+++ b/storage/xtradb/os/os0file.cc
@@ -103,6 +103,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:
@@ -904,7 +910,9 @@ os_file_create_tmpfile(
const char* path)
{
FILE* file = NULL;
- int fd = innobase_mysql_tmpfile(path);
+ int fd;
+ WAIT_ALLOW_WRITES();
+ fd = innobase_mysql_tmpfile(path);
ut_ad(!srv_read_only_mode);
@@ -1195,6 +1203,7 @@ os_file_create_directory(
return(TRUE);
#else
int rcode;
+ WAIT_ALLOW_WRITES();
rcode = mkdir(pathname, 0770);
@@ -1322,6 +1331,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));
@@ -1371,7 +1382,7 @@ os_file_create_simple_func(
}
do {
- file = ::open(name, create_flag, os_innodb_umask);
+ file = ::open(name, create_flag | O_CLOEXEC, os_innodb_umask);
if (file == -1) {
*success = FALSE;
@@ -1520,6 +1531,8 @@ os_file_create_simple_no_error_handling_func(
int create_flag;
const char* mode_str = NULL;
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));
@@ -1565,7 +1578,7 @@ os_file_create_simple_no_error_handling_func(
return(file);
}
- file.m_file = ::open(name, create_flag, os_innodb_umask);
+ file.m_file = ::open(name, create_flag | O_CLOEXEC , os_innodb_umask);
*success = file.m_file == -1 ? FALSE : TRUE;
@@ -1925,6 +1938,9 @@ 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;
on_error_silent = create_mode & OS_FILE_ON_ERROR_SILENT
@@ -1983,7 +1999,7 @@ os_file_create_func(
#endif /* O_SYNC */
do {
- file.m_file = ::open(name, create_flag, os_innodb_umask);
+ file.m_file = ::open(name, create_flag | O_CLOEXEC, os_innodb_umask);
if (file.m_file == -1) {
const char* operation;
@@ -2108,6 +2124,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -2172,6 +2189,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -2243,6 +2261,7 @@ os_file_rename_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = rename(oldpath, newpath);
@@ -2521,6 +2540,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__ */
}
@@ -2540,6 +2560,7 @@ os_file_set_eof_at_func(
return(SetFilePointerEx(file, li, &li2,FILE_BEGIN)
&& SetEndOfFile(file));
#else
+ WAIT_ALLOW_WRITES();
/* TODO: works only with -D_FILE_OFFSET_BITS=64 ? */
return(!ftruncate(file, new_len));
#endif
@@ -2637,6 +2658,7 @@ os_file_flush_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
#if defined(HAVE_DARWIN_THREADS)
# ifndef F_FULLFSYNC
@@ -3262,6 +3284,7 @@ retry:
return(FALSE);
#else
ssize_t ret;
+ WAIT_ALLOW_WRITES();
ret = os_file_pwrite(file, buf, n, offset);
@@ -3500,7 +3523,7 @@ os_file_get_status(
access = !srv_read_only_mode ? O_RDWR : O_RDONLY;
- fh = ::open(path, access, os_innodb_umask);
+ fh = ::open(path, access | O_CLOEXEC, os_innodb_umask);
if (fh == -1) {
stat_info->rw_perm = false;
@@ -3929,7 +3952,7 @@ os_aio_native_aio_supported(void)
strcpy(name + dirnamelen, "ib_logfile0");
- fd = ::open(name, O_RDONLY);
+ fd = ::open(name, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc
index 8fb51b69ceb..f6af2921719 100644
--- a/storage/xtradb/rem/rem0rec.cc
+++ b/storage/xtradb/rem/rem0rec.cc
@@ -34,6 +34,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)
===========================
@@ -1919,6 +1922,138 @@ rec_print(
}
}
}
+#endif /* !UNIV_HOTBACKUP */
+
+#ifdef WITH_WSREP
+int
+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 */
# ifdef UNIV_DEBUG
/************************************************************//**
@@ -1961,5 +2096,4 @@ rec_get_trx_id(
return(trx_read_trx_id(trx_id));
}
-# endif /* UNIV_DEBUG */
-#endif /* !UNIV_HOTBACKUP */
+#endif /* UNIV_DEBUG */
diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc
index 27dbddec067..36f83104201 100644
--- a/storage/xtradb/row/row0ins.cc
+++ b/storage/xtradb/row/row0ins.cc
@@ -937,6 +937,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
@@ -1288,7 +1296,19 @@ row_ins_foreign_check_on_constraint(
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
- err = row_update_cascade_for_mysql(thr, cascade,
+#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 /* WITH_WSREP */
+ err = row_update_cascade_for_mysql(thr, cascade,
foreign->foreign_table);
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
@@ -1443,6 +1463,9 @@ row_ins_check_foreign_constraint(
ulint* offsets = offsets_;
rec_offs_init(offsets_);
+#ifdef WITH_WSREP
+ upd_node= NULL;
+#endif /* WITH_WSREP */
run_again:
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
@@ -1628,7 +1651,15 @@ 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,
+ (upd_node) ? TRUE : FALSE);
+#endif /* WITH_WSREP */
goto end_scan;
} else if (foreign->type != 0) {
/* There is an ON UPDATE or ON DELETE
diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc
index 4d42e370166..5a0f58d1492 100644
--- a/storage/xtradb/row/row0upd.cc
+++ b/storage/xtradb/row/row0upd.cc
@@ -56,6 +56,10 @@ Created 12/27/1996 Heikki Tuuri
#include "buf0lru.h"
#include <algorithm>
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+#endif
+
/* What kind of latch and lock can we assume when the control comes to
-------------------------------------------------------------------
an update node?
@@ -165,6 +169,50 @@ 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;
+ dict_foreign_t* foreign;
+ 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;
+ }
+
+ for (dict_foreign_set::iterator it= table->foreign_set.begin();
+ it != table->foreign_set.end();
+ ++ it)
+ {
+ foreign= *it;
+
+ if (foreign->foreign_index == index)
+ {
+ is_referenced= TRUE;
+ goto func_exit;
+ }
+ }
+
+func_exit:
+ 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.
@@ -284,7 +332,123 @@ run_again:
}
err = DB_SUCCESS;
+func_exit:
+ if (got_s_lock) {
+ row_mysql_unfreeze_data_dictionary(trx);
+ }
+
+ mem_heap_free(heap);
+
+ 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);
+ }
+
+ 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 = (foreign->referenced_table) ? TRUE : FALSE;
+ }
+
+ 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, FALSE, FALSE);
+ opened = FALSE;
+ }
+ }
+
+ if (err != DB_SUCCESS) {
+ goto func_exit;
+ }
+ }
+ }
+
+ err = DB_SUCCESS;
func_exit:
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
@@ -296,6 +460,7 @@ func_exit:
return(err);
}
+#endif /* WITH_WSREP */
/*********************************************************************//**
Creates an update node for a query graph.
@@ -1666,6 +1831,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);
@@ -1796,6 +1964,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);
@@ -1813,6 +1984,39 @@ row_upd_sec_index_entry(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ err == DB_SUCCESS && !referenced &&
+ !wsrep_thd_is_BF(trx->mysql_thd, FALSE) &&
+ !(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;
}
@@ -1967,6 +2171,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;
@@ -1980,6 +2187,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));
@@ -2065,6 +2275,34 @@ err_exit:
goto err_exit;
}
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) && !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);
@@ -2260,11 +2498,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));
@@ -2281,8 +2526,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 ! */
@@ -2290,6 +2543,33 @@ row_upd_del_mark_clust_rec(
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
+#ifdef WITH_WSREP
+ trx_t* trx = thr_get_trx(thr) ;
+
+ if (err == DB_SUCCESS && !referenced && trx && wsrep_on(trx->mysql_thd) &&
+ !(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, 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);
@@ -2322,6 +2602,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;
@@ -2437,7 +2721,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;
@@ -2482,7 +2770,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/xtradb/srv/srv0conc.cc b/storage/xtradb/srv/srv0conc.cc
index eac1b52a64f..dadb1f19a8a 100644
--- a/storage/xtradb/srv/srv0conc.cc
+++ b/storage/xtradb/srv/srv0conc.cc
@@ -44,6 +44,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. */
@@ -90,6 +94,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 */
@@ -149,6 +156,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 */
}
@@ -210,6 +220,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;
@@ -328,6 +348,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 */
@@ -338,6 +361,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;
@@ -397,6 +433,13 @@ retry:
return;
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_thd_is_brute_force(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 */
@@ -464,6 +507,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);
@@ -471,6 +517,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
@@ -494,6 +552,9 @@ retry:
os_event_wait(slot->event);
thd_wait_end(trx->mysql_thd);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
trx->op_info = "";
@@ -511,6 +572,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);
@@ -621,5 +685,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/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index 6d9ae62bd9e..0c4f6f622e0 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -77,6 +77,14 @@ Created 10/8/1995 Heikki Tuuri
/* prototypes for new functions added to ha_innodb.cc */
ibool innobase_get_slow_log();
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+extern int wsrep_trx_is_aborting(void *thd_ptr);
+#endif
+/* The following counter is incremented whenever there is some user activity
+in the server */
+UNIV_INTERN ulint srv_activity_count = 0;
+
/* The following is the maximum allowed duration of a lock wait. */
UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600;
@@ -160,6 +168,8 @@ Currently we support native aio on windows and linux */
my_bool srv_use_native_aio = TRUE;
UNIV_INTERN my_bool srv_numa_interleave = FALSE;
+UNIV_INTERN my_bool srv_lock_timeout_active = FALSE;
+
#ifdef __WIN__
/* Windows native condition variables. We use runtime loading / function
pointers, because they are not available on Windows Server 2003 and
@@ -238,6 +248,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;
@@ -1180,6 +1194,14 @@ srv_init(void)
dict_ind_init();
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);
@@ -1217,6 +1239,10 @@ srv_free(void)
mutex_free(&srv_sys.tasks_mutex);
}
+#ifdef WITH_INNODB_DISALLOW_WRITES
+ os_event_free(srv_allow_writes_event);
+#endif /* WITH_INNODB_DISALLOW_WRITES */
+
#ifndef HAVE_ATOMIC_BUILTINS
mutex_free(&server_mutex);
#endif
@@ -2258,7 +2284,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/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index f12f895488d..b2b3a9299cc 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -68,6 +68,8 @@ Created 2/16/1996 Heikki Tuuri
#include "ibuf0ibuf.h"
#include "srv0start.h"
#include "srv0srv.h"
+#include "wsrep_mysqld.h" /* wsrep_recovery */
+
#ifndef UNIV_HOTBACKUP
# include "trx0rseg.h"
# include "os0proc.h"
@@ -2986,9 +2988,21 @@ files_checked:
}
if (!srv_read_only_mode) {
+#ifdef WITH_WSREP
+ /* Create the dump/load thread only when not running with
+ --wsrep-recover */
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
/* Create the buffer pool dump/load thread */
buf_dump_thread_handle = os_thread_create(buf_dump_thread, NULL, NULL);
buf_dump_thread_started = true;
+#ifdef WITH_WSREP
+ } else {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Skipping buffer pool dump/restore during wsrep "
+ "recovery.");
+ }
+#endif /* WITH_WSREP */
}
srv_was_started = TRUE;
diff --git a/storage/xtradb/trx/trx0roll.cc b/storage/xtradb/trx/trx0roll.cc
index a9f3da0dc89..87b6f2ade35 100644
--- a/storage/xtradb/trx/trx0roll.cc
+++ b/storage/xtradb/trx/trx0roll.cc
@@ -46,6 +46,9 @@ Created 3/26/1996 Heikki Tuuri
#include "pars0pars.h"
#include "srv0mon.h"
#include "trx0sys.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h"
+#endif /* WITH_WSREP */
/** This many pages must be undone before a truncate is tried within
rollback */
@@ -368,6 +371,13 @@ trx_rollback_to_savepoint_for_mysql_low(
trx->op_info = "";
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->lock.was_chosen_as_deadlock_victim) {
+ trx->lock.was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
+
return(err);
}
@@ -1055,6 +1065,12 @@ 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/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc
index 80ea0374567..eb429b749fa 100644
--- a/storage/xtradb/trx/trx0sys.cc
+++ b/storage/xtradb/trx/trx0sys.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
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
@@ -47,6 +48,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 */
@@ -177,7 +182,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);
@@ -205,9 +215,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) {
@@ -216,7 +231,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)
@@ -303,6 +320,136 @@ 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];
+
+/** Read WSREP XID seqno */
+static inline long long read_wsrep_xid_seqno(const XID* xid)
+{
+ long long seqno;
+ memcpy(&seqno, xid->data + 24, sizeof(long long));
+ return seqno;
+}
+
+/** Read WSREP XID UUID */
+static inline void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
+{
+ memcpy(buf, xid->data + 8, 16);
+}
+
+#endif /* UNIV_DEBUG */
+
+/** Update WSREP XID info in sys_header of TRX_SYS_PAGE_NO = 5.
+@param[in] xid Transaction XID
+@param[in,out] sys_header sys_header
+@param[in] mtr minitransaction */
+UNIV_INTERN
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid,
+ trx_sysf_t* sys_header,
+ mtr_t* mtr)
+{
+#ifdef UNIV_DEBUG
+ if (xid->formatID != -1
+ && mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
+ == TRX_SYS_WSREP_XID_MAGIC_N) {
+ /* 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);
+ ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid((const void *)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);
+}
+
+/** Read WSREP XID from sys_header of TRX_SYS_PAGE_NO = 5.
+@param[out] xid Transaction XID
+@retval true if found, false if not */
+UNIV_INTERN
+bool
+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 false;
+ }
+
+ 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);
+ return true;
+}
+
+#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/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 8e62a7dba46..39b0498a0ed 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -298,6 +298,9 @@ trx_create(void)
trx->lock.table_locks = ib_vector_create(
heap_alloc, sizeof(void**), 32);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
return(trx);
}
@@ -1034,6 +1037,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: */
@@ -1165,6 +1173,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;
@@ -1211,6 +1222,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((const void *)&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 */
@@ -1221,7 +1241,11 @@ trx_write_serialisation_history(
trx_sys_update_mysql_binlog_offset(
trx->mysql_log_file_name,
trx->mysql_log_offset,
- TRX_SYS_MYSQL_LOG_INFO, mtr);
+ TRX_SYS_MYSQL_LOG_INFO,
+#ifdef WITH_WSREP
+ sys_header,
+#endif /* WITH_WSREP */
+ mtr);
trx->mysql_log_file_name = NULL;
}
@@ -1534,6 +1558,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;
@@ -1748,6 +1777,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:
@@ -2110,6 +2143,119 @@ trx_print_latched(
mem_heap_get_size(trx->lock.lock_heap));
}
+#ifdef WITH_WSREP
+/**********************************************************************//**
+Prints info about a transaction.
+Transaction information may be retrieved without having trx_sys->mutex acquired
+so it may not be completely accurate. The caller must own lock_sys->mutex
+and the trx must have some locks to make sure that it does not escape
+without locking lock_sys->mutex. */
+UNIV_INTERN
+void
+wsrep_trx_print_locking(
+/*==========*/
+ FILE* f,
+ /*!< in: output stream */
+ const trx_t* trx,
+ /*!< in: transaction */
+ ulint max_query_len)
+ /*!< in: max query length to print,
+ or 0 to use the default max length */
+{
+ ibool newline;
+ const char* op_info;
+
+ ut_ad(lock_mutex_own());
+ ut_ad(trx->lock.trx_locks.count > 0);
+
+ fprintf(f, "TRANSACTION " TRX_ID_FMT, trx->id);
+
+ /* trx->state may change since trx_sys->mutex is not required */
+ switch (trx->state) {
+ case TRX_STATE_NOT_STARTED:
+ fputs(", not started", f);
+ goto state_ok;
+ case TRX_STATE_ACTIVE:
+ fprintf(f, ", ACTIVE %lu sec",
+ (ulong) difftime(time(NULL), trx->start_time));
+ goto state_ok;
+ case TRX_STATE_PREPARED:
+ fprintf(f, ", ACTIVE (PREPARED) %lu sec",
+ (ulong) difftime(time(NULL), trx->start_time));
+ goto state_ok;
+ case TRX_STATE_COMMITTED_IN_MEMORY:
+ fputs(", COMMITTED IN MEMORY", f);
+ goto state_ok;
+ }
+ fprintf(f, ", state %lu", (ulong) trx->state);
+ ut_ad(0);
+state_ok:
+
+ /* prevent a race condition */
+ op_info = trx->op_info;
+
+ if (*op_info) {
+ putc(' ', f);
+ fputs(op_info, f);
+ }
+
+ if (trx->is_recovered) {
+ fputs(" recovered trx", f);
+ }
+
+ if (trx->declared_to_be_inside_innodb) {
+ fprintf(f, ", thread declared inside InnoDB %lu",
+ (ulong) trx->n_tickets_to_enter_innodb);
+ }
+
+ putc('\n', f);
+
+ if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
+ fprintf(f, "mysql tables in use %lu, locked %lu\n",
+ (ulong) trx->n_mysql_tables_in_use,
+ (ulong) trx->mysql_n_tables_locked);
+ }
+
+ newline = TRUE;
+
+ /* trx->lock.que_state of an ACTIVE transaction may change
+ while we are not holding trx->mutex. We perform a dirty read
+ for performance reasons. */
+
+ switch (trx->lock.que_state) {
+ case TRX_QUE_RUNNING:
+ newline = FALSE; break;
+ case TRX_QUE_LOCK_WAIT:
+ fputs("LOCK WAIT ", f); break;
+ case TRX_QUE_ROLLING_BACK:
+ fputs("ROLLING BACK ", f); break;
+ case TRX_QUE_COMMITTING:
+ fputs("COMMITTING ", f); break;
+ default:
+ fprintf(f, "que state %lu ", (ulong) trx->lock.que_state);
+ }
+
+ if (trx->has_search_latch) {
+ newline = TRUE;
+ fputs(", holds adaptive hash latch", f);
+ }
+
+ if (trx->undo_no != 0) {
+ newline = TRUE;
+ fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no);
+ }
+
+ if (newline) {
+ putc('\n', f);
+ }
+
+ if (trx->mysql_thd != NULL) {
+ innobase_mysql_print_thd(
+ f, trx->mysql_thd, static_cast<uint>(max_query_len));
+ }
+}
+#endif /* WITH_WSREP */
+
/**********************************************************************//**
Prints info about a transaction.
Acquires and releases lock_sys->mutex and trx_sys->mutex. */
@@ -2511,6 +2657,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:
@@ -2545,6 +2695,10 @@ trx_start_for_ddl_low(
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/storage/xtradb/wsrep/md5.cc b/storage/xtradb/wsrep/md5.cc
new file mode 100644
index 00000000000..30be6ab7dd3
--- /dev/null
+++ b/storage/xtradb/wsrep/md5.cc
@@ -0,0 +1,74 @@
+/*
+ Copyright (c) 2014 SkySQL AB.
+
+ 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
+*/
+
+#ifdef WITH_WSREP
+
+#if defined(HAVE_YASSL)
+#include "my_config.h"
+#include "md5.hpp"
+#elif defined(HAVE_OPENSSL)
+#include <openssl/md5.h>
+#endif /* HAVE_YASSL */
+
+/* Initialize md5 object. */
+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 */
+}
+
+/**
+ Supply message to be hashed.
+
+ @param ctx [IN] Pointer to MD5 context
+ @param buf [IN] Message to be computed.
+ @param len [IN] Length of the message.
+*/
+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 */
+}
+
+/**
+ Place computed MD5 digest into the given buffer.
+
+ @param digest [OUT] Computed MD5 digest
+ @param ctx [IN] Pointer to MD5 context
+*/
+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 /* WITH_WSREP */
+
diff --git a/storage/xtradb/wsrep/wsrep_md5.h b/storage/xtradb/wsrep/wsrep_md5.h
new file mode 100644
index 00000000000..1339f7f4b86
--- /dev/null
+++ b/storage/xtradb/wsrep/wsrep_md5.h
@@ -0,0 +1,26 @@
+#ifndef WSREP_MD5_INCLUDED
+#define WSREP_MD5_INCLUDED
+
+/* Copyright (c) 2014 SkySQL AB.
+
+ 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
+*/
+
+#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 /* WITH_WSREP */
+
+#endif /* WSREP_MD5_INCLUDED */
diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt
index cc9eed6c7be..80de8333db8 100644
--- a/support-files/CMakeLists.txt
+++ b/support-files/CMakeLists.txt
@@ -96,6 +96,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)
IF (INSTALL_SYSCONFDIR)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/mysql-log-rotate DESTINATION ${INSTALL_SYSCONFDIR}/logrotate.d
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index 794b3ecbbbb..34f3ca4af34 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -25,7 +25,6 @@
# Description: MariaDB is a very fast and reliable SQL database engine.
### END INIT INFO
-# If you install MariaDB on some other places than @prefix@, then you
# have to do one of the following things for this script to work:
#
# - Run this script from within the MariaDB installation directory
@@ -52,6 +51,7 @@ datadir=
# 0 means don't wait at all
# Negative numbers mean to wait indefinitely
service_startup_timeout=900
+startup_sleep=1
# Lock directory for RedHat / SuSE.
lockdir='/var/lock/subsys'
@@ -239,6 +239,8 @@ wait_for_gone () {
wait_for_ready () {
+ sst_progress_file=$datadir/sst_in_progress
+
i=0
while test $i -ne $service_startup_timeout ; do
@@ -252,9 +254,14 @@ wait_for_ready () {
break
fi
+ if test -e $sst_progress_file && [ $startup_sleep -ne 10 ];then
+ echo $echo_n "SST in progress, setting sleep higher"
+ startup_sleep=10
+ fi
+
echo $echo_n ".$echo_c"
i=`expr $i + 1`
- sleep 1
+ sleep $startup_sleep
done
@@ -340,7 +347,10 @@ case "$mode" in
# Stop the service and regardless of whether it was
# running or not, start it again.
if $0 stop "$@"; then
- $0 start "$@"
+ if ! $0 start "$@"; 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
@@ -417,10 +427,16 @@ case "$mode" in
fi
exit $r
;;
+ '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
+ exit $?
+ ;;
*)
# usage
basename=`basename "$0"`
- echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest} [ MariaDB server options ]"
exit 1
;;
esac
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 5af4783f919..ed3b697c0f9 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -69,6 +69,14 @@
#
# ----------------------------------------------------------------------------
+# wsrep builds
+# ----------------------------------------------------------------------------
+%if %{defined with_wsrep}
+%define mysql_version @VERSION@_wsrep_@WSREP_API_VERSION@.@WSREP_PATCH_VERSION@
+%define wsrep_version @WSREP_VERSION@
+%endif
+
+# ----------------------------------------------------------------------------
# Commercial builds
# ----------------------------------------------------------------------------
%if %{undefined commercial}
@@ -116,6 +124,13 @@
%endif
# ----------------------------------------------------------------------------
+# Packager
+# ----------------------------------------------------------------------------
+%if %{undefined mysql_packager}
+%define mysql_packager MySQL Build Team <build@mysql.com>
+%endif
+
+# ----------------------------------------------------------------------------
# Distribution support
# ----------------------------------------------------------------------------
%if %{undefined distro_specific}
@@ -284,9 +299,16 @@ documentation and the manual for more information.
##############################################################################
%package -n MySQL-server%{product_suffix}
+%if %{defined with_wsrep}
+Version: %{mysql_version}
+%endif
Summary: MySQL: a very fast and reliable SQL database server
Group: Applications/Databases
+%if %{defined with_wsrep}
+Requires: %{distro_requires} rsync lsof
+%else
Requires: %{distro_requires}
+%endif
%if 0%{?commercial}
Obsoletes: MySQL-server
%else
@@ -320,6 +342,9 @@ 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.
+%if %{defined with_wsrep}
+Built with wsrep patch %{wsrep_version}.
+%endif
If you want to access and work with the database, you have to install
package "MySQL-client%{product_suffix}" as well!
@@ -411,6 +436,7 @@ This package contains the shared libraries (*.so*) which certain languages
and applications need to dynamically load and use MySQL.
# ----------------------------------------------------------------------------
+%if %{undefined with_wsrep}
%package -n MySQL-embedded%{product_suffix}
Summary: MySQL - Embedded library
Group: Applications/Databases
@@ -440,6 +466,7 @@ 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/
+%endif
##############################################################################
%prep
@@ -519,6 +546,9 @@ mkdir debug
-DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \
-DFEATURE_SET="%{feature_set}" \
-DCOMPILATION_COMMENT="%{compilation_comment_debug}" \
+%if %{defined with_wsrep}
+ -DWITH_WSREP=1 \
+%endif
-DMYSQL_SERVER_SUFFIX="%{server_suffix}"
echo BEGIN_DEBUG_CONFIG ; egrep '^#define' include/config.h ; echo END_DEBUG_CONFIG
make ${MAKE_JFLAG} VERBOSE=1
@@ -535,6 +565,9 @@ mkdir release
-DMYSQL_UNIX_ADDR="%{mysqldatadir}/mysql.sock" \
-DFEATURE_SET="%{feature_set}" \
-DCOMPILATION_COMMENT="%{compilation_comment_release}" \
+%if %{defined with_wsrep}
+ -DWITH_WSREP=1 \
+%endif
-DMYSQL_SERVER_SUFFIX="%{server_suffix}"
echo BEGIN_NORMAL_CONFIG ; egrep '^#define' include/config.h ; echo END_NORMAL_CONFIG
make ${MAKE_JFLAG} VERBOSE=1
@@ -599,11 +632,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
+
+%if %{defined with_wsrep}
+# Create a wsrep_sst_rsync_wan symlink.
+install -d $RBR%{_bindir}
+ln -sf wsrep_sst_rsync $RBR%{_bindir}/wsrep_sst_rsync_wan
+%endif
# 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
+%if %{defined with_wsrep}
+touch $RBR%{_sysconfdir}/wsrep.cnf
+%endif
# Install SELinux files in datadir
install -m 600 $MBD/%{src_dir}/support-files/RHEL4-SElinux/mysql.{fc,te} \
@@ -1065,6 +1107,11 @@ echo "=====" >> $STATUS_HISTORY
%doc %{src_dir}/Docs/INFO_SRC*
%doc release/Docs/INFO_BIN*
%doc release/support-files/my-*.cnf
+%if %{defined with_wsrep}
+%doc %{src_dir}/Docs/README-wsrep
+%doc release/support-files/wsrep.cnf
+%doc release/support-files/wsrep_notify
+%endif
%if 0%{?commercial}
%doc %attr(644, root, root) %{_infodir}/mysql.info*
@@ -1100,6 +1147,9 @@ echo "=====" >> $STATUS_HISTORY
%doc %attr(644, root, man) %{_mandir}/man1/resolveip.1*
%ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf
+%if %{defined with_wsrep}
+%ghost %config(noreplace,missingok) %{_sysconfdir}/wsrep.cnf
+%endif
%dir %{_sysconfdir}/my.cnf.d
%attr(755, root, root) %{_bindir}/innochecksum
@@ -1127,6 +1177,14 @@ echo "=====" >> $STATUS_HISTORY
%attr(755, root, root) %{_bindir}/replace
%attr(755, root, root) %{_bindir}/resolve_stack_dump
%attr(755, root, root) %{_bindir}/resolveip
+%if %{defined with_wsrep}
+%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
+%endif
%attr(755, root, root) %{_sbindir}/mysqld
%attr(755, root, root) %{_sbindir}/mysqld-debug
@@ -1205,8 +1263,10 @@ echo "=====" >> $STATUS_HISTORY
%defattr(-, root, root, 0755)
%attr(-, root, root) %{_datadir}/mysql-test
%attr(755, root, root) %{_bindir}/mysql_client_test
+%if %{undefined with_wsrep}
%attr(755, root, root) %{_bindir}/mysql_client_test_embedded
%attr(755, root, root) %{_bindir}/mysqltest_embedded
+%endif
%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*
@@ -1214,11 +1274,13 @@ echo "=====" >> $STATUS_HISTORY
%doc %attr(644, root, man) %{_mandir}/man1/mysqltest_embedded.1*
# ----------------------------------------------------------------------------
+%if %{undefined with_wsrep}
%files -n MySQL-embedded%{product_suffix}
%defattr(-, root, root, 0755)
%attr(755, root, root) %{_bindir}/mysql_embedded
%attr(644, root, root) %{_libdir}/mysql/libmysqld.a
%attr(644, root, root) %{_libdir}/mysql/libmysqld-debug.a
+%endif
##############################################################################
# The spec file changelog only includes changes made to the spec file
@@ -1252,6 +1314,10 @@ echo "=====" >> $STATUS_HISTORY
* Mon Jun 11 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
- Make sure newly added "SPECIFIC-ULN/" directory does not disturb packaging.
+
+* Wed Dec 07 2011 Alexey Yurchenko <alexey.yurchenko@codership.com>
+
+- wsrep-related cleanups.
* Wed Sep 28 2011 Joerg Bruehe <joerg.bruehe@oracle.com>
@@ -1305,7 +1371,6 @@ echo "=====" >> $STATUS_HISTORY
- 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.
diff --git a/support-files/rpm/server.cnf b/support-files/rpm/server.cnf
index a197868d16c..124fabcb985 100644
--- a/support-files/rpm/server.cnf
+++ b/support-files/rpm/server.cnf
@@ -11,6 +11,22 @@
# this is only for the mysqld standalone daemon
[mysqld]
+#
+# * Galera-related settings
+#
+[galera]
+# Mandatory settings
+#wsrep_provider=
+#wsrep_cluster_address=
+#binlog_format=row
+#default_storage_engine=InnoDB
+#innodb_autoinc_lock_mode=2
+#bind-address=0.0.0.0
+#
+# Optional setting
+#wsrep_slave_threads=1
+#innodb_flush_log_at_trx_commit=0
+
# this is only for embedded server
[embedded]
diff --git a/support-files/wsrep.cnf.sh b/support-files/wsrep.cnf.sh
new file mode 100644
index 00000000000..51ce3dca2dd
--- /dev/null
+++ b/support-files/wsrep.cnf.sh
@@ -0,0 +1,125 @@
+# 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
+
+# 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
+##
+
+# Enable wsrep
+wsrep_on=1
+
+# 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 00000000000..bdbe3d12a39
--- /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/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt
new file mode 100644
index 00000000000..182e4586ddc
--- /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/wsrep_api.h b/wsrep/wsrep_api.h
new file mode 100644
index 00000000000..c3304d7ed7c
--- /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 00000000000..1780e91f89d
--- /dev/null
+++ b/wsrep/wsrep_dummy.c
@@ -0,0 +1,414 @@
+/* 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)
+{
+ char *options;
+
+ WSREP_DBUG_ENTER(w);
+ options= WSREP_DUMMY(w)->options;
+
+ if (options)
+ options= strdup(WSREP_DUMMY(w)->options);
+
+ return 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 00000000000..e618c5ab7d0
--- /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 00000000000..5f98b0ace6a
--- /dev/null
+++ b/wsrep/wsrep_loader.c
@@ -0,0 +1,225 @@
+/* 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 wsrep_check_iface_version(const char* found, const char* iface_ver)
+{
+ const size_t msg_len = 128;
+ char msg[128];
+
+ if (strcmp(found, iface_ver)) {
+ snprintf (msg, msg_len,
+ "provider interface version mismatch: need '%s', found '%s'",
+ iface_ver, found);
+ logger (WSREP_LOG_ERROR, msg);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static int verify(const wsrep_t *wh, const char *iface_ver)
+{
+ char msg[128];
+
+#define VERIFY(_p) if (!(_p)) { \
+ snprintf(msg, sizeof(msg), "wsrep_load(): verify(): %s\n", # _p); \
+ logger (WSREP_LOG_ERROR, msg); \
+ return EINVAL; \
+ }
+
+ VERIFY(wh);
+ VERIFY(wh->version);
+
+ if (wsrep_check_iface_version(wh->version, iface_ver))
+ 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;
+}
+
+static int wsrep_check_version_symbol(void *dlh)
+{
+ char** dlversion = NULL;
+ dlversion = (char**) dlsym(dlh, "wsrep_interface_version");
+ if (dlversion == NULL)
+ return 0;
+ return wsrep_check_iface_version(*dlversion, WSREP_INTERFACE_VERSION);
+}
+
+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;
+ char msg[1024];
+
+ if (NULL != log_cb)
+ logger = log_cb;
+
+ if (!(spec && hptr))
+ return EINVAL;
+
+ snprintf (msg, sizeof(msg),
+ "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, sizeof(msg), "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 (wsrep_check_version_symbol(dlh) != 0) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ if ((ret = (*dlfun)(*hptr)) != 0) {
+ snprintf(msg, sizeof(msg), "wsrep_load(): loader failed: %s",
+ strerror(ret));
+ logger (WSREP_LOG_ERROR, msg);
+ goto out;
+ }
+
+ if ((ret = verify(*hptr, WSREP_INTERFACE_VERSION)) != 0) {
+ snprintf (msg, sizeof(msg),
+ "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, sizeof(msg),
+ "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 00000000000..baa95b2578a
--- /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;
+ }
+}