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
-rwxr-xr-xBUILD/compile-pentium-debug-wsrep12
-rwxr-xr-xBUILD/compile-pentium-wsrep11
-rwxr-xr-xBUILD/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.cmake28
-rw-r--r--cmake/os/FreeBSD.cmake2
-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--config.h.cmake1
-rw-r--r--configure.cmake1
-rw-r--r--debian/additions/my.cnf16
-rw-r--r--debian/dist/Debian/control207
-rw-r--r--debian/dist/Debian/mariadb-galera-server-5.5.README.Debian (renamed from debian/dist/Debian/mariadb-server-5.5.README.Debian)0
-rw-r--r--debian/dist/Debian/mariadb-galera-server-5.5.dirs (renamed from debian/dist/Ubuntu/mariadb-server-5.5.dirs)2
-rw-r--r--debian/dist/Debian/mariadb-galera-server-5.5.files.in (renamed from debian/dist/Debian/mariadb-server-5.5.files.in)42
-rw-r--r--debian/dist/Debian/mariadb-galera-server-5.5.postinst (renamed from debian/dist/Debian/mariadb-server-5.5.postinst)0
-rw-r--r--debian/dist/Debian/mariadb-galera-server-5.5.postrm (renamed from debian/dist/Debian/mariadb-server-5.5.postrm)0
-rwxr-xr-xdebian/dist/Debian/rules20
-rw-r--r--debian/dist/Ubuntu/control199
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-5.5.README.Debian (renamed from debian/dist/Ubuntu/mariadb-server-5.5.README.Debian)0
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-5.5.dirs (renamed from debian/dist/Debian/mariadb-server-5.5.dirs)2
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-5.5.files.in (renamed from debian/dist/Ubuntu/mariadb-server-5.5.files.in)43
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-5.5.postinst (renamed from debian/dist/Ubuntu/mariadb-server-5.5.postinst)0
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-5.5.postrm (renamed from debian/dist/Ubuntu/mariadb-server-5.5.postrm)0
-rw-r--r--debian/dist/Ubuntu/mariadb-galera-server-5.5.py (renamed from debian/dist/Ubuntu/mariadb-server-5.5.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-5.5.README.Debian4
-rw-r--r--debian/mariadb-client-5.5.dirs3
-rw-r--r--debian/mariadb-client-5.5.docs2
-rw-r--r--debian/mariadb-client-5.5.files28
-rw-r--r--debian/mariadb-client-5.5.links6
-rw-r--r--debian/mariadb-client-5.5.lintian-overrides3
-rw-r--r--debian/mariadb-client-5.5.menu3
-rw-r--r--debian/mariadb-client-core-5.5.files4
-rw-r--r--debian/mariadb-common.files1
-rw-r--r--debian/mariadb-common.postrm8
-rw-r--r--debian/mariadb-galera-server-5.5.NEWS (renamed from debian/mariadb-server-5.5.NEWS)0
-rw-r--r--debian/mariadb-galera-server-5.5.config (renamed from debian/mariadb-server-5.5.config)0
-rw-r--r--debian/mariadb-galera-server-5.5.lintian-overrides5
-rw-r--r--debian/mariadb-galera-server-5.5.logcheck.ignore.paranoid (renamed from debian/mariadb-server-5.5.logcheck.ignore.paranoid)0
-rw-r--r--debian/mariadb-galera-server-5.5.logcheck.ignore.server (renamed from debian/mariadb-server-5.5.logcheck.ignore.server)0
-rw-r--r--debian/mariadb-galera-server-5.5.logcheck.ignore.workstation (renamed from debian/mariadb-server-5.5.logcheck.ignore.workstation)0
-rw-r--r--debian/mariadb-galera-server-5.5.mysql-server.logrotate (renamed from debian/mariadb-server-5.5.mysql-server.logrotate)0
-rw-r--r--debian/mariadb-galera-server-5.5.mysql.init (renamed from debian/mariadb-server-5.5.mysql.init)12
-rw-r--r--debian/mariadb-galera-server-5.5.preinst (renamed from debian/mariadb-server-5.5.preinst)0
-rw-r--r--debian/mariadb-galera-server-5.5.prerm (renamed from debian/mariadb-server-5.5.prerm)0
-rw-r--r--debian/mariadb-galera-server-5.5.templates (renamed from debian/mariadb-server-5.5.templates)0
-rw-r--r--debian/mariadb-galera-test-5.5.dirs (renamed from debian/mariadb-test-5.5.dirs)6
-rw-r--r--debian/mariadb-galera-test-5.5.files (renamed from debian/mariadb-test-5.5.files)4
-rw-r--r--debian/mariadb-galera-test-5.5.links (renamed from debian/mariadb-test-5.5.links)0
-rw-r--r--debian/mariadb-server-5.5.lintian-overrides5
-rw-r--r--debian/mariadb-server-core-5.5.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.po48
-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.po48
-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/mysqld_default_groups.h3
-rw-r--r--include/thr_lock.h13
-rw-r--r--mysql-test/extra/binlog_tests/binlog.test6
-rw-r--r--mysql-test/include/check-testcase.test2
-rw-r--r--mysql-test/include/check-warnings.test4
-rw-r--r--mysql-test/include/galera_clear_sync_point.inc1
-rw-r--r--mysql-test/include/galera_cluster.inc10
-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_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.sql1
-rw-r--r--mysql-test/include/not_wsrep.inc7
-rw-r--r--mysql-test/include/wait_until_ready.inc34
-rwxr-xr-xmysql-test/mysql-test-run.pl6
-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.result20
-rw-r--r--mysql-test/r/mysqld--help.result127
-rw-r--r--mysql-test/r/not_wsrep.require2
-rw-r--r--mysql-test/r/show_check.result6
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_binlog.result6
-rw-r--r--mysql-test/suite/binlog/r/binlog_stm_binlog.result6
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_is.result16
-rw-r--r--mysql-test/suite/galera/disabled.def2
-rw-r--r--mysql-test/suite/galera/galera_2nodes.cnf36
-rw-r--r--mysql-test/suite/galera/include/galera_have_debug_sync.inc9
-rw-r--r--mysql-test/suite/galera/my.cnf1
-rw-r--r--mysql-test/suite/galera/r/MW-292.result30
-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/fk.result96
-rw-r--r--mysql-test/suite/galera/r/galera_concurrent_ctas.result1
-rw-r--r--mysql-test/suite/galera/r/galera_forced_binlog_format.result40
-rw-r--r--mysql-test/suite/galera/r/galera_read_only.result18
-rw-r--r--mysql-test/suite/galera/r/galera_sbr.result14
-rw-r--r--mysql-test/suite/galera/r/galera_var_dirty_reads.result95
-rw-r--r--mysql-test/suite/galera/r/galera_var_load_data_splitting.result9
-rw-r--r--mysql-test/suite/galera/r/mdev_9290.result14
-rw-r--r--mysql-test/suite/galera/r/partition.result59
-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.result60
-rw-r--r--mysql-test/suite/galera/r/unique_key.result47
-rw-r--r--mysql-test/suite/galera/r/view.result46
-rw-r--r--mysql-test/suite/galera/suite.pm48
-rw-r--r--mysql-test/suite/galera/t/MW-292.test79
-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/fk.test116
-rw-r--r--mysql-test/suite/galera/t/galera_concurrent_ctas.test57
-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_read_only.test39
-rw-r--r--mysql-test/suite/galera/t/galera_sbr.test27
-rw-r--r--mysql-test/suite/galera/t/galera_var_dirty_reads.test130
-rw-r--r--mysql-test/suite/galera/t/galera_var_load_data_splitting.test38
-rw-r--r--mysql-test/suite/galera/t/mdev_9290.test24
-rw-r--r--mysql-test/suite/galera/t/partition.test144
-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.test43
-rw-r--r--mysql-test/suite/innodb/r/innodb-autoinc.result22
-rw-r--r--mysql-test/suite/innodb/r/innodb_uninstall.result4
-rw-r--r--mysql-test/suite/perfschema/r/all_instances.result13
-rw-r--r--mysql-test/suite/perfschema/r/dml_setup_instruments.result6
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_disallow_writes_basic.result45
-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.result52
-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.result53
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result58
-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.result60
-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.result56
-rw-r--r--mysql-test/suite/sys_vars/t/innodb_disallow_writes_basic.test42
-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.test45
-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.test50
-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/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/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.result97
-rw-r--r--mysql-test/suite/wsrep/suite.pm37
-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/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.test90
-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.test5
-rw-r--r--mysys/default.c12
-rw-r--r--mysys/my_alloc.c5
-rw-r--r--mysys/my_delete.c1
-rw-r--r--mysys/thr_lock.c125
-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.txt28
-rw-r--r--scripts/mysql_config.pl284
-rw-r--r--scripts/mysqld_multi.sh123
-rw-r--r--scripts/mysqld_safe.sh138
-rw-r--r--scripts/wsrep_sst_common.sh204
-rw-r--r--scripts/wsrep_sst_mysqldump.sh133
-rw-r--r--scripts/wsrep_sst_rsync.sh289
-rw-r--r--scripts/wsrep_sst_xtrabackup-v2.sh1008
-rw-r--r--scripts/wsrep_sst_xtrabackup.sh719
-rw-r--r--sql/CMakeLists.txt22
-rw-r--r--sql/event_data_objects.cc17
-rw-r--r--sql/events.cc53
-rw-r--r--sql/ha_partition.cc8
-rw-r--r--sql/ha_partition.h8
-rw-r--r--sql/handler.cc148
-rw-r--r--sql/handler.h16
-rw-r--r--sql/item_func.cc12
-rw-r--r--sql/lock.cc46
-rw-r--r--sql/log.cc196
-rw-r--r--sql/log.h19
-rw-r--r--sql/log_event.cc171
-rw-r--r--sql/mdl.cc154
-rw-r--r--sql/mdl.h13
-rw-r--r--sql/mysqld.cc874
-rw-r--r--sql/mysqld.h16
-rw-r--r--sql/protocol.cc8
-rw-r--r--sql/rpl_record.cc20
-rw-r--r--sql/rpl_rli.cc41
-rw-r--r--sql/rpl_rli.h3
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/slave.cc77
-rw-r--r--sql/sp.cc34
-rw-r--r--sql/sql_acl.cc38
-rw-r--r--sql/sql_admin.cc3
-rw-r--r--sql/sql_alter.cc26
-rw-r--r--sql/sql_base.cc61
-rw-r--r--sql/sql_builtin.cc.in9
-rw-r--r--sql/sql_cache.cc20
-rw-r--r--sql/sql_class.cc308
-rw-r--r--sql/sql_class.h68
-rw-r--r--sql/sql_connect.cc27
-rw-r--r--sql/sql_delete.cc12
-rw-r--r--sql/sql_insert.cc109
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_parse.cc646
-rw-r--r--sql/sql_parse.h16
-rw-r--r--sql/sql_partition_admin.cc13
-rw-r--r--sql/sql_plugin.cc6
-rw-r--r--sql/sql_prepare.cc20
-rw-r--r--sql/sql_reload.cc13
-rw-r--r--sql/sql_repl.cc14
-rw-r--r--sql/sql_show.cc66
-rw-r--r--sql/sql_show.h2
-rw-r--r--sql/sql_table.cc67
-rw-r--r--sql/sql_trigger.cc52
-rw-r--r--sql/sql_truncate.cc10
-rw-r--r--sql/sql_update.cc12
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/sys_vars.cc295
-rw-r--r--sql/table.cc9
-rw-r--r--sql/threadpool_common.cc3
-rw-r--r--sql/transaction.cc63
-rw-r--r--sql/tztime.cc11
-rw-r--r--sql/wsrep_applier.cc396
-rw-r--r--sql/wsrep_applier.h38
-rw-r--r--sql/wsrep_binlog.cc382
-rw-r--r--sql/wsrep_binlog.h52
-rw-r--r--sql/wsrep_check_opts.cc396
-rw-r--r--sql/wsrep_hton.cc570
-rw-r--r--sql/wsrep_mysqld.cc1585
-rw-r--r--sql/wsrep_mysqld.h325
-rw-r--r--sql/wsrep_notify.cc111
-rw-r--r--sql/wsrep_priv.h51
-rw-r--r--sql/wsrep_sst.cc1121
-rw-r--r--sql/wsrep_sst.h67
-rw-r--r--sql/wsrep_thd.cc531
-rw-r--r--sql/wsrep_thd.h35
-rw-r--r--sql/wsrep_utils.cc611
-rw-r--r--sql/wsrep_utils.h229
-rw-r--r--sql/wsrep_var.cc618
-rw-r--r--sql/wsrep_var.h86
-rw-r--r--storage/innobase/CMakeLists.txt4
-rw-r--r--storage/innobase/dict/dict0dict.c22
-rw-r--r--storage/innobase/handler/ha_innodb.cc1421
-rw-r--r--storage/innobase/handler/ha_innodb.h41
-rw-r--r--storage/innobase/handler/handler0alter.cc4
-rw-r--r--storage/innobase/include/dict0mem.h3
-rw-r--r--storage/innobase/include/ha_prototypes.h13
-rw-r--r--storage/innobase/include/lock0lock.h3
-rw-r--r--storage/innobase/include/rem0rec.h9
-rw-r--r--storage/innobase/include/srv0srv.h12
-rw-r--r--storage/innobase/include/trx0sys.h35
-rw-r--r--storage/innobase/include/trx0trx.h3
-rw-r--r--storage/innobase/lock/lock0lock.c364
-rw-r--r--storage/innobase/os/os0file.c23
-rw-r--r--storage/innobase/rem/rem0rec.c133
-rw-r--r--storage/innobase/row/row0ins.c29
-rw-r--r--storage/innobase/row/row0upd.c299
-rw-r--r--storage/innobase/srv/srv0srv.c143
-rw-r--r--storage/innobase/trx/trx0roll.c27
-rw-r--r--storage/innobase/trx/trx0sys.c131
-rw-r--r--storage/innobase/trx/trx0trx.c32
-rw-r--r--storage/innobase/ut/ut0ut.c4
-rw-r--r--storage/tokudb/CMakeLists.txt2
-rw-r--r--storage/tokudb/mysql-test/tokudb_bugs/disabled.def2
-rw-r--r--storage/xtradb/buf/buf0buf.c2
-rw-r--r--storage/xtradb/dict/dict0dict.c22
-rw-r--r--storage/xtradb/handler/ha_innodb.cc1421
-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.h13
-rw-r--r--storage/xtradb/include/lock0lock.h3
-rw-r--r--storage/xtradb/include/rem0rec.h9
-rw-r--r--storage/xtradb/include/srv0srv.h12
-rw-r--r--storage/xtradb/include/trx0sys.h32
-rw-r--r--storage/xtradb/include/trx0trx.h3
-rw-r--r--storage/xtradb/lock/lock0lock.c365
-rw-r--r--storage/xtradb/os/os0file.c23
-rw-r--r--storage/xtradb/os/os0proc.c9
-rw-r--r--storage/xtradb/rem/rem0rec.c133
-rw-r--r--storage/xtradb/row/row0ins.c29
-rw-r--r--storage/xtradb/row/row0upd.c299
-rw-r--r--storage/xtradb/srv/srv0srv.c143
-rw-r--r--storage/xtradb/srv/srv0start.c12
-rw-r--r--storage/xtradb/trx/trx0roll.c27
-rw-r--r--storage/xtradb/trx/trx0sys.c123
-rw-r--r--storage/xtradb/trx/trx0trx.c26
-rw-r--r--support-files/CMakeLists.txt8
-rw-r--r--support-files/mysql.server.sh34
-rw-r--r--support-files/mysql.spec.sh184
-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/Makefile.am7
-rw-r--r--wsrep/wsrep_api.h1118
-rw-r--r--wsrep/wsrep_dummy.c409
-rw-r--r--wsrep/wsrep_gtid.c74
-rw-r--r--wsrep/wsrep_loader.c225
-rw-r--r--wsrep/wsrep_uuid.c83
441 files changed, 33074 insertions, 1387 deletions
diff --git a/.gitignore b/.gitignore
index 4e3d2a1e66e..b00f7dd5643 100644
--- a/.gitignore
+++ b/.gitignore
@@ -116,6 +116,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 1ec50ed5bb3..968a336bf4a 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -214,7 +214,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 100755
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 100755
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 100755
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 6ab17ebf64c..fb466e7b2ee 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(zlib)
INCLUDE(ssl)
@@ -263,6 +264,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)
@@ -389,6 +397,9 @@ ADD_SUBDIRECTORY(vio)
ADD_SUBDIRECTORY(regex)
ADD_SUBDIRECTORY(mysys)
ADD_SUBDIRECTORY(libmysql)
+IF(WITH_WSREP)
+ADD_SUBDIRECTORY(wsrep)
+ENDIF()
ADD_SUBDIRECTORY(client)
ADD_SUBDIRECTORY(extra)
ADD_SUBDIRECTORY(libservices)
@@ -440,8 +451,8 @@ CONFIGURE_FILE(
IF(DEB)
CONFIGURE_FILE(
- ${CMAKE_SOURCE_DIR}/debian/mariadb-server-5.5.files.in
- ${CMAKE_SOURCE_DIR}/debian/mariadb-server-5.5.files)
+ ${CMAKE_SOURCE_DIR}/debian/mariadb-galera-server-5.5.files.in
+ ${CMAKE_SOURCE_DIR}/debian/mariadb-galera-server-5.5.files)
ENDIF(DEB)
# Handle the "INFO_*" files.
@@ -467,7 +478,7 @@ INSTALL_DOCUMENTATION(README 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 7daeec0495f..d6b9ebee5f4 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 836f2c1686b..4f5283f2a74 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -531,7 +531,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 8b938580679..42317084e69 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -837,9 +837,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);
}
diff --git a/cmake/configure.pl b/cmake/configure.pl
index d5c0b9b061a..9f46a5668c9 100644
--- a/cmake/configure.pl
+++ b/cmake/configure.pl
@@ -206,6 +206,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 4e9410306a8..c6f62b3b8d4 100644
--- a/cmake/cpack_rpm.cmake
+++ b/cmake/cpack_rpm.cmake
@@ -23,11 +23,8 @@ SET(CPACK_COMPONENT_SHAREDLIBRARIES_GROUP "shared")
SET(CPACK_COMPONENT_COMMON_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)
-
-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()
@@ -129,9 +126,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")
SETA(CPACK_RPM_shared_PACKAGE_OBSOLETES
"mysql-shared"
@@ -151,10 +154,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 22a525d7344..e5c8c54e975 100644
--- a/cmake/install_macros.cmake
+++ b/cmake/install_macros.cmake
@@ -13,8 +13,30 @@
# 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(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)
@@ -31,6 +53,7 @@ FUNCTION (INSTALL_DEBUG_SYMBOLS)
SET(ARG_INSTALL_LOCATION lib)
ENDIF()
SET(targets ${ARG_DEFAULT_ARGS})
+
FOREACH(target ${targets})
GET_TARGET_PROPERTY(type ${target} TYPE)
GET_TARGET_PROPERTY(location ${target} LOCATION)
@@ -157,9 +180,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})
@@ -289,6 +312,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..b1be01ef4d8 100644
--- a/cmake/os/FreeBSD.cmake
+++ b/cmake/os/FreeBSD.cmake
@@ -33,3 +33,5 @@ IF(EXECINFO)
SET(LIBEXECINFO ${EXECINFO})
ENDIF()
+SET(HAVE_SYS_TIMEB_H CACHE INTERNAL "")
+
diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake
index 1694b238e7b..21a2b3e0d49 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 4ba8fc18e3f..87db39d68d4 100644
--- a/cmake/package_name.cmake
+++ b/cmake/package_name.cmake
@@ -123,7 +123,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 e166275811e..0072ac1c0e2 100644
--- a/cmake/plugin.cmake
+++ b/cmake/plugin.cmake
@@ -190,17 +190,7 @@ MACRO(MYSQL_ADD_PLUGIN)
SET_TARGET_PROPERTIES(${target} PROPERTIES
OUTPUT_NAME "${ARG_MODULE_OUTPUT_NAME}")
# Install dynamic library
- IF(ARG_COMPONENT)
- IF(RPM AND NOT CPACK_COMPONENTS_ALL MATCHES ${ARG_COMPONENT})
- SET(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} ${ARG_COMPONENT} PARENT_SCOPE)
- SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_REQUIRES "MariaDB-server" PARENT_SCOPE)
-
- # workarounds for cmake issues #13248 and #12864:
- SET(CPACK_RPM_${ARG_COMPONENT}_USER_FILELIST ${ignored} PARENT_SCOPE)
- SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_PROVIDES "cmake_bug_13248" PARENT_SCOPE)
- SET(CPACK_RPM_${ARG_COMPONENT}_PACKAGE_OBSOLETES "cmake_bug_13248" PARENT_SCOPE)
- ENDIF()
- ELSE()
+ IF(NOT ARG_COMPONENT)
SET(ARG_COMPONENT Server)
ENDIF()
MYSQL_INSTALL_TARGETS(${target} DESTINATION ${INSTALL_PLUGINDIR} COMPONENT ${ARG_COMPONENT})
diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake
new file mode 100644
index 00000000000..b9e79539ac6
--- /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 "20")
+
+# 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.5
+SET(WSREP_PATCH_REVNO "9949137") # 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/config.h.cmake b/config.h.cmake
index dfdd4215e4a..ae0947d52b4 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -165,6 +165,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 4051b553747..b79c53b42fe 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -367,6 +367,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/dist/Debian/control b/debian/dist/Debian/control
index e83ac1ffa5d..9ff7705b007 100644
--- a/debian/dist/Debian/control
+++ b/debian/dist/Debian/control
@@ -15,173 +15,16 @@ Homepage: http://mariadb.org/
Vcs-Browser: http://bazaar.launchpad.net/~maria-captains/maria/5.5/files
Vcs-Bzr: bzr://lp:maria
-Package: libmariadbclient18
-Section: libs
-Architecture: any
-Depends: mariadb-common, libmysqlclient18 (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
-Conflicts: mariadb-server-5.5 (<< 5.5.33), mariadb-galera-server-5.5 (<< 5.5.33),
- mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3
-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, , ${shlibs:Depends}, ${misc:Depends}
-Replaces: libmariadbclient16-dev, libmysqlclient16-dev
-Conflicts: libmysqlclient-dev, libmariadbclient16-dev, libmysqlclient14-dev, libmysqlclient12-dev, libmysqlclient10-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: ${shlibs:Depends}, ${misc: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, ${shlibs:Depends}, ${misc: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-5.5
-Architecture: any
-Depends: mariadb-common, libmariadbclient18 (>= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
-Provides: mysql-client-core, mysql-client-core-5.1, mysql-client-core-5.5
-Conflicts: 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,
- mariadb-client-5.1, mariadb-client-core-5.1,
- mariadb-client-5.2, mariadb-client-core-5.2,
- mariadb-client-5.3, mariadb-client-core-5.3
-Replaces: 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,
- mariadb-client-5.1, mariadb-client-core-5.1,
- mariadb-client-5.2, mariadb-client-core-5.2,
- mariadb-client-5.3, mariadb-client-core-5.3
-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-5.5
-Architecture: any
-Depends: debianutils (>=1.6), libdbi-perl, libdbd-mysql-perl (>= 1.2202),
- mariadb-common, libmariadbclient18 (>= ${source:Version}),
- mariadb-client-core-5.5 (>= ${source:Version}), ${perl:Depends},
- ${shlibs:Depends}, ${misc:Depends}
-Suggests: libterm-readkey-perl
-Provides: virtual-mysql-client, mysql-client,
- mysql-client-4.1, mysql-client-5.1, mysql-client-5.5
-Conflicts: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1,
- mariadb-client (<< ${source:Version}),
- mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3, mysql-client-5.5
-Replaces: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1,
- mysql-client-5.5,
- mariadb-client (<< ${source:Version}),
- mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3
-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-5.5
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version})
-Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5
-Conflicts: mariadb-server-5.1 (<< 5.1.60),
- mariadb-server-5.2 (<< 5.2.10),
- mariadb-server-5.3 (<< 5.3.3),
- mysql-server-5.0,
- mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
- mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5
-Replaces: mariadb-server-5.1 (<< 5.1.60),
- mariadb-server-5.2 (<< 5.2.10),
- mariadb-server-5.3 (<< 5.3.3),
- mysql-server-5.0,
- mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
- mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5
-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-5.5
+Package: mariadb-galera-test-5.5
Section: database
Architecture: any
-Depends: mariadb-server-5.5 (= ${source:Version}), mariadb-client-5.5 (= ${source:Version})
-Conflicts: mariadb-test (<< ${source:Version}),
- mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3,
- mariadb-server-5.5 (<< 5.5.33), mariadb-galera-server-5.5 (<< 5.5.33)
+Depends: mariadb-galera-server-5.5 (= ${source:Version}), mariadb-client-5.5 (>= ${source:Version})
Suggests: patch
-Replaces: 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.5,
+ mariadb-server-5.5, mariadb-galera-server-5.5 (<< 5.5.33)
+Replaces: mariadb-test (<< ${source:Version}), mariadb-galera-test (<< ${source:Version}),
mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3
Description: MariaDB database regression test suite
MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
@@ -191,26 +34,31 @@ Description: MariaDB database regression test suite
.
This package includes the regression test suite.
-Package: mariadb-server-5.5
+Package: mariadb-galera-server-5.5
Architecture: any
-Suggests: tinyca, mailx, mariadb-test
+Suggests: tinyca, mailx, mariadb-galera-test, netcat-openbsd, socat
Recommends: libhtml-template-perl
Pre-Depends: mariadb-common, adduser (>= 3.40), debconf
Depends: mariadb-client-5.5 (>= ${source:Version}), libdbi-perl,
perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc,
passwd, lsb-base (>= 3.0-10), bsdutils,
- mariadb-server-core-5.5 (>= ${binary:Version})
-Provides: mariadb-server, mysql-server, virtual-mysql-server
-Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}),
+ libmariadbclient18 (>= ${binary:Version}), galera-3 (>=25.3),
+ rsync, lsof, grep, gawk, iproute, coreutils, findutils
+Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5, mysql-server, virtual-mysql-server, mariadb-galera-server
+Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mariadb-galera-server (<< ${source:Version}),
mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5,
mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3,
+ mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
+ mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5,
mariadb-tokudb-engine-5.5
-Replaces: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}),
+Replaces: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mariadb-galera-server (<< ${source:Version}),
mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5,
mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3,
libmariadbclient16 (<< 5.3.4), libmariadbclient-dev (<< 5.5.0),
+ mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
+ mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5,
mariadb-tokudb-engine-5.5
-Description: MariaDB database server binaries
+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
@@ -218,14 +66,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-5.5 (= ${source:Version}), ${misc:Depends}
-Description: MariaDB database server (metapackage depending on the latest version)
+Depends: mariadb-galera-server-5.5 (= ${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-5.5), as determined by the MariaDB
- maintainers. Install this package if in doubt about which MariaDB
+ mariadb-galera-server (currently mariadb-galera-server-5.5), 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.
.
@@ -244,12 +92,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-5.5 (= ${source:Version})
+Depends: mariadb-galera-test-5.5 (= ${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-5.5), as determined by the MariaDB
+ mariadb-galera-test (currently mariadb-galera-test-5.5), as determined by the MariaDB
maintainers.
-
diff --git a/debian/dist/Debian/mariadb-server-5.5.README.Debian b/debian/dist/Debian/mariadb-galera-server-5.5.README.Debian
index f398f2fa236..f398f2fa236 100644
--- a/debian/dist/Debian/mariadb-server-5.5.README.Debian
+++ b/debian/dist/Debian/mariadb-galera-server-5.5.README.Debian
diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.dirs b/debian/dist/Debian/mariadb-galera-server-5.5.dirs
index 6afd2a1854c..39fa440b07f 100644
--- a/debian/dist/Ubuntu/mariadb-server-5.5.dirs
+++ b/debian/dist/Debian/mariadb-galera-server-5.5.dirs
@@ -5,6 +5,6 @@ usr/bin
usr/sbin
usr/share/man/man8
usr/share/mysql
-usr/share/doc/mariadb-server-5.5
+usr/share/doc/mariadb-galera-server-5.5
var/run/mysqld
var/lib/mysql-upgrade
diff --git a/debian/dist/Debian/mariadb-server-5.5.files.in b/debian/dist/Debian/mariadb-galera-server-5.5.files.in
index 47a9887b075..2182954948c 100644
--- a/debian/dist/Debian/mariadb-server-5.5.files.in
+++ b/debian/dist/Debian/mariadb-galera-server-5.5.files.in
@@ -1,3 +1,4 @@
+usr/sbin/mysqld
usr/lib/mysql/plugin/ha_innodb.so
usr/lib/mysql/plugin/sphinx.so
usr/lib/mysql/plugin/auth_socket.so
@@ -38,10 +39,16 @@ usr/bin/perror
usr/bin/replace
usr/bin/resolve_stack_dump
usr/bin/resolveip
-usr/share/doc/mariadb-server-5.5/mysqld.sym.gz
-usr/share/doc/mariadb-server-5.5/INFO_SRC
-usr/share/doc/mariadb-server-5.5/INFO_BIN
-usr/share/lintian/overrides/mariadb-server-5.5
+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-5.5/mysqld.sym.gz
+usr/share/doc/mariadb-galera-server-5.5/INFO_SRC
+usr/share/doc/mariadb-galera-server-5.5/INFO_BIN
+usr/share/doc/mariadb-galera-server-5.5/README-wsrep
+usr/share/lintian/overrides/mariadb-galera-server-5.5
usr/share/man/man1/msql2mysql.1
usr/share/man/man1/myisamchk.1
usr/share/man/man1/myisam_ftdump.1
@@ -64,6 +71,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
@@ -74,3 +106,5 @@ usr/share/mysql/mysql_performance_tables.sql
usr/share/mysql/mysql_test_data_timezone.sql
@TOKUDB_DEB_FILES@
@OQGRAPH_DEB_FILES@
+usr/share/mysql/wsrep.cnf
+usr/share/mysql/wsrep_notify
diff --git a/debian/dist/Debian/mariadb-server-5.5.postinst b/debian/dist/Debian/mariadb-galera-server-5.5.postinst
index 4da8979fd03..4da8979fd03 100644
--- a/debian/dist/Debian/mariadb-server-5.5.postinst
+++ b/debian/dist/Debian/mariadb-galera-server-5.5.postinst
diff --git a/debian/dist/Debian/mariadb-server-5.5.postrm b/debian/dist/Debian/mariadb-galera-server-5.5.postrm
index 469b1627aff..469b1627aff 100644
--- a/debian/dist/Debian/mariadb-server-5.5.postrm
+++ b/debian/dist/Debian/mariadb-galera-server-5.5.postrm
diff --git a/debian/dist/Debian/rules b/debian/dist/Debian/rules
index 9b98c507e8e..b899a9a971d 100755
--- a/debian/dist/Debian/rules
+++ b/debian/dist/Debian/rules
@@ -166,39 +166,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-5.5/examples
+ mkdir -p $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5/examples/
+ # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5/mysqld.sym.gz
+ nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5/INFO_SRC
- install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-server-5.5/INFO_BIN
+ install -m 0644 $(builddir)/Docs/INFO_SRC $(TMP)/usr/share/doc/mariadb-galera-server-5.5/INFO_SRC
+ install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-server-5.5
- cp debian/mariadb-client-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-client-5.5
+ cp debian/mariadb-galera-server-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-galera-server-5.5
# For 5.0 -> 5.5 transition
d=$(TMP)/usr/share/mysql-common/internal-use-only/; \
mkdir -p $$d; \
- cp debian/mariadb-server-5.5.mysql.init $$d/_etc_init.d_mysql; \
- cp debian/mariadb-server-5.5.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \
+ cp debian/mariadb-galera-server-5.5.mysql.init $$d/_etc_init.d_mysql; \
+ cp debian/mariadb-galera-server-5.5.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/control b/debian/dist/Ubuntu/control
index 94424f38db8..7d6e90abd82 100644
--- a/debian/dist/Ubuntu/control
+++ b/debian/dist/Ubuntu/control
@@ -15,167 +15,16 @@ Homepage: http://mariadb.org/
Vcs-Browser: http://bazaar.launchpad.net/~maria-captains/maria/5.5/files
Vcs-Bzr: bzr://lp:maria
-Package: libmariadbclient18
-Section: libs
-Architecture: any
-Depends: mariadb-common, libmysqlclient18 (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
-Conflicts: mariadb-server-5.5 (<< 5.5.33), mariadb-galera-server-5.5 (<< 5.5.33),
- mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3
-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, , ${shlibs:Depends}, ${misc:Depends}
-Replaces: libmariadbclient16-dev, libmysqlclient16-dev
-Conflicts: libmysqlclient-dev, libmariadbclient16-dev, libmysqlclient14-dev, libmysqlclient12-dev, libmysqlclient10-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: ${shlibs:Depends}, ${misc: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
+Package: mariadb-galera-test-5.5
Section: database
-Architecture: all
-Depends: mysql-common, ${shlibs:Depends}, ${misc: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-5.5
-Architecture: any
-Depends: mariadb-common, libmariadbclient18 (>= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}
-Provides: mysql-client-core, mysql-client-core-5.1, mysql-client-core-5.5
-Conflicts: 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,
- mariadb-client-5.1, mariadb-client-core-5.1,
- mariadb-client-5.2, mariadb-client-core-5.2,
- mariadb-client-5.3, mariadb-client-core-5.3
-Replaces: 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,
- mariadb-client-5.1, mariadb-client-core-5.1,
- mariadb-client-5.2, mariadb-client-core-5.2,
- mariadb-client-5.3, mariadb-client-core-5.3
-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-5.5
Architecture: any
-Depends: debianutils (>=1.6), libdbi-perl, libdbd-mysql-perl (>= 1.2202),
- mariadb-common, libmariadbclient18 (>= ${source:Version}),
- mariadb-client-core-5.5 (>= ${source:Version}), ${perl:Depends},
- ${shlibs:Depends}, ${misc:Depends}
-Suggests: libterm-readkey-perl
-Provides: virtual-mysql-client, mysql-client,
- mysql-client-4.1, mysql-client-5.1, mysql-client-5.5
-Conflicts: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1,
- mariadb-client (<< ${source:Version}),
- mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3, mysql-client-5.5
-Replaces: mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1,
- mysql-client-5.5,
- mariadb-client (<< ${source:Version}),
- mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3
-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-5.5
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libmariadbclient18 (>= ${binary:Version})
-Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5
-Conflicts: mysql-server-5.0,
- mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
- mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5
-Replaces: mysql-server-5.0,
- mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
- mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5
-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-5.5
-Section: database
-Architecture: any
-Depends: mariadb-server-5.5 (= ${source:Version}), mariadb-client-5.5 (= ${source:Version})
+Depends: mariadb-galera-server-5.5 (= ${source:Version}), mariadb-client-5.5 (>= ${source:Version})
Suggests: patch
-Conflicts: 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-server-5.5 (<< 5.5.33), mariadb-galera-server-5.5 (<< 5.5.33)
-Replaces: mariadb-test (<< ${source:Version}),
+ mariadb-test-5.5,
+ mariadb-server-5.5, mariadb-galera-server-5.5 (<< 5.5.33)
+Replaces: mariadb-test (<< ${source:Version}), mariadb-galera-test (<< ${source:Version}),
mariadb-test-5.1, mariadb-test-5.2, mariadb-test-5.3
Description: MariaDB database regression test suite
MariaDB is a fast, stable and true multi-user, multi-threaded SQL database
@@ -185,26 +34,31 @@ Description: MariaDB database regression test suite
.
This package includes the regression test suite.
-Package: mariadb-server-5.5
+Package: mariadb-galera-server-5.5
Architecture: any
-Suggests: tinyca, mailx, mariadb-test
+Suggests: tinyca, mailx, mariadb-galera-test, netcat-openbsd, socat
Recommends: libhtml-template-perl
Pre-Depends: mariadb-common, adduser (>= 3.40), debconf
Depends: mariadb-client-5.5 (>= ${source:Version}), libdbi-perl,
perl (>= 5.6), ${shlibs:Depends}, ${misc:Depends}, psmisc,
passwd, lsb-base (>= 3.0-10), bsdutils,
- mariadb-server-core-5.5 (>= ${binary:Version})
-Provides: mariadb-server, mysql-server, virtual-mysql-server
-Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}),
+ libmariadbclient18 (>= ${binary:Version}), galera-3 (>=25.3),
+ rsync, lsof, grep, gawk, iproute, coreutils, findutils
+Provides: mysql-server-core, mysql-server-core-5.1, mysql-server-core-5.5, mysql-server, virtual-mysql-server, mariadb-galera-server
+Conflicts: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mariadb-galera-server (<< ${source:Version}),
mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5,
mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3,
+ mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
+ mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5,
mariadb-tokudb-engine-5.5
-Replaces: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}),
+Replaces: mariadb-server (<< ${source:Version}), mysql-server (<< ${source:Version}), mariadb-galera-server (<< ${source:Version}),
mysql-server-4.1, mysql-server-5.0, mysql-server-5.1, mysql-server-5.5,
mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3,
libmariadbclient16 (<< 5.3.4), libmariadbclient-dev (<< 5.5.0),
+ mysql-server-core-5.0, mysql-server-core-5.1, mysql-server-core-5.5,
+ mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.5,
mariadb-tokudb-engine-5.5
-Description: MariaDB database server binaries
+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
@@ -212,14 +66,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-5.5 (= ${source:Version}), ${misc:Depends}
-Description: MariaDB database server (metapackage depending on the latest version)
+Depends: mariadb-galera-server-5.5 (= ${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-5.5), as determined by the MariaDB
- maintainers. Install this package if in doubt about which MariaDB
+ mariadb-galera-server (currently mariadb-galera-server-5.5), 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.
.
@@ -238,12 +92,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-5.5 (= ${source:Version})
+Depends: mariadb-galera-test-5.5 (= ${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-5.5), as determined by the MariaDB
+ mariadb-galera-test (currently mariadb-galera-test-5.5), as determined by the MariaDB
maintainers.
-
diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.README.Debian b/debian/dist/Ubuntu/mariadb-galera-server-5.5.README.Debian
index 741243f1ec3..741243f1ec3 100644
--- a/debian/dist/Ubuntu/mariadb-server-5.5.README.Debian
+++ b/debian/dist/Ubuntu/mariadb-galera-server-5.5.README.Debian
diff --git a/debian/dist/Debian/mariadb-server-5.5.dirs b/debian/dist/Ubuntu/mariadb-galera-server-5.5.dirs
index 6afd2a1854c..39fa440b07f 100644
--- a/debian/dist/Debian/mariadb-server-5.5.dirs
+++ b/debian/dist/Ubuntu/mariadb-galera-server-5.5.dirs
@@ -5,6 +5,6 @@ usr/bin
usr/sbin
usr/share/man/man8
usr/share/mysql
-usr/share/doc/mariadb-server-5.5
+usr/share/doc/mariadb-galera-server-5.5
var/run/mysqld
var/lib/mysql-upgrade
diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.files.in b/debian/dist/Ubuntu/mariadb-galera-server-5.5.files.in
index 5182dd76346..ccfc7350ed0 100644
--- a/debian/dist/Ubuntu/mariadb-server-5.5.files.in
+++ b/debian/dist/Ubuntu/mariadb-galera-server-5.5.files.in
@@ -1,3 +1,4 @@
+usr/sbin/mysqld
usr/lib/mysql/plugin/ha_innodb.so
usr/lib/mysql/plugin/sphinx.so
usr/lib/mysql/plugin/auth_socket.so
@@ -40,10 +41,17 @@ usr/bin/perror
usr/bin/replace
usr/bin/resolve_stack_dump
usr/bin/resolveip
-usr/share/doc/mariadb-server-5.5/mysqld.sym.gz
-usr/share/doc/mariadb-server-5.5/INFO_SRC
-usr/share/doc/mariadb-server-5.5/INFO_BIN
-usr/share/lintian/overrides/mariadb-server-5.5
+usr/bin/wsrep_sst_common
+usr/bin/wsrep_sst_mysqldump
+usr/bin/wsrep_sst_rsync
+usr/bin/wsrep_sst_rsync_wan
+usr/bin/wsrep_sst_xtrabackup
+usr/bin/wsrep_sst_xtrabackup-v2
+usr/share/doc/mariadb-galera-server-5.5/mysqld.sym.gz
+usr/share/doc/mariadb-galera-server-5.5/INFO_SRC
+usr/share/doc/mariadb-galera-server-5.5/INFO_BIN
+usr/share/doc/mariadb-galera-server-5.5/README-wsrep
+usr/share/lintian/overrides/mariadb-galera-server-5.5
usr/share/man/man1/msql2mysql.1
usr/share/man/man1/myisamchk.1
usr/share/man/man1/myisam_ftdump.1
@@ -66,6 +74,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
@@ -76,3 +109,5 @@ usr/share/mysql/mysql_performance_tables.sql
usr/share/mysql/mysql_test_data_timezone.sql
@TOKUDB_DEB_FILES@
@OQGRAPH_DEB_FILES@
+usr/share/mysql/wsrep.cnf
+usr/share/mysql/wsrep_notify
diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.postinst b/debian/dist/Ubuntu/mariadb-galera-server-5.5.postinst
index 920868e22e6..920868e22e6 100644
--- a/debian/dist/Ubuntu/mariadb-server-5.5.postinst
+++ b/debian/dist/Ubuntu/mariadb-galera-server-5.5.postinst
diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.postrm b/debian/dist/Ubuntu/mariadb-galera-server-5.5.postrm
index 7cee5150ef9..7cee5150ef9 100644
--- a/debian/dist/Ubuntu/mariadb-server-5.5.postrm
+++ b/debian/dist/Ubuntu/mariadb-galera-server-5.5.postrm
diff --git a/debian/dist/Ubuntu/mariadb-server-5.5.py b/debian/dist/Ubuntu/mariadb-galera-server-5.5.py
index a1372a3baf5..1a94e1399a2 100644
--- a/debian/dist/Ubuntu/mariadb-server-5.5.py
+++ b/debian/dist/Ubuntu/mariadb-galera-server-5.5.py
@@ -20,7 +20,7 @@ def _add_my_conf_files(report, filename):
continue
def add_info(report):
- attach_conffiles(report, 'mariadb-server-5.5', conffiles=None)
+ attach_conffiles(report, 'mariadb-galera-server-5.5', 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 5f3ea672770..dbd4be31b2f 100755
--- a/debian/dist/Ubuntu/rules
+++ b/debian/dist/Ubuntu/rules
@@ -166,45 +166,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-5.5/examples
+ mkdir -p $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5/examples/
+ # $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5/mysqld.sym.gz
+ nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5/INFO_SRC
- install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-server-5.5/INFO_BIN
+ install -m 0644 $(builddir)/Docs/INFO_SRC $(TMP)/usr/share/doc/mariadb-galera-server-5.5/INFO_SRC
+ install -m 0644 $(builddir)/Docs/INFO_BIN $(TMP)/usr/share/doc/mariadb-galera-server-5.5/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-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-server-5.5
- cp debian/mariadb-client-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-client-5.5
+ cp debian/mariadb-galera-server-5.5.lintian-overrides $(TMP)/usr/share/lintian/overrides/mariadb-galera-server-5.5
# For 5.0 -> 5.5 transition
d=$(TMP)/usr/share/mysql-common/internal-use-only/; \
mkdir -p $$d; \
- cp debian/mariadb-server-5.5.mysql.init $$d/_etc_init.d_mysql; \
- cp debian/mariadb-server-5.5.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \
+ cp debian/mariadb-galera-server-5.5.mysql.init $$d/_etc_init.d_mysql; \
+ cp debian/mariadb-galera-server-5.5.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-5.5.py $(TMP)/usr/share/apport/package-hooks/source_mariadb-5.5.py
+ install -D -m 644 debian/mariadb-galera-server-5.5.py $(TMP)/usr/share/apport/package-hooks/source_mariadb-5.5.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-5.5.README.Debian b/debian/mariadb-client-5.5.README.Debian
deleted file mode 100644
index b245638f9c9..00000000000
--- a/debian/mariadb-client-5.5.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-5.5.dirs b/debian/mariadb-client-5.5.dirs
deleted file mode 100644
index ceda5922c5d..00000000000
--- a/debian/mariadb-client-5.5.dirs
+++ /dev/null
@@ -1,3 +0,0 @@
-usr/bin/
-usr/share/man/man1/
-usr/share/perl5/
diff --git a/debian/mariadb-client-5.5.docs b/debian/mariadb-client-5.5.docs
deleted file mode 100644
index 21446855f51..00000000000
--- a/debian/mariadb-client-5.5.docs
+++ /dev/null
@@ -1,2 +0,0 @@
-debian/additions/innotop/changelog.innotop
-README
diff --git a/debian/mariadb-client-5.5.files b/debian/mariadb-client-5.5.files
deleted file mode 100644
index 5bd737f5267..00000000000
--- a/debian/mariadb-client-5.5.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-5.5
-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-5.5.links b/debian/mariadb-client-5.5.links
deleted file mode 100644
index 0b86e87f2e9..00000000000
--- a/debian/mariadb-client-5.5.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-5.5.lintian-overrides b/debian/mariadb-client-5.5.lintian-overrides
deleted file mode 100644
index d4dc1a70b1e..00000000000
--- a/debian/mariadb-client-5.5.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-5.5.menu b/debian/mariadb-client-5.5.menu
deleted file mode 100644
index 1378555c423..00000000000
--- a/debian/mariadb-client-5.5.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-5.5.files b/debian/mariadb-client-core-5.5.files
deleted file mode 100644
index a2781309439..00000000000
--- a/debian/mariadb-client-core-5.5.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-server-5.5.NEWS b/debian/mariadb-galera-server-5.5.NEWS
index a3042dc2918..a3042dc2918 100644
--- a/debian/mariadb-server-5.5.NEWS
+++ b/debian/mariadb-galera-server-5.5.NEWS
diff --git a/debian/mariadb-server-5.5.config b/debian/mariadb-galera-server-5.5.config
index 162017caf71..162017caf71 100644
--- a/debian/mariadb-server-5.5.config
+++ b/debian/mariadb-galera-server-5.5.config
diff --git a/debian/mariadb-galera-server-5.5.lintian-overrides b/debian/mariadb-galera-server-5.5.lintian-overrides
new file mode 100644
index 00000000000..377e6e0dd75
--- /dev/null
+++ b/debian/mariadb-galera-server-5.5.lintian-overrides
@@ -0,0 +1,5 @@
+mariadb-galera-server-5.5: command-with-path-in-maintainer-script postinst
+mariadb-galera-server-5.5: possible-bashism-in-maintainer-script postinst:81 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}'
+mariadb-galera-server-5.5: possible-bashism-in-maintainer-script preinst:33 '${cmd/ */}'
+mariadb-galera-server-5.5: statically-linked-binary ./usr/bin/mysql_tzinfo_to_sql
+mariadb-galera-server-5.5: statically-linked-binary ./usr/sbin/mysqld
diff --git a/debian/mariadb-server-5.5.logcheck.ignore.paranoid b/debian/mariadb-galera-server-5.5.logcheck.ignore.paranoid
index 00cc5c3e29d..00cc5c3e29d 100644
--- a/debian/mariadb-server-5.5.logcheck.ignore.paranoid
+++ b/debian/mariadb-galera-server-5.5.logcheck.ignore.paranoid
diff --git a/debian/mariadb-server-5.5.logcheck.ignore.server b/debian/mariadb-galera-server-5.5.logcheck.ignore.server
index 37f25cb01ea..37f25cb01ea 100644
--- a/debian/mariadb-server-5.5.logcheck.ignore.server
+++ b/debian/mariadb-galera-server-5.5.logcheck.ignore.server
diff --git a/debian/mariadb-server-5.5.logcheck.ignore.workstation b/debian/mariadb-galera-server-5.5.logcheck.ignore.workstation
index 37f25cb01ea..37f25cb01ea 100644
--- a/debian/mariadb-server-5.5.logcheck.ignore.workstation
+++ b/debian/mariadb-galera-server-5.5.logcheck.ignore.workstation
diff --git a/debian/mariadb-server-5.5.mysql-server.logrotate b/debian/mariadb-galera-server-5.5.mysql-server.logrotate
index 789ad353e43..789ad353e43 100644
--- a/debian/mariadb-server-5.5.mysql-server.logrotate
+++ b/debian/mariadb-galera-server-5.5.mysql-server.logrotate
diff --git a/debian/mariadb-server-5.5.mysql.init b/debian/mariadb-galera-server-5.5.mysql.init
index 07edda2f079..874d099a0c6 100644
--- a/debian/mariadb-server-5.5.mysql.init
+++ b/debian/mariadb-galera-server-5.5.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-5.5.preinst b/debian/mariadb-galera-server-5.5.preinst
index 1c48fde2837..1c48fde2837 100644
--- a/debian/mariadb-server-5.5.preinst
+++ b/debian/mariadb-galera-server-5.5.preinst
diff --git a/debian/mariadb-server-5.5.prerm b/debian/mariadb-galera-server-5.5.prerm
index 03e9ea37420..03e9ea37420 100644
--- a/debian/mariadb-server-5.5.prerm
+++ b/debian/mariadb-galera-server-5.5.prerm
diff --git a/debian/mariadb-server-5.5.templates b/debian/mariadb-galera-server-5.5.templates
index dfe5f68b319..dfe5f68b319 100644
--- a/debian/mariadb-server-5.5.templates
+++ b/debian/mariadb-galera-server-5.5.templates
diff --git a/debian/mariadb-test-5.5.dirs b/debian/mariadb-galera-test-5.5.dirs
index 65dbbc81c2a..b40bd89463d 100644
--- a/debian/mariadb-test-5.5.dirs
+++ b/debian/mariadb-galera-test-5.5.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-5.5.files b/debian/mariadb-galera-test-5.5.files
index b95f8e0b51c..79eb9520607 100644
--- a/debian/mariadb-test-5.5.files
+++ b/debian/mariadb-galera-test-5.5.files
@@ -9,11 +9,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-5.5.links b/debian/mariadb-galera-test-5.5.links
index 082680fe5ed..082680fe5ed 100644
--- a/debian/mariadb-test-5.5.links
+++ b/debian/mariadb-galera-test-5.5.links
diff --git a/debian/mariadb-server-5.5.lintian-overrides b/debian/mariadb-server-5.5.lintian-overrides
deleted file mode 100644
index a5075e2231a..00000000000
--- a/debian/mariadb-server-5.5.lintian-overrides
+++ /dev/null
@@ -1,5 +0,0 @@
-mariadb-server-5.5: command-with-path-in-maintainer-script postinst
-mariadb-server-5.5: possible-bashism-in-maintainer-script postinst:81 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}'
-mariadb-server-5.5: possible-bashism-in-maintainer-script preinst:33 '${cmd/ */}'
-mariadb-server-5.5: statically-linked-binary ./usr/bin/mysql_tzinfo_to_sql
-mariadb-server-5.5: statically-linked-binary ./usr/sbin/mysqld
diff --git a/debian/mariadb-server-core-5.5.files b/debian/mariadb-server-core-5.5.files
deleted file mode 100644
index 5c60ca5ec67..00000000000
--- a/debian/mariadb-server-core-5.5.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 8ca17f69cc1..347ab715d2f 100644
--- a/debian/po/POTFILES.in
+++ b/debian/po/POTFILES.in
@@ -1 +1 @@
-[type: gettext/rfc822deb] mariadb-server-5.5.templates
+[type: gettext/rfc822deb] mariadb-galera-server-5.5.templates
diff --git a/debian/po/ar.po b/debian/po/ar.po
index 7791fbebf2e..a076d4757e7 100644
--- a/debian/po/ar.po
+++ b/debian/po/ar.po
@@ -27,19 +27,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "هل ÙØ¹Ù„اً تريد التثبيط؟"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "ملاحظة هامة لمستخدمي NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "إزالة جميع قواعد بيانات MariaDB؟"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "تشغيل خادم MariaDB عند الإقلاع؟"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص بـMariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "تعذر تعيين كلمة مرور للمستخدم \"root\" الخاص بـMariaDB."
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 612ed584c96..20c7da86f6c 100644
--- a/debian/po/ca.po
+++ b/debian/po/ca.po
@@ -17,19 +17,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
"more information."
@@ -167,25 +167,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 87d9645a4c5..7db6cce1ad8 100644
--- a/debian/po/cs.po
+++ b/debian/po/cs.po
@@ -26,19 +26,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Opravdu pokraÄovat v degradaci?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Odstranit všechny MariaDB databáze?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Spustit MariaDB server při startu systému?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nové heslo MariaDB uživatele \"root\":"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 a42e3bd67d7..934065e71fb 100644
--- a/debian/po/da.po
+++ b/debian/po/da.po
@@ -27,20 +27,20 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Ønsker du virkelig at fortsætte nedgraderingen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Vigtig oplysning til NIS/YP-brugere"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Fjern alle MariaDB-databaser?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Start MariaDB-serveren under systemopstart?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Ny adgangskode for MariaDB's \"root\"-bruger:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 bbefb910646..5238f43e9fc 100644
--- a/debian/po/de.po
+++ b/debian/po/de.po
@@ -29,13 +29,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Möchten Sie wirklich eine ältere Version einspielen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Wichtige Anmerkung für NIS/YP-Benutzer!"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Alle MariaDB-Datenbanken entfernen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Soll der MariaDB-Server automatisch beim Booten starten?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Neues Passwort für den MariaDB »root«-Benutzer:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "Passwort-Eingabefehler"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB-Cluster scheint gerade benutzt zu werden"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 cb77ed5a50e..eae3a157e98 100644
--- a/debian/po/es.po
+++ b/debian/po/es.po
@@ -52,20 +52,20 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "¿Desea realmente continuar con la desactualización?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante para los usuarios de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "¿Desea eliminar todas las bases de datos MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 ef195532d2a..972239ae97f 100644
--- a/debian/po/eu.po
+++ b/debian/po/eu.po
@@ -20,19 +20,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Benetan bertsio zaharragora itzuli nahi duzu?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "NIS/YP erabiltzaileentzat ohar garrantzitsua"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Ezabatu MariaDB datubase guztiak?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Abioan MariaDB zerbitzaria abiarazi?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "MariaDB \"root\" erabiltzailearen pasahitz berria:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Errepikatu MariaDB \"root\" erabiltzailearen pasahitza:"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
@@ -196,25 +196,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "Pasahitz sarrera errorea"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "Dirudienez NDB Cluster-a erabilia dago"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 d9f59de8e3e..66ab77e101d 100644
--- a/debian/po/fr.po
+++ b/debian/po/fr.po
@@ -22,19 +22,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Faut-il vraiment revenir à la version précédente ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Note importante pour les utilisateurs NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Faut-il supprimer toutes les bases de données MariaDB ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Faut-il lancer MariaDB au démarrage ?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nouveau mot de passe du superutilisateur de MariaDB :"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
@@ -190,13 +190,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "Erreur de saisie du mot de passe"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "Abandon de la gestion de NDB"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 0f05f62ba6d..87e102069d2 100644
--- a/debian/po/gl.po
+++ b/debian/po/gl.po
@@ -17,19 +17,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "¿Quere pasar a unha versión anterior?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante para os usuarios de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "¿Eliminar tódalas bases de datos de MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "¿Iniciar o servidor MariaDB co ordenador?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Novo contrasinal para o usuario \"root\" de MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 b1a3eba1836..b3b0a808303 100644
--- a/debian/po/it.po
+++ b/debian/po/it.po
@@ -18,20 +18,20 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Procedere realmente con l'abbassamento di versione?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante per gli utenti NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Eliminare tutti i database MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Lanciare il server MariaDB all'avvio?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Nuova password per l'utente «root» di MariaDB:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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,14 +168,14 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
@@ -189,25 +189,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "Errore di inserimento della password"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "È in uso un cluster NDB"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 f63f21fdb8d..1f756492263 100644
--- a/debian/po/ja.po
+++ b/debian/po/ja.po
@@ -27,13 +27,13 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "本当ã«ãƒ€ã‚¦ãƒ³ã‚°ãƒ¬ãƒ¼ãƒ‰ã‚’実行ã—ã¾ã™ã‹?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "NIS/YP ユーザã¸ã®é‡è¦ãªæ³¨æ„"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "ã™ã¹ã¦ã® MariaDB データベースを削除ã—ã¾ã™ã‹?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "MariaDB をシステム起動時ã«é–‹å§‹ã—ã¾ã™ã‹?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "MariaDB ã® \"root\" ユーザã«å¯¾ã™ã‚‹æ–°ã—ã„パスワード:"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "ã“ã®å€¤ã‚’空ã®ã¾ã¾ã«ã—ã¦ãŠã„ãŸå ´åˆã¯ã€ãƒ‘スワードã¯å¤‰æ›´ã•れã¾ã›ã‚“。"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "MariaDB ã® \"root\" ユーザã«å¯¾ã™ã‚‹æ–°ã—ã„パスワード:"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "MariaDB ã® \"root\" ユーザã®ãƒ‘スワードを設定ã§ãã¾ã›ã‚“"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
"パッケージã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«å¾Œã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®ãƒ‘スワードを確èªã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
@@ -195,25 +195,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "パスワード入力エラー"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "入力ã•れãŸäºŒã¤ã®ãƒ‘スワードãŒä¸€è‡´ã—ã¾ã›ã‚“。å†å…¥åŠ›ã—ã¦ãã ã•ã„。"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB クラスタãŒåˆ©ç”¨ã•れã¦ã„るよã†ã§ã™"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 3dd6ec7ae5c..d6e136afc6e 100644
--- a/debian/po/nb.po
+++ b/debian/po/nb.po
@@ -19,7 +19,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
"more information."
@@ -212,25 +212,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 09cf06c7c47..8fc82aebd66 100644
--- a/debian/po/nl.po
+++ b/debian/po/nl.po
@@ -18,7 +18,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
"more information."
@@ -213,25 +213,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 e1a3cad5c24..73fbae3248c 100644
--- a/debian/po/pt.po
+++ b/debian/po/pt.po
@@ -18,19 +18,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Deseja mesmo fazer downgrade?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Nota importante para utilizadores de NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Remover todas as bases de dados MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Iniciar o servidor MariaDB no arranque?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 26a5ac3d6fa..50979feeee2 100644
--- a/debian/po/pt_BR.po
+++ b/debian/po/pt_BR.po
@@ -21,19 +21,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Realmente proceder com o rebaixamento de versão?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Aviso importante para usuários NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Remover todas as bases de dados do MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 81d64f37658..7c38a8e8ba7 100644
--- a/debian/po/ro.po
+++ b/debian/po/ro.po
@@ -19,7 +19,7 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
"more information."
@@ -212,25 +212,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 8ce5690ffe1..3e0bbe884ed 100644
--- a/debian/po/ru.po
+++ b/debian/po/ru.po
@@ -32,19 +32,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "ДейÑтвительно уÑтановить более Ñтарую верÑию?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Важное замечание Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹ NIS/YP"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Удалить вÑе базы данных MariaDB?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "ЗапуÑкать MariaDB при загрузке ÑиÑтемы?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr "Ðовый пароль Ð´Ð»Ñ MariaDB Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"root\":"
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr "ЕÑли оÑтавить поле пуÑтым, то пароль изменён не будет."
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr "Повторите ввод Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð´Ð»Ñ MariaDB Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"root\":"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr "Ðевозможно задать пароль MariaDB пользователю \"root\""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr "Проверьте пароль учётной запиÑи поÑле уÑтановки пакета."
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
@@ -196,25 +196,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "Ошибка ввода паролÑ"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr "Два введённых Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½Ðµ одинаковы. Повторите ввод."
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB Cluster уже иÑпользуетÑÑ"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 a05943fa719..e50af88f373 100644
--- a/debian/po/sv.po
+++ b/debian/po/sv.po
@@ -21,19 +21,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr "Vill du verkligen genomföra nedgraderingen?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr "Viktig information för NIS/YP-användare"
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr "Ta bort alla MariaDB-databaser?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr "Ska MariaDB startas vid systemets uppstart?"
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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,13 +170,13 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
#, fuzzy
#| msgid ""
#| "Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
@@ -190,25 +190,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr "Fel vid inmatning av lösenord"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr "NDB-kluster används inte"
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 742ea566a84..94174d24233 100644
--- a/debian/po/templates.pot
+++ b/debian/po/templates.pot
@@ -19,19 +19,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.templates:3001
msgid "Important note for NIS/YP users"
msgstr ""
#. Type: note
#. Description
-#: ../mariadb-server-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.templates:5001
msgid "Start the MariaDB server on boot?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
"more information."
@@ -161,25 +161,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 046c346e85c..9a91efbf61a 100644
--- a/debian/po/tr.po
+++ b/debian/po/tr.po
@@ -18,19 +18,19 @@ msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "Really proceed with downgrade?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.templates:2001
msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:2001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:3001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.templates:4001
msgid "Remove all MariaDB databases?"
msgstr ""
#. Type: boolean
#. Description
-#: ../mariadb-server-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:4001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:5001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "New password for the MariaDB \"root\" user:"
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:6001
+#: ../mariadb-galera-server-5.5.templates:6001
msgid "If this field is left blank, the password will not be changed."
msgstr ""
#. Type: password
#. Description
-#: ../mariadb-server-5.5.templates:7001
+#: ../mariadb-galera-server-5.5.templates:7001
msgid "Repeat password for the MariaDB \"root\" user:"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "Unable to set password for the MariaDB \"root\" user"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.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-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid "You should check the account's password after the package installation."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:8001
+#: ../mariadb-galera-server-5.5.templates:8001
msgid ""
"Please read the /usr/share/doc/mariadb-server-5.5/README.Debian file for "
"more information."
@@ -168,25 +168,25 @@ msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "Password input error"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:9001
+#: ../mariadb-galera-server-5.5.templates:9001
msgid "The two passwords you entered were not the same. Please try again."
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.templates:10001
msgid "NDB Cluster seems to be in use"
msgstr ""
#. Type: error
#. Description
-#: ../mariadb-server-5.5.templates:10001
+#: ../mariadb-galera-server-5.5.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 7558d6d00ae..8e2ca4ee662 100644
--- a/extra/my_print_defaults.c
+++ b/extra/my_print_defaults.c
@@ -96,6 +96,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 usage(my_bool version)
{
@@ -110,7 +115,7 @@ static void usage(my_bool version)
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);
}
@@ -123,7 +128,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(0);
@@ -172,7 +177,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/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 63088365b0c..afaaef7b04b 100644
--- a/mysql-test/extra/binlog_tests/binlog.test
+++ b/mysql-test/extra/binlog_tests/binlog.test
@@ -369,7 +369,7 @@ dfLtTBcBAAAAIgAAAPkAAAAAABcAAAAAAAcAAf/+AQAAAA==
SELECT * FROM t1;
--echo # Their values should be ON
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
--echo
SET @@SESSION.foreign_key_checks= OFF;
@@ -384,7 +384,7 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA==
SELECT * FROM t1;
--echo # Their values should be OFF
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
--echo # INSERT INTO t1 VALUES(2)
--echo # foreign_key_checks=1 and unique_checks=1
@@ -398,7 +398,7 @@ dfLtTBcBAAAAIgAAAM0BAAAAABcAAAAAAAEAAf/+AgAAAA==
SELECT * FROM t1;
--echo # Their values should be OFF
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
DROP TABLE t1;
diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test
index 858a89f706c..38559fc9898 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 3a26f7eecb1..cd3fa0b0153 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/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..bc652225722
--- /dev/null
+++ b/mysql-test/include/galera_cluster.inc
@@ -0,0 +1,10 @@
+# galera_cluster.inc
+# ==================
+#
+# Description
+# -----------
+# Configure galera cluster with 2 nodes.
+#
+
+--let $galera_cluster_size = 2
+--source include/galera_init.inc
diff --git a/mysql-test/include/galera_connect.inc b/mysql-test/include/galera_connect.inc
new file mode 100644
index 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_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 7f990431762..a4cc3f2fc96 100644
--- a/mysql-test/include/mtr_check.sql
+++ b/mysql-test/include/mtr_check.sql
@@ -32,6 +32,7 @@ BEGIN
AND variable_name not like "Last_IO_Err*"
AND variable_name != 'INNODB_IBUF_MAX_SIZE'
AND variable_name != 'INNODB_USE_NATIVE_AIO'
+ AND variable_name != 'WSREP_DATA_HOME_DIR'
ORDER BY variable_name;
-- Dump all databases, there should be none
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/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/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 5beb2956638..197127b56ab 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 == $$ )
{
@@ -187,6 +189,8 @@ my @DEFAULT_SUITES= qw(
sys_vars-
unit-
vcol-
+ wsrep-
+ galera-
);
my $opt_suites;
@@ -3145,7 +3149,6 @@ sub ndbcluster_start ($) {
return 0;
}
-
sub mysql_server_start($) {
my ($mysqld, $tinfo) = @_;
@@ -4737,6 +4740,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]`/,
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 1f765a70137..3667cbedb4c 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1566,50 +1566,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..8b1e48bb8ca
--- /dev/null
+++ b/mysql-test/r/innodb_load_xa_with_wsrep.result
@@ -0,0 +1,20 @@
+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;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb
+mysqld-bin.000001 # Query # # BEGIN
+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/mysqld--help.result b/mysql-test/r/mysqld--help.result
index ef68c064dd4..34d4bae0f28 100644
--- a/mysql-test/r/mysqld--help.result
+++ b/mysql-test/r/mysqld--help.result
@@ -855,6 +855,95 @@ The following options may be given as the first argument:
-V, --version Output version information and exit.
--wait-timeout=# The number of seconds the server waits for activity on a
connection before closing it
+ --wsrep-OSU-method[=name]
+ Method for Online Schema Upgrade
+ --wsrep-auto-increment-control
+ To automatically control the assignment of autoincrement
+ variables
+ (Defaults to on; use --skip-wsrep-auto-increment-control to disable.)
+ --wsrep-causal-reads
+ (DEPRECATED) Setting this variable is equivalent to
+ setting wsrep_sync_wait READ flag
+ --wsrep-certify-nonPK
+ Certify tables with no primary key
+ (Defaults to on; use --skip-wsrep-certify-nonPK to disable.)
+ --wsrep-cluster-address=name
+ Address to initially connect to cluster
+ --wsrep-cluster-name=name
+ Name for the cluster
+ --wsrep-convert-LOCK-to-trx
+ To convert locking sessions into transactions
+ --wsrep-data-home-dir=name
+ home directory for wsrep provider
+ --wsrep-dbug-option=name
+ DBUG options to provider library
+ --wsrep-debug To enable debug level logging
+ --wsrep-desync To desynchronize the node from the cluster
+ --wsrep-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-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 chesks
+ --wsrep-slave-threads=#
+ Number of slave appliers to launch
+ --wsrep-sst-auth=name
+ Authentication for SST connection
+ --wsrep-sst-donor=name
+ preferred donor node for the SST
+ --wsrep-sst-donor-rejects-queries
+ Reject client queries when donating state snapshot
+ transfer
+ --wsrep-sst-method=name
+ State snapshot transfer method
+ --wsrep-sst-receive-address=name
+ Address where node is waiting for SST contact
+ --wsrep-start-position=name
+ global transaction position to start from
+ --wsrep-sync-wait[=#]
+ Ensure "synchronous" read view before executing an
+ operation of the type specified by bitmask: 1 -
+ READ(includes SELECT, SHOW and BEGIN/START TRANSACTION);
+ 2 - UPDATE and DELETE; 4 - INSERT and REPLACE
Variables (--variable-name=value)
allow-suspicious-udfs FALSE
@@ -1104,6 +1193,44 @@ updatable-views-with-limit YES
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 131072
+wsrep-max-ws-size 1073741824
+wsrep-mysql-replication-bundle 0
+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/show_check.result b/mysql-test/r/show_check.result
index 0e4cf6c6775..b7f1b4b7e30 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/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result
index 109328dfdad..e4842d0b9ef 100644
--- a/mysql-test/suite/binlog/r/binlog_row_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result
@@ -780,7 +780,7 @@ SELECT * FROM t1;
c1
1
# Their values should be ON
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
Variable_name Value
foreign_key_checks ON
unique_checks ON
@@ -798,7 +798,7 @@ c1
1
2
# Their values should be OFF
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
Variable_name Value
foreign_key_checks OFF
unique_checks OFF
@@ -816,7 +816,7 @@ c1
1
2
# Their values should be OFF
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
Variable_name Value
foreign_key_checks OFF
unique_checks OFF
diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
index 68e76921ff3..97a2846d063 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
@@ -587,7 +587,7 @@ SELECT * FROM t1;
c1
1
# Their values should be ON
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
Variable_name Value
foreign_key_checks ON
unique_checks ON
@@ -605,7 +605,7 @@ c1
1
2
# Their values should be OFF
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
Variable_name Value
foreign_key_checks OFF
unique_checks OFF
@@ -623,7 +623,7 @@ c1
1
2
# Their values should be OFF
-SHOW SESSION VARIABLES LIKE "%_checks";
+SHOW SESSION VARIABLES WHERE VARIABLE_NAME LIKE "%_checks" AND VARIABLE_NAME NOT LIKE 'wsrep%';
Variable_name Value
foreign_key_checks OFF
unique_checks OFF
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 15015ce4786..11e7fb4d308 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_is.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_is.result
@@ -134,9 +134,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
@@ -284,9 +284,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
@@ -602,9 +602,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)
@@ -752,9 +752,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..c91654c2023
--- /dev/null
+++ b/mysql-test/suite/galera/disabled.def
@@ -0,0 +1,2 @@
+galera_var_dirty_reads : MDEV-12539
+query_cache : MDEV-12539
diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf
new file mode 100644
index 00000000000..91f9861a12a
--- /dev/null
+++ b/mysql-test/suite/galera/galera_2nodes.cnf
@@ -0,0 +1,36 @@
+# 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-cluster-address=gcomm://
+wsrep-provider=@ENV.WSREP_PROVIDER
+# enforce read-committed characteristics across the cluster
+wsrep-causal-reads=ON
+wsrep-sync-wait=7
+
+[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'
+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_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/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/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/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/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/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_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_forced_binlog_format.result b/mysql-test/suite/galera/r/galera_forced_binlog_format.result
new file mode 100644
index 00000000000..f08aad8be1a
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_forced_binlog_format.result
@@ -0,0 +1,40 @@
+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 245;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
+mysqld-bin.000001 <Pos> Query 1 <End_log_pos> BEGIN
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows 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> Query 1 <End_log_pos> BEGIN
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows 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_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_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_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
new file mode 100644
index 00000000000..8a3175912c7
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
@@ -0,0 +1,95 @@
+CREATE TABLE t1(i INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES(1);
+SELECT * FROM t1;
+i
+1
+create user user1;
+grant all privileges on *.* to user1;
+create user user2;
+grant all privileges on *.* to user2;
+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
+SET @@session.wsrep_dirty_reads=ON;
+SELECT * FROM t1;
+i
+1
+connect con1, localhost, user1,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2;
+SET SESSION wsrep_sync_wait=0;
+set session wsrep_dirty_reads=1;
+prepare stmt_show from 'select 1';
+prepare stmt_select from 'select * from t1';
+prepare stmt_insert from 'insert into t1 values(1)';
+set session wsrep_dirty_reads=0;
+execute stmt_show;
+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
+execute stmt_insert;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET wsrep_dirty_reads=ON;
+select @@session.wsrep_dirty_reads;
+@@session.wsrep_dirty_reads
+1
+execute stmt_show;
+1
+1
+execute stmt_select;
+i
+1
+execute stmt_insert;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET @@global.wsrep_dirty_reads=ON;
+connect con2, localhost, user2,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2;
+select @@session.wsrep_dirty_reads;
+@@session.wsrep_dirty_reads
+1
+prepare stmt_show from 'select 1';
+prepare stmt_select from 'select * from t1';
+prepare stmt_insert from 'insert into t1 values(1)';
+execute stmt_show;
+1
+1
+execute stmt_select;
+i
+1
+execute stmt_insert;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET SESSION wsrep_sync_wait=1;
+execute stmt_show;
+1
+1
+execute stmt_select;
+i
+1
+execute stmt_insert;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET SESSION wsrep_sync_wait=7;
+execute stmt_show;
+1
+1
+execute stmt_select;
+i
+1
+execute stmt_insert;
+ERROR 08S01: WSREP has not yet prepared node for application use
+connection node_2;
+SET @@global.wsrep_dirty_reads=OFF;
+connection node_1;
+SELECT * FROM t1;
+i
+1
+DROP TABLE t1;
+drop user user1;
+drop user user2;
+disconnect node_2;
+disconnect node_1;
+# End of test
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/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/partition.result b/mysql-test/suite/galera/r/partition.result
new file mode 100644
index 00000000000..379b82fabf8
--- /dev/null
+++ b/mysql-test/suite/galera/r/partition.result
@@ -0,0 +1,59 @@
+#
+# 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-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/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..b5a6c31a7f2
--- /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..267b48551f2
--- /dev/null
+++ b/mysql-test/suite/galera/r/rpl_row_annotate.result
@@ -0,0 +1,60 @@
+# 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 # Query 1 # use `test`; CREATE TABLE t1(i INT)ENGINE=INNODB
+mysqld-bin.000001 # Query 1 # BEGIN
+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 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Query 1 # BEGIN
+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 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Query 2 # BEGIN
+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 2 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
+mysqld-bin.000001 # Query 2 # BEGIN
+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 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 # Query 1 # use `test`; CREATE TABLE t1(i INT)ENGINE=INNODB
+mysqld-bin.000001 # Query 1 # BEGIN
+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 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Query 1 # BEGIN
+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 1 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 1 # COMMIT /* xid= */
+mysqld-bin.000001 # Query 2 # BEGIN
+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 2 # table_id: # flags: STMT_END_F
+mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
+mysqld-bin.000001 # Query 2 # BEGIN
+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 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..4ab34e4a26a
--- /dev/null
+++ b/mysql-test/suite/galera/r/view.result
@@ -0,0 +1,46 @@
+#
+# 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..a790e951762
--- /dev/null
+++ b/mysql-test/suite/galera/suite.pm
@@ -0,0 +1,48 @@
+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 ($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: no nodes coming from prim view, prim not possible|,
+ qr(WSREP: SYNC message from member .* in non-primary configuration. Ignored.),
+ qr(WSREP: discarding established .*),
+ );
+
+
+$ENV{PATH}="$epath:$ENV{PATH}";
+$ENV{PATH}="$spath:$ENV{PATH}" unless $epath eq $spath;
+
+bless { };
+
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..7e4cf9050ae
--- /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/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/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_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_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..38e07526de1
--- /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 245;
+
+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_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_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_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
new file mode 100644
index 00000000000..8fd3b1d22f2
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
@@ -0,0 +1,130 @@
+#
+# Check the handling of @@wsrep_dirty_reads
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--disable_query_log
+# Save original auto_increment_offset values.
+--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`;
+--enable_query_log
+
+--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;
+
+create user user1;
+grant all privileges on *.* to user1;
+create user user2;
+grant all privileges on *.* to user2;
+
+SET @@global.wsrep_cluster_address = '';
+SET @@session.wsrep_dirty_reads=OFF;
+
+# Set wsrep_sync_wait to avoid ER_LOCK_WAIT_TIMEOUT (MDEV-6832).
+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;
+
+SET @@session.wsrep_dirty_reads=ON;
+
+SELECT * FROM t1;
+
+--enable_connect_log
+--connect (con1, localhost, user1,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2)
+#Just test the session behavior
+SET SESSION wsrep_sync_wait=0;
+
+set session wsrep_dirty_reads=1;
+#Prepared statement creation should be allowed MDEV-11479
+prepare stmt_show from 'select 1';
+prepare stmt_select from 'select * from t1';
+prepare stmt_insert from 'insert into t1 values(1)';
+set session wsrep_dirty_reads=0;
+
+#No Preapare stmt/proceure will be allowed
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_show;
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_select;
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_insert;
+
+SET wsrep_dirty_reads=ON;
+select @@session.wsrep_dirty_reads;
+#Only prepare statement which does not change data should be allowed
+execute stmt_show;
+execute stmt_select;
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_insert;
+SET @@global.wsrep_dirty_reads=ON;
+
+--connect (con2, localhost, user2,,test,$NODE_MYPORT_2,$NODE_MYSOCK_2)
+#Just test the session behavior
+select @@session.wsrep_dirty_reads;
+
+prepare stmt_show from 'select 1';
+prepare stmt_select from 'select * from t1';
+prepare stmt_insert from 'insert into t1 values(1)';
+
+#Only prepare statement which does not change data should be allowed
+execute stmt_show;
+execute stmt_select;
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_insert;
+
+#wsrep_dirty_read should work when wsrep_sync_wait is 1 or non zero
+#because we already are disconnected , So It does not make any sense
+#to wait for other nodes
+SET SESSION wsrep_sync_wait=1;
+execute stmt_show;
+execute stmt_select;
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_insert;
+
+SET SESSION wsrep_sync_wait=7;
+execute stmt_show;
+execute stmt_select;
+--error ER_UNKNOWN_COM_ERROR
+execute stmt_insert;
+
+--connection node_2
+SET @@global.wsrep_dirty_reads=OFF;
+
+--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
+SELECT * FROM t1;
+# Cleanup
+DROP TABLE t1;
+drop user user1;
+drop user user2;
+
+--disable_query_log
+# Restore original auto_increment_offset values.
+--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;
+--enable_query_log
+
+--source include/galera_end.inc
+--echo # End of test
+
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..0783dc897f8
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_load_data_splitting.test
@@ -0,0 +1,38 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--let $wsrep_load_data_splitting_orig = `SELECT @@wsrep_load_data_splitting`
+
+# Create a file for LOAD DATA with 95K entries
+--perl
+open(FILE, ">", "$ENV{'MYSQLTEST_VARDIR'}/tmp/galera_var_load_data_splitting.csv") or die;
+foreach my $i (1..95000) {
+ print FILE "$i\n";
+}
+EOF
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+# Record wsrep_last_committed as it was before LOAD DATA
+--connection node_2
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+SET GLOBAL wsrep_load_data_splitting = TRUE;
+--disable_query_log
+--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/galera_var_load_data_splitting.csv' INTO TABLE t1;
+--enable_query_log
+
+--connection node_2
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+SELECT COUNT(*) = 95000 FROM t1;
+
+# LOAD-ing 95K rows causes 10 commits to be registered
+--disable_query_log
+--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 10 AS wsrep_last_committed_diff;
+--enable_query_log
+
+--connection node_1
+--eval SET GLOBAL wsrep_load_data_splitting = $wsrep_load_data_splitting_orig;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/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/partition.test b/mysql-test/suite/galera/t/partition.test
new file mode 100644
index 00000000000..e4775e1e730
--- /dev/null
+++ b/mysql-test/suite/galera/t/partition.test
@@ -0,0 +1,144 @@
+--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-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/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..d72ad264358
--- /dev/null
+++ b/mysql-test/suite/galera/t/view.test
@@ -0,0 +1,43 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--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/innodb/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result
index 2ea6869291e..24a4558ff4e 100644
--- a/mysql-test/suite/innodb/r/innodb-autoinc.result
+++ b/mysql-test/suite/innodb/r/innodb-autoinc.result
@@ -201,6 +201,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -234,6 +235,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -273,6 +275,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -286,6 +289,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL);
INSERT INTO t1 VALUES (250),(NULL);
SELECT * FROM t1;
@@ -319,6 +323,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -334,6 +339,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (-2);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
@@ -374,6 +380,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -389,6 +396,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 100
auto_increment_offset 10
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL);
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
@@ -423,6 +431,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -438,6 +447,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 2
auto_increment_offset 10
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
SELECT * FROM t1;
c1
@@ -456,6 +466,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -471,6 +482,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 2
auto_increment_offset 10
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL);
ERROR HY000: Failed to read auto-increment value from storage engine
SELECT * FROM t1;
@@ -484,6 +496,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -499,6 +512,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 5
auto_increment_offset 7
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
ERROR HY000: Failed to read auto-increment value from storage engine
SELECT * FROM t1;
@@ -512,6 +526,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -531,6 +546,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 3
auto_increment_offset 3
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (NULL),(NULL), (NULL);
SELECT * FROM t1;
c1
@@ -548,6 +564,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
@@ -566,6 +583,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 65535
auto_increment_offset 65535
+wsrep_auto_increment_control ON
INSERT INTO t1 VALUES (NULL),(NULL);
ERROR HY000: Failed to read auto-increment value from storage engine
SELECT * FROM t1;
@@ -579,6 +597,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
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);
@@ -878,6 +897,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, NULL);
INSERT INTO t1 VALUES (-1, 'innodb');
@@ -1268,6 +1288,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 256
+wsrep_auto_increment_control ON
CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, NULL);
SHOW CREATE TABLE t1;
@@ -1286,6 +1307,7 @@ SHOW VARIABLES LIKE "%auto_inc%";
Variable_name Value
auto_increment_increment 1
auto_increment_offset 1
+wsrep_auto_increment_control ON
CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (2147483648, 'a');
SHOW CREATE TABLE t1;
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/perfschema/r/all_instances.result b/mysql-test/suite/perfschema/r/all_instances.result
index 6e4206b2b51..3b0b4db4541 100644
--- a/mysql-test/suite/perfschema/r/all_instances.result
+++ b/mysql-test/suite/perfschema/r/all_instances.result
@@ -68,6 +68,13 @@ wait/synch/mutex/sql/LOCK_thread_count
wait/synch/mutex/sql/LOCK_user_conn
wait/synch/mutex/sql/LOCK_user_locks
wait/synch/mutex/sql/LOCK_uuid_short_generator
+wait/synch/mutex/sql/LOCK_wsrep_desync
+wait/synch/mutex/sql/LOCK_wsrep_ready
+wait/synch/mutex/sql/LOCK_wsrep_replaying
+wait/synch/mutex/sql/LOCK_wsrep_rollback
+wait/synch/mutex/sql/LOCK_wsrep_slave_threads
+wait/synch/mutex/sql/LOCK_wsrep_sst
+wait/synch/mutex/sql/LOCK_wsrep_sst_init
wait/synch/mutex/sql/LOCK_xid_cache
wait/synch/mutex/sql/LOG::LOCK_log
wait/synch/mutex/sql/LOG_INFO::lock
@@ -87,6 +94,7 @@ wait/synch/mutex/sql/Slave_reporting_capability::err_lock
wait/synch/mutex/sql/TABLE_SHARE::LOCK_ha_data
wait/synch/mutex/sql/THD::LOCK_thd_data
wait/synch/mutex/sql/THD::LOCK_wakeup_ready
+wait/synch/mutex/sql/THD::LOCK_wsrep_thd
wait/synch/mutex/sql/tz_LOCK
select name from rwlock_instances
where name not in ("wait/synch/rwlock/sql/CRYPTO_dynlock_value::lock")
@@ -122,6 +130,11 @@ wait/synch/cond/sql/COND_rpl_status
wait/synch/cond/sql/COND_server_started
wait/synch/cond/sql/COND_thread_cache
wait/synch/cond/sql/COND_thread_count
+wait/synch/cond/sql/COND_wsrep_ready
+wait/synch/cond/sql/COND_wsrep_replaying
+wait/synch/cond/sql/COND_wsrep_rollback
+wait/synch/cond/sql/COND_wsrep_sst
+wait/synch/cond/sql/COND_wsrep_sst_init
wait/synch/cond/sql/Event_scheduler::COND_state
wait/synch/cond/sql/Master_info::data_cond
wait/synch/cond/sql/Master_info::sleep_cond
diff --git a/mysql-test/suite/perfschema/r/dml_setup_instruments.result b/mysql-test/suite/perfschema/r/dml_setup_instruments.result
index 9f48a085eca..807cc3e079e 100644
--- a/mysql-test/suite/perfschema/r/dml_setup_instruments.result
+++ b/mysql-test/suite/perfschema/r/dml_setup_instruments.result
@@ -43,9 +43,9 @@ wait/synch/cond/sql/COND_rpl_status YES YES
wait/synch/cond/sql/COND_server_started YES YES
wait/synch/cond/sql/COND_thread_cache YES YES
wait/synch/cond/sql/COND_thread_count YES YES
-wait/synch/cond/sql/Delayed_insert::cond YES YES
-wait/synch/cond/sql/Delayed_insert::cond_client YES YES
-wait/synch/cond/sql/Event_scheduler::COND_state YES YES
+wait/synch/cond/sql/COND_wsrep_ready YES YES
+wait/synch/cond/sql/COND_wsrep_replaying YES YES
+wait/synch/cond/sql/COND_wsrep_rollback YES YES
select * from performance_schema.setup_instruments
where name='Wait';
select * from performance_schema.setup_instruments
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/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..69599c4b47a
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_desync_basic.result
@@ -0,0 +1,52 @@
+#
+# wsrep_desync
+#
+call mtr.add_suppression("WSREP: SET desync failed 9 for 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
+1
+
+# valid values
+SET @@global.wsrep_desync='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
+1
+SET @@global.wsrep_desync=default;
+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..15438a2afd5
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_rows_basic.result
@@ -0,0 +1,53 @@
+#
+# 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
+131072
+
+# 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;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_max_ws_rows value: '0'
+SELECT @@global.wsrep_max_ws_rows;
+@@global.wsrep_max_ws_rows
+1
+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..26d8d823a5c
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_max_ws_size_basic.result
@@ -0,0 +1,58 @@
+#
+# wsrep_max_ws_size
+#
+# save the initial value
+SET @wsrep_max_ws_size_global_saved = @@global.wsrep_max_ws_size;
+# default
+SELECT @@global.wsrep_max_ws_size;
+@@global.wsrep_max_ws_size
+1073741824
+
+# 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;
+# 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..95b59e62adc
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_osu_method_basic.result
@@ -0,0 +1,60 @@
+#
+# 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;
+ERROR HY000: Variable 'wsrep_OSU_method' is a GLOBAL variable
+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..1e7b9364570
--- /dev/null
+++ b/mysql-test/suite/sys_vars/r/wsrep_sync_wait_basic.result
@@ -0,0 +1,56 @@
+#
+# 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;
+Warnings:
+Warning 1292 Truncated incorrect wsrep_sync_wait value: '8'
+SELECT @@session.wsrep_sync_wait;
+@@session.wsrep_sync_wait
+7
+
+# 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/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..15226c75d8b
--- /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 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..e7af4558f24
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_max_ws_size_basic.test
@@ -0,0 +1,45 @@
+--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;
+
+--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;
+
+--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..d6d461075a5
--- /dev/null
+++ b/mysql-test/suite/sys_vars/t/wsrep_osu_method_basic.test
@@ -0,0 +1,50 @@
+--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
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+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/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/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..5117dd1b048
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/variables.result
@@ -0,0 +1,97 @@
+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#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
+#
+# 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/suite.pm b/mysql-test/suite/wsrep/suite.pm
new file mode 100644
index 00000000000..ec7a3e374f5
--- /dev/null
+++ b/mysql-test/suite/wsrep/suite.pm
@@ -0,0 +1,37 @@
+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: 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/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..3093d8ba942
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/variables.test
@@ -0,0 +1,90 @@
+--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 #
+--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';
+
+--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/t/file_contents.test b/mysql-test/t/file_contents.test
index 9147727d3e8..d22b5c2c78c 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 943eb8bab8a..436a3980030 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 5f61b4b7c43..b28cc8bfd8d 100644
--- a/mysql-test/t/mysqld--help.test
+++ b/mysql-test/t/mysqld--help.test
@@ -10,7 +10,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).
@@ -20,7 +20,8 @@ perl;
# their paths may vary:
@skipvars=qw/basedir open-files-limit general-log-file log plugin-dir
log-slow-queries pid-file slow-query-log-file log-basename
- datadir slave-load-tmpdir tmpdir socket/;
+ datadir slave-load-tmpdir tmpdir socket wsrep-node-name
+ wsrep-data-home-dir/;
# Plugins which may or may not be there:
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster
diff --git a/mysys/default.c b/mysys/default.c
index 39c9b0226f2..6f7ea583a1d 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -87,6 +87,12 @@ static char my_defaults_extra_file_buffer[FN_REFLEN];
static my_bool defaults_already_read= FALSE;
+#ifdef WITH_WSREP
+/* The only purpose of this global array is to hold full name of my.cnf
+ * which seems to be otherwise unavailable */
+char wsrep_defaults_file[FN_REFLEN + 10]={0,};
+#endif /* WITH_WREP */
+
/* Which directories are searched for options (and in which order) */
#define MAX_DEFAULT_DIRS 6
@@ -804,6 +810,12 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
return 1; /* Ignore wrong files */
+#ifdef WITH_WSREP
+ /* make sure we do this only once - for top-level file */
+ if ('\0' == wsrep_defaults_file[0])
+ strncpy(wsrep_defaults_file, name, sizeof(wsrep_defaults_file) - 1);
+#endif /* WITH_WSREP */
+
while (mysql_file_fgets(buff, sizeof(buff) - 1, fp))
{
line++;
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index 1054db6cee4..9e44707b1a2 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -93,6 +93,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;
@@ -114,7 +115,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)
{
@@ -142,6 +143,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_delete.c b/mysys/my_delete.c
index 8487f1d2e5a..a97de4fa83d 100644
--- a/mysys/my_delete.c
+++ b/mysys/my_delete.c
@@ -160,3 +160,4 @@ error:
DBUG_RETURN(-1);
}
#endif
+
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 890140fc34f..06e7802b4e6 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -94,7 +94,24 @@ be any number of TL_WRITE_CONCURRENT_INSERT locks aktive at the same time.
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
@@ -645,8 +662,111 @@ 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;
-static enum enum_thr_lock_result
+ /* 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)
{
THR_LOCK *lock=data->lock;
@@ -1150,6 +1270,7 @@ 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/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 b4bd930029d..0fa74c93d2d 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -329,9 +329,20 @@ 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)
+
# On Unix, most of the files end up in the bin directory
SET(BIN_SCRIPTS
msql2mysql
@@ -348,6 +359,7 @@ ELSE()
mysqldumpslow
mysqld_multi
mysqld_safe
+ ${WSREP_BINARIES}
)
FOREACH(file ${BIN_SCRIPTS})
IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.sh)
@@ -370,6 +382,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/mysql_config.pl b/scripts/mysql_config.pl
new file mode 100644
index 00000000000..5490853c091
--- /dev/null
+++ b/scripts/mysql_config.pl
@@ -0,0 +1,284 @@
+#!/usr/bin/perl
+# -*- cperl -*-
+#
+# Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+##############################################################################
+#
+# This script reports various configuration settings that may be needed
+# when using the MySQL client library.
+#
+# This script try to match the shell script version as close as possible,
+# but in addition being compatible with ActiveState Perl on Windows.
+#
+# All unrecognized arguments to this script are passed to mysqld.
+#
+# NOTE: This script will only be used on Windows until solved how to
+# handle and other strings inserted that might contain
+# several arguments, possibly with spaces in them.
+#
+# NOTE: This script was deliberately written to be as close to the shell
+# script as possible, to make the maintenance of both in parallel
+# easier.
+#
+##############################################################################
+
+use File::Basename;
+use Getopt::Long;
+use Cwd;
+use strict;
+
+my @exclude_cflags =
+ qw/DDBUG_OFF DSAFE_MUTEX DUNIV_MUST_NOT_INLINE DFORCE_INIT_OF_VARS
+ DEXTRA_DEBUG DHAVE_valgrind O O[0-9] xO[0-9] W[-A-Za-z]*
+ Xa xstrconst xc99=none
+ unroll2 ip mp restrict/;
+
+my @exclude_libs = qw/lmtmalloc static-libcxa i-static static-intel/;
+
+my $cwd = cwd();
+my $basedir;
+
+my $socket = '/tmp/mysql.sock';
+my $version = '5.5.38';
+
+sub which
+{
+ my $file = shift;
+
+ my $IFS = $^O eq "MSWin32" ? ";" : ":";
+
+ foreach my $dir ( split($IFS, $ENV{PATH}) )
+ {
+ if ( -f "$dir/$file" or -f "$dir/$file.exe" )
+ {
+ return "$dir/$file";
+ }
+ }
+ print STDERR "which: no $file in ($ENV{PATH})\n";
+ exit 1;
+}
+
+# ----------------------------------------------------------------------
+# If we can find the given directory relatively to where mysql_config is
+# we should use this instead of the incompiled one.
+# This is to ensure that this script also works with the binary MySQL
+# version
+# ----------------------------------------------------------------------
+
+sub fix_path
+{
+ my $default = shift;
+ my @dirs = @_;
+
+ foreach my $dirname ( @dirs )
+ {
+ my $path = "$basedir/$dirname";
+ if ( -d $path )
+ {
+ return $path;
+ }
+ }
+ return $default;
+}
+
+sub get_full_path
+{
+ my $file = shift;
+
+ # if the file is a symlink, try to resolve it
+ if ( $^O ne "MSWin32" and -l $file )
+ {
+ $file = readlink($file);
+ }
+
+ if ( $file =~ m,^/, )
+ {
+ # Do nothing, absolute path
+ }
+ elsif ( $file =~ m,/, )
+ {
+ # Make absolute, and remove "/./" in path
+ $file = "$cwd/$file";
+ $file =~ s,/\./,/,g;
+ }
+ else
+ {
+ # Find in PATH
+ $file = which($file);
+ }
+
+ return $file;
+}
+
+##############################################################################
+#
+# Form a command line that can handle spaces in paths and arguments
+#
+##############################################################################
+
+sub quote_options {
+ my @cmd;
+ foreach my $opt ( @_ )
+ {
+ next unless $opt; # If undefined or empty, just skip
+ push(@cmd, "\"$opt\""); # Quote argument
+ }
+ return join(" ", @cmd);
+}
+
+##############################################################################
+#
+# Main program
+#
+##############################################################################
+
+my $me = get_full_path($0);
+$basedir = dirname(dirname($me)); # Remove "/bin/mysql_config" part
+
+my $ldata = '/usr/local/mysql/data';
+my $execdir = '/usr/local/mysql/bin';
+my $bindir = '/usr/local/mysql/bin';
+
+# ----------------------------------------------------------------------
+# If installed, search for the compiled in directory first (might be "lib64")
+# ----------------------------------------------------------------------
+
+my $pkglibdir = fix_path('/usr/local/mysql/lib',"libmysql/relwithdebinfo",
+ "libmysql/release","libmysql/debug","lib/mysql","lib");
+
+my $pkgincludedir = fix_path('/usr/local/mysql/include/mysql', "include/mysql", "include");
+
+# Assume no argument with space in it
+my @ldflags = split(" ",'');
+
+my $port;
+if ( '0' == 0 ) {
+ $port = 0;
+} else {
+ $port = '3306';
+}
+
+# ----------------------------------------------------------------------
+# Create options
+# We intentionally add a space to the beginning and end of lib strings, simplifies replace later
+# ----------------------------------------------------------------------
+
+my (@lib_opts,@lib_r_opts,@lib_e_opts);
+if ( $^O eq "MSWin32" )
+{
+ my $linkpath = "$pkglibdir";
+ # user32 is only needed for debug or embedded
+ my @winlibs = ("wsock32.lib","advapi32.lib","user32.lib");
+ @lib_opts = ("$linkpath/mysqlclient.lib",@winlibs);
+ @lib_r_opts = @lib_opts;
+ @lib_e_opts = ("$linkpath/mysqlserver.lib",@winlibs);
+}
+else
+{
+ my $linkpath = "-L$pkglibdir ";
+ @lib_opts = ($linkpath,"-lmysqlclient");
+ @lib_r_opts = ($linkpath,"-lmysqlclient_r");
+ @lib_e_opts = ($linkpath,"-lmysqld");
+}
+
+my $flags;
+$flags->{libs} =
+ [@ldflags,@lib_opts,'',' -lpthread -lz -lm -ldl ','',''];
+$flags->{libs_r} =
+ [@ldflags,@lib_r_opts,'','',''];
+$flags->{embedded_libs} =
+ [@ldflags,@lib_e_opts,'','','','',''];
+
+$flags->{include} = ["-I$pkgincludedir"];
+$flags->{cflags} = [@{$flags->{include}},split(" ",'-Wall -DWITH_WSREP -DWSREP_PROC_INFO -DMYSQL_MAX_VARIABLE_VALUE_LEN=2048 -DWITH_INNODB_DISALLOW_WRITES -O2 -g -DNDEBUG -DDBUG_OFF')];
+
+# ----------------------------------------------------------------------
+# Remove some options that a client doesn't have to care about
+# FIXME until we have a --cxxflags, we need to remove -Xa
+# and -xstrconst to make --cflags usable for Sun Forte C++
+# ----------------------------------------------------------------------
+
+my $filter = join("|", @exclude_cflags);
+my @tmp = @{$flags->{cflags}}; # Copy the flag list
+$flags->{cflags} = []; # Clear it
+foreach my $cflag ( @tmp )
+{
+ push(@{$flags->{cflags}}, $cflag) unless $cflag =~ m/^($filter)$/o;
+}
+
+# Same for --libs(_r)
+$filter = join("|", @exclude_libs);
+foreach my $lib_type ( "libs","libs_r","embedded_libs" )
+{
+ my @tmp = @{$flags->{$lib_type}}; # Copy the flag list
+ $flags->{$lib_type} = []; # Clear it
+ foreach my $lib ( @tmp )
+ {
+ push(@{$flags->{$lib_type}}, $lib) unless $lib =~ m/^($filter)$/o;
+ }
+}
+
+my $include = quote_options(@{$flags->{include}});
+my $cflags = quote_options(@{$flags->{cflags}});
+my $libs = quote_options(@{$flags->{libs}});
+my $libs_r = quote_options(@{$flags->{libs_r}});
+my $embedded_libs = quote_options(@{$flags->{embedded_libs}});
+
+##############################################################################
+#
+# Usage information, output if no option is given
+#
+##############################################################################
+
+sub usage
+{
+ print <<EOF;
+Usage: $0 [OPTIONS]
+Options:
+ --cflags [$cflags]
+ --include [$include]
+ --libs [$libs]
+ --libs_r [$libs_r]
+ --socket [$socket]
+ --port [$port]
+ --version [$version]
+ --libmysqld-libs [$embedded_libs]
+EOF
+ exit 0;
+}
+
+@ARGV or usage();
+
+##############################################################################
+#
+# Get options and output the values
+#
+##############################################################################
+
+GetOptions(
+ "cflags" => sub { print "$cflags\n" },
+ "include" => sub { print "$include\n" },
+ "libs" => sub { print "$libs\n" },
+ "libs_r" => sub { print "$libs_r\n" },
+ "socket" => sub { print "$socket\n" },
+ "port" => sub { print "$port\n" },
+ "version" => sub { print "$version\n" },
+ "embedded-libs|embedded|libmysqld-libs" =>
+ sub { print "$embedded_libs\n" },
+ ) or usage();
+
+exit 0
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index e96d12e3f89..e4a23440be6 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 b644184b1e1..de09abc6fc9 100644
--- a/scripts/mysqld_safe.sh
+++ b/scripts/mysqld_safe.sh
@@ -167,7 +167,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)
@@ -203,6 +203,90 @@ 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"
@@ -262,9 +346,16 @@ parse_arguments() {
--skip-syslog) want_syslog=0 ;;
--syslog-tag=*) syslog_tag="$val" ;;
--timezone=*) TZ="$val"; export TZ; ;;
+ --wsrep[-_]urls=*) wsrep_urls="$val"; ;;
--flush-caches) flush_caches=1 ;;
--numa-interleave) numa_interleave=1 ;;
-
+ --wsrep[-_]provider=*)
+ if test -n "$val" && test "$val" != "none"
+ then
+ wsrep_restart=1
+ fi
+ append_arg_to_args "$arg"
+ ;;
--help) usage ;;
*)
@@ -852,7 +943,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"
@@ -863,6 +955,9 @@ max_fast_restarts=5
# flag whether a usable sleep command exists
have_sleep=1
+# maximum number of wsrep restarts
+max_wsrep_restarts=0
+
# close stdout and stderr, everything goes to $logging now
if expr "${-}" : '.*x' > /dev/null
then
@@ -874,11 +969,30 @@ fi
while true
do
- rm -f "$pid_file" # Some extra safety
+ rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety
start_time=`date +%M%S`
- eval_log_error "$cmd"
+ # this sets wsrep_start_position_opt
+ wsrep_recover_position "$cmd"
+
+ [ $? -ne 0 ] && exit 1 #
+
+ [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address
+
+ if [ -z "$url" ]
+ then
+ eval_log_error "$cmd $wsrep_start_position_opt $nohup_redir"
+ else
+ eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir"
+ fi
+
+ if [ $want_syslog -eq 0 -a ! -f "$err_log" ]; then
+ touch "$err_log" # hypothetical: log was renamed but not
+ chown $user "$err_log" # flushed yet. we'd recreate it with
+ chmod "$fmode" "$err_log" # wrong owner next time we log, so set
+ fi # it up correctly while we can!
+
end_time=`date +%M%S`
if test ! -f "$pid_file" # This is removed if normal shutdown
@@ -941,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..0aa338510e0
--- /dev/null
+++ b/scripts/wsrep_sst_common.sh
@@ -0,0 +1,204 @@
+# 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_CONF_SUFFIX=""
+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:-}
+
+while [ $# -gt 0 ]; do
+case "$1" in
+ '--address')
+ readonly WSREP_SST_OPT_ADDR="$2"
+ shift
+ ;;
+ '--bypass')
+ WSREP_SST_OPT_BYPASS=1
+ ;;
+ '--datadir')
+ readonly WSREP_SST_OPT_DATA="$2"
+ shift
+ ;;
+ '--defaults-file')
+ readonly WSREP_SST_OPT_CONF="$2"
+ shift
+ ;;
+ '--defaults-group-suffix')
+ WSREP_SST_OPT_CONF_SUFFIX="$2"
+ shift
+ ;;
+ '--host')
+ readonly WSREP_SST_OPT_HOST="$2"
+ shift
+ ;;
+ '--local-port')
+ readonly WSREP_SST_OPT_LPORT="$2"
+ shift
+ ;;
+ '--parent')
+ readonly WSREP_SST_OPT_PARENT="$2"
+ shift
+ ;;
+ '--password')
+ WSREP_SST_OPT_PSWD="$2"
+ shift
+ ;;
+ '--port')
+ readonly WSREP_SST_OPT_PORT="$2"
+ shift
+ ;;
+ '--role')
+ readonly WSREP_SST_OPT_ROLE="$2"
+ shift
+ ;;
+ '--socket')
+ readonly WSREP_SST_OPT_SOCKET="$2"
+ shift
+ ;;
+ '--user')
+ WSREP_SST_OPT_USER="$2"
+ shift
+ ;;
+ '--gtid')
+ readonly WSREP_SST_OPT_GTID="$2"
+ shift
+ ;;
+ '--binlog')
+ WSREP_SST_OPT_BINLOG="$2"
+ shift
+ ;;
+ *) # must be command
+ # usage
+ # exit 1
+ ;;
+esac
+shift
+done
+readonly WSREP_SST_OPT_BYPASS
+readonly WSREP_SST_OPT_BINLOG
+readonly WSREP_SST_OPT_CONF_SUFFIX
+
+# 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
+
+wsrep_auth_not_set()
+{
+ [ -z "$WSREP_SST_OPT_AUTH" -o "$WSREP_SST_OPT_AUTH" = "(null)" ]
+}
+
+# For Bug:1200727
+if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF sst | grep -q "wsrep_sst_auth"
+then
+ if wsrep_auth_not_set
+ then
+ WSREP_SST_OPT_AUTH=$(MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF 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_info()
+{
+ wsrep_log "[INFO] $*"
+}
+
+wsrep_cleanup_progress_file()
+{
+ [ -n "$SST_PROGRESS_FILE" ] && rm -f "$SST_PROGRESS_FILE" 2>/dev/null
+}
+
+wsrep_check_program()
+{
+ local prog=$1
+
+ if ! which $prog >/dev/null
+ then
+ echo "'$prog' not found in PATH"
+ return 2 # no such file or directory
+ fi
+}
+
+wsrep_check_programs()
+{
+ local ret=0
+
+ while [ $# -gt 0 ]
+ do
+ wsrep_check_program $1 || ret=$?
+ shift
+ done
+
+ return $ret
+}
diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh
new file mode 100644
index 00000000000..988f9232da8
--- /dev/null
+++ b/scripts/wsrep_sst_mysqldump.sh
@@ -0,0 +1,133 @@
+#!/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
+
+EINVAL=22
+
+local_ip()
+{
+ PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
+
+ [ "$1" = "127.0.0.1" ] && return 0
+ [ "$1" = "localhost" ] && return 0
+ [ "$1" = "$(hostname -s)" ] && return 0
+ [ "$1" = "$(hostname -f)" ] && return 0
+ [ "$1" = "$(hostname -d)" ] && return 0
+
+ # Now if ip program is not found in the path, we can't return 0 since
+ # it would block any address. Thankfully grep should fail in this case
+ ip route get "$1" | grep local >/dev/null && return 0
+
+ return 1
+}
+
+if test -z "$WSREP_SST_OPT_HOST"; then wsrep_log_error "HOST cannot be nil"; exit $EINVAL; fi
+if test -z "$WSREP_SST_OPT_PORT"; then wsrep_log_error "PORT cannot be nil"; exit $EINVAL; fi
+if test -z "$WSREP_SST_OPT_LPORT"; then wsrep_log_error "LPORT cannot be nil"; exit $EINVAL; fi
+if test -z "$WSREP_SST_OPT_SOCKET";then wsrep_log_error "SOCKET cannot be nil";exit $EINVAL; fi
+if test -z "$WSREP_SST_OPT_GTID"; then wsrep_log_error "GTID cannot be nil"; exit $EINVAL; fi
+
+if local_ip $WSREP_SST_OPT_HOST && \
+ [ "$WSREP_SST_OPT_PORT" = "$WSREP_SST_OPT_LPORT" ]
+then
+ wsrep_log_error \
+ "destination address '$WSREP_SST_OPT_HOST:$WSREP_SST_OPT_PORT' matches source address."
+ exit $EINVAL
+fi
+
+# Check client version
+CLIENT_MINOR=$($MYSQL_CLIENT --version | cut -d ' ' -f 6 | cut -d '.' -f 2)
+if [ $CLIENT_MINOR -lt "5" ]
+then
+ $MYSQL_CLIENT --version >&2
+ wsrep_log_error "this operation requires MySQL client version 5.5.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;"
+
+# NOTE: we don't use --routines here because we're dumping mysql.proc table
+MYSQLDUMP="$MYSQLDUMP --defaults-extra-file=$WSREP_SST_OPT_CONF \
+$AUTH -S$WSREP_SST_OPT_SOCKET \
+--add-drop-database --add-drop-table --skip-add-locks --create-options \
+--disable-keys --extended-insert --skip-lock-tables --quick --set-charset \
+--skip-comments --flush-privileges --all-databases --events"
+
+# mysqldump cannot restore CSV tables, fix this issue
+CSV_TABLES_FIX="
+set sql_mode='';
+
+USE mysql;
+
+SET @str = IF (@@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, thread_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, command_type VARCHAR(64) NOT NULL,argument MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment=\"General log\"', 'SET @dummy = 0');
+
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;
+
+SET @str = IF (@@have_csv = 'YES', 'CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP NOT NULL, user_host MEDIUMTEXT NOT NULL, query_time TIME NOT NULL, lock_time TIME NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512) NOT NULL, last_insert_id INTEGER NOT NULL, insert_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, sql_text MEDIUMTEXT NOT NULL) engine=CSV CHARACTER SET utf8 comment=\"Slow log\"', 'SET @dummy = 0');
+
+PREPARE stmt FROM @str;
+EXECUTE stmt;
+DROP PREPARE stmt;"
+
+SET_START_POSITION="SET GLOBAL wsrep_start_position='$WSREP_SST_OPT_GTID';"
+
+MYSQL="$MYSQL_CLIENT --defaults-extra-file=$WSREP_SST_OPT_CONF "\
+"$AUTH -h$WSREP_SST_OPT_HOST -P$WSREP_SST_OPT_PORT "\
+"--disable-reconnect --connect_timeout=10"
+
+# need to disable logging when loading the dump
+# reason is that dump contains ALTER TABLE for log tables, and
+# this causes an error if logging is enabled
+GENERAL_LOG_OPT=`$MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@GENERAL_LOG"`
+SLOW_LOG_OPT=`$MYSQL --skip-column-names -e "$STOP_WSREP SELECT @@SLOW_QUERY_LOG"`
+$MYSQL -e "$STOP_WSREP SET GLOBAL GENERAL_LOG=OFF"
+$MYSQL -e "$STOP_WSREP SET GLOBAL SLOW_QUERY_LOG=OFF"
+
+# commands to restore log settings
+RESTORE_GENERAL_LOG="SET GLOBAL GENERAL_LOG=$GENERAL_LOG_OPT;"
+RESTORE_SLOW_QUERY_LOG="SET GLOBAL SLOW_QUERY_LOG=$SLOW_LOG_OPT;"
+
+if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
+then
+ (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
+wsrep_cleanup_progress_file
+#
diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh
new file mode 100644
index 00000000000..7f0901c10fb
--- /dev/null
+++ b/scripts/wsrep_sst_rsync.sh
@@ -0,0 +1,289 @@
+#!/bin/bash -ue
+
+# Copyright (C) 2010-2014 Codership Oy
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
+# MA 02110-1301 USA.
+
+# This is a reference script for rsync-based state snapshot tansfer
+
+RSYNC_PID=
+RSYNC_CONF=
+OS=$(uname)
+[ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH
+
+# Setting the path for lsof on CentOS
+export PATH="/usr/sbin:/sbin:$PATH"
+
+. $(dirname $0)/wsrep_sst_common
+
+wsrep_check_programs rsync
+
+cleanup_joiner()
+{
+ local PID=$(cat "$RSYNC_PID" 2>/dev/null || echo 0)
+ wsrep_log_info "Joiner cleanup. rsync PID: $PID"
+ [ "0" != "$PID" ] && kill $PID && sleep 0.5 && kill -9 $PID >/dev/null 2>&1 \
+ || :
+ rm -rf "$RSYNC_CONF"
+ rm -rf "$MAGIC_FILE"
+ rm -rf "$RSYNC_PID"
+ wsrep_log_info "Joiner cleanup done."
+ if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then
+ wsrep_cleanup_progress_file
+ fi
+}
+
+check_pid()
+{
+ local pid_file=$1
+ [ -r "$pid_file" ] && ps -p $(cat $pid_file) >/dev/null 2>&1
+}
+
+check_pid_and_port()
+{
+ local pid_file=$1
+ local rsync_pid=$2
+ local rsync_port=$3
+
+ 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"
+
+WSREP_LOG_DIR=${WSREP_LOG_DIR:-""}
+
+# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf
+if [ -z "$WSREP_LOG_DIR" ]; then
+ WSREP_LOG_DIR=$($MY_PRINT_DEFAULTS --defaults-file \
+ "$WSREP_SST_OPT_CONF" mysqld server mysqld-5.5 mariadb mariadb-5.5 \
+ | grep -- '--innodb[-_]log[-_]group[-_]home[-_]dir=' \
+ | cut -b 29- )
+fi
+
+if [ -n "$WSREP_LOG_DIR" ]; then
+ # handle both relative and absolute paths
+ WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; mkdir -p "$WSREP_LOG_DIR"; cd $WSREP_LOG_DIR; pwd -P)
+else
+ # default to datadir
+ WSREP_LOG_DIR=$(cd $WSREP_SST_OPT_DATA; pwd -P)
+fi
+
+# Old filter - include everything except selected
+# FILTER=(--exclude '*.err' --exclude '*.pid' --exclude '*.sock' \
+# --exclude '*.conf' --exclude core --exclude 'galera.*' \
+# --exclude grastate.txt --exclude '*.pem' \
+# --exclude '*.[0-9][0-9][0-9][0-9][0-9][0-9]' --exclude '*.index')
+
+# New filter - exclude everything except dirs (schemas) and innodb files
+FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes'
+ -f '+ /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
+
+ # 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"
+
+ ADDR=$WSREP_SST_OPT_ADDR
+ RSYNC_PORT=$(echo $ADDR | awk -F ':' '{ print $2 }')
+ if [ -z "$RSYNC_PORT" ]
+ then
+ RSYNC_PORT=4444
+ ADDR="$(echo $ADDR | awk -F ':' '{ print $1 }'):$RSYNC_PORT"
+ fi
+
+ trap "exit 32" HUP PIPE
+ trap "exit 3" INT TERM ABRT
+ trap cleanup_joiner EXIT
+
+ RSYNC_CONF="$WSREP_SST_OPT_DATA/$MODULE.conf"
+
+cat << EOF > "$RSYNC_CONF"
+pid file = $RSYNC_PID
+use chroot = no
+read only = no
+timeout = 300
+[$MODULE]
+ path = $WSREP_SST_OPT_DATA
+[$MODULE-log_dir]
+ path = $WSREP_LOG_DIR
+EOF
+
+# rm -rf "$DATA"/ib_logfile* # we don't want old logs around
+
+ # listen at all interfaces (for firewalled setups)
+ rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" &
+ RSYNC_REAL_PID=$!
+
+ until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT
+ do
+ sleep 0.2
+ done
+
+ echo "ready $ADDR/$MODULE"
+
+ # wait for SST to complete by monitoring magic file
+ while [ ! -r "$MAGIC_FILE" ] && check_pid "$RSYNC_PID" && \
+ ps -p $MYSQLD_PID >/dev/null
+ do
+ sleep 1
+ done
+
+ if ! ps -p $MYSQLD_PID >/dev/null
+ then
+ wsrep_log_error \
+ "Parent mysqld process (PID:$MYSQLD_PID) terminated unexpectedly."
+ exit 32
+ fi
+
+ if [ -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
+
+exit 0
diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh
new file mode 100644
index 00000000000..327c92fb6cf
--- /dev/null
+++ b/scripts/wsrep_sst_xtrabackup-v2.sh
@@ -0,0 +1,1008 @@
+#!/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=""
+SST_PORT=""
+REMOTEIP=""
+tcert=""
+tpem=""
+tkey=""
+sockopt=""
+progress=""
+ttime=0
+totime=0
+lsn=""
+ecmd=""
+rlimit=""
+# Initially
+stagemsg="${WSREP_SST_OPT_ROLE}"
+cpat=""
+speciald=1
+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=""
+
+# Required for backup locks
+# For backup locks it is 1 sent by joiner
+# 5.6.21 PXC and later can't donate to an older joiner
+sst_ver=1
+
+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 -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then
+ wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
+ fi
+ return
+ fi
+
+ if [[ $sfmt == 'tar' ]];then
+ wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format"
+ encrypt=-1
+ return
+ fi
+
+ wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4"
+
+ if [[ -z $ealgo ]];then
+ wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out"
+ exit 3
+ fi
+
+ if [[ -z $ekey && ! -r $ekeyfile ]];then
+ wsrep_log_error "FATAL: Either key or keyfile must be readable"
+ exit 3
+ fi
+
+ if [[ -z $ekey ]];then
+ ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile"
+ else
+ ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey"
+ fi
+
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ ecmd+=" -d"
+ fi
+
+ stagemsg+="-XB-Encrypted"
+}
+
+get_transfer()
+{
+ if [[ -z $SST_PORT ]];then
+ TSST_PORT=4444
+ else
+ TSST_PORT=$SST_PORT
+ fi
+
+ if [[ $tfmt == 'nc' ]];then
+ if [[ ! -x `which nc` ]];then
+ wsrep_log_error "nc(netcat) not found in path: $PATH"
+ exit 2
+ fi
+ wsrep_log_info "Using netcat as streamer"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ if nc -h 2>&1 | grep -q ncat;then
+ tcmd="nc -l ${TSST_PORT}"
+ else
+ tcmd="nc -dl ${TSST_PORT}"
+ fi
+ else
+ tcmd="nc ${REMOTEIP} ${TSST_PORT}"
+ fi
+ else
+ tfmt='socat'
+ wsrep_log_info "Using socat as streamer"
+ if [[ ! -x `which socat` ]];then
+ wsrep_log_error "socat not found in path: $PATH"
+ exit 2
+ fi
+
+ if [[ $encrypt -eq 2 || $encrypt -eq 3 ]] && ! socat -V | grep -q WITH_OPENSSL;then
+ wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer"
+ encrypt=-1
+ fi
+
+ if [[ $encrypt -eq 2 ]];then
+ wsrep_log_info "Using openssl based encryption with socat: with crt and pem"
+ if [[ -z $tpem || -z $tcert ]];then
+ wsrep_log_error "Both PEM and CRT files required"
+ exit 22
+ fi
+ stagemsg+="-OpenSSL-Encrypted-2"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert"
+ tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio"
+ else
+ wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert"
+ tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}"
+ fi
+ elif [[ $encrypt -eq 3 ]];then
+ wsrep_log_info "Using openssl based encryption with socat: with key and crt"
+ if [[ -z $tpem || -z $tkey ]];then
+ wsrep_log_error "Both certificate and key files required"
+ exit 22
+ fi
+ stagemsg+="-OpenSSL-Encrypted-3"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ wsrep_log_info "Decrypting with certificate $tpem, key $tkey"
+ tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,key=${tkey},verify=0${sockopt} stdio"
+ else
+ wsrep_log_info "Encrypting with certificate $tpem, key $tkey"
+ tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,key=${tkey},verify=0${sockopt}"
+ fi
+
+ else
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ tcmd="socat -u TCP-LISTEN:${TSST_PORT},reuseaddr${sockopt} stdio"
+ else
+ tcmd="socat -u stdio TCP:${REMOTEIP}:${TSST_PORT}${sockopt}"
+ fi
+ fi
+ fi
+
+}
+
+parse_cnf()
+{
+ local group=$1
+ local var=$2
+ reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-)
+ if [[ -z $reval ]];then
+ [[ -n $3 ]] && reval=$3
+ fi
+ echo $reval
+}
+
+get_footprint()
+{
+ pushd $WSREP_SST_OPT_DATA 1>/dev/null
+ payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c | awk 'END { print $1 }')
+ if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then
+ # QuickLZ has around 50% compression ratio
+ # When compression/compaction used, the progress is only an approximate.
+ payload=$(( payload*1/2 ))
+ fi
+ popd 1>/dev/null
+ pcmd+=" -s $payload"
+ adjust_progress
+}
+
+adjust_progress()
+{
+
+ if [[ ! -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")
+ tcert=$(parse_cnf sst tca "")
+ tpem=$(parse_cnf sst tcert "")
+ tkey=$(parse_cnf sst tkey "")
+ encrypt=$(parse_cnf sst encrypt 0)
+ sockopt=$(parse_cnf sst sockopt "")
+ progress=$(parse_cnf sst progress "")
+ rebuild=$(parse_cnf sst rebuild 0)
+ ttime=$(parse_cnf sst time 0)
+ cpat=$(parse_cnf sst cpat '.*galera\.cache$\|.*sst_in_progress$\|.*\.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
+ rlimit=$(parse_cnf sst rlimit "")
+ uextra=$(parse_cnf sst use-extra 0)
+ speciald=$(parse_cnf sst sst-special-dirs 1)
+ iopts=$(parse_cnf sst inno-backup-opts "")
+ iapts=$(parse_cnf sst inno-apply-opts "")
+ impts=$(parse_cnf sst inno-move-opts "")
+ stimeout=$(parse_cnf sst sst-initial-timeout 100)
+ ssyslog=$(parse_cnf sst sst-syslog 0)
+ ssystag=$(parse_cnf mysqld_safe syslog-tag "${SST_SYSLOG_TAG:-}")
+ ssystag+="-"
+
+ if [[ $speciald -eq 0 ]];then
+ wsrep_log_error "sst-special-dirs equal to 0 is not supported, falling back to 1"
+ speciald=1
+ fi
+
+ if [[ $ssyslog -ne -1 ]];then
+ if my_print_defaults -c $WSREP_SST_OPT_CONF mysqld_safe | tr '_' '-' | 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
+}
+
+setup_ports()
+{
+ if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then
+ SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }')
+ REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }')
+ lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }')
+ sst_ver=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $5 }')
+ else
+ SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }')
+ fi
+}
+
+# waits ~10 seconds for nc to open the port and then reports ready
+# (regardless of timeout)
+wait_for_listen()
+{
+ local PORT=$1
+ local ADDR=$2
+ local MODULE=$3
+ for i in {1..50}
+ do
+ ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break
+ sleep 0.2
+ done
+ echo "ready ${ADDR}/${MODULE}//$sst_ver"
+}
+
+check_extra()
+{
+ local use_socket=1
+ if [[ $uextra -eq 1 ]];then
+ if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then
+ local eport=$(my_print_defaults -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2)
+ if [[ -n $eport ]];then
+ # Xtrabackup works only locally.
+ # Hence, setting host to 127.0.0.1 unconditionally.
+ wsrep_log_info "SST through extra_port $eport"
+ INNOEXTRA+=" --host=127.0.0.1 --port=$eport "
+ use_socket=0
+ else
+ wsrep_log_error "Extra port $eport null, failing"
+ exit 1
+ fi
+ else
+ wsrep_log_info "Thread pool not set, ignore the option use_extra"
+ fi
+ fi
+ if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then
+ INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}"
+ fi
+}
+
+recv_joiner()
+{
+ local dir=$1
+ local msg=$2
+ local tmt=$3
+ local 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
+
+}
+
+if [[ ! -x `which $INNOBACKUPEX_BIN` ]];then
+ wsrep_log_error "innobackupex not in path: $PATH"
+ exit 2
+fi
+
+rm -f "${MAGIC_FILE}"
+
+if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then
+ wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}"
+ exit 22
+fi
+
+read_cnf
+setup_ports
+
+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="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-apply "
+ INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $impts --move-back --force-non-empty-directories \${DATA} 2>&1 | logger -p daemon.err -t ${ssystag}innobackupex-move "
+ INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2> >(logger -p daemon.err -t ${ssystag}innobackupex-backup)"
+ fi
+
+else
+ INNOAPPLY="${INNOBACKUPEX_BIN} $disver $iapts --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log"
+ INNOMOVE="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $impts --move-back --force-non-empty-directories \${DATA} &>\${DATA}/innobackup.move.log"
+ INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --defaults-group=mysqld${WSREP_SST_OPT_CONF_SUFFIX} $disver $iopts \$tmpopts \$INNOEXTRA --galera-info --stream=\$sfmt \$itmpdir 2>\${DATA}/innobackup.backup.log"
+fi
+
+get_stream
+get_transfer
+
+if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
+then
+ trap cleanup_donor EXIT
+
+ if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
+ then
+ if [[ -z $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 [ "$WSREP_SST_OPT_USER" != "(null)" ]; then
+ INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
+ fi
+
+ if [ -n "$WSREP_SST_OPT_PSWD" ]; then
+# INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
+ export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
+ else
+ # 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
+
+
+ check_extra
+
+ wsrep_log_info "Streaming GTID file before SST"
+
+ echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}"
+
+ ttcmd="$tcmd"
+
+ if [[ $encrypt -eq 1 ]];then
+ if [[ -n $scomp ]];then
+ tcmd=" $ecmd | $scomp | $tcmd "
+ else
+ tcmd=" $ecmd | $tcmd "
+ fi
+ elif [[ -n $scomp ]];then
+ tcmd=" $scomp | $tcmd "
+ fi
+
+
+ send_donor $DATA "${stagemsg}-gtid"
+
+ tcmd="$ttcmd"
+ if [[ -n $progress ]];then
+ get_footprint
+ tcmd="$pcmd | $tcmd"
+ elif [[ -n $rlimit ]];then
+ adjust_progress
+ tcmd="$pcmd | $tcmd"
+ fi
+
+ wsrep_log_info "Sleeping before data transfer for SST"
+ sleep 10
+
+ wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT:-4444}"
+
+ if [[ -n $scomp ]];then
+ tcmd="$scomp | $tcmd"
+ fi
+
+ set +e
+ timeit "${stagemsg}-SST" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
+ set -e
+
+ if [ ${RC[0]} -ne 0 ]; then
+ wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \
+ "Check ${DATA}/innobackup.backup.log"
+ exit 22
+ elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then
+ wsrep_log_error "$tcmd finished with error: ${RC[1]}"
+ exit 22
+ fi
+
+ # innobackupex implicitly writes PID to fixed location in $xtmpdir
+ XTRABACKUP_PID="$xtmpdir/xtrabackup_pid"
+
+
+ else # BYPASS FOR IST
+
+ wsrep_log_info "Bypassing the SST for IST"
+ echo "continue" # now server can resume updating data
+ echo "${WSREP_SST_OPT_GTID}" > "${MAGIC_FILE}"
+ echo "1" > "${DATA}/${IST_FILE}"
+ get_keys
+ if [[ $encrypt -eq 1 ]];then
+ if [[ -n $scomp ]];then
+ tcmd=" $ecmd | $scomp | $tcmd "
+ else
+ tcmd=" $ecmd | $tcmd "
+ fi
+ elif [[ -n $scomp ]];then
+ tcmd=" $scomp | $tcmd "
+ fi
+ strmcmd+=" \${IST_FILE}"
+
+ send_donor $DATA "${stagemsg}-IST"
+
+ fi
+
+ echo "done ${WSREP_SST_OPT_GTID}"
+ wsrep_log_info "Total time on donor: $totime seconds"
+
+elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ]
+then
+ [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE"
+ [[ -n $SST_PROGRESS_FILE ]] && touch $SST_PROGRESS_FILE
+
+ 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
+
+ ADDR=${WSREP_SST_OPT_ADDR}
+ if [ -z "${SST_PORT}" ]
+ then
+ SST_PORT=4444
+ ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}"
+ fi
+
+ wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} &
+
+ trap sig_joiner_cleanup HUP PIPE INT TERM
+ trap cleanup_joiner EXIT
+
+ if [[ -n $progress ]];then
+ adjust_progress
+ tcmd+=" | $pcmd"
+ fi
+
+ 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 -regex $cpat -prune -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}.*);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..7ba421840ab
--- /dev/null
+++ b/scripts/wsrep_sst_xtrabackup.sh
@@ -0,0 +1,719 @@
+#!/bin/bash -ue
+# Copyright (C) 2013 Percona Inc
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING. If not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston
+# MA 02110-1301 USA.
+
+# Optional dependencies and options documented here: http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html
+# Make sure to read that before proceeding!
+
+
+
+
+. $(dirname $0)/wsrep_sst_common
+
+ealgo=""
+ekey=""
+ekeyfile=""
+encrypt=0
+nproc=1
+ecode=0
+XTRABACKUP_PID=""
+SST_PORT=""
+REMOTEIP=""
+tcert=""
+tpem=""
+sockopt=""
+progress=""
+ttime=0
+totime=0
+lsn=""
+incremental=0
+ecmd=""
+rlimit=""
+
+sfmt="tar"
+strmcmd=""
+tfmt=""
+tcmd=""
+rebuild=0
+rebuildcmd=""
+payload=0
+pvformat="-F '%N => Rate:%r Avg:%a Elapsed:%t %e Bytes: %b %p' "
+pvopts="-f -i 10 -N $WSREP_SST_OPT_ROLE "
+uextra=0
+
+if which pv &>/dev/null && pv --help | grep -q FORMAT;then
+ pvopts+=$pvformat
+fi
+pcmd="pv $pvopts"
+declare -a RC
+
+INNOBACKUPEX_BIN=innobackupex
+DATA="${WSREP_SST_OPT_DATA}"
+INFO_FILE="xtrabackup_galera_info"
+IST_FILE="xtrabackup_ist"
+MAGIC_FILE="${DATA}/${INFO_FILE}"
+
+# Setting the path for ss and ip
+export PATH="/usr/sbin:/sbin:$PATH"
+
+timeit(){
+ local stage=$1
+ shift
+ local cmd="$@"
+ local x1 x2 took extcode
+
+ if [[ $ttime -eq 1 ]];then
+ x1=$(date +%s)
+ wsrep_log_info "Evaluating $cmd"
+ eval "$cmd"
+ extcode=$?
+ x2=$(date +%s)
+ took=$(( x2-x1 ))
+ wsrep_log_info "NOTE: $stage took $took seconds"
+ totime=$(( totime+took ))
+ else
+ wsrep_log_info "Evaluating $cmd"
+ eval "$cmd"
+ extcode=$?
+ fi
+ return $extcode
+}
+
+get_keys()
+{
+ if [[ $encrypt -eq 2 ]];then
+ return
+ fi
+
+ if [[ $encrypt -eq 0 ]];then
+ if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q encrypt;then
+ wsrep_log_error "Unexpected option combination. SST may fail. Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html "
+ fi
+ return
+ fi
+
+ if [[ $sfmt == 'tar' ]];then
+ wsrep_log_info "NOTE: Xtrabackup-based encryption - encrypt=1 - cannot be enabled with tar format"
+ encrypt=0
+ return
+ fi
+
+ wsrep_log_info "Xtrabackup based encryption enabled in my.cnf - Supported only from Xtrabackup 2.1.4"
+
+ if [[ -z $ealgo ]];then
+ wsrep_log_error "FATAL: Encryption algorithm empty from my.cnf, bailing out"
+ exit 3
+ fi
+
+ if [[ -z $ekey && ! -r $ekeyfile ]];then
+ wsrep_log_error "FATAL: Either key or keyfile must be readable"
+ exit 3
+ fi
+
+ if [[ -z $ekey ]];then
+ ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key-file=$ekeyfile"
+ else
+ ecmd="xbcrypt --encrypt-algo=$ealgo --encrypt-key=$ekey"
+ fi
+
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ ecmd+=" -d"
+ fi
+}
+
+get_transfer()
+{
+ if [[ -z $SST_PORT ]];then
+ TSST_PORT=4444
+ else
+ TSST_PORT=$SST_PORT
+ fi
+
+ if [[ $tfmt == 'nc' ]];then
+ if [[ ! -x `which nc` ]];then
+ wsrep_log_error "nc(netcat) not found in path: $PATH"
+ exit 2
+ fi
+ wsrep_log_info "Using netcat as streamer"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ if nc -h 2>&1 | grep -q ncat;then
+ tcmd="nc -l ${TSST_PORT}"
+ else
+ tcmd="nc -dl ${TSST_PORT}"
+ fi
+ else
+ tcmd="nc ${REMOTEIP} ${TSST_PORT}"
+ fi
+ else
+ tfmt='socat'
+ wsrep_log_info "Using socat as streamer"
+ if [[ ! -x `which socat` ]];then
+ wsrep_log_error "socat not found in path: $PATH"
+ exit 2
+ fi
+
+ if [[ $encrypt -eq 2 ]] && ! socat -V | grep -q OPENSSL;then
+ wsrep_log_info "NOTE: socat is not openssl enabled, falling back to plain transfer"
+ encrypt=0
+ fi
+
+ if [[ $encrypt -eq 2 ]];then
+ wsrep_log_info "Using openssl based encryption with socat"
+ if [[ -z $tpem || -z $tcert ]];then
+ wsrep_log_error "Both PEM and CRT files required"
+ exit 22
+ fi
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ wsrep_log_info "Decrypting with PEM $tpem, CA: $tcert"
+ tcmd="socat -u openssl-listen:${TSST_PORT},reuseaddr,cert=$tpem,cafile=${tcert}${sockopt} stdio"
+ else
+ wsrep_log_info "Encrypting with PEM $tpem, CA: $tcert"
+ tcmd="socat -u stdio openssl-connect:${REMOTEIP}:${TSST_PORT},cert=$tpem,cafile=${tcert}${sockopt}"
+ fi
+ else
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ tcmd="socat -u TCP-LISTEN:${TSST_PORT},reuseaddr${sockopt} stdio"
+ else
+ tcmd="socat -u stdio TCP:${REMOTEIP}:${TSST_PORT}${sockopt}"
+ fi
+ fi
+ fi
+
+}
+
+parse_cnf()
+{
+ local group=$1
+ local var=$2
+ reval=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2-)
+ if [[ -z $reval ]];then
+ [[ -n $3 ]] && reval=$3
+ fi
+ echo $reval
+}
+
+get_footprint()
+{
+ pushd $WSREP_SST_OPT_DATA 1>/dev/null
+ payload=$(find . -regex '.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' -type f -print0 | du --files0-from=- --block-size=1 -c | awk 'END { print $1 }')
+ if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF xtrabackup | grep -q -- "--compress";then
+ # QuickLZ has around 50% compression ratio
+ # When compression/compaction used, the progress is only an approximate.
+ payload=$(( payload*1/2 ))
+ fi
+ popd 1>/dev/null
+ pcmd+=" -s $payload"
+ adjust_progress
+}
+
+adjust_progress()
+{
+ if [[ -n $progress && $progress != '1' ]];then
+ if [[ -e $progress ]];then
+ pcmd+=" 2>>$progress"
+ else
+ pcmd+=" 2>$progress"
+ fi
+ elif [[ -z $progress && -n $rlimit ]];then
+ # When rlimit is non-zero
+ pcmd="pv -q"
+ fi
+
+ if [[ -n $rlimit && "$WSREP_SST_OPT_ROLE" == "donor" ]];then
+ wsrep_log_info "Rate-limiting SST to $rlimit"
+ pcmd+=" -L \$rlimit"
+ fi
+}
+
+read_cnf()
+{
+ sfmt=$(parse_cnf sst streamfmt "tar")
+ tfmt=$(parse_cnf sst transferfmt "socat")
+ tcert=$(parse_cnf sst tca "")
+ tpem=$(parse_cnf sst tcert "")
+ encrypt=$(parse_cnf sst encrypt 0)
+ sockopt=$(parse_cnf sst sockopt "")
+ progress=$(parse_cnf sst progress "")
+ rebuild=$(parse_cnf sst rebuild 0)
+ ttime=$(parse_cnf sst time 0)
+ incremental=$(parse_cnf sst incremental 0)
+ ealgo=$(parse_cnf xtrabackup encrypt "")
+ ekey=$(parse_cnf xtrabackup encrypt-key "")
+ ekeyfile=$(parse_cnf xtrabackup encrypt-key-file "")
+
+ # Refer to http://www.percona.com/doc/percona-xtradb-cluster/manual/xtrabackup_sst.html
+ if [[ -z $ealgo ]];then
+ ealgo=$(parse_cnf sst encrypt-algo "")
+ ekey=$(parse_cnf sst encrypt-key "")
+ ekeyfile=$(parse_cnf sst encrypt-key-file "")
+ fi
+ rlimit=$(parse_cnf sst rlimit "")
+ uextra=$(parse_cnf sst use_extra 0)
+}
+
+get_stream()
+{
+ if [[ $sfmt == 'xbstream' ]];then
+ wsrep_log_info "Streaming with xbstream"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ strmcmd="xbstream -x"
+ else
+ strmcmd="xbstream -c \${INFO_FILE} \${IST_FILE}"
+ fi
+ else
+ sfmt="tar"
+ wsrep_log_info "Streaming with tar"
+ if [[ "$WSREP_SST_OPT_ROLE" == "joiner" ]];then
+ strmcmd="tar xfi - --recursive-unlink -h"
+ else
+ strmcmd="tar cf - \${INFO_FILE} \${IST_FILE}"
+ fi
+
+ fi
+}
+
+get_proc()
+{
+ set +e
+ nproc=$(grep -c processor /proc/cpuinfo)
+ [[ -z $nproc || $nproc -eq 0 ]] && nproc=1
+ set -e
+}
+
+sig_joiner_cleanup()
+{
+ wsrep_log_error "Removing $MAGIC_FILE file due to signal"
+ rm -f "$MAGIC_FILE"
+}
+
+cleanup_joiner()
+{
+ # Since this is invoked just after exit NNN
+ local estatus=$?
+ if [[ $estatus -ne 0 ]];then
+ wsrep_log_error "Cleanup after exit with status:$estatus"
+ fi
+ if [ "${WSREP_SST_OPT_ROLE}" = "joiner" ];then
+ wsrep_log_info "Removing the sst_in_progress file"
+ wsrep_cleanup_progress_file
+ fi
+ if [[ -n $progress && -p $progress ]];then
+ wsrep_log_info "Cleaning up fifo file $progress"
+ rm $progress
+ fi
+}
+
+check_pid()
+{
+ local pid_file="$1"
+ [ -r "$pid_file" ] && ps -p $(cat "$pid_file") >/dev/null 2>&1
+}
+
+cleanup_donor()
+{
+ # Since this is invoked just after exit NNN
+ local estatus=$?
+ if [[ $estatus -ne 0 ]];then
+ wsrep_log_error "Cleanup after exit with status:$estatus"
+ fi
+
+ if [[ -n $XTRABACKUP_PID ]];then
+ if check_pid $XTRABACKUP_PID
+ then
+ wsrep_log_error "xtrabackup process is still running. Killing... "
+ kill_xtrabackup
+ fi
+
+ rm -f $XTRABACKUP_PID
+ fi
+ rm -f ${DATA}/${IST_FILE}
+
+ if [[ -n $progress && -p $progress ]];then
+ wsrep_log_info "Cleaning up fifo file $progress"
+ rm $progress
+ fi
+}
+
+kill_xtrabackup()
+{
+ local PID=$(cat $XTRABACKUP_PID)
+ [ -n "$PID" -a "0" != "$PID" ] && kill $PID && (kill $PID && kill -9 $PID) || :
+ rm -f "$XTRABACKUP_PID"
+}
+
+setup_ports()
+{
+ if [[ "$WSREP_SST_OPT_ROLE" == "donor" ]];then
+ SST_PORT=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $2 }')
+ REMOTEIP=$(echo $WSREP_SST_OPT_ADDR | awk -F ':' '{ print $1 }')
+ lsn=$(echo $WSREP_SST_OPT_ADDR | awk -F '[:/]' '{ print $4 }')
+ else
+ SST_PORT=$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $2 }')
+ fi
+}
+
+# waits ~10 seconds for nc to open the port and then reports ready
+# (regardless of timeout)
+wait_for_listen()
+{
+ local PORT=$1
+ local ADDR=$2
+ local MODULE=$3
+ for i in {1..50}
+ do
+ ss -p state listening "( sport = :$PORT )" | grep -qE 'socat|nc' && break
+ sleep 0.2
+ done
+ if [[ $incremental -eq 1 ]];then
+ echo "ready ${ADDR}/${MODULE}/$lsn"
+ else
+ echo "ready ${ADDR}/${MODULE}"
+ fi
+}
+
+check_extra()
+{
+ local use_socket=1
+ if [[ $uextra -eq 1 ]];then
+ if $MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--thread-handling=" | grep -q 'pool-of-threads';then
+ local eport=$($MY_PRINT_DEFAULTS -c $WSREP_SST_OPT_CONF mysqld | tr '_' '-' | grep -- "--extra-port=" | cut -d= -f2)
+ if [[ -n $eport ]];then
+ # Xtrabackup works only locally.
+ # Hence, setting host to 127.0.0.1 unconditionally.
+ wsrep_log_info "SST through extra_port $eport"
+ INNOEXTRA+=" --host=127.0.0.1 --port=$eport "
+ use_socket=0
+ else
+ wsrep_log_error "Extra port $eport null, failing"
+ exit 1
+ fi
+ else
+ wsrep_log_info "Thread pool not set, ignore the option use_extra"
+ fi
+ fi
+ if [[ $use_socket -eq 1 ]] && [[ -n "${WSREP_SST_OPT_SOCKET}" ]];then
+ INNOEXTRA+=" --socket=${WSREP_SST_OPT_SOCKET}"
+ fi
+}
+
+if [[ ! -x `which innobackupex` ]];then
+ wsrep_log_error "innobackupex not in path: $PATH"
+ exit 2
+fi
+
+rm -f "${MAGIC_FILE}"
+
+if [[ ! ${WSREP_SST_OPT_ROLE} == 'joiner' && ! ${WSREP_SST_OPT_ROLE} == 'donor' ]];then
+ wsrep_log_error "Invalid role ${WSREP_SST_OPT_ROLE}"
+ exit 22
+fi
+
+read_cnf
+setup_ports
+get_stream
+get_transfer
+
+INNOEXTRA=""
+INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} --apply-log \$rebuildcmd \${DATA} &>\${DATA}/innobackup.prepare.log"
+INNOBACKUP="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \$INNOEXTRA --galera-info --stream=\$sfmt \${TMPDIR} 2>\${DATA}/innobackup.backup.log"
+
+if [ "$WSREP_SST_OPT_ROLE" = "donor" ]
+then
+ trap cleanup_donor EXIT
+
+ if [ $WSREP_SST_OPT_BYPASS -eq 0 ]
+ then
+ TMPDIR="${TMPDIR:-/tmp}"
+
+ if [ "$WSREP_SST_OPT_USER" != "(null)" ]; then
+ INNOEXTRA+=" --user=$WSREP_SST_OPT_USER"
+ fi
+
+ if [ -n "$WSREP_SST_OPT_PSWD" ]; then
+# INNOEXTRA+=" --password=$WSREP_SST_OPT_PSWD"
+ export MYSQL_PWD="$WSREP_SST_OPT_PSWD"
+ else
+ # Empty password, used for testing, debugging etc.
+ INNOEXTRA+=" --password="
+ fi
+
+ get_keys
+ if [[ $encrypt -eq 1 ]];then
+ if [[ -n $ekey ]];then
+ INNOEXTRA+=" --encrypt=$ealgo --encrypt-key=$ekey "
+ else
+ INNOEXTRA+=" --encrypt=$ealgo --encrypt-key-file=$ekeyfile "
+ fi
+ fi
+
+ if [[ -n $lsn ]];then
+ INNOEXTRA+=" --incremental --incremental-lsn=$lsn "
+ fi
+
+ check_extra
+
+ wsrep_log_info "Streaming the backup to joiner at ${REMOTEIP} ${SST_PORT}"
+
+ if [[ -n $progress ]];then
+ get_footprint
+ tcmd="$pcmd | $tcmd"
+ elif [[ -n $rlimit ]];then
+ adjust_progress
+ tcmd="$pcmd | $tcmd"
+ fi
+
+ set +e
+ timeit "Donor-Transfer" "$INNOBACKUP | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
+ set -e
+
+ if [ ${RC[0]} -ne 0 ]; then
+ wsrep_log_error "${INNOBACKUPEX_BIN} finished with error: ${RC[0]}. " \
+ "Check ${DATA}/innobackup.backup.log"
+ exit 22
+ elif [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then
+ wsrep_log_error "$tcmd finished with error: ${RC[1]}"
+ exit 22
+ fi
+
+ # innobackupex implicitly writes PID to fixed location in ${TMPDIR}
+ XTRABACKUP_PID="${TMPDIR}/xtrabackup_pid"
+
+
+ else # BYPASS FOR IST
+
+ wsrep_log_info "Bypassing the SST for IST"
+ STATE="${WSREP_SST_OPT_GTID}"
+ echo "continue" # now server can resume updating data
+ echo "${STATE}" > "${MAGIC_FILE}"
+ echo "1" > "${DATA}/${IST_FILE}"
+ get_keys
+ pushd ${DATA} 1>/dev/null
+ set +e
+ if [[ $encrypt -eq 1 ]];then
+ tcmd=" $ecmd | $tcmd"
+ fi
+ timeit "Donor-IST-Unencrypted-transfer" "$strmcmd | $tcmd; RC=( "\${PIPESTATUS[@]}" )"
+ set -e
+ popd 1>/dev/null
+
+ for ecode in "${RC[@]}";do
+ if [[ $ecode -ne 0 ]];then
+ wsrep_log_error "Error while streaming data to joiner node: " \
+ "exit codes: ${RC[@]}"
+ exit 1
+ fi
+ done
+ fi
+
+ echo "done ${WSREP_SST_OPT_GTID}"
+ wsrep_log_info "Total time on donor: $totime seconds"
+
+elif [ "${WSREP_SST_OPT_ROLE}" = "joiner" ]
+then
+ [[ -e $SST_PROGRESS_FILE ]] && wsrep_log_info "Stale sst_in_progress file: $SST_PROGRESS_FILE"
+ touch $SST_PROGRESS_FILE
+
+ if [[ ! -e ${DATA}/ibdata1 ]];then
+ incremental=0
+ fi
+
+ if [[ $incremental -eq 1 ]];then
+ wsrep_log_info "Incremental SST enabled"
+ #lsn=$(/pxc/bin/mysqld --defaults-file=$WSREP_SST_OPT_CONF --basedir=/pxc --wsrep-recover 2>&1 | grep -o 'log sequence number .*' | cut -d " " -f 4 | head -1)
+ lsn=$(grep to_lsn xtrabackup_checkpoints | cut -d= -f2 | tr -d ' ')
+ wsrep_log_info "Recovered LSN: $lsn"
+ fi
+
+ sencrypted=1
+ nthreads=1
+
+ MODULE="xtrabackup_sst"
+
+ # May need xtrabackup_checkpoints later on
+ rm -f ${DATA}/xtrabackup_binary ${DATA}/xtrabackup_galera_info ${DATA}/xtrabackup_logfile
+
+ ADDR=${WSREP_SST_OPT_ADDR}
+ if [ -z "${SST_PORT}" ]
+ then
+ SST_PORT=4444
+ ADDR="$(echo ${WSREP_SST_OPT_ADDR} | awk -F ':' '{ print $1 }'):${SST_PORT}"
+ fi
+
+ wait_for_listen ${SST_PORT} ${ADDR} ${MODULE} &
+
+ trap sig_joiner_cleanup HUP PIPE INT TERM
+ trap cleanup_joiner EXIT
+
+ if [[ -n $progress ]];then
+ adjust_progress
+ tcmd+=" | $pcmd"
+ fi
+
+ if [[ $incremental -eq 1 ]];then
+ BDATA=$DATA
+ DATA=$(mktemp -d)
+ MAGIC_FILE="${DATA}/${INFO_FILE}"
+ fi
+
+ get_keys
+ set +e
+ if [[ $encrypt -eq 1 && $sencrypted -eq 1 ]];then
+ strmcmd=" $ecmd | $strmcmd"
+ fi
+
+ pushd ${DATA} 1>/dev/null
+ timeit "Joiner-Recv-Unencrypted" "$tcmd | $strmcmd; RC=( "\${PIPESTATUS[@]}" )"
+ popd 1>/dev/null
+
+ set -e
+
+ if [[ $sfmt == 'xbstream' ]];then
+ # Special handling till lp:1193240 is fixed"
+ if [[ ${RC[$(( ${#RC[@]}-1 ))]} -eq 1 ]];then
+ wsrep_log_error "Xbstream failed"
+ wsrep_log_error "Data directory ${DATA} may not be empty: lp:1193240" \
+ "Manual intervention required in that case"
+ exit 32
+ fi
+ fi
+
+ wait %% # join for wait_for_listen thread
+
+ for ecode in "${RC[@]}";do
+ if [[ $ecode -ne 0 ]];then
+ wsrep_log_error "Error while getting data from donor node: " \
+ "exit codes: ${RC[@]}"
+ exit 32
+ fi
+ done
+
+ if [ ! -r "${MAGIC_FILE}" ]
+ then
+ # this message should cause joiner to abort
+ wsrep_log_error "xtrabackup process ended without creating '${MAGIC_FILE}'"
+ wsrep_log_info "Contents of datadir"
+ wsrep_log_info "$(ls -l ${DATA}/**/*)"
+ exit 32
+ fi
+
+ if ! ps -p ${WSREP_SST_OPT_PARENT} &>/dev/null
+ then
+ wsrep_log_error "Parent mysqld process (PID:${WSREP_SST_OPT_PARENT}) terminated unexpectedly."
+ exit 32
+ fi
+
+ if [ ! -r "${DATA}/${IST_FILE}" ]
+ then
+ wsrep_log_info "Proceeding with SST"
+ wsrep_log_info "Removing existing ib_logfile files"
+ if [[ $incremental -ne 1 ]];then
+ rm -f ${DATA}/ib_logfile*
+ else
+ rm -f ${BDATA}/ib_logfile*
+ fi
+
+ get_proc
+
+ # Rebuild indexes for compact backups
+ if grep -q 'compact = 1' ${DATA}/xtrabackup_checkpoints;then
+ wsrep_log_info "Index compaction detected"
+ rebuild=1
+ fi
+
+ if [[ $rebuild -eq 1 ]];then
+ nthreads=$(parse_cnf xtrabackup rebuild-threads $nproc)
+ wsrep_log_info "Rebuilding during prepare with $nthreads threads"
+ rebuildcmd="--rebuild-indexes --rebuild-threads=$nthreads"
+ fi
+
+ if test -n "$(find ${DATA} -maxdepth 1 -type f -name '*.qp' -print -quit)";then
+
+ wsrep_log_info "Compressed qpress files found"
+
+ if [[ ! -x `which qpress` ]];then
+ wsrep_log_error "qpress not found in path: $PATH"
+ exit 22
+ fi
+
+ if [[ -n $progress ]] && pv --help | grep -q 'line-mode';then
+ count=$(find ${DATA} -type f -name '*.qp' | wc -l)
+ count=$(( count*2 ))
+ if pv --help | grep -q FORMAT;then
+ pvopts="-f -s $count -l -N Decompression -F '%N => Rate:%r Elapsed:%t %e Progress: [%b/$count]'"
+ else
+ pvopts="-f -s $count -l -N Decompression"
+ fi
+ pcmd="pv $pvopts"
+ adjust_progress
+ dcmd="$pcmd | xargs -n 2 qpress -T${nproc}d"
+ else
+ dcmd="xargs -n 2 qpress -T${nproc}d"
+ fi
+
+ wsrep_log_info "Removing existing ibdata1 file"
+ rm -f ${DATA}/ibdata1
+
+ # Decompress the qpress files
+ wsrep_log_info "Decompression with $nproc threads"
+ timeit "Decompression" "find ${DATA} -type f -name '*.qp' -printf '%p\n%h\n' | $dcmd"
+ extcode=$?
+
+ if [[ $extcode -eq 0 ]];then
+ wsrep_log_info "Removing qpress files after decompression"
+ find ${DATA} -type f -name '*.qp' -delete
+ if [[ $? -ne 0 ]];then
+ wsrep_log_error "Something went wrong with deletion of qpress files. Investigate"
+ fi
+ else
+ wsrep_log_error "Decompression failed. Exit code: $extcode"
+ exit 22
+ fi
+ fi
+
+ if [[ $incremental -eq 1 ]];then
+ # Added --ibbackup=xtrabackup_55 because it fails otherwise citing connection issues.
+ INNOAPPLY="${INNOBACKUPEX_BIN} --defaults-file=${WSREP_SST_OPT_CONF} \
+ --ibbackup=xtrabackup_55 --apply-log $rebuildcmd --redo-only $BDATA --incremental-dir=${DATA} &>>${BDATA}/innobackup.prepare.log"
+ fi
+
+ wsrep_log_info "Preparing the backup at ${DATA}"
+ timeit "Xtrabackup prepare stage" "$INNOAPPLY"
+
+ if [[ $incremental -eq 1 ]];then
+ wsrep_log_info "Cleaning up ${DATA} after incremental SST"
+ [[ -d ${DATA} ]] && rm -rf ${DATA}
+ DATA=$BDATA
+ fi
+
+ if [ $? -ne 0 ];
+ then
+ wsrep_log_error "${INNOBACKUPEX_BIN} finished with errors. Check ${DATA}/innobackup.prepare.log"
+ exit 22
+ fi
+ else
+ wsrep_log_info "${IST_FILE} received from donor: Running IST"
+ fi
+
+ if [[ ! -r ${MAGIC_FILE} ]];then
+ wsrep_log_error "SST magic file ${MAGIC_FILE} not found/readable"
+ exit 2
+ fi
+
+ cat "${MAGIC_FILE}" # output UUID:seqno
+ wsrep_log_info "Total time on joiner: $totime seconds"
+fi
+
+exit 0
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 7172294e4f6..7fcdf601d81 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 @@ ${CMAKE_SOURCE_DIR}/regex
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}/sql
+${WSREP_INCLUDES}
)
SET(GEN_SOURCES
@@ -36,6 +41,21 @@ ADD_DEFINITIONS(-DMYSQL_SERVER -DHAVE_EVENT_SCHEDULER)
IF(SSL_DEFINES)
ADD_DEFINITIONS(${SSL_DEFINES})
ENDIF()
+IF(WITH_WSREP)
+ SET(WSREP_SOURCES
+ wsrep_check_opts.cc
+ wsrep_hton.cc
+ wsrep_mysqld.cc
+ wsrep_notify.cc
+ wsrep_sst.cc
+ wsrep_utils.cc
+ wsrep_var.cc
+ wsrep_binlog.cc
+ wsrep_applier.cc
+ wsrep_thd.cc
+ )
+ SET(WSREP_LIB wsrep)
+ENDIF()
SET (SQL_SOURCE
../sql-common/client.c derror.cc des_key_file.cc
@@ -87,6 +107,7 @@ SET (SQL_SOURCE
threadpool_common.cc
../sql-common/mysql_async.c
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
+ ${WSREP_SOURCES}
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
@@ -112,6 +133,7 @@ DTRACE_INSTRUMENT(sql)
TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
mysys dbug strings vio regex ${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 dfd35583581..656881b9977 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -1467,8 +1467,25 @@ end:
saved_master_access= thd->security_ctx->master_access;
thd->security_ctx->master_access |= SUPER_ACL;
+#ifdef WITH_WSREP
+ if (WSREP(thd)) {
+ // sql_print_information("sizeof(LEX) = %d", sizeof(struct LEX));
+ // sizeof(LEX) = 4512, so it's relatively safe to allocate it on stack.
+ LEX lex;
+ lex.sql_command = SQLCOM_DROP_EVENT;
+ LEX* saved = thd->lex;
+ thd->lex = &lex;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ thd->lex = saved;
+ }
+#endif
+
ret= Events::drop_event(thd, dbname, name, FALSE);
+#ifdef WITH_WSREP
+ WSREP_TO_ISOLATION_END;
+ error:
+#endif
thd->security_ctx->master_access= saved_master_access;
}
}
diff --git a/sql/events.cc b/sql/events.cc
index 763c75e77b0..9e15a5f47bd 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -1104,6 +1104,20 @@ Events::load_events_from_db(THD *thd)
delete et;
goto end;
}
+#ifdef WITH_WSREP
+ // when SST from master node who initials event, the event status is ENABLED
+ // this is problematic because there are two nodes with same events and both enabled.
+ if (et->originator != thd->server_id)
+ {
+ store_record(table, record[1]);
+ table->field[ET_FIELD_STATUS]->
+ store((longlong) Event_parse_data::SLAVESIDE_DISABLED,
+ TRUE);
+ (void) table->file->ha_update_row(table->record[1], table->record[0]);
+ delete et;
+ continue;
+ }
+#endif
drop_on_completion= (et->on_completion ==
Event_parse_data::ON_COMPLETION_DROP);
@@ -1146,7 +1160,46 @@ end:
close_mysql_tables(thd);
DBUG_RETURN(ret);
}
+#ifdef WITH_WSREP
+int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len)
+{
+ String log_query;
+
+ if (create_query_string(thd, &log_query))
+ {
+ WSREP_WARN("events create string failed: %s", thd->query());
+ return 1;
+ }
+ return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
+}
+static int
+wsrep_alter_query_string(THD *thd, String *buf)
+{
+ /* Append the "ALTER" part of the query */
+ if (buf->append(STRING_WITH_LEN("ALTER ")))
+ return 1;
+ /* Append definer */
+ append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
+ /* Append the left part of thd->query after event name part */
+ if (buf->append(thd->lex->stmt_definition_begin,
+ thd->lex->stmt_definition_end -
+ thd->lex->stmt_definition_begin))
+ return 1;
+
+ return 0;
+}
+int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len)
+{
+ String log_query;
+ if (wsrep_alter_query_string(thd, &log_query))
+ {
+ WSREP_WARN("events alter string failed: %s", thd->query());
+ return 1;
+ }
+ return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
+}
+#endif /* WITH_WSREP */
/**
@} (End of group Event_Scheduler)
*/
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index e048dbad5e6..99e61520ddb 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -309,7 +309,13 @@ const char *ha_partition::table_type() const
// we can do this since we only support a single engine type
return m_file && m_file[0] ? m_file[0]->table_type() : "Unknown";
}
-
+#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 e8e3858d076..c044f9daa9c 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1191,6 +1191,14 @@ public:
return h;
}
+#ifdef WITH_WSREP
+ void wsrep_reset_files()
+ {
+ for (uint i=0; i < m_tot_parts; i++)
+ m_file[i]->ft_handler= 0;
+ }
+ 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 dc40e34bc3d..5917ba505a3 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -54,6 +54,9 @@
#include "../storage/maria/ha_maria.h"
#endif
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
@@ -1255,7 +1258,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);
@@ -1301,8 +1309,38 @@ 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)
+ {
+#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);
+ error= 1;
+#ifdef WITH_WSREP
+ } /* End of else */
+#endif
+ }
if (err)
goto err;
@@ -1313,6 +1351,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);
@@ -1399,6 +1444,18 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
int error= 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("commit_one_phase_2");
+#ifdef WITH_WSREP
+#ifdef WSREP_PROC_INFO
+ char info[64]= { 0, };
+ snprintf (info, sizeof(info) - 1, "ha_commit_one_phase(%lld)",
+ (long long)wsrep_thd_trx_seqno(thd));
+#else
+ const char info[]="ha_commit_one_phase()";
+#endif /* WSREP_PROC_INFO */
+ char* tmp_info= NULL;
+ if (WSREP(thd)) tmp_info= (char *)thd_proc_info(thd, info);
+#endif /* WITH_WSREP */
+
if (ha_info)
{
for (; ha_info; ha_info= ha_info_next)
@@ -1427,7 +1484,10 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
}
/* Free resources and perform other cleanup even for 'empty' transactions. */
if (is_real_trans)
- thd->transaction.cleanup();
+ thd->transaction.cleanup();
+#ifdef WITH_WSREP
+ if (WSREP(thd)) thd_proc_info(thd, tmp_info);
+#endif /* WITH_WSREP */
DBUG_RETURN(error);
}
@@ -1508,7 +1568,7 @@ int ha_rollback_trans(THD *thd, bool all)
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
- thd->transaction.cleanup();
+ thd->transaction.cleanup();
if (all)
thd->transaction_rollback_request= FALSE;
@@ -1673,7 +1733,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
@@ -2696,7 +2762,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);
@@ -4953,7 +5024,11 @@ 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
+ ((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()));
+#else
mysql_bin_log.is_open());
+#endif
}
@@ -5055,6 +5130,17 @@ 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)))
+ // !strcmp(table->file->table_type(), "InnoDB"))
+ {
+ return 0;
+ }
+#endif /* WITH_WSREP */
if (check_table_binlog_row_based(thd, table))
{
MY_BITMAP cols;
@@ -5295,6 +5381,64 @@ 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) &&
+ !(wsrep_OSU_method_options == WSREP_OSU_RSU &&
+ bf_thd->wsrep_exec_mode == TOTAL_ORDER)) {
+ DBUG_RETURN(0);
+ }
+
+ handlerton *hton= installed_htons[DB_TYPE_INNODB];
+ if (hton && hton->wsrep_abort_transaction)
+ {
+ hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal);
+ }
+ else
+ {
+ WSREP_WARN("cannot abort InnoDB transaction");
+ }
+
+ DBUG_RETURN(0);
+}
+
+void ha_wsrep_fake_trx_id(THD *thd)
+{
+ DBUG_ENTER("ha_wsrep_fake_trx_id");
+ if (!WSREP(thd))
+ {
+ DBUG_VOID_RETURN;
+ }
+
+ handlerton *hton= installed_htons[DB_TYPE_INNODB];
+ if (hton && hton->wsrep_fake_trx_id)
+ {
+ hton->wsrep_fake_trx_id(hton, thd);
+ }
+ else
+ {
+ WSREP_WARN("cannot get 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 3d6c8dea2bf..1f0241bef86 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -358,6 +358,7 @@ enum legacy_db_type
DB_TYPE_MARIA,
/** Performance schema engine. */
DB_TYPE_PERFORMANCE_SCHEMA,
+ DB_TYPE_WSREP,
DB_TYPE_ARIA=42,
DB_TYPE_TOKUDB=43,
DB_TYPE_FIRST_DYNAMIC=44,
@@ -1052,6 +1053,11 @@ struct handlerton
const char *wild, bool dir, List<LEX_STRING> *files);
int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db,
const char *name);
+ int (*wsrep_abort_transaction)(handlerton *hton, THD *bf_thd,
+ THD *victim_thd, my_bool signal);
+ int (*wsrep_set_checkpoint)(handlerton *hton, const XID* xid);
+ int (*wsrep_get_checkpoint)(handlerton *hton, XID* xid);
+ void (*wsrep_fake_trx_id)(handlerton *hton, THD *thd);
uint32 license; /* Flag for Engine License */
/*
@@ -2975,6 +2981,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;
@@ -3071,6 +3080,10 @@ int ha_enable_transaction(THD *thd, bool on);
int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv);
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);
@@ -3101,6 +3114,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 cfccd66ea8a..b822509e534 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2760,7 +2760,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/lock.cc b/sql/lock.cc
index 31ef1314f5a..7747414ee48 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -84,6 +84,10 @@
#include <hash.h>
#include <assert.h>
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
+
/**
@defgroup Locking Locking
@{
@@ -314,6 +318,9 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
/* Copy the lock data array. thr_multi_lock() reorders its contents. */
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
sql_lock->lock_count * sizeof(*sql_lock->locks));
+#ifdef WITH_WSREP
+ thd->lock_info.in_lock_tables= thd->in_lock_tables;
+#endif /* Lock on the copied half of the lock data array. */
/* Lock on the copied half of the lock data array. */
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
sql_lock->lock_count,
@@ -336,6 +343,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);
}
@@ -1054,11 +1064,15 @@ void Global_read_lock::unlock_global_read_lock(THD *thd)
{
thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
m_mdl_blocks_commits_lock= NULL;
+#ifdef WITH_WSREP
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ wsrep->resume(wsrep);
+#endif /* WITH_WSREP */
}
thd->mdl_context.release_lock(m_mdl_global_shared_lock);
m_mdl_global_shared_lock= NULL;
m_state= GRL_NONE;
-
+
DBUG_VOID_RETURN;
}
@@ -1086,6 +1100,20 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
If we didn't succeed lock_global_read_lock(), or if we already suceeded
make_global_read_lock_block_commit(), do nothing.
*/
+
+#ifdef WITH_WSREP
+ if (m_mdl_blocks_commits_lock)
+ {
+ WSREP_DEBUG("GRL was in block commit mode when entering "
+ "make_global_read_lock_block_commit");
+ thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
+ m_mdl_blocks_commits_lock= NULL;
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ wsrep->resume(wsrep);
+ m_state= GRL_ACQUIRED;
+ }
+#endif /* WITH_WSREP */
+
if (m_state != GRL_ACQUIRED)
DBUG_RETURN(0);
@@ -1098,6 +1126,22 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
m_mdl_blocks_commits_lock= mdl_request.ticket;
m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
+#ifdef WITH_WSREP
+ long long ret = wsrep->pause(wsrep);
+ if (ret >= 0)
+ {
+ wsrep_locked_seqno= ret;
+ }
+ else if (ret != -ENOSYS) /* -ENOSYS - no provider */
+ {
+ WSREP_ERROR("Failed to pause provider: %lld (%s)", -ret, strerror(-ret));
+
+ /* m_mdl_blocks_commits_lock is always NULL here */
+ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+#endif /* WITH_WSREP */
DBUG_RETURN(FALSE);
}
diff --git a/sql/log.cc b/sql/log.cc
index f8c256e645f..d7aebb4ccf7 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -51,6 +51,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"
@@ -491,6 +494,59 @@ private:
handlerton *binlog_hton;
+#if WITH_WSREP
+/* the functions below depend on the definition of binlog_cache_manager class,
+ * so have to stay in this unit. */
+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(TRUE, TRUE);
+ }
+ 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 /* WITH_WSREP */
+
bool LOGGER::is_log_table_enabled(uint log_table_type)
{
switch (log_table_type) {
@@ -1535,7 +1591,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;
@@ -1583,7 +1643,16 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos)
int binlog_init(void *p)
{
binlog_hton= (handlerton *)p;
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ binlog_hton->state= SHOW_OPTION_YES;
+ else
+ {
+#endif /* WITH_WSREP */
binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
binlog_hton->db_type=DB_TYPE_BINLOG;
binlog_hton->savepoint_offset= sizeof(my_off_t);
binlog_hton->close_connection= binlog_close_connection;
@@ -1701,6 +1770,13 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all,
static inline int
binlog_commit_flush_trx_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr)
{
+#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"),
TRUE, TRUE, TRUE, 0);
return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE));
@@ -1839,6 +1915,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",
@@ -1895,6 +1974,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),
@@ -1923,8 +2005,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
@@ -1954,12 +2040,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
if (ending_trans(thd, all) &&
((thd->variables.option_bits & OPTION_KEEP_LOG) ||
(trans_has_updated_non_trans_table(thd) &&
- thd->variables.binlog_format == BINLOG_FORMAT_STMT) ||
+ WSREP_BINLOG_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_BINLOG_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_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_MIXED)))
error= binlog_rollback_flush_trx_cache(thd, all, cache_mngr);
/*
Truncate the cache if:
@@ -1973,9 +2059,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_BINLOG_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_BINLOG_FORMAT(thd->variables.binlog_format) != BINLOG_FORMAT_MIXED)))
error= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
@@ -2067,8 +2153,19 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
{
DBUG_ENTER("binlog_savepoint_set");
+#ifdef WITH_WSREP
+ /*
+ If wsrep_emulate_bin_log is true, (i.e opt_bin_log == false),
+ we should return from here if wsrep_on is off.
+ */
+ if (wsrep_emulate_bin_log && !WSREP(thd)) DBUG_RETURN(0);
+#endif /* WITH_WSREP */
+
binlog_trans_log_savepos(thd, (my_off_t*) sv);
/* Write it to the binary log */
+#ifdef WITH_WSREP
+ if (wsrep_emulate_bin_log) DBUG_RETURN(0);
+#endif /* WITH_WSREP */
char buf[1024];
String log_query(buf, sizeof(buf), &my_charset_bin);
@@ -2092,7 +2189,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];
@@ -4757,6 +4859,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.
@@ -4873,7 +4976,12 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
table->s->table_map_id));
/* Pre-conditions */
+#ifdef WITH_WSREP
+ DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
+ (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()));
+#else
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
+#endif
DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
Table_map_log_event
@@ -5013,7 +5121,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;
@@ -5071,7 +5183,19 @@ 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;
+
+#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->binlog_evt_union.do_union)
{
@@ -5099,7 +5223,11 @@ 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
+ if ((WSREP(thd) && wsrep_emulate_bin_log) || is_open())
+#else
if (likely(is_open()))
+#endif
{
my_off_t UNINIT_VAR(my_org_b_tell);
#ifdef HAVE_REPLICATION
@@ -5370,6 +5498,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;
@@ -5842,6 +5979,13 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
group_commit_entry entry;
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;
@@ -7485,7 +7629,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;
@@ -7560,6 +7711,22 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
HASH xids;
MEM_ROOT mem_root;
+#ifdef WITH_WSREP
+ /*
+ Read current wsrep position from storage engines to have consistent
+ end position for binlog scan.
+ */
+ 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("Binlog recovery, found wsrep position %s:%lld", uuid_str,
+ (long long)seqno);
+ const wsrep_seqno_t last_xid_seqno= seqno;
+ wsrep_seqno_t cur_xid_seqno= WSREP_SEQNO_UNDEFINED;
+#endif /* WITH_WSREP */
+
if (! fdle->is_valid() ||
my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
sizeof(my_xid), 0, 0, MYF(0)))
@@ -7571,7 +7738,12 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
while ((ev= Log_event::read_log_event(log, 0, fdle,
opt_master_verify_checksum))
- && ev->is_valid())
+ && ev->is_valid()
+#ifdef WITH_WSREP
+ && (last_xid_seqno == WSREP_SEQNO_UNDEFINED ||
+ last_xid_seqno != cur_xid_seqno)
+#endif
+ )
{
if (ev->get_type_code() == XID_EVENT)
{
@@ -7580,10 +7752,18 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
sizeof(xev->xid));
if (!x || my_hash_insert(&xids, x))
goto err2;
+#ifdef WITH_WSREP
+ cur_xid_seqno= xev->xid;
+#endif /* WITH_WSREP */
}
delete ev;
}
+#ifdef WITH_WSREP
+ WSREP_INFO("Binlog recovery scan stopped at Xid event %lld",
+ (long long)cur_xid_seqno);
+#endif /* WITH_WSREP */
+
if (ha_recover(&xids))
goto err2;
diff --git a/sql/log.h b/sql/log.h
index c6e5c135b25..419a64227e4 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -94,7 +94,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; }
@@ -853,12 +853,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_BINLOG_FORMAT(my_format) \
+ ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
+ wsrep_forced_binlog_format : my_format)
+#else
+#define WSREP_BINLOG_FORMAT(my_format) my_format
+#endif
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 d5b5b5a4870..cd6b780cb0e 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -49,6 +49,9 @@
#include <my_dir.h>
#include "sql_show.h" // append_identifier
+#if WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif
#endif /* MYSQL_CLIENT */
#include <base64.h>
@@ -2828,7 +2831,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));
@@ -4049,6 +4059,21 @@ Query_log_event::do_shall_skip(Relay_log_info *rli)
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(rli));
}
@@ -6238,6 +6263,20 @@ Xid_log_event::do_shall_skip(Relay_log_info *rli)
thd->variables.option_bits&= ~OPTION_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(rli));
}
#endif /* !MYSQL_CLIENT */
@@ -7261,7 +7300,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) */
@@ -7432,7 +7478,14 @@ int Append_block_log_event::do_apply_event(Relay_log_info const *rli)
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
@@ -8399,10 +8452,21 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
/* A small test to verify that objects have consistent types */
DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
-
if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0))
{
uint actual_error= thd->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->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)
{
/*
@@ -8524,7 +8588,18 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
}
#ifdef HAVE_QUERY_CACHE
- query_cache.invalidate_locked_for_write(thd, rli->tables_to_lock);
+#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, rli->tables_to_lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
#endif
}
@@ -8717,6 +8792,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
DBUG_RETURN(error);
}
+#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
+ if (get_flags(STMT_END_F) &&
+ WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
+ {
+ query_cache.invalidate_locked_for_write(thd, rli->tables_to_lock);
+ }
+#endif /* WITH_WSREP */
if (get_flags(STMT_END_F) && (error= rows_event_stmt_cleanup(rli, thd)))
slave_rows_error_report(ERROR_LEVEL,
thd->is_error() ? 0 : error,
@@ -9549,8 +9631,12 @@ check_table_map(Relay_log_info const *rli, RPL_TABLE_LIST *table_list)
{
DBUG_ENTER("check_table_map");
enum_tbl_map_status res= OK_TO_PROCESS;
-
+#ifdef WITH_WSREP
+ if ((rli->sql_thd->slave_thread /* filtering is for slave only */ ||
+ (WSREP(rli->sql_thd) && rli->sql_thd->wsrep_applier)) &&
+#else
if (rli->sql_thd->slave_thread /* filtering is for slave only */ &&
+#endif /* WITH_WSREP */
(!rpl_filter->db_ok(table_list->db) ||
(rpl_filter->is_on() && !rpl_filter->tables_ok("", table_list))))
res= FILTERED_OUT;
@@ -10246,8 +10332,23 @@ int
Write_rows_log_event::do_exec_row(const Relay_log_info *const rli)
{
DBUG_ASSERT(m_table != NULL);
+#ifdef WITH_WSREP
+#ifdef WSREP_PROC_INFO
+ char info[64];
+ info[sizeof(info) - 1] = '\0';
+ snprintf(info, sizeof(info) - 1, "Write_rows_log_event::write_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ const char* tmp = (WSREP(thd)) ? thd_proc_info(thd, info) : NULL;
+#else
+ const char* tmp = (WSREP(thd)) ?
+ thd_proc_info(thd,"Write_rows_log_event::write_row()") : NULL;
+#endif /* WSREP_PROC_INFO */
+#endif /* WITH_WSREP */
int error= write_row(rli, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
+#ifdef WITH_WSREP
+ if (WSREP(thd)) thd_proc_info(thd, tmp);
+#endif /* WITH_WSREP */
if (error && !thd->is_error())
{
DBUG_ASSERT(0);
@@ -10908,14 +11009,39 @@ int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli)
int error;
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(rli)))
{
/*
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 */
error= m_table->file->ha_delete_row(m_table->record[0]);
m_table->file->ha_index_or_rnd_end();
}
+#ifdef WITH_WSREP
+ if (WSREP(thd)) thd_proc_info(thd, tmp);
+#endif /* WITH_WSREP */
return error;
}
@@ -11035,6 +11161,18 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
{
DBUG_ASSERT(m_table != NULL);
+#ifdef WITH_WSREP
+#ifdef WSREP_PROC_INFO
+ char info[64];
+ info[sizeof(info) - 1] = '\0';
+ snprintf(info, sizeof(info) - 1, "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(rli);
if (error)
{
@@ -11061,6 +11199,17 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
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(rli)))
goto err;
@@ -11079,10 +11228,23 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli)
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 */
error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]);
if (error == HA_ERR_RECORD_IS_THE_SAME)
error= 0;
+#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;
@@ -11256,6 +11418,7 @@ st_print_event_info::st_print_event_info()
}
#endif
+
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 415d56887d5..5183a9806c9 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -20,7 +20,18 @@
#include <mysqld_error.h>
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
-
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
+extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
+extern "C" char *wsrep_thd_query(THD *thd);
+void sql_print_information(const char *format, ...)
+ ATTRIBUTE_FORMAT(printf, 1, 2);
+
+extern bool
+wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
+ MDL_ticket *ticket);
+#endif /* WITH_WSREP */
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_MDL_map_mutex;
static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
@@ -1188,6 +1199,13 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
while (!m_wait_status && !thd->killed &&
wait_result != ETIMEDOUT && wait_result != ETIME)
{
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_BF(thd, true))
+ {
+ wait_result= mysql_cond_wait(&m_COND_wait_status, &m_LOCK_wait_status);
+ }
+ else
+#endif
wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
abs_timeout);
}
@@ -1254,11 +1272,57 @@ 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))
+ {
+ 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());
}
@@ -1564,7 +1628,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.
@@ -1589,6 +1652,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:
@@ -1611,12 +1677,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))
+ {
+ 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;
}
@@ -2635,7 +2748,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.
@@ -2917,3 +3035,33 @@ void MDL_context::set_transaction_duration_for_all_locks()
ticket->m_duration= MDL_TRANSACTION;
#endif
}
+#ifdef WITH_WSREP
+void MDL_ticket::wsrep_report(bool debug)
+{
+ if (debug)
+ {
+ WSREP_DEBUG("MDL ticket: type: %s space: %s db: %s name: %s (%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(),
+ m_lock->key.get_wait_state_name());
+ }
+}
+#endif /* WITH_WSREP */
diff --git a/sql/mdl.h b/sql/mdl.h
index 68f24a7a0e8..1363a07e7ab 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -481,6 +481,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; }
@@ -663,6 +666,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(),
@@ -675,6 +685,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);
inline THD *get_thd() const { return m_thd; }
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 3d2de3126ff..9198f616d15 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -72,6 +72,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"
@@ -347,7 +354,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;
@@ -359,6 +370,9 @@ static DYNAMIC_ARRAY all_options;
/* Global variables */
+#ifdef WITH_WSREP
+ulong my_bind_addr;
+#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;
@@ -452,6 +466,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;
@@ -685,6 +703,23 @@ pthread_attr_t connection_attrib;
mysql_mutex_t LOCK_server_started;
mysql_cond_t COND_server_started;
+#ifdef WITH_WSREP
+mysql_mutex_t LOCK_wsrep_ready;
+mysql_cond_t COND_wsrep_ready;
+mysql_mutex_t LOCK_wsrep_sst;
+mysql_cond_t COND_wsrep_sst;
+mysql_mutex_t LOCK_wsrep_sst_init;
+mysql_cond_t COND_wsrep_sst_init;
+mysql_mutex_t LOCK_wsrep_rollback;
+mysql_cond_t COND_wsrep_rollback;
+wsrep_aborting_thd_t wsrep_aborting_thd= NULL;
+mysql_mutex_t LOCK_wsrep_replaying;
+mysql_cond_t COND_wsrep_replaying;
+mysql_mutex_t LOCK_wsrep_slave_threads;
+mysql_mutex_t LOCK_wsrep_desync;
+int wsrep_replaying= 0;
+static void wsrep_close_threads(THD* thd);
+#endif /* WITH_WSREP */
int mysqld_server_started= 0;
File_parser_dummy_hook file_parser_dummy_hook;
@@ -753,6 +788,12 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data,
key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count,
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_stats,
@@ -820,6 +861,18 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL},
{ &key_LOG_INFO_lock, "LOG_INFO::lock", 0},
{ &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL},
+#ifdef WITH_WSREP
+ { &key_LOCK_wsrep_ready, "LOCK_wsrep_ready", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_sst_thread, "wsrep_sst_thread", 0},
+ { &key_LOCK_wsrep_sst_init, "LOCK_wsrep_sst_init", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_sst, "LOCK_wsrep_sst", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_rollback, "LOCK_wsrep_rollback", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_thd, "THD::LOCK_wsrep_thd", 0},
+ { &key_LOCK_wsrep_replaying, "LOCK_wsrep_replaying", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_slave_threads, "LOCK_wsrep_slave_threads", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_desync, "LOCK_wsrep_desync", PSI_FLAG_GLOBAL},
+#endif
{ &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}
};
@@ -857,6 +910,11 @@ PSI_cond_key key_BINLOG_COND_prep_xids, 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_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;
PSI_cond_key key_RELAYLOG_COND_queue_busy;
PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy;
@@ -898,6 +956,14 @@ 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_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL},
+#endif
{ &key_COND_flush_thread_cache, "COND_flush_thread_cache", PSI_FLAG_GLOBAL}
};
@@ -1424,6 +1490,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);
@@ -1487,6 +1558,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);
}
@@ -1648,8 +1746,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 */
@@ -1744,6 +1850,26 @@ 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);
@@ -1942,6 +2068,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);
@@ -2198,6 +2338,9 @@ static my_socket activate_tcp_port(uint port)
socket_errno);
unireg_abort(1);
}
+#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
+ (void) fcntl(ip_sock, F_SETFD, FD_CLOEXEC);
+#endif /* WITH_WSREP */
DBUG_RETURN(ip_sock);
}
@@ -2310,6 +2453,9 @@ static void network_init(void)
if (listen(unix_sock,(int) back_log) < 0)
sql_print_warning("listen() on Unix socket failed with error %d",
socket_errno);
+#if defined(WITH_WSREP) && defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
+ (void) fcntl(unix_sock, F_SETFD, FD_CLOEXEC);
+#endif /* WITH_WSREP */
}
#endif
DBUG_PRINT("info",("server started"));
@@ -2384,9 +2530,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);
+ }
}
@@ -2536,10 +2692,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 /* WITH_WSREP */
+
unlink_thd(thd);
/* Mark that current_thd is not valid anymore */
my_pthread_setspecific_ptr(THR_THD, 0);
+
+#ifdef WITH_WSREP
+ if (put_in_cache && !wsrep_applier)
+#else
if (put_in_cache)
+#endif /* WITH_WSREP */
{
mysql_mutex_lock(&LOCK_thread_count);
put_in_cache= cache_thread();
@@ -3478,7 +3643,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);
@@ -3537,7 +3701,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();
@@ -3959,6 +4127,27 @@ static int init_thread_environment()
sql_print_error("Can't create thread-keys");
return 1;
}
+#ifdef WITH_WSREP
+ mysql_mutex_init(key_LOCK_wsrep_ready,
+ &LOCK_wsrep_ready, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_ready, &COND_wsrep_ready, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_sst,
+ &LOCK_wsrep_sst, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_sst, &COND_wsrep_sst, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_sst_init,
+ &LOCK_wsrep_sst_init, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_sst_init, &COND_wsrep_sst_init, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_rollback,
+ &LOCK_wsrep_rollback, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_rollback, &COND_wsrep_rollback, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_replaying,
+ &LOCK_wsrep_replaying, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_replaying, &COND_wsrep_replaying, NULL);
+ mysql_mutex_init(key_LOCK_wsrep_slave_threads,
+ &LOCK_wsrep_slave_threads, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_wsrep_desync,
+ &LOCK_wsrep_desync, MY_MUTEX_INIT_FAST);
+#endif
return 0;
}
@@ -4193,10 +4382,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.");
}
@@ -4222,6 +4419,42 @@ will be ignored as the --log-bin option is not defined.");
}
#endif
+#ifdef WITH_WSREP /* WSREP BEFORE SE */
+ 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())
+ {
+#ifndef EMBEDDED_LIBRARY
+ set_ports(); // this is also called in network_init() later but we need
+ // to know mysqld_port now - lp:1071882
+#endif /* !EMBEDDED_LIBRARY */
+
+ wsrep_init_startup(true);
+ }
+ }
+ }
+#endif /* WITH_WSREP */
DBUG_ASSERT(!opt_bin_log || opt_bin_logname);
if (opt_bin_log)
@@ -4298,6 +4531,49 @@ a file name for --log-bin-index option", opt_binlog_index_name);
}
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;
+ my_pthread_setspecific_ptr(THR_THD, tmp);
+
+ tmp->init_for_queries();
+
+ /* Restore current_thd. */
+ my_pthread_setspecific_ptr(THR_THD, current_thd_saved);
+
+ tmp->server_status= server_status_saved;
+ tmp->variables.option_bits= option_bits_saved;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_thread_count);
+ }
+#endif
+
have_csv= plugin_status(STRING_WITH_LEN("csv"),
MYSQL_STORAGE_ENGINE_PLUGIN);
have_ndbcluster= plugin_status(STRING_WITH_LEN("ndbcluster"),
@@ -4431,8 +4707,20 @@ a file name for --log-bin-index option", opt_binlog_index_name);
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 (WSREP_ON && tc_log == &tc_log_mmap)
+ tc_log= &tc_log_dummy;
+#endif
+
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
sql_print_error("Can't init tc log");
@@ -4489,8 +4777,6 @@ a file name for --log-bin-index option", opt_binlog_index_name);
init_global_client_stats();
DBUG_RETURN(0);
}
-
-
#ifndef EMBEDDED_LIBRARY
static void create_shutdown_thread()
@@ -4512,6 +4798,461 @@ 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);
+
+ 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->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)
+ {
+ if (wsrep_debug) WSREP_INFO("aborting replicated trx: %lu", thd->real_id);
+
+ (void)wsrep_abort_thd(thd, thd, TRUE);
+ ret_code= true;
+ }
+ return ret_code;
+}
+/**/
+static inline bool is_client_connection(THD *thd)
+{
+#if REMOVE
+// REMOVE THIS LATER (lp:777201). Below we had to add an explicit check for
+// wsrep_applier since wsrep_exec_mode didn't seem to always work
+if (thd->wsrep_applier && thd->wsrep_exec_mode != REPL_RECV)
+WSREP_WARN("applier has wsrep_exec_mode = %d", thd->wsrep_exec_mode);
+
+ if ( thd->slave_thread || /* declared as mysql slave */
+ thd->system_thread || /* declared as system thread */
+ !thd->vio_ok() || /* server internal thread */
+ thd->wsrep_exec_mode==REPL_RECV || /* applier or replaying thread */
+ thd->wsrep_applier || /* wsrep slave applier */
+ !thd->variables.wsrep_on) /* client, but fenced outside wsrep */
+ return false;
+
+ return true;
+#else
+ return (thd->wsrep_client_thread && thd->variables.wsrep_on);
+#endif /* REMOVE */
+}
+
+static inline bool is_replaying_connection(THD *thd)
+{
+ bool ret;
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ return ret;
+}
+
+static inline bool is_committing_connection(THD *thd)
+{
+ bool ret;
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ return ret;
+}
+
+static bool have_client_connections()
+{
+ 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))
+ {
+ mysql_mutex_unlock(&LOCK_thread_count);
+ 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));
+ if (wsrep_debug)
+ WSREP_INFO("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_close_applier_threads(int count)
+{
+ THD *tmp;
+ mysql_mutex_lock(&LOCK_thread_count); // For unlink from list
+
+ I_List_iterator<THD> it(threads);
+ while ((tmp=it++) && count)
+ {
+ DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
+ tmp->thread_id));
+ /* We skip slave threads & scheduler on this first loop through. */
+ if (tmp->wsrep_applier)
+ {
+ WSREP_DEBUG("closing wsrep applier thread %ld", tmp->thread_id);
+ tmp->wsrep_applier_closing= TRUE;
+ count--;
+ }
+ }
+
+ mysql_mutex_unlock(&LOCK_thread_count);
+}
+
+void wsrep_wait_appliers_close(THD *thd)
+{
+ /* Wait for wsrep appliers to gracefully exit */
+ mysql_mutex_lock(&LOCK_thread_count);
+ while (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()
@@ -4685,6 +5426,9 @@ int mysqld_main(int argc, char **argv)
return 1;
}
#endif
+#ifdef WITH_WSREP
+ wsrep_filter_new_cluster (&argc, argv);
+#endif /* WITH_WSREP */
orig_argc= argc;
orig_argv= argv;
@@ -4916,6 +5660,14 @@ int mysqld_main(int argc, char **argv)
my_str_malloc= &my_str_malloc_mysqld;
my_str_free= &my_str_free_mysqld;
+#ifdef WITH_WSREP /* WSREP AFTER SE */
+ if (wsrep_recovery)
+ {
+ select_thread_in_use= 0;
+ wsrep_recover();
+ unireg_abort(0);
+ }
+#endif /* WITH_WSREP */
/*
init signals & alarm
After this we can't quit by a simple unireg_abort
@@ -4980,6 +5732,38 @@ int mysqld_main(int argc, char **argv)
if (Events::init(opt_noacl || opt_bootstrap))
unireg_abort(1);
+#ifdef WITH_WSREP /* WSREP AFTER SE */
+ if (wsrep_recovery)
+ {
+ select_thread_in_use= 0;
+ wsrep_recover();
+ unireg_abort(0);
+ }
+
+ 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
@@ -5031,6 +5815,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
@@ -5297,6 +6084,9 @@ static void bootstrap(MYSQL_FILE *file)
DBUG_ENTER("bootstrap");
THD *thd= new THD;
+#ifdef WITH_WSREP
+ thd->variables.wsrep_on= 0;
+#endif
thd->bootstrap=1;
my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet;
@@ -5665,6 +6455,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(new_sock, F_SETFD, FD_CLOEXEC);
+#endif /* WITH_WSREP */
#ifdef HAVE_LIBWRAP
{
@@ -7134,6 +7927,21 @@ SHOW_VAR status_vars[]= {
#ifdef ENABLED_PROFILING
{"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_FUNC},
#endif
+#ifdef WITH_WSREP
+ {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL},
+ {"wsrep_ready", (char*) &wsrep_ready, SHOW_BOOL},
+ {"wsrep_cluster_state_uuid", (char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR},
+ {"wsrep_cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG},
+ {"wsrep_cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR},
+ {"wsrep_cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH},
+ {"wsrep_local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH},
+ {"wsrep_local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_FUNC},
+ {"wsrep_provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR},
+ {"wsrep_provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR},
+ {"wsrep_provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR},
+ {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH},
+ {"wsrep", (char*) &wsrep_show_status, SHOW_FUNC},
+#endif
{NullS, NullS, SHOW_LONG}
};
@@ -7451,6 +8259,10 @@ static int mysql_init_variables(void)
tmpenv = DEFAULT_MYSQL_HOME;
strmake_buf(mysql_home, tmpenv);
#endif
+#ifdef WITH_WSREP
+ if (WSREP_ON && wsrep_init_vars())
+ return 1;
+#endif
return 0;
}
@@ -7709,6 +8521,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:
/*
@@ -7928,6 +8748,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;
@@ -8064,6 +8918,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));
@@ -8357,6 +9214,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 d0679a3fa82..14997455f2f 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -221,6 +221,9 @@ extern pthread_key(MEM_ROOT**,THR_MALLOC);
extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
key_LOCK_pool;
#endif /* HAVE_MMAP */
+#ifdef WITH_WSREP
+extern PSI_mutex_key key_LOCK_wsrep_thd;
+#endif /* HAVE_WSREP */
#ifdef HAVE_OPENSSL
extern PSI_mutex_key key_LOCK_des_key_file;
@@ -411,6 +414,14 @@ enum options_mysqld
OPT_THREAD_CONCURRENCY,
OPT_UPDATE_LOG,
OPT_WANT_CORE,
+#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
@@ -565,4 +576,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 ac9fb1e9384..5afddb277e4 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -488,6 +488,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->stmt_da->is_sent);
bool error= FALSE;
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index db65cfa8757..b3b3e836638 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -307,7 +307,11 @@ unpack_row(Relay_log_info const *rli,
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 /* !DBUG_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",
@@ -316,6 +320,20 @@ unpack_row(Relay_log_info const *rli,
(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 */
+
rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT,
"Could not read field '%s' of table '%s.%s'",
f->field_name, table->s->db.str,
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 52e60c237dc..c0c541eee93 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1250,6 +1250,47 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos,
}
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+
+void
+delete_or_keep_event_post_apply(Relay_log_info *rli,
+ Log_event_type typ, Log_event *ev)
+{
+ switch (typ) {
+ case FORMAT_DESCRIPTION_EVENT:
+ /*
+ Format_description_log_event should not be deleted because it
+ will be used to read info about the relay log's format;
+ it will be deleted when the SQL thread does not need it,
+ i.e. when this thread terminates.
+ */
+ break;
+ case ANNOTATE_ROWS_EVENT:
+ /*
+ Annotate_rows event should not be deleted because after it has
+ been applied, thd->query points to the string inside this event.
+ The thd->query will be used to generate new Annotate_rows event
+ during applying the subsequent Rows events.
+ */
+ rli->set_annotate_event((Annotate_rows_log_event*) ev);
+ break;
+ case DELETE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT:
+ case WRITE_ROWS_EVENT:
+ /*
+ After the last Rows event has been applied, the saved Annotate_rows
+ event (if any) is not needed anymore and can be deleted.
+ */
+ if (((Rows_log_event*)ev)->get_flags(Rows_log_event::STMT_END_F))
+ rli->free_annotate_event();
+ /* fall through */
+ default:
+ DBUG_PRINT("info", ("Deleting the event after it has been executed"));
+ if (!rli->is_deferred_event(ev))
+ delete ev;
+ break;
+ }
+}
+
void Relay_log_info::cleanup_context(THD *thd, bool error)
{
DBUG_ENTER("Relay_log_info::cleanup_context");
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 5d31a8d1cdc..75cb9b7a645 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -588,6 +588,7 @@ private:
// Defined in rpl_rli.cc
int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
-
+void delete_or_keep_event_post_apply(Relay_log_info *rli,
+ Log_event_type typ, Log_event *ev);
#endif /* RPL_RLI_H */
diff --git a/sql/set_var.h b/sql/set_var.h
index 32207e834d9..4a499421f07 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -243,6 +243,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
};
@@ -323,6 +326,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 3a03464ccf9..f043ea3c477 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"
@@ -2818,41 +2821,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
exec_res= apply_event_and_update_pos(ev, thd, rli);
- switch (ev->get_type_code()) {
- case FORMAT_DESCRIPTION_EVENT:
- /*
- Format_description_log_event should not be deleted because it
- will be used to read info about the relay log's format;
- it will be deleted when the SQL thread does not need it,
- i.e. when this thread terminates.
- */
- break;
- case ANNOTATE_ROWS_EVENT:
- /*
- Annotate_rows event should not be deleted because after it has
- been applied, thd->query points to the string inside this event.
- The thd->query will be used to generate new Annotate_rows event
- during applying the subsequent Rows events.
- */
- rli->set_annotate_event((Annotate_rows_log_event*) ev);
- break;
- case DELETE_ROWS_EVENT:
- case UPDATE_ROWS_EVENT:
- case WRITE_ROWS_EVENT:
- /*
- After the last Rows event has been applied, the saved Annotate_rows
- event (if any) is not needed anymore and can be deleted.
- */
- if (((Rows_log_event*)ev)->get_flags(Rows_log_event::STMT_END_F))
- rli->free_annotate_event();
- /* fall through */
- default:
- DBUG_PRINT("info", ("Deleting the event after it has been executed"));
- if (!rli->is_deferred_event(ev))
- delete ev;
- break;
- }
-
+ delete_or_keep_event_post_apply(rli, ev->get_type_code(), ev);
/*
update_log_pos failed: this should not happen, so we don't
@@ -3475,12 +3444,18 @@ pthread_handler_t handle_slave_sql(void *arg)
my_off_t UNINIT_VAR(saved_log_pos);
my_off_t UNINIT_VAR(saved_master_log_pos);
my_off_t saved_skip= 0;
+#ifdef WITH_WSREP
+ my_bool wsrep_node_dropped= FALSE;
+#endif /* WITH_WSREP */
Relay_log_info* rli = &((Master_info*)arg)->rli;
const char *errmsg;
// 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);
@@ -3598,6 +3573,11 @@ pthread_handler_t handle_slave_sql(void *arg)
#endif
DBUG_ASSERT(rli->sql_thd == thd);
+#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)));
@@ -3739,6 +3719,12 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
Error running query, slave SQL thread aborted. Fix the problem, and restart \
the slave SQL thread with \"SLAVE START\". We stopped at log \
'%s' position %s", RPL_LOG_NAME, llstr(rli->group_master_log_pos, llbuff));
+#ifdef WITH_WSREP
+ if (WSREP_ON && last_errno == ER_UNKNOWN_COM_ERROR)
+ {
+ wsrep_node_dropped= TRUE;
+ }
+#endif /* WITH_WSREP */
}
goto err;
}
@@ -3803,6 +3789,27 @@ err_during_init:
THD_CHECK_SENTRY(thd);
delete thd;
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)
+ {
+ WSREP_INFO("Slave error due to node temporarily non-primary"
+ "SQL slave will continue");
+ wsrep_node_dropped= FALSE;
+ mysql_mutex_unlock(&rli->run_lock);
+ goto wsrep_restart_point;
+ } else {
+ WSREP_INFO("Slave error due to node going non-primary");
+ WSREP_INFO("wsrep_restart_slave was set and therefore slave will be "
+ "automatically restarted when node joins back to cluster");
+ wsrep_restart_slave_activated= TRUE;
+ }
+ }
+#endif /* WITH_WSREP */
/*
Note: the order of the broadcast and unlock calls below (first broadcast, then unlock)
is important. Otherwise a killer_thread can execute between the calls and
diff --git a/sql/sp.cc b/sql/sp.cc
index c12dcc76f27..932e801a01d 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -2290,3 +2290,37 @@ 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: %s", thd->query());
+ return 1;
+ }
+ return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
+}
+#endif /* WITH_WSREP */
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 03f0e878db6..11351f28a07 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1861,6 +1861,9 @@ int check_change_password(THD *thd, const char *host, const char *user,
return(1);
}
if (!thd->slave_thread &&
+#ifdef WITH_WSREP
+ (!WSREP(thd) || !thd->wsrep_applier) &&
+#endif /* WITH_WSREP */
(strcmp(thd->security_ctx->user, user) ||
my_strcasecmp(system_charset_info, host,
thd->security_ctx->priv_host)))
@@ -1868,7 +1871,12 @@ int check_change_password(THD *thd, const char *host, const char *user,
if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 0))
return(1);
}
+#ifdef WITH_WSREP
+ if ((!WSREP(thd) || !thd->wsrep_applier) &&
+ !thd->slave_thread && !thd->security_ctx->user[0])
+#else
if (!thd->slave_thread && !thd->security_ctx->user[0])
+#endif /* WITH_WSREP */
{
my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
MYF(0));
@@ -1907,11 +1915,14 @@ bool change_password(THD *thd, const char *host, const char *user,
TABLE *table;
/* Buffer should be extended when password length is extended. */
char buff[512];
- ulong query_length;
+ ulong query_length=0;
bool save_binlog_row_based;
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));
@@ -1919,6 +1930,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);
@@ -1998,13 +2021,26 @@ 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 */
/* Restore the state of binlog format */
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
if (save_binlog_row_based)
thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(result);
+#ifdef WITH_WSREP
+ error:
+ WSREP_ERROR("Replication of SET PASSWORD failed: %s", buff);
+ DBUG_RETURN(result);
+#endif /* WITH_WSREP */
}
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 55effcd7002..f318902aa95 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1132,6 +1132,8 @@ bool Optimize_table_statement::execute(THD *thd)
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
+
+ WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ?
mysql_recreate_table(thd, first_table) :
mysql_admin_table(thd, first_table, &m_lex->check_opt,
@@ -1163,6 +1165,7 @@ bool Repair_table_statement::execute(THD *thd)
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
thd->enable_slow_log= opt_log_slow_admin_statements;
+ WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL)
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "repair",
TL_WRITE, 1,
test(m_lex->check_opt.sql_flags & TT_USEFRM),
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index c6c02773286..0b4636c1f0f 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -17,7 +17,9 @@
#include "sql_table.h" // mysql_alter_table,
// mysql_exchange_partition
#include "sql_alter.h"
-
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
bool Alter_table_statement::execute(THD *thd)
{
LEX *lex= thd->lex;
@@ -97,6 +99,26 @@ bool Alter_table_statement::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 (WSREP(thd) &&
+ (!thd->is_current_stmt_binlog_format_row() ||
+ !find_temporary_table(thd, first_table)))
+ {
+ if (wsrep_to_isolation_begin(thd,
+ lex->name.str ? select_lex->db : NULL,
+ lex->name.str ? lex->name.str : NULL,
+ first_table))
+ {
+ WSREP_WARN("ALTER TABLE isolation failure");
+ DBUG_RETURN(TRUE);
+ }
+
+ thd->variables.auto_increment_offset = 1;
+ thd->variables.auto_increment_increment = 1;
+ }
+#endif /* WITH_WSREP */
result= mysql_alter_table(thd, select_lex->db, lex->name.str,
&create_info,
first_table,
@@ -105,5 +127,7 @@ bool Alter_table_statement::execute(THD *thd)
select_lex->order_list.first,
lex->ignore, lex->online);
+#ifdef WITH_WSREP
+#endif /* WITH_WSREP */
DBUG_RETURN(result);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7f84f35c825..345c7acb508 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -59,7 +59,10 @@
#ifdef __WIN__
#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 *,
@@ -4312,7 +4315,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_BINLOG_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) ||
@@ -5235,6 +5238,25 @@ restart:
}
}
}
+#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_proc_info(thd, "After opening tables");
@@ -9398,7 +9420,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);
}
@@ -9454,9 +9488,13 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
mysql_mutex_assert_owner(&LOCK_open);
}
+#ifdef WITH_WSREP
+ /* if thd was BF aborted, exclusive locks were canceled */
+#else
DBUG_ASSERT(remove_type == TDC_RT_REMOVE_UNUSED ||
thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
MDL_EXCLUSIVE));
+#endif /* WITH_WSREP */
key_length= create_table_def_key(key, db, table_name);
@@ -9476,10 +9514,21 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
{
I_P_List_iterator<TABLE, TABLE_share> it2(share->used_tables);
while ((table= it2++))
- if (table->in_use != thd)
- {
- DBUG_ASSERT(0);
- }
+#ifdef WITH_WSREP
+ /* if thd was BF aborted, exclusive locks were canceled,
+ thus others can use table */
+
+ if (table->in_use != thd &&
+ table->in_use->wsrep_conflict_state != MUST_ABORT)
+ {
+#endif
+ if (table->in_use != thd)
+ {
+ DBUG_ASSERT(0);
+ }
+#ifdef WITH_WSREP
+ }
+#endif
}
#endif
/*
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 ad0472cfc2c..8794cdb2a45 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1903,6 +1903,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 */
@@ -1915,6 +1922,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 00d860e7887..43d7ffd94d6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -62,6 +62,9 @@
#include "debug_sync.h"
#include "sql_parse.h" // is_update_query
#include "sql_callback.h"
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif
#include "sql_connect.h"
/*
@@ -766,6 +769,173 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
return buffer;
}
+#ifdef WITH_WSREP
+extern "C" int wsrep_on(void *thd)
+{
+ return (int)(WSREP(((THD*)thd)));
+}
+extern "C" bool wsrep_thd_is_wsrep_on(THD *thd)
+{
+ return thd->variables.wsrep_on;
+}
+
+extern "C" bool wsrep_consistency_check(void *thd)
+{
+ return ((THD*)thd)->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING;
+}
+
+extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode)
+{
+ thd->wsrep_exec_mode= mode;
+}
+extern "C" void wsrep_thd_set_query_state(
+ THD *thd, enum wsrep_query_state state)
+{
+ thd->wsrep_query_state= state;
+}
+extern "C" void wsrep_thd_set_conflict_state(
+ THD *thd, enum wsrep_conflict_state state)
+{
+ thd->wsrep_conflict_state= state;
+}
+
+
+extern "C" enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd)
+{
+ return thd->wsrep_exec_mode;
+}
+
+extern "C" const char *wsrep_thd_exec_mode_str(THD *thd)
+{
+ return
+ (!thd) ? "void" :
+ (thd->wsrep_exec_mode == LOCAL_STATE) ? "local" :
+ (thd->wsrep_exec_mode == REPL_RECV) ? "applier" :
+ (thd->wsrep_exec_mode == TOTAL_ORDER) ? "total order" :
+ (thd->wsrep_exec_mode == LOCAL_COMMIT) ? "local commit" : "void";
+}
+
+extern "C" enum wsrep_query_state wsrep_thd_query_state(THD *thd)
+{
+ return thd->wsrep_query_state;
+}
+
+extern "C" const char *wsrep_thd_query_state_str(THD *thd)
+{
+ return
+ (!thd) ? "void" :
+ (thd->wsrep_query_state == QUERY_IDLE) ? "idle" :
+ (thd->wsrep_query_state == QUERY_EXEC) ? "executing" :
+ (thd->wsrep_query_state == QUERY_COMMITTING) ? "committing" :
+ (thd->wsrep_query_state == QUERY_EXITING) ? "exiting" :
+ (thd->wsrep_query_state == QUERY_ROLLINGBACK) ? "rolling back" : "void";
+}
+
+extern "C" enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd)
+{
+ return thd->wsrep_conflict_state;
+}
+extern "C" const char *wsrep_thd_conflict_state_str(THD *thd)
+{
+ return
+ (!thd) ? "void" :
+ (thd->wsrep_conflict_state == NO_CONFLICT) ? "no conflict" :
+ (thd->wsrep_conflict_state == MUST_ABORT) ? "must abort" :
+ (thd->wsrep_conflict_state == ABORTING) ? "aborting" :
+ (thd->wsrep_conflict_state == MUST_REPLAY) ? "must replay" :
+ (thd->wsrep_conflict_state == REPLAYING) ? "replaying" :
+ (thd->wsrep_conflict_state == RETRY_AUTOCOMMIT) ? "retrying" :
+ (thd->wsrep_conflict_state == CERT_FAILURE) ? "cert failure" : "void";
+}
+
+extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd)
+{
+ return &thd->wsrep_ws_handle;
+}
+
+extern "C" void wsrep_thd_LOCK(THD *thd)
+{
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+}
+extern "C" void wsrep_thd_UNLOCK(THD *thd)
+{
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+}
+extern "C" time_t wsrep_thd_query_start(THD *thd)
+{
+ return thd->query_start();
+}
+extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd)
+{
+ return thd->wsrep_rand;
+}
+extern "C" my_thread_id wsrep_thd_thread_id(THD *thd)
+{
+ return thd->thread_id;
+}
+extern "C" wsrep_seqno_t wsrep_thd_trx_seqno(THD *thd)
+{
+ return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED;
+}
+extern "C" query_id_t wsrep_thd_query_id(THD *thd)
+{
+ return thd->query_id;
+}
+extern "C" char *wsrep_thd_query(THD *thd)
+{
+ return (thd) ? thd->query() : NULL;
+}
+extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd)
+{
+ return thd->wsrep_last_query_id;
+}
+extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id)
+{
+ thd->wsrep_last_query_id= id;
+}
+extern "C" void wsrep_thd_awake(THD* bf_thd, THD *thd, my_bool signal)
+{
+ if (signal)
+ {
+ thd->wsrep_bf_thd = bf_thd;
+ 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_trx_order_before(void *thd1, void *thd2)
+{
+ if (wsrep_thd_trx_seqno((THD*)thd1) < wsrep_thd_trx_seqno((THD*)thd2)) {
+ WSREP_DEBUG("BF conflict, order: %lld %lld\n",
+ (long long)wsrep_thd_trx_seqno((THD*)thd1),
+ (long long)wsrep_thd_trx_seqno((THD*)thd2));
+ return 1;
+ }
+ WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
+ (long long)wsrep_thd_trx_seqno((THD*)thd1),
+ (long long)wsrep_thd_trx_seqno((THD*)thd2));
+ return 0;
+}
+extern "C" int
+wsrep_trx_is_aborting(void *thd_ptr)
+{
+ if (thd_ptr) {
+ if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) ||
+ (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
/**
Implementation of Drop_table_error_handler::handle_condition().
@@ -794,7 +964,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), rli_slave(NULL),
@@ -822,6 +996,13 @@ THD::THD()
bootstrap(0),
derived_tables_processing(FALSE),
spcont(NULL),
+#ifdef WITH_WSREP
+ wsrep_applier(is_applier),
+ wsrep_applier_closing(FALSE),
+ wsrep_client_thread(0),
+ wsrep_apply_format(0),
+ wsrep_apply_toi(false),
+#endif
m_parser_state(NULL),
#if defined(ENABLED_DEBUG_SYNC)
debug_sync_control(0),
@@ -922,6 +1103,23 @@ THD::THD()
command=COM_CONNECT;
*scramble= '\0';
+#ifdef WITH_WSREP
+ mysql_mutex_init(key_LOCK_wsrep_thd, &LOCK_wsrep_thd, MY_MUTEX_INIT_FAST);
+ 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_bf_thd = NULL;
+ wsrep_TOI_pre_query = NULL;
+ wsrep_TOI_pre_query_len = 0;
+ wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -954,6 +1152,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_internal_handler= NULL;
m_binlog_invoker= FALSE;
@@ -1267,6 +1472,33 @@ void THD::init(void)
start_bytes_received= 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_autocommit= ::wsrep_retry_autocommit;
+ wsrep_retry_counter= 0;
+ wsrep_rli= NULL;
+ wsrep_PA_safe= true;
+ wsrep_consistency_check = NO_CONSISTENCY_CHECK;
+ wsrep_mysql_replicated = 0;
+ wsrep_bf_thd = NULL;
+ wsrep_TOI_pre_query = NULL;
+ wsrep_TOI_pre_query_len = 0;
+ wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+
+ /*
+ @@wsrep_causal_reads is now being handled via wsrep_sync_wait, update it
+ appropriately.
+ */
+ if (variables.wsrep_causal_reads)
+ variables.wsrep_sync_wait|= WSREP_SYNC_WAIT_BEFORE_READ;
+#endif /* WITH_WSREP */
+
if (variables.sql_log_bin)
variables.option_bits|= OPTION_BIN_LOG;
else
@@ -1457,6 +1689,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_rli) delete wsrep_rli;
+ if (wsrep_status_vars) wsrep->stats_free(wsrep, wsrep_status_vars);
+#endif
/* Close connection */
#ifndef EMBEDDED_LIBRARY
if (net.vio)
@@ -1625,6 +1864,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
+ if (!wsrep_bf_thd || wsrep_bf_thd->wsrep_exec_mode == LOCAL_STATE)
+#endif /* WITH_WSREP */
ha_kill_query(this, thd_kill_level(this));
/* Broadcast a condition to kick the target if it is waiting on it. */
@@ -1891,12 +2133,17 @@ void THD::cleanup_after_query()
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= FALSE;
+ /* reset replication info structure */
#ifndef EMBEDDED_LIBRARY
if (rli_slave)
rli_slave->cleanup_after_query();
#endif
+#ifdef WITH_WSREP
+ wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
+#endif /* WITH_WSREP */
+
DBUG_VOID_RETURN;
}
@@ -2312,6 +2559,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;
@@ -4042,8 +4296,13 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
extern "C" int thd_binlog_format(const MYSQL_THD thd)
{
+#ifdef WITH_WSREP
+ if (((WSREP(thd) && wsrep_emulate_bin_log) || mysql_bin_log.is_open()) &&
+ (thd->variables.option_bits & OPTION_BIN_LOG))
+#else
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
- return (int) thd->variables.binlog_format;
+#endif
+ return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
else
return BINLOG_FORMAT_UNSPEC;
}
@@ -4696,7 +4955,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_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT &&
!binlog_filter->db_ok(db)))
{
/*
@@ -4907,7 +5166,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
*/
my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
}
- else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
+ else if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW &&
sqlcom_can_generate_row_events(this))
{
/*
@@ -4936,7 +5195,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
else
{
/* binlog_format = STATEMENT */
- if (variables.binlog_format == BINLOG_FORMAT_STMT)
+ if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT)
{
if (lex->is_stmt_row_injection())
{
@@ -4953,7 +5212,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)
{
@@ -5041,7 +5307,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
"and binlog_filter->db_ok(db) = %d",
mysql_bin_log.is_open(),
(variables.option_bits & OPTION_BIN_LOG),
- variables.binlog_format,
+ WSREP_BINLOG_FORMAT(variables.binlog_format),
binlog_filter->db_ok(db)));
#endif
@@ -5295,7 +5561,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
@@ -5325,7 +5597,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);
@@ -5370,7 +5648,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
@@ -5401,7 +5685,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);
mysql_bin_log.remove_pending_rows_event(this, is_transactional);
@@ -5420,7 +5708,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);
/*
@@ -5668,8 +5960,12 @@ 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 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 5dd7cd18a5d..8a9c3d2429a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -45,6 +45,19 @@
THR_LOCK_INFO */
+#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;
+};
+#endif
class Reprepare_observer;
class Relay_log_info;
class Query_log_event;
@@ -579,6 +592,13 @@ 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;
+#endif
double long_query_time_double;
my_bool pseudo_slave_mode;
@@ -2354,6 +2374,42 @@ public:
query_id_t first_query_id;
} binlog_evt_union;
+#ifdef WITH_WSREP
+ const bool wsrep_applier; /* dedicated slave applier thread */
+ bool wsrep_applier_closing; /* applier marked to close */
+ bool wsrep_client_thread; /* to identify client threads*/
+ enum wsrep_exec_mode wsrep_exec_mode;
+ query_id_t wsrep_last_query_id;
+ enum wsrep_query_state wsrep_query_state;
+ enum wsrep_conflict_state wsrep_conflict_state;
+ mysql_mutex_t LOCK_wsrep_thd;
+ // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75
+ // wsrep_seqno_t wsrep_trx_seqno;
+ wsrep_trx_meta_t wsrep_trx_meta;
+ uint32 wsrep_rand;
+ Relay_log_info* wsrep_rli;
+ bool wsrep_converted_lock_session;
+ wsrep_ws_handle_t wsrep_ws_handle;
+#ifdef WSREP_PROC_INFO
+ char wsrep_info[128]; /* string for dynamic proc info */
+#endif /* WSREP_PROC_INFO */
+ ulong wsrep_retry_counter; // of autocommit
+ bool wsrep_PA_safe;
+ char* wsrep_retry_query;
+ size_t wsrep_retry_query_len;
+ enum enum_server_command wsrep_retry_command;
+ enum wsrep_consistency_check_mode
+ wsrep_consistency_check;
+ wsrep_stats_var* wsrep_status_vars;
+ int wsrep_mysql_replicated;
+ THD* wsrep_bf_thd;
+ const char* wsrep_TOI_pre_query; /* a query to apply before
+ the actual TOI query */
+ size_t wsrep_TOI_pre_query_len;
+ void* wsrep_apply_format;
+ bool wsrep_apply_toi; /* applier processing in TOI */
+ wsrep_gtid_t wsrep_sync_wait_gtid;
+#endif /* WITH_WSREP */
/**
Internal parser state.
Note that since the parser is not re-entrant, we keep only one parser
@@ -2385,7 +2441,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);
@@ -2799,7 +2859,7 @@ public:
tests fail and so force them to propagate the
lex->binlog_row_based_if_mixed upwards to the caller.
*/
- if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
+ if ((WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_MIXED)&&
(in_sub_stmt == 0))
set_current_stmt_binlog_format_row();
@@ -2841,7 +2901,7 @@ public:
show_system_thread(system_thread)));
if (in_sub_stmt == 0)
{
- if (variables.binlog_format == BINLOG_FORMAT_ROW)
+ if (WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
else if (temporary_tables == NULL)
clear_current_stmt_binlog_format_row();
@@ -3030,6 +3090,8 @@ private:
public:
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
+ inline enum enum_server_command get_command() const
+ { return command; }
/**
Assign a new value to thd->query and thd->query_id and mysys_var.
@@ -3429,6 +3491,8 @@ class select_insert :public select_result_interceptor {
virtual void store_values(List<Item> &values);
virtual bool can_rollback_data() { return 0; }
void send_error(uint errcode,const char *err);
+ 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 e2e56c48b3b..e0d246cd030 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -44,6 +44,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
@@ -1065,6 +1068,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)
@@ -1197,6 +1211,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;
}
@@ -1269,7 +1286,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 8aca415a9d0..f40e7a67ee4 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -417,7 +417,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)
@@ -870,7 +874,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 */
@@ -1046,7 +1054,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 70a12faafb5..4f0129c6e70 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1040,7 +1040,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)
@@ -3201,6 +3205,11 @@ 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);
@@ -3652,19 +3661,26 @@ void select_insert::send_error(uint errcode,const char *err)
}
-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->stmt_da->sql_errno();
@@ -3692,7 +3708,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;
@@ -3705,7 +3725,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();
@@ -3713,27 +3733,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),
- (ulong) thd->warning_info->statement_warn_count());
+ my_snprintf(message, sizeof(message), ER(ER_INSERT_INFO),
+ (ulong) info.records, (ulong) (info.records - info.copied),
+ (ulong) thd->warning_info->statement_warn_count());
else
- sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
- (ulong) (info.deleted+info.updated),
- (ulong) thd->warning_info->statement_warn_count());
+ my_snprintf(message, sizeof(message), ER(ER_INSERT_INFO),
+ (ulong) info.records, (ulong) (info.deleted + info.updated),
+ (ulong) thd->warning_info->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() {
@@ -3776,7 +3818,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 */
@@ -4193,7 +4239,11 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
/* show_database */ TRUE);
DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */
+#ifdef WITH_WSREP
+ if (WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open())
+#else
if (mysql_bin_log.is_open())
+#endif /* WITH_WSREP */
{
int errcode= query_error_code(thd, thd->killed == NOT_KILLED);
result= thd->binlog_query(THD::STMT_QUERY_TYPE,
@@ -4203,6 +4253,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;
}
@@ -4245,9 +4298,12 @@ void select_create::send_error(uint errcode,const char *err)
bool select_create::send_eof()
{
- bool tmp=select_insert::send_eof();
- if (tmp)
+ DBUG_ENTER("select_create::send_eof");
+ if (prepare_eof())
+ {
abort_result_set();
+ DBUG_RETURN(true);
+ }
else
{
/*
@@ -4259,10 +4315,25 @@ bool select_create::send_eof()
{
trans_commit_stmt(thd);
trans_commit_implicit(thd);
+#ifdef WITH_WSREP
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state != NO_CONFLICT)
+ {
+ WSREP_DEBUG("select_create commit failed, thd: %lu err: %d %s",
+ thd->thread_id, thd->wsrep_conflict_state, thd->query());
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ abort_result_set();
+ DBUG_RETURN(true);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+#endif /* WITH_WSREP */
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
+
+ send_ok_packet();
+
if (m_plock)
{
mysql_unlock_tables(thd, *m_plock);
@@ -4270,7 +4341,7 @@ bool select_create::send_eof()
m_plock= NULL;
}
}
- return tmp;
+ DBUG_RETURN(false);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 6611fd43876..446a4449e2f 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1585,6 +1585,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 ba0520de4bb..745ea171030 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -52,7 +52,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,
@@ -102,6 +102,12 @@
#include "../storage/maria/ha_maria.h"
#endif
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#include "wsrep_thd.h"
+static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
+ Parser_state *parser_state);
+#endif /* WITH_WSREP */
/**
@defgroup Runtime_Environment Runtime Environment
@{
@@ -121,7 +127,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
static void sql_kill(THD *thd, ulong id, killed_state state);
static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state);
static bool execute_show_status(THD *, TABLE_LIST *);
-static bool execute_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
+static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *);
const char *any_db="*any*"; // Special symbol for check_access
@@ -687,11 +693,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)
@@ -736,11 +757,49 @@ bool do_command(THD *thd)
*/
DEBUG_SYNC(thd, "before_do_command_net_read");
+#ifdef WITH_WSREP
+ if (WSREP(thd)) {
+ packet_length= my_net_read(net);
+ 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_bf_thd = NULL;
+ }
+
+ thd->wsrep_query_state= QUERY_EXEC;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ if ((WSREP(thd) && packet_length == packet_error) ||
+ (!WSREP(thd) && (packet_length= my_net_read(net)) == packet_error))
+#else
if ((packet_length= my_net_read(net)) == packet_error)
+#endif /* WITH_WSREP */
{
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 */
/* Check if we can continue without closing the connection */
@@ -786,12 +845,69 @@ bool do_command(THD *thd)
vio_description(net->vio), command,
command_name[command].str));
+#ifdef WITH_WSREP
+ if (WSREP(thd)) {
+ /*
+ * bail out if DB snapshot has not been installed. We however,
+ * allow queries "SET" and "SHOW", they are trapped later in execute_command
+ */
+ if (thd->variables.wsrep_on && !thd->wsrep_applier && !wsrep_ready &&
+ command != COM_QUERY &&
+ command != COM_PING &&
+ command != COM_QUIT &&
+ command != COM_PROCESS_INFO &&
+ command != COM_PROCESS_KILL &&
+ command != COM_SET_OPTION &&
+ command != COM_SHUTDOWN &&
+ command != COM_SLEEP &&
+ command != COM_STATISTICS &&
+ command != COM_TIME &&
+ command != COM_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();
+ 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);
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)
+ {
+ 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 */
out:
DBUG_RETURN(return_value);
}
@@ -861,6 +977,21 @@ static my_bool deny_updates_if_read_only_option(THD *thd,
DBUG_RETURN(FALSE);
}
+#ifdef WITH_WSREP
+static void wsrep_copy_query(THD *thd)
+{
+ thd->wsrep_retry_command = thd->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.
@@ -890,6 +1021,43 @@ 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;
+ thd->wsrep_bf_thd = NULL;
+ /*
+ 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
@@ -1072,7 +1240,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())
@@ -1128,10 +1300,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"));
@@ -1461,6 +1642,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)));
@@ -1470,6 +1671,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);
@@ -1487,7 +1691,16 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->command=COM_SLEEP;
thd->set_time();
dec_thread_running();
+#ifdef WITH_WSREP
+ if (WSREP(thd)) {
+ thd_proc_info(thd, "sleeping");
+ } else {
+#endif /* WITH_WSREP */
thd_proc_info(thd, 0);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
+
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
@@ -1920,6 +2133,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.
@@ -2139,7 +2359,72 @@ 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 &&
+ lex->sql_command != SQLCOM_SET_OPTION &&
+ !(thd->variables.wsrep_dirty_reads &&
+ !is_update_query(lex->sql_command)) &&
+ !wsrep_is_show_query(lex->sql_command))
+ {
+#if DIRTY_HACK
+ /* Dirty hack for lp:1002714 - trying to recognize mysqldump connection
+ * and allow it to continue. Actuall mysqldump_magic_str may be longer
+ * and is obviously version dependent and may be issued by any client
+ * connection after which connection becomes non-replicating. */
+ static char const mysqldump_magic_str[]=
+"SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL";
+ static const size_t mysqldump_magic_str_len= sizeof(mysqldump_magic_str) -1;
+ if (SQLCOM_SELECT != lex->sql_command ||
+ thd->query_length() < mysqldump_magic_str_len ||
+ strncmp(thd->query(), mysqldump_magic_str, mysqldump_magic_str_len))
+ {
+#endif /* DIRTY_HACK */
+ my_message(ER_UNKNOWN_COM_ERROR,
+ "WSREP has not yet prepared node for application use",
+ MYF(0));
+ goto error;
+#if DIRTY_HACK
+ }
+ else
+ {
+ /* mysqldump connection, allow all further queries to pass */
+ thd->variables.wsrep_on= FALSE;
+ }
+#endif /* DIRTY_HACK */
+ }
+ }
+#endif /* WITH_WSREP */
status_var_increment(thd->status_var.com_stat[lex->sql_command]);
thd->progress.report_to_client= test(sql_command_flags[lex->sql_command] &
CF_REPORT_PROGRESS);
@@ -2163,7 +2448,13 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(thd->transaction.stmt.is_empty());
/* 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();
}
@@ -2182,6 +2473,9 @@ mysql_execute_command(THD *thd)
#endif
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
if ((res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE)))
goto error;
@@ -2190,6 +2484,9 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_STATUS:
{
execute_show_status(thd, all_tables);
+#ifdef WITH_WSREP
+ if (lex->sql_command == SQLCOM_SHOW_STATUS) wsrep_free_status(thd);
+#endif /* WITH_WSREP */
break;
}
case SQLCOM_SHOW_DATABASES:
@@ -2200,16 +2497,26 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_PLUGINS:
case SQLCOM_SHOW_FIELDS:
case SQLCOM_SHOW_KEYS:
+#ifndef WITH_WSREP
case SQLCOM_SHOW_VARIABLES:
case SQLCOM_SHOW_CHARSETS:
case SQLCOM_SHOW_COLLATIONS:
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
+#endif /* WITH_WSREP */
case SQLCOM_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 (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+ case SQLCOM_SHOW_VARIABLES:
+ case SQLCOM_SHOW_CHARSETS:
+ case SQLCOM_SHOW_COLLATIONS:
+ case SQLCOM_SHOW_STORAGE_ENGINES:
+ case SQLCOM_SHOW_PROFILE:
+#endif /* WITH_WSREP */
{
thd->status_var.last_query_cost= 0.0;
@@ -2520,7 +2827,7 @@ case SQLCOM_PREPARE:
*/
if (thd->query_name_consts &&
mysql_bin_log.is_open() &&
- thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
+ WSREP_BINLOG_FORMAT(thd->variables.binlog_format) == BINLOG_FORMAT_STMT &&
!mysql_bin_log.is_query_in_union(thd, thd->query_id))
{
List_iterator_fast<Item> it(select_lex->item_list);
@@ -2605,6 +2912,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,
@@ -2639,6 +2947,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);
@@ -2672,6 +2989,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
@@ -2729,7 +3047,12 @@ end_with_restore_list:
case SQLCOM_RENAME_TABLE:
{
- if (execute_rename_table(thd, first_table, all_tables))
+ if (check_rename_table(thd, first_table, all_tables))
+ goto error;
+
+ WSREP_TO_ISOLATION_BEGIN(0, 0, first_table)
+
+ if (mysql_rename_tables(thd, first_table, 0))
goto error;
break;
}
@@ -2756,6 +3079,10 @@ end_with_restore_list:
goto error;
#else
{
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
+
/*
Access check:
SHOW CREATE TABLE require any privileges on the table level (ie
@@ -2811,6 +3138,10 @@ end_with_restore_list:
case SQLCOM_CHECKSUM:
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd)) goto error;
+#endif /* WITH_WSREP */
+
if (check_table_access(thd, SELECT_ACL, all_tables,
FALSE, UINT_MAX, FALSE))
goto error; /* purecov: inspected */
@@ -2819,6 +3150,10 @@ end_with_restore_list:
break;
}
case SQLCOM_UPDATE:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
+#endif /* WITH_WSREP */
{
ha_rows found= 0, updated= 0;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -2858,6 +3193,10 @@ end_with_restore_list:
/* if we switched from normal update, rights are checked */
if (up_result != 2)
{
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
+#endif /* WITH_WSREP */
if ((res= multi_update_precheck(thd, all_tables)))
break;
}
@@ -2927,6 +3266,10 @@ end_with_restore_list:
break;
}
case SQLCOM_REPLACE:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error;
+#endif /* WITH_WSREP */
#ifndef DBUG_OFF
if (mysql_bin_log.is_open())
{
@@ -2962,6 +3305,10 @@ end_with_restore_list:
}
#endif
case SQLCOM_INSERT:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error;
+#endif /* WITH_WSREP */
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
@@ -3003,11 +3350,23 @@ end_with_restore_list:
}
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) goto error;
+#endif /* WITH_WSREP */
{
select_result *sel_result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= insert_precheck(thd, all_tables)))
break;
+#ifdef WITH_WSREP
+ if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED)
+ {
+ thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING;
+ WSREP_TO_ISOLATION_BEGIN(first_table->db, first_table->table_name, NULL);
+ }
+
+#endif
/*
INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/
INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY
@@ -3091,6 +3450,10 @@ end_with_restore_list:
break;
}
case SQLCOM_DELETE:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
+#endif /* WITH_WSREP */
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= delete_precheck(thd, all_tables)))
@@ -3106,6 +3469,10 @@ end_with_restore_list:
break;
}
case SQLCOM_DELETE_MULTI:
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT(thd) &&
+ wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) goto error;
+#endif /* WITH_WSREP */
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
@@ -3171,6 +3538,18 @@ end_with_restore_list:
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
thd->variables.option_bits|= OPTION_KEEP_LOG;
}
+#ifdef WITH_WSREP
+ for (TABLE_LIST *table= all_tables; table; table= table->next_global)
+ {
+ if (!lex->drop_temporary &&
+ (!thd->is_current_stmt_binlog_format_row() ||
+ !find_temporary_table(thd, table)))
+ {
+ WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables);
+ break;
+ }
+ }
+#endif /* WITH_WSREP */
/* DDL and binlog write order are protected by metadata locks. */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
lex->drop_temporary);
@@ -3214,7 +3593,6 @@ end_with_restore_list:
if (!mysql_change_db(thd, &db_str, FALSE))
my_ok(thd);
-
break;
}
@@ -3357,6 +3735,7 @@ end_with_restore_list:
#endif
if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
+ WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias :
lex->name.str), &create_info, 0);
break;
@@ -3386,6 +3765,7 @@ end_with_restore_list:
#endif
if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
+ WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0);
break;
}
@@ -3414,6 +3794,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);
@@ -3446,6 +3827,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;
}
@@ -3478,6 +3860,7 @@ end_with_restore_list:
if (res)
break;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
{
@@ -3512,6 +3895,7 @@ end_with_restore_list:
lex->spname->m_name);
break;
case SQLCOM_DROP_EVENT:
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res= Events::drop_event(thd,
lex->spname->m_db, lex->spname->m_name,
lex->drop_if_exists)))
@@ -3526,6 +3910,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
@@ -3540,6 +3925,7 @@ end_with_restore_list:
if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list)))
my_ok(thd);
@@ -3551,6 +3937,7 @@ end_with_restore_list:
check_global_access(thd,CREATE_USER_ACL))
break;
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res= mysql_drop_user(thd, lex->users_list)))
my_ok(thd);
break;
@@ -3561,6 +3948,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;
@@ -3575,6 +3963,7 @@ end_with_restore_list:
thd->binlog_invoker();
/* Conditionally writes to binlog */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd);
break;
@@ -3641,6 +4030,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,
@@ -3654,6 +4044,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);
@@ -3669,6 +4060,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,
@@ -3716,6 +4108,21 @@ end_with_restore_list:
break;
}
+#ifdef WITH_WSREP
+ if (lex->type & (
+ REFRESH_GRANT |
+ REFRESH_HOSTS |
+ REFRESH_DES_KEY_FILE |
+#ifdef HAVE_QUERY_CACHE
+ REFRESH_QUERY_CACHE_FREE |
+#endif /* HAVE_QUERY_CACHE */
+ REFRESH_STATUS |
+ REFRESH_USER_RESOURCES))
+ {
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ }
+#endif /* WITH_WSREP*/
+
/*
reload_acl_and_cache() will tell us if we are allowed to write to the
binlog or not.
@@ -3807,14 +4214,28 @@ 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:
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:
@@ -3828,7 +4249,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)
@@ -3847,7 +4274,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:
@@ -3861,7 +4301,13 @@ end_with_restore_list:
(thd->variables.completion_type == 2 &&
lex->tx_release != TVL_NO));
if (trans_rollback(thd))
+ {
+ thd->mdl_context.release_transactional_locks();
+#ifdef WITH_WSREP
+ WSREP_DEBUG("rollback failed, MDL released: %lu", thd->thread_id);
+#endif /* WITH_WSREP */
goto error;
+ }
thd->mdl_context.release_transactional_locks();
/* Begin transaction with the same isolation level. */
if (tx_chain)
@@ -3877,7 +4323,17 @@ end_with_restore_list:
/* Disconnect the current client connection. */
if (tx_release)
thd->killed= KILL_CONNECTION;
+#ifdef WITH_WSREP
+ if (WSREP(thd)) {
+ if (thd->wsrep_conflict_state == NO_CONFLICT) {
+ my_ok(thd);
+ }
+ } else {
+#endif /* WITH_WSREP */
my_ok(thd);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
break;
}
case SQLCOM_RELEASE_SAVEPOINT:
@@ -3946,6 +4402,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: {
@@ -4157,6 +4614,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)
{
@@ -4228,6 +4686,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);
@@ -4342,6 +4801,7 @@ create_sp_error:
Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
as specified through the thd->lex->create_view_mode flag.
*/
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
break;
}
@@ -4350,12 +4810,14 @@ create_sp_error:
if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE))
goto error;
/* Conditionally writes to binlog. */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
break;
}
case SQLCOM_CREATE_TRIGGER:
{
/* Conditionally writes to binlog. */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
break;
@@ -4363,6 +4825,7 @@ create_sp_error:
case SQLCOM_DROP_TRIGGER:
{
/* Conditionally writes to binlog. */
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
}
@@ -4383,7 +4846,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
@@ -4394,7 +4863,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
@@ -4413,11 +4888,13 @@ create_sp_error:
my_ok(thd);
break;
case SQLCOM_INSTALL_PLUGIN:
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
my_ok(thd);
break;
case SQLCOM_UNINSTALL_PLUGIN:
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
my_ok(thd);
@@ -4577,6 +5054,9 @@ finish:
/* Free tables */
close_thread_tables(thd);
+#ifdef WITH_WSREP
+ thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
+#endif /* WITH_WSREP */
thd_proc_info(thd, 0);
#ifndef DBUG_OFF
@@ -4623,6 +5103,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());
}
@@ -4692,6 +5188,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->sent_row_count);
+#ifdef WITH_WSREP
+ if (lex->sql_command == SQLCOM_SHOW_STATUS) wsrep_free_status(thd);
+#endif /* WITH_WSREP */
return res;
}
@@ -4720,8 +5219,8 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
}
-static bool execute_rename_table(THD *thd, TABLE_LIST *first_table,
- TABLE_LIST *all_tables)
+static bool check_rename_table(THD *thd, TABLE_LIST *first_table,
+ TABLE_LIST *all_tables)
{
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *table;
@@ -4735,7 +5234,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;
TABLE_LIST old_list, new_list;
/*
we do not need initialize old_list and new_list because we will
@@ -4748,10 +5247,10 @@ 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;
}
- return mysql_rename_tables(thd, first_table, 0);
+ return false;
}
@@ -5633,6 +6132,26 @@ void THD::reset_for_next_command()
thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+#ifdef WITH_WSREP
+ /*
+ Autoinc variables should be adjusted only for locally executed
+ transactions. Appliers and replayers are either processing ROW
+ events or get autoinc variable values from Query_log_event.
+ */
+ if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE) {
+ if (wsrep_auto_increment_control)
+ {
+ if (thd->variables.auto_increment_offset !=
+ global_system_variables.auto_increment_offset)
+ thd->variables.auto_increment_offset=
+ global_system_variables.auto_increment_offset;
+ if (thd->variables.auto_increment_increment !=
+ global_system_variables.auto_increment_increment)
+ thd->variables.auto_increment_increment=
+ global_system_variables.auto_increment_increment;
+ }
+ }
+#endif /* WITH_WSREP */
thd->query_start_used= 0;
thd->query_start_sec_part_used= 0;
thd->is_fatal_error= thd->time_zone_used= 0;
@@ -5836,6 +6355,97 @@ 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;
+ }
+ mysql_parse(thd, rawbuf, length, parser_state);
+
+ if (WSREP(thd)) {
+ /* wsrep BF abort in query exec phase */
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state == MUST_ABORT) {
+ wsrep_client_rollback(thd);
+
+ WSREP_DEBUG("abort in exec query state, avoiding autocommit");
+ }
+
+ /* checking if BF trx must be replayed */
+ if (thd->wsrep_conflict_state== MUST_REPLAY)
+ {
+ wsrep_replay_transaction(thd);
+ }
+
+ /* setting error code for BF aborted trxs */
+ if (thd->wsrep_conflict_state == ABORTED ||
+ thd->wsrep_conflict_state == CERT_FAILURE)
+ {
+ mysql_reset_thd_for_next_command(thd);
+ thd->killed= NOT_KILLED;
+ if (is_autocommit &&
+ thd->lex->sql_command != SQLCOM_SELECT &&
+ (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
+ {
+ WSREP_DEBUG("wsrep retrying AC query: %s",
+ (thd->query()) ? thd->query() : "void");
+
+ close_thread_tables(thd);
+
+ thd->wsrep_conflict_state= RETRY_AUTOCOMMIT;
+ thd->wsrep_retry_counter++; // grow
+ wsrep_copy_query(thd);
+ thd->set_time();
+ parser_state->reset(rawbuf, length);
+ }
+ else
+ {
+ WSREP_DEBUG("%s, thd: %lu is_AC: %d, retry: %lu - %lu SQL: %s",
+ (thd->wsrep_conflict_state == ABORTED) ?
+ "BF Aborted" : "cert failure",
+ thd->thread_id, is_autocommit, thd->wsrep_retry_counter,
+ thd->variables.wsrep_retry_autocommit, thd->query());
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
+ thd->killed= NOT_KILLED;
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ if (thd->wsrep_conflict_state != REPLAYING)
+ thd->wsrep_retry_counter= 0; // reset
+ }
+ }
+ else
+ {
+ set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ } while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT);
+
+ if (thd->wsrep_retry_query)
+ {
+ WSREP_DEBUG("releasing retry_query: "
+ "conf %d sent %d kill %d errno %d SQL %s",
+ thd->wsrep_conflict_state,
+ thd->stmt_da->is_sent,
+ thd->killed,
+ thd->stmt_da->is_error() ? thd->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
@@ -5953,6 +6563,12 @@ void mysql_parse(THD *thd, char *rawbuf, uint length,
thd->lex->sql_command= SQLCOM_SELECT;
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;
}
@@ -6816,8 +7432,14 @@ uint kill_one_thread(THD *thd, ulong id, killed_state kill_signal)
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;
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index c5ea38706c4..58885594a5d 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -208,6 +208,22 @@ inline bool is_supported_parser_charset(CHARSET_INFO *cs)
{
return 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);
+
+#else
+
+#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_)
+#define WSREP_TO_ISOLATION_END
+
+#endif /* WITH_WSREP */
#endif /* SQL_PARSE_INCLUDED */
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index a104676a3ff..809a2b651d6 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -134,6 +134,19 @@ bool Alter_table_truncate_partition_statement::execute(THD *thd)
if (check_one_table_access(thd, DROP_ACL, first_table))
DBUG_RETURN(TRUE);
+#ifdef WITH_WSREP
+ TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
+
+ if ((!thd->is_current_stmt_binlog_format_row() ||
+ !find_temporary_table(thd, first_table)) &&
+ wsrep_to_isolation_begin(
+ thd, first_table->db, first_table->table_name, NULL)
+ )
+ {
+ WSREP_WARN("ALTER TABLE isolation failure");
+ DBUG_RETURN(TRUE);
+ }
+#endif /* WITH_WSREP */
if (open_and_lock_tables(thd, first_table, FALSE, 0))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 75aca02990d..f527fcce34c 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -2963,11 +2963,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 094677e150d..1f95ac279fd 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -3509,7 +3509,9 @@ Prepared_statement::set_parameters(String *expanded_query,
return res;
}
-
+#ifdef WITH_WSREP
+void wsrep_replay_transaction(THD *thd);
+#endif /* WITH_WSREP */
/**
Execute a prepared statement. Re-prepare it a limited number
of times if necessary.
@@ -3589,6 +3591,22 @@ 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->stmt_da->sql_errno() );
+ thd->wsrep_conflict_state = NO_CONFLICT;
+ break;
+
+ case MUST_REPLAY:
+ (void)wsrep_replay_transaction(thd);
+ default: break;
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+#endif /* WITH_WSREP */
if (error && !thd->is_fatal_error && !thd->killed &&
reprepare_observer.is_invalidated() &&
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index 8cc9dbd45fb..24116238cda 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -227,7 +227,18 @@ bool reload_acl_and_cache(THD *thd, unsigned 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)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 871cb27f0d0..3bfc417f2f6 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1419,7 +1419,14 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
ER(ER_SLAVE_WAS_NOT_RUNNING));
}
unlock_slave_threads(mi);
+#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)
{
@@ -1880,7 +1887,14 @@ bool change_master(THD* thd, Master_info* mi)
err:
unlock_slave_threads(mi);
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ thd_proc_info(thd, "exit change_master()");
+ else
+ thd_proc_info(thd, 0);
+#else /* WITH_WSREP */
thd_proc_info(thd, 0);
+#endif /* WITH_WSREP */
if (ret == FALSE)
my_ok(thd);
DBUG_RETURN(ret);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index d8ea232caea..8a125fc7305 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -59,6 +59,9 @@
#include "datadict.h" // dd_frm_type()
#include "keycaches.h"
+#if !defined(MYSQL_MAX_VARIABLE_VALUE_LEN)
+#define MYSQL_MAX_VARIABLE_VALUE_LEN 1024
+#endif // !defined(MYSQL_MAX_VARIABLE_VALUE_LEN)
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -116,9 +119,6 @@ static void get_cs_converted_string_value(THD *thd,
bool use_hex);
#endif
-static void
-append_algorithm(TABLE_LIST *table, String *buff);
-
static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table);
/***************************************************************************
@@ -1966,32 +1966,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:
@@ -2006,6 +2004,8 @@ static void append_algorithm(TABLE_LIST *table, String *buff)
default:
DBUG_ASSERT(0); // never should happen
}
+
+ DBUG_VOID_RETURN;
}
/*
@@ -2029,6 +2029,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);
+}
int
view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
@@ -8408,7 +8425,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 0a0d4a4d4dd..864216ebc06 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -116,6 +116,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 6ab39d7f8c6..0d946a2aa8b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4816,6 +4816,60 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
uint not_used;
DBUG_ENTER("mysql_create_like_table");
+#ifdef WITH_WSREP
+ if (WSREP(thd) && !thd->wsrep_applier)
+ {
+ TABLE *tmp_table;
+ bool is_tmp_table= FALSE;
+
+ for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next)
+ {
+ if (!strcmp(src_table->db, tmp_table->s->db.str) &&
+ !strcmp(src_table->table_name, tmp_table->s->table_name.str))
+ {
+ is_tmp_table= TRUE;
+ break;
+ }
+ }
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */
+ WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s",
+ thd->query());
+ }
+ else if (!is_tmp_table)
+ {
+ /* this is straight CREATE TABLE LIKE... eith no tmp tables */
+ WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
+ }
+ else
+ {
+ /* here we have CREATE TABLE LIKE <temporary table>
+ the temporary table definition will be needed in slaves to
+ enable the create to succeed
+ */
+ TABLE_LIST tbl;
+ 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) store_create_info(thd, &tbl, &query, NULL, TRUE);
+ WSREP_DEBUG("TMP TABLE: %s", query.ptr());
+
+ thd->wsrep_TOI_pre_query= query.ptr();
+ thd->wsrep_TOI_pre_query_len= query.length();
+
+ WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
+
+ thd->wsrep_TOI_pre_query= NULL;
+ thd->wsrep_TOI_pre_query_len= 0;
+ }
+ }
+#endif
/*
We the open source table to get its description in HA_CREATE_INFO
@@ -4981,6 +5035,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
err:
DBUG_RETURN(res);
+#ifdef WITH_WSREP
+ error:
+ thd->wsrep_TOI_pre_query= NULL;
+ DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
+
}
@@ -6378,12 +6438,16 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
error= 0;
break;
}
+
if (error == HA_ERR_WRONG_COMMAND)
{
error= 0;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->alias.c_ptr());
+#ifdef WITH_WSREP
+ WSREP_DEBUG("ignoring DDL failure: %d %s", error, thd->query());
+#endif /* WITH_WSREP */
}
if (!error && (new_name != table_name || new_db != db))
@@ -6436,6 +6500,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->alias.c_ptr());
+#ifdef WITH_WSREP
+ WSREP_DEBUG("ignoring DDL failure: %d %s", error, thd->query());
+#endif /* WITH_WSREP */
}
if (!error)
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 4d7338b2e1d..c562ee9762c 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -2462,3 +2462,55 @@ bool load_table_name_for_trigger(THD *thd,
DBUG_RETURN(FALSE);
}
+#ifdef WITH_WSREP
+int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len)
+{
+ LEX *lex= thd->lex;
+ String stmt_query;
+
+ LEX_STRING definer_user;
+ LEX_STRING definer_host;
+
+ if (!lex->definer)
+ {
+ if (!thd->slave_thread)
+ {
+ if (!(lex->definer= create_default_definer(thd)))
+ return 1;
+ }
+ }
+
+ if (lex->definer)
+ {
+ /* SUID trigger. */
+
+ definer_user= lex->definer->user;
+ definer_host= lex->definer->host;
+ }
+ else
+ {
+ /* non-SUID trigger. */
+
+ definer_user.str= 0;
+ definer_user.length= 0;
+
+ definer_host.str= 0;
+ definer_host.length= 0;
+ }
+
+ stmt_query.append(STRING_WITH_LEN("CREATE "));
+
+ append_definer(thd, &stmt_query, &definer_user, &definer_host);
+
+ LEX_STRING stmt_definition;
+ stmt_definition.str= (char*) thd->lex->stmt_definition_begin;
+ stmt_definition.length= thd->lex->stmt_definition_end
+ - thd->lex->stmt_definition_begin;
+ trim_whitespace(thd->charset(), & stmt_definition);
+
+ stmt_query.append(stmt_definition.str, stmt_definition.length);
+
+ return wsrep_to_buf_helper(thd, stmt_query.c_ptr(), stmt_query.length(),
+ buf, buf_len);
+}
+#endif /* WITH_WSREP */
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index 9b37996f377..388232b2a21 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()
@@ -473,6 +476,12 @@ bool Truncate_statement::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);
@@ -555,7 +564,6 @@ bool Truncate_statement::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 060952a589d..49fcf16a045 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -930,7 +930,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)
@@ -2096,7 +2100,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
@@ -2363,7 +2371,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_yacc.yy b/sql/sql_yacc.yy
index 35c7203ca0d..29719f70962 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -6560,7 +6560,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
@@ -6572,9 +6572,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
@@ -6582,7 +6585,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;
@@ -6592,6 +6595,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 ffe861ddfbc..a0475c136ae 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -281,6 +281,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, MYSQL_ERROR::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;
@@ -2585,6 +2606,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;
}
/*
@@ -3682,6 +3707,276 @@ static Sys_var_tz Sys_time_zone(
"time_zone", "time_zone",
SESSION_VAR(time_zone), NO_CMD_LINE,
DEFAULT(&default_tz), NO_MUTEX_GUARD, IN_BINLOG);
+#ifdef WITH_WSREP
+#include "wsrep_var.h"
+#include "wsrep_sst.h"
+#include "wsrep_binlog.h"
+
+static Sys_var_charptr Sys_wsrep_provider(
+ "wsrep_provider", "Path to replication provider library",
+ PREALLOCATED GLOBAL_VAR(wsrep_provider), CMD_LINE(REQUIRED_ARG, OPT_WSREP_PROVIDER),
+ IN_FS_CHARSET, DEFAULT(WSREP_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(wsrep_slave_threads_check),
+ ON_UPDATE(wsrep_slave_threads_update));
+
+static Sys_var_charptr Sys_wsrep_dbug_option(
+ "wsrep_dbug_option", "DBUG options to provider library",
+ GLOBAL_VAR(wsrep_dbug_option),CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(""),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG);
+
+static Sys_var_mybool Sys_wsrep_debug(
+ "wsrep_debug", "To enable debug level logging",
+ GLOBAL_VAR(wsrep_debug), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_wsrep_convert_LOCK_to_trx(
+ "wsrep_convert_LOCK_to_trx", "To convert locking sessions "
+ "into transactions",
+ GLOBAL_VAR(wsrep_convert_LOCK_to_trx),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_ulong Sys_wsrep_retry_autocommit(
+ "wsrep_retry_autocommit", "Max number of times to retry "
+ "a failed autocommit statement",
+ SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1));
+
+static Sys_var_mybool Sys_wsrep_auto_increment_control(
+ "wsrep_auto_increment_control", "To automatically control the "
+ "assignment of autoincrement variables",
+ GLOBAL_VAR(wsrep_auto_increment_control),
+ CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_wsrep_drupal_282555_workaround(
+ "wsrep_drupal_282555_workaround", "To use a workaround for"
+ "bad autoincrement value",
+ GLOBAL_VAR(wsrep_drupal_282555_workaround),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_charptr sys_wsrep_sst_method(
+ "wsrep_sst_method", "State snapshot transfer method",
+ GLOBAL_VAR(wsrep_sst_method),CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(WSREP_SST_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(0),
+ ON_UPDATE(wsrep_on_update));
+
+static Sys_var_charptr Sys_wsrep_start_position (
+ "wsrep_start_position", "global transaction position to start from ",
+ PREALLOCATED GLOBAL_VAR(wsrep_start_position),
+ CMD_LINE(REQUIRED_ARG, OPT_WSREP_START_POSITION),
+ IN_FS_CHARSET, DEFAULT(WSREP_START_POSITION_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),
+ /* Upper limit is 65K short of 4G to avoid overlows on 32-bit systems */
+ VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(1073741824UL), BLOCK_SIZE(1));
+
+static Sys_var_ulong Sys_wsrep_max_ws_rows (
+ "wsrep_max_ws_rows", "Max number of rows in write set",
+ GLOBAL_VAR(wsrep_max_ws_rows), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, 1048576), DEFAULT(131072), BLOCK_SIZE(1));
+
+static Sys_var_charptr Sys_wsrep_notify_cmd(
+ "wsrep_notify_cmd", "",
+ GLOBAL_VAR(wsrep_notify_cmd),CMD_LINE(REQUIRED_ARG),
+ IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG);
+
+static Sys_var_mybool Sys_wsrep_certify_nonPK(
+ "wsrep_certify_nonPK", "Certify tables with no primary key",
+ GLOBAL_VAR(wsrep_certify_nonPK),
+ CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_wsrep_causal_reads(
+ "wsrep_causal_reads", "(DEPRECATED) Setting this variable is equivalent "
+ "to setting wsrep_sync_wait READ flag",
+ SESSION_VAR(wsrep_causal_reads), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(wsrep_causal_reads_update));
+
+static Sys_var_uint Sys_wsrep_sync_wait(
+ "wsrep_sync_wait", "Ensure \"synchronous\" read view before executing "
+ "an operation of the type specified by bitmask: 1 - READ(includes "
+ "SELECT, SHOW and BEGIN/START TRANSACTION); 2 - UPDATE and DELETE; 4 - "
+ "INSERT and REPLACE",
+ SESSION_VAR(wsrep_sync_wait), CMD_LINE(OPT_ARG),
+ VALID_RANGE(WSREP_SYNC_WAIT_NONE, WSREP_SYNC_WAIT_MAX),
+ DEFAULT(WSREP_SYNC_WAIT_NONE), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(wsrep_sync_wait_update));
+
+static const char *wsrep_OSU_method_names[]= { "TOI", "RSU", NullS };
+static Sys_var_enum Sys_wsrep_OSU_method(
+ "wsrep_OSU_method", "Method for Online Schema Upgrade",
+ GLOBAL_VAR(wsrep_OSU_method_options), CMD_LINE(OPT_ARG),
+ wsrep_OSU_method_names, DEFAULT(WSREP_OSU_TOI),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(0));
+
+static PolyLock_mutex PLock_wsrep_desync(&LOCK_wsrep_desync);
+static Sys_var_mybool Sys_wsrep_desync (
+ "wsrep_desync", "To desynchronize the node from the cluster",
+ GLOBAL_VAR(wsrep_desync),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ &PLock_wsrep_desync, NOT_IN_BINLOG,
+ ON_CHECK(wsrep_desync_check),
+ ON_UPDATE(wsrep_desync_update));
+
+static Sys_var_enum Sys_wsrep_forced_binlog_format(
+ "wsrep_forced_binlog_format", "binlog format to take effect over user's choice",
+ GLOBAL_VAR(wsrep_forced_binlog_format),
+ CMD_LINE(REQUIRED_ARG, OPT_BINLOG_FORMAT),
+ wsrep_binlog_format_names, DEFAULT(BINLOG_FORMAT_UNSPEC),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
+ ON_UPDATE(0));
+
+static Sys_var_mybool Sys_wsrep_recover_datadir(
+ "wsrep_recover", "Recover database state after crash and exit",
+ READ_ONLY GLOBAL_VAR(wsrep_recovery),
+ CMD_LINE(OPT_ARG, OPT_WSREP_RECOVER), DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_wsrep_replicate_myisam(
+ "wsrep_replicate_myisam", "To enable myisam replication",
+ GLOBAL_VAR(wsrep_replicate_myisam), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_wsrep_log_conflicts(
+ "wsrep_log_conflicts", "To log multi-master conflicts",
+ GLOBAL_VAR(wsrep_log_conflicts), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_ulong Sys_wsrep_mysql_replication_bundle(
+ "wsrep_mysql_replication_bundle", "mysql replication group commit ",
+ GLOBAL_VAR(wsrep_mysql_replication_bundle), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 1000), DEFAULT(0), BLOCK_SIZE(1));
+
+static Sys_var_mybool Sys_wsrep_load_data_splitting(
+ "wsrep_load_data_splitting", "To commit LOAD DATA "
+ "transaction after every 10K rows inserted",
+ GLOBAL_VAR(wsrep_load_data_splitting),
+ CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_wsrep_slave_FK_checks(
+ "wsrep_slave_FK_checks", "Should slave thread do "
+ "foreign key constraint checks",
+ GLOBAL_VAR(wsrep_slave_FK_checks),
+ CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+
+static Sys_var_mybool Sys_wsrep_slave_UK_checks(
+ "wsrep_slave_UK_checks", "Should slave thread do "
+ "secondary index uniqueness chesks",
+ GLOBAL_VAR(wsrep_slave_UK_checks),
+ CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+static Sys_var_mybool Sys_wsrep_restart_slave(
+ "wsrep_restart_slave", "Should MySQL slave be restarted automatically, when node joins back to cluster",
+ GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+
+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 Sys_var_charptr Sys_ignore_db_dirs(
"ignore_db_dirs",
diff --git a/sql/table.cc b/sql/table.cc
index 9d52d5f87a2..0c6e02b7a5c 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -39,6 +39,9 @@
#include "sql_select.h"
#include "sql_derived.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")};
@@ -3974,6 +3977,12 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
insert_values= 0;
fulltext_searched= 0;
file->ft_handler= 0;
+#ifdef WITH_WSREP
+ if (file->ht->db_type == DB_TYPE_PARTITION_DB)
+ {
+ ((ha_partition*)file)->wsrep_reset_files();
+ }
+#endif
reginfo.impossible_range= 0;
created= TRUE;
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index 9e0cb07b86c..75b8f821d22 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -148,9 +148,8 @@ int threadpool_add_connection(THD *thd)
if (!setup_connection_thread_globals(thd))
{
- if (!login_connection(thd))
+ if (!thd_prepare_connection(thd))
{
- prepare_new_connection_state(thd);
/*
Check if THD is ok, as prepare_new_connection_state()
diff --git a/sql/transaction.cc b/sql/transaction.cc
index ae38e920a1d..c293c651c04 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -96,6 +96,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));
@@ -134,8 +137,14 @@ 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;
res= 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);
@@ -150,6 +159,12 @@ bool trans_begin(THD *thd, uint flags)
*/
thd->mdl_context.release_transactional_locks();
+#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;
@@ -177,8 +192,14 @@ 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;
res= ha_commit_trans(thd, TRUE);
+#ifdef WITH_WSREP
+ wsrep_post_commit(thd, TRUE);
+#endif /* WITH_WSREP */
if (res)
/*
if res is non-zero, then ha_commit_trans has rolled back the
@@ -220,8 +241,14 @@ 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;
res= 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);
@@ -251,11 +278,16 @@ bool trans_commit_implicit(THD *thd)
bool trans_rollback(THD *thd)
{
int res;
- DBUG_ENTER("trans_rollback");
-
- if (trans_check(thd))
+ 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;
res= ha_rollback_trans(thd, TRUE);
RUN_HOOK(transaction, after_rollback, (thd, FALSE));
@@ -295,6 +327,9 @@ bool trans_rollback_implicit(THD *thd)
*/
DBUG_ASSERT(thd->transaction.stmt.is_empty() && !thd->in_sub_stmt);
+#ifdef WITH_WSREP
+ wsrep_register_hton(thd, true);
+#endif /* WITH_WSREP */
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= ha_rollback_trans(thd, true);
@@ -342,9 +377,19 @@ bool trans_commit_stmt(THD *thd)
if (thd->transaction.stmt.ha_list)
{
+#ifdef WITH_WSREP
+ wsrep_register_hton(thd, FALSE);
+#endif /* WITH_WSREP */
res= ha_commit_trans(thd, FALSE);
if (! thd->in_active_multi_stmt_transaction())
+#ifdef WITH_WSREP
+ {
+#endif /* WITH_WSREP */
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+#ifdef WITH_WSREP
+ wsrep_post_commit(thd, FALSE);
+ }
+#endif /* WITH_WSREP */
}
if (res)
@@ -384,6 +429,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())
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
@@ -739,9 +787,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= 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)
{
@@ -760,6 +814,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 079611504cc..88169a41915 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2707,6 +2707,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 */
@@ -2754,6 +2760,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..3736431cd30
--- /dev/null
+++ b/sql/wsrep_applier.cc
@@ -0,0 +1,396 @@
+/* Copyright (C) 2013 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+#include "wsrep_priv.h"
+#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
+
+#include "log_event.h" // EVENT_LEN_OFFSET, etc.
+#include "wsrep_applier.h"
+
+/*
+ read the first event from (*buf). The size of the (*buf) is (*buf_len).
+ At the end (*buf) is shitfed to point to the following event or NULL and
+ (*buf_len) will be changed to account just being read bytes of the 1st event.
+*/
+
+static Log_event* wsrep_read_log_event(
+ char **arg_buf, size_t *arg_buf_len,
+ const Format_description_log_event *description_event)
+{
+ DBUG_ENTER("wsrep_read_log_event");
+ char *head= (*arg_buf);
+
+ uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
+ char *buf= (*arg_buf);
+ const char *error= 0;
+ Log_event *res= 0;
+
+ if (data_len > wsrep_max_ws_size)
+ {
+ error = "Event too big";
+ goto err;
+ }
+
+ res= Log_event::read_log_event(buf, data_len, &error, description_event,
+ 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);
+}
+
+#include "transaction.h" // trans_commit(), trans_rollback()
+#include "rpl_rli.h" // class Relay_log_info;
+#include "sql_base.h" // close_temporary_table()
+
+static inline void
+wsrep_set_apply_format(THD* thd, Format_description_log_event* ev)
+{
+ if (thd->wsrep_apply_format)
+ {
+ delete (Format_description_log_event*)thd->wsrep_apply_format;
+ }
+ thd->wsrep_apply_format= ev;
+}
+
+static inline Format_description_log_event*
+wsrep_get_apply_format(THD* thd)
+{
+ if (thd->wsrep_apply_format)
+ {
+ return (Format_description_log_event*) thd->wsrep_apply_format;
+ }
+ return thd->wsrep_rli->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;
+ int error = 0;
+ 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;
+ case WRITE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT:
+ DBUG_ASSERT(buf_len != 0 ||
+ ((Rows_log_event*)ev)->get_flags(Rows_log_event::STMT_END_F));
+ break;
+ 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)
+ ev->when = time(NULL);
+
+ 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_rli);
+ DBUG_PRINT("info", ("exec_event result: %d", exec_res));
+
+ if (exec_res)
+ {
+ WSREP_WARN("RBR event %d %s apply warning: %d, %lld",
+ event, ev->get_type_str(), exec_res,
+ (long long) wsrep_thd_trx_seqno(thd));
+ rcode= exec_res;
+ /* stop processing for the first error */
+ delete ev;
+ goto error;
+ }
+ event++;
+
+ if (thd->wsrep_conflict_state!= NO_CONFLICT &&
+ thd->wsrep_conflict_state!= REPLAYING)
+ WSREP_WARN("conflict state after RBR event applying: %d, %lld",
+ thd->wsrep_query_state, (long long)wsrep_thd_trx_seqno(thd));
+
+ if (thd->wsrep_conflict_state == MUST_ABORT) {
+ WSREP_WARN("RBR event apply failed, rolling back: %lld",
+ (long long) wsrep_thd_trx_seqno(thd));
+ trans_rollback(thd);
+ thd->locked_tables_list.unlock_locked_tables(thd);
+ /* Release transactional metadata locks. */
+ thd->mdl_context.release_transactional_locks();
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ DBUG_RETURN(WSREP_CB_FAILURE);
+ }
+
+ if ((ev->get_type_code() == WRITE_ROWS_EVENT ||
+ ev->get_type_code() == UPDATE_ROWS_EVENT ||
+ ev->get_type_code() == DELETE_ROWS_EVENT) &&
+ ((Rows_log_event *) ev)->get_flags(Rows_log_event::STMT_END_F))
+ {
+ thd->wsrep_rli->cleanup_context(thd, 0);
+
+ if (error == 0)
+ {
+ thd->clear_error();
+ }
+ else
+ WSREP_ERROR("Error in %s event: commit of row events failed: %lld",
+ ev->get_type_str(), (long long)wsrep_thd_trx_seqno(thd));
+ }
+
+ delete_or_keep_event_post_apply(thd->wsrep_rli, 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);
+
+ thd->wsrep_trx_meta = *meta;
+
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "applying write set %lld: %p, %zu",
+ (long long)wsrep_thd_trx_seqno(thd), buf, buf_len);
+ thd_proc_info(thd, thd->wsrep_info);
+#else
+ thd_proc_info(thd, "applying write set");
+#endif /* WSREP_PROC_INFO */
+
+ /* tune FK and UK checking policy */
+ if (wsrep_slave_UK_checks == FALSE)
+ thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+
+ if (wsrep_slave_FK_checks == FALSE)
+ thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+
+ if (flags & WSREP_FLAG_ISOLATION)
+ {
+ thd->wsrep_apply_toi= true;
+ /*
+ Don't run in transaction mode with TOI actions.
+ */
+ thd->variables.option_bits&= ~OPTION_BEGIN;
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ }
+ wsrep_cb_status_t rcode(wsrep_apply_events(thd, buf, buf_len));
+
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "applied write set %lld", (long long)wsrep_thd_trx_seqno(thd));
+ thd_proc_info(thd, thd->wsrep_info);
+#else
+ thd_proc_info(thd, "applied write set");
+#endif /* WSREP_PROC_INFO */
+
+ if (WSREP_CB_SUCCESS != rcode)
+ {
+ wsrep_dump_rbr_buf(thd, buf, buf_len);
+ }
+
+ TABLE *tmp;
+ while ((tmp = thd->temporary_tables))
+ {
+ WSREP_DEBUG("Applier %lu, has temporary tables: %s.%s",
+ thd->thread_id,
+ (tmp->s) ? tmp->s->db.str : "void",
+ (tmp->s) ? tmp->s->table_name.str : "void");
+ close_temporary_table(thd, tmp, 1, 1);
+ }
+
+ return rcode;
+}
+
+static wsrep_cb_status_t wsrep_commit(THD* const thd,
+ wsrep_seqno_t const global_seqno)
+{
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "committing %lld", (long long)wsrep_thd_trx_seqno(thd));
+ thd_proc_info(thd, thd->wsrep_info);
+#else
+ thd_proc_info(thd, "committing");
+#endif /* WSREP_PROC_INFO */
+
+ wsrep_cb_status_t const rcode(trans_commit(thd) ?
+ WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
+
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "committed %lld", (long long)wsrep_thd_trx_seqno(thd));
+ thd_proc_info(thd, thd->wsrep_info);
+#else
+ thd_proc_info(thd, "committed");
+#endif /* WSREP_PROC_INFO */
+
+ if (WSREP_CB_SUCCESS == rcode)
+ {
+ // TODO: mark snapshot with global_seqno.
+ }
+
+ return rcode;
+}
+
+static wsrep_cb_status_t wsrep_rollback(THD* const thd,
+ wsrep_seqno_t const global_seqno)
+{
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "rolling back %lld", (long long)wsrep_thd_trx_seqno(thd));
+ thd_proc_info(thd, thd->wsrep_info);
+#else
+ thd_proc_info(thd, "rolling back");
+#endif /* WSREP_PROC_INFO */
+
+ wsrep_cb_status_t const rcode(trans_rollback(thd) ?
+ WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
+
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "rolled back %lld", (long long)wsrep_thd_trx_seqno(thd));
+ thd_proc_info(thd, thd->wsrep_info);
+#else
+ thd_proc_info(thd, "rolled back");
+#endif /* WSREP_PROC_INFO */
+
+ return rcode;
+}
+
+wsrep_cb_status_t wsrep_commit_cb(void* const ctx,
+ uint32_t const flags,
+ const wsrep_trx_meta_t* meta,
+ wsrep_bool_t* const exit,
+ bool const commit)
+{
+ THD* const thd((THD*)ctx);
+
+ assert(meta->gtid.seqno == wsrep_thd_trx_seqno(thd));
+
+ wsrep_cb_status_t rcode;
+
+ if (commit)
+ rcode = wsrep_commit(thd, meta->gtid.seqno);
+ else
+ rcode = wsrep_rollback(thd, meta->gtid.seqno);
+
+ wsrep_set_apply_format(thd, NULL);
+ thd->mdl_context.release_transactional_locks();
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+
+ if (wsrep_slave_count_change < 0 && commit && WSREP_CB_SUCCESS == rcode)
+ {
+ mysql_mutex_lock(&LOCK_wsrep_slave_threads);
+ if (wsrep_slave_count_change < 0)
+ {
+ wsrep_slave_count_change++;
+ *exit = true;
+ }
+ mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
+ }
+
+ if (*exit == false && thd->wsrep_applier)
+ {
+ /* From trans_begin() */
+ thd->variables.option_bits|= OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+ thd->wsrep_apply_toi= false;
+ }
+
+ return rcode;
+}
+
+
+wsrep_cb_status_t wsrep_unordered_cb(void* const ctx,
+ const void* const data,
+ size_t const size)
+{
+ return WSREP_CB_SUCCESS;
+}
diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h
new file mode 100644
index 00000000000..816970db67c
--- /dev/null
+++ b/sql/wsrep_applier.h
@@ -0,0 +1,38 @@
+/* Copyright 2013 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef WSREP_APPLIER_H
+#define WSREP_APPLIER_H
+
+#include <sys/types.h>
+
+/* wsrep callback prototypes */
+
+wsrep_cb_status_t wsrep_apply_cb(void *ctx,
+ const void* buf, size_t buf_len,
+ uint32_t flags,
+ const wsrep_trx_meta_t* meta);
+
+wsrep_cb_status_t wsrep_commit_cb(void *ctx,
+ uint32_t flags,
+ const wsrep_trx_meta_t* meta,
+ wsrep_bool_t* exit,
+ bool commit);
+
+wsrep_cb_status_t wsrep_unordered_cb(void* ctx,
+ const void* data,
+ size_t size);
+
+#endif /* WSREP_APPLIER_H */
diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
new file mode 100644
index 00000000000..7feebc63cf4
--- /dev/null
+++ b/sql/wsrep_binlog.cc
@@ -0,0 +1,382 @@
+/* Copyright (C) 2013 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+#include "wsrep_binlog.h"
+#include "wsrep_priv.h"
+
+/*
+ Write the contents of a cache to a memory buffer.
+
+ This function quite the same as MYSQL_BIN_LOG::write_cache(),
+ with the exception that here we write in buffer instead of log file.
+ */
+int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
+{
+ *buf= NULL;
+ *buf_len= 0;
+
+ my_off_t const saved_pos(my_b_tell(cache));
+
+ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
+ {
+ WSREP_ERROR("failed to initialize io-cache");
+ return ER_ERROR_ON_WRITE;
+ }
+
+ uint length = my_b_bytes_in_cache(cache);
+ if (unlikely(0 == length)) length = my_b_fill(cache);
+
+ size_t total_length = 0;
+
+ if (likely(length > 0)) do
+ {
+ total_length += length;
+ /*
+ Bail out if buffer grows too large.
+ A temporary fix to avoid allocating indefinitely large buffer,
+ not a real limit on a writeset size which includes other things
+ like header and keys.
+ */
+ if (total_length > wsrep_max_ws_size)
+ {
+ WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
+ wsrep_max_ws_size, total_length);
+ goto error;
+ }
+
+ uchar* tmp = (uchar *)my_realloc(*buf, total_length, MYF(0));
+ if (!tmp)
+ {
+ WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
+ *buf_len, length);
+ goto error;
+ }
+ *buf = tmp;
+
+ memcpy(*buf + *buf_len, cache->read_pos, length);
+ *buf_len = total_length;
+ cache->read_pos = cache->read_end;
+ } while ((cache->file >= 0) && (length = my_b_fill(cache)));
+
+ if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
+ {
+ WSREP_WARN("failed to initialize io-cache");
+ goto cleanup;
+ }
+
+ return 0;
+
+error:
+ if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
+ {
+ WSREP_ERROR("failed to initialize io-cache");
+ }
+cleanup:
+ my_free(*buf);
+ *buf= NULL;
+ *buf_len= 0;
+ return ER_ERROR_ON_WRITE;
+}
+
+#define STACK_SIZE 4096 /* 4K - for buffer preallocated on the stack:
+ * many transactions would fit in there
+ * so there is no need to reach for the heap */
+
+/* Returns minimum multiple of HEAP_PAGE_SIZE that is >= length */
+static inline size_t
+heap_size(size_t length)
+{
+ return (length + HEAP_PAGE_SIZE - 1)/HEAP_PAGE_SIZE*HEAP_PAGE_SIZE;
+}
+
+/* append data to writeset */
+static inline wsrep_status_t
+wsrep_append_data(wsrep_t* const wsrep,
+ wsrep_ws_handle_t* const ws,
+ const void* const data,
+ size_t const len)
+{
+ struct wsrep_buf const buff = { data, len };
+ wsrep_status_t const rc(wsrep->append_data(wsrep, ws, &buff, 1,
+ WSREP_DATA_ORDERED, true));
+ if (rc != WSREP_OK)
+ {
+ WSREP_WARN("append_data() returned %d", rc);
+ }
+
+ return rc;
+}
+
+/*
+ Write the contents of a cache to wsrep provider.
+
+ This function quite the same as MYSQL_BIN_LOG::write_cache(),
+ with the exception that here we write in buffer instead of log file.
+
+ This version reads all of cache into single buffer and then appends to a
+ writeset at once.
+ */
+static int wsrep_write_cache_once(wsrep_t* const wsrep,
+ THD* const thd,
+ IO_CACHE* const cache,
+ size_t* const len)
+{
+ my_off_t const saved_pos(my_b_tell(cache));
+
+ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
+ {
+ WSREP_ERROR("failed to initialize io-cache");
+ return ER_ERROR_ON_WRITE;
+ }
+
+ int err(WSREP_OK);
+
+ size_t total_length(0);
+ uchar stack_buf[STACK_SIZE]; /* to avoid dynamic allocations for few data*/
+ uchar* heap_buf(NULL);
+ uchar* buf(stack_buf);
+ size_t allocated(sizeof(stack_buf));
+ size_t used(0);
+
+ uint length(my_b_bytes_in_cache(cache));
+ if (unlikely(0 == length)) length = my_b_fill(cache);
+
+ if (likely(length > 0)) do
+ {
+ total_length += length;
+ /*
+ Bail out if buffer grows too large.
+ A temporary fix to avoid allocating indefinitely large buffer,
+ not a real limit on a writeset size which includes other things
+ like header and keys.
+ */
+ if (unlikely(total_length > wsrep_max_ws_size))
+ {
+ WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
+ wsrep_max_ws_size, total_length);
+ err = WSREP_TRX_SIZE_EXCEEDED;
+ goto cleanup;
+ }
+
+ if (total_length > allocated)
+ {
+ size_t const new_size(heap_size(total_length));
+ uchar* tmp = (uchar *)my_realloc(heap_buf, new_size, MYF(0));
+ if (!tmp)
+ {
+ WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
+ allocated, length);
+ err = WSREP_TRX_SIZE_EXCEEDED;
+ goto cleanup;
+ }
+
+ heap_buf = tmp;
+ buf = heap_buf;
+ allocated = new_size;
+
+ if (used <= STACK_SIZE && used > 0) // there's data in stack_buf
+ {
+ DBUG_ASSERT(buf == stack_buf);
+ memcpy(heap_buf, stack_buf, used);
+ }
+ }
+
+ memcpy(buf + used, cache->read_pos, length);
+ used = total_length;
+ cache->read_pos = cache->read_end;
+ } while ((cache->file >= 0) && (length = my_b_fill(cache)));
+
+ if (used > 0)
+ err = wsrep_append_data(wsrep, &thd->wsrep_ws_handle, buf, used);
+
+ if (WSREP_OK == err) *len = total_length;
+
+cleanup:
+ if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
+ {
+ WSREP_ERROR("failed to reinitialize io-cache");
+ }
+
+ if (unlikely(WSREP_OK != err)) wsrep_dump_rbr_buf(thd, buf, used);
+
+ my_free(heap_buf);
+ return err;
+}
+
+/*
+ Write the contents of a cache to wsrep provider.
+
+ This function quite the same as MYSQL_BIN_LOG::write_cache(),
+ with the exception that here we write in buffer instead of log file.
+
+ This version uses incremental data appending as it reads it from cache.
+ */
+static int wsrep_write_cache_inc(wsrep_t* const wsrep,
+ THD* const thd,
+ IO_CACHE* const cache,
+ size_t* const len)
+{
+ my_off_t const saved_pos(my_b_tell(cache));
+
+ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
+ {
+ WSREP_ERROR("failed to initialize io-cache");
+ return WSREP_TRX_ERROR;
+ }
+
+ int err(WSREP_OK);
+
+ size_t total_length(0);
+
+ uint length(my_b_bytes_in_cache(cache));
+ if (unlikely(0 == length)) length = my_b_fill(cache);
+
+ if (likely(length > 0)) do
+ {
+ total_length += length;
+ /* bail out if buffer grows too large
+ not a real limit on a writeset size which includes other things
+ like header and keys.
+ */
+ if (unlikely(total_length > wsrep_max_ws_size))
+ {
+ WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
+ wsrep_max_ws_size, total_length);
+ err = WSREP_TRX_SIZE_EXCEEDED;
+ goto cleanup;
+ }
+
+ if(WSREP_OK != (err=wsrep_append_data(wsrep, &thd->wsrep_ws_handle,
+ cache->read_pos, length)))
+ goto cleanup;
+
+ cache->read_pos = cache->read_end;
+ } while ((cache->file >= 0) && (length = my_b_fill(cache)));
+
+ if (WSREP_OK == err) *len = total_length;
+
+cleanup:
+ if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
+ {
+ WSREP_ERROR("failed to reinitialize io-cache");
+ }
+
+ return err;
+}
+
+/*
+ Write the contents of a cache to wsrep provider.
+
+ This function quite the same as MYSQL_BIN_LOG::write_cache(),
+ with the exception that here we write in buffer instead of log file.
+ */
+int wsrep_write_cache(wsrep_t* const wsrep,
+ THD* const thd,
+ IO_CACHE* const cache,
+ size_t* const len)
+{
+ if (wsrep_incremental_data_collection) {
+ return wsrep_write_cache_inc(wsrep, thd, cache, len);
+ }
+ else {
+ return wsrep_write_cache_once(wsrep, thd, cache, len);
+ }
+}
+
+void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len)
+{
+ char filename[PATH_MAX]= {0};
+ int len= snprintf(filename, PATH_MAX, "%s/GRA_%ld_%lld.log",
+ wsrep_data_home_dir, thd->thread_id,
+ (long long)wsrep_thd_trx_seqno(thd));
+ if (len >= PATH_MAX)
+ {
+ WSREP_ERROR("RBR dump path too long: %d, skipping dump.", len);
+ return;
+ }
+
+ FILE *of= fopen(filename, "wb");
+
+ if (of)
+ {
+ 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));
+ }
+}
+
+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..76192f6e119
--- /dev/null
+++ b/sql/wsrep_binlog.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2013 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+#ifndef WSREP_BINLOG_H
+#define WSREP_BINLOG_H
+
+#include "sql_class.h" // THD, IO_CACHE
+
+#define HEAP_PAGE_SIZE 65536 /* 64K */
+#define WSREP_MAX_WS_SIZE (0xFFFFFFFFUL - HEAP_PAGE_SIZE)
+
+/*
+ Write the contents of a cache to a memory buffer.
+
+ This function quite the same as MYSQL_BIN_LOG::write_cache(),
+ with the exception that here we write in buffer instead of log file.
+ */
+int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len);
+
+/*
+ Write the contents of a cache to wsrep provider.
+
+ This function quite the same as MYSQL_BIN_LOG::write_cache(),
+ with the exception that here we write in buffer instead of log file.
+
+ @param len total amount of data written
+ @return wsrep error status
+ */
+int wsrep_write_cache (wsrep_t* wsrep,
+ THD* thd,
+ IO_CACHE* cache,
+ size_t* len);
+
+/* Dump replication buffer to disk */
+void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len);
+
+/* Dump replication buffer to disk without intermediate buffer */
+void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache);
+
+#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..0572230b18b
--- /dev/null
+++ b/sql/wsrep_hton.cc
@@ -0,0 +1,570 @@
+/* Copyright 2008 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <mysqld.h>
+#include "sql_base.h"
+#include "rpl_filter.h"
+#include <sql_class.h>
+#include "wsrep_mysqld.h"
+#include "wsrep_binlog.h"
+#include <cstdio>
+#include <cstdlib>
+
+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_emulate_bin_log) thd_binlog_trx_reset(thd);
+ thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
+ thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
+ thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
+ thd->wsrep_exec_mode= LOCAL_STATE;
+ return;
+}
+
+/*
+ wsrep hton
+*/
+handlerton *wsrep_hton;
+
+
+/*
+ Registers wsrep hton at commit time if transaction has registered htons
+ for supported engine types.
+
+ Hton should not be registered for TOTAL_ORDER operations.
+
+ Registration is needed for both LOCAL_MODE and REPL_RECV transactions to run
+ commit in 2pc so that wsrep position gets properly recorded in storage
+ engines.
+
+ Note that all hton calls should immediately return for threads that are
+ in REPL_RECV mode as their states are controlled by wsrep appliers or
+ replaying code. Only threads in LOCAL_MODE should run wsrep callbacks
+ from hton methods.
+*/
+void wsrep_register_hton(THD* thd, bool all)
+{
+ if (thd->wsrep_exec_mode != TOTAL_ORDER && !thd->wsrep_apply_toi)
+ {
+ THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
+ for (Ha_trx_info *i= trans->ha_list; WSREP(thd) && i; i = i->next())
+ {
+ if (i->ht()->db_type == DB_TYPE_INNODB)
+ {
+ trans_register_ha(thd, all, wsrep_hton);
+
+ /* follow innodb read/write settting
+ * but, as an exception: CTAS with empty result set will not be
+ * replicated unless we declare wsrep hton as read/write here
+ */
+ if (i->is_trx_read_write() ||
+ (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
+ thd->wsrep_exec_mode == LOCAL_STATE))
+ {
+ thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write();
+ }
+ break;
+ }
+ }
+ }
+}
+
+/*
+ Calls wsrep->post_commit() for locally executed transactions that have
+ got seqno from provider (must commit) and don't require replaying.
+ */
+void wsrep_post_commit(THD* thd, bool all)
+{
+ if (thd->wsrep_exec_mode == LOCAL_COMMIT)
+ {
+ DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
+ if (wsrep->post_commit(wsrep, &thd->wsrep_ws_handle))
+ {
+ DBUG_PRINT("wsrep", ("set committed fail"));
+ WSREP_WARN("set committed fail: %llu %d",
+ (long long)thd->real_id, thd->stmt_da->status());
+ }
+ wsrep_cleanup_transaction(thd);
+ }
+}
+
+/*
+ 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) return 0;
+ int rcode = binlog_hton->savepoint_set(binlog_hton, thd, sv);
+ 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) return 0;
+ int rcode = binlog_hton->savepoint_rollback(binlog_hton, thd, sv);
+ 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);
+ if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
+ (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
+ {
+ if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
+ {
+ DBUG_PRINT("wsrep", ("setting rollback fail"));
+ WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
+ (long long)thd->real_id, thd->query());
+ }
+ wsrep_cleanup_transaction(thd);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ DBUG_RETURN(0);
+}
+
+int wsrep_commit(handlerton *hton, THD *thd, bool all)
+{
+ DBUG_ENTER("wsrep_commit");
+
+ if (thd->wsrep_exec_mode == REPL_RECV)
+ {
+ DBUG_RETURN(0);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
+ (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
+ {
+ if (thd->wsrep_exec_mode == LOCAL_COMMIT)
+ {
+ DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
+ /*
+ Call to wsrep->post_commit() (moved to wsrep_post_commit()) must
+ be done only after commit has done for all involved htons.
+ */
+ DBUG_PRINT("wsrep", ("commit"));
+ }
+ else
+ {
+ /*
+ Transaction didn't go through wsrep->pre_commit() so just roll back
+ possible changes to clean state.
+ */
+ if (WSREP_PROVIDER_EXISTS) {
+ if (wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
+ {
+ DBUG_PRINT("wsrep", ("setting rollback fail"));
+ WSREP_ERROR("settting rollback fail: thd: %llu SQL: %s",
+ (long long)thd->real_id, thd->query());
+ }
+ }
+ wsrep_cleanup_transaction(thd);
+ }
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ DBUG_RETURN(0);
+}
+
+
+extern Rpl_filter* binlog_filter;
+extern my_bool opt_log_slave_updates;
+
+enum wsrep_trx_status
+wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all)
+{
+ int rcode= -1;
+ size_t data_len= 0;
+ IO_CACHE *cache;
+ int replay_round= 0;
+
+ if (thd->stmt_da->is_error()) {
+ WSREP_ERROR("commit issue, error: %d %s",
+ thd->stmt_da->sql_errno(), thd->stmt_da->message());
+ }
+
+ DBUG_ENTER("wsrep_run_wsrep_commit");
+
+ if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK);
+
+ if (thd->wsrep_exec_mode == REPL_RECV) {
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state == MUST_ABORT) {
+ if (wsrep_debug)
+ WSREP_INFO("WSREP: must abort for BF");
+ DBUG_PRINT("wsrep", ("BF apply commit fail"));
+ thd->wsrep_conflict_state = NO_CONFLICT;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ //
+ // TODO: test all calls of the rollback.
+ // rollback must happen automagically innobase_rollback(hton, thd, 1);
+ //
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+
+ if (thd->wsrep_exec_mode != LOCAL_STATE) DBUG_RETURN(WSREP_TRX_OK);
+
+ if (thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING) {
+ WSREP_DEBUG("commit for consistency check: %s", thd->query());
+ DBUG_RETURN(WSREP_TRX_OK);
+ }
+
+ DBUG_PRINT("wsrep", ("replicating commit"));
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ if (thd->wsrep_conflict_state == MUST_ABORT) {
+ DBUG_PRINT("wsrep", ("replicate commit fail"));
+ thd->wsrep_conflict_state = ABORTED;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ if (wsrep_debug) {
+ WSREP_INFO("innobase_commit, abort %s",
+ (thd->query()) ? thd->query() : "void");
+ }
+ DBUG_RETURN(WSREP_TRX_CERT_FAIL);
+ }
+
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+
+ while (wsrep_replaying > 0 &&
+ thd->wsrep_conflict_state == NO_CONFLICT &&
+ thd->killed == 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->stmt_da->is_ok() &&
+ thd->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->stmt_da->affected_rows(),
+ stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin,
+ thd->wsrep_exec_mode, thd->wsrep_query_state,
+ thd->wsrep_conflict_state);
+ }
+ else
+ {
+ WSREP_DEBUG("empty rbr buffer, query: %s", thd->query());
+ }
+ thd->wsrep_query_state= QUERY_EXEC;
+ DBUG_RETURN(WSREP_TRX_OK);
+ }
+
+ if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id)
+ {
+ WSREP_WARN("SQL statement was ineffective, THD: %lu, buf: %zu\n"
+ "QUERY: %s\n"
+ " => Skipping replication",
+ thd->thread_id, data_len, thd->query());
+ rcode = WSREP_TRX_FAIL;
+ }
+ else if (!rcode)
+ {
+ if (WSREP_OK == rcode)
+ rcode = wsrep->pre_commit(wsrep,
+ (wsrep_conn_id_t)thd->thread_id,
+ &thd->wsrep_ws_handle,
+ WSREP_FLAG_COMMIT |
+ ((thd->wsrep_PA_safe) ?
+ 0ULL : WSREP_FLAG_PA_UNSAFE),
+ &thd->wsrep_trx_meta);
+
+ if (rcode == WSREP_TRX_MISSING) {
+ WSREP_WARN("Transaction missing in provider, thd: %ld, SQL: %s",
+ thd->thread_id, thd->query());
+ rcode = WSREP_TRX_FAIL;
+ } else if (rcode == WSREP_BF_ABORT) {
+ WSREP_DEBUG("thd %lu seqno %lld BF aborted by provider, will replay",
+ thd->thread_id, (long long)thd->wsrep_trx_meta.gtid.seqno);
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ thd->wsrep_conflict_state = MUST_REPLAY;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ wsrep_replaying++;
+ WSREP_DEBUG("replaying increased: %d, thd: %lu",
+ wsrep_replaying, thd->thread_id);
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ }
+ } else {
+ WSREP_ERROR("I/O error reading from thd's binlog iocache: "
+ "errno=%d, io cache code=%d", my_errno, cache->error);
+ DBUG_ASSERT(0); // failure like this can not normally happen
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+ switch(rcode) {
+ case 0:
+ /*
+ About MUST_ABORT: We assume that even if thd conflict state was set
+ to MUST_ABORT, underlying transaction was not rolled back or marked
+ as deadlock victim in QUERY_COMMITTING state. Conflict state is
+ set to NO_CONFLICT and commit proceeds as usual.
+ */
+ if (thd->wsrep_conflict_state == MUST_ABORT)
+ thd->wsrep_conflict_state= NO_CONFLICT;
+
+ if (thd->wsrep_conflict_state != NO_CONFLICT)
+ {
+ WSREP_WARN("thd %lu seqno %lld: conflict state %d after post commit",
+ thd->thread_id,
+ (long long)thd->wsrep_trx_meta.gtid.seqno,
+ thd->wsrep_conflict_state);
+ }
+ thd->wsrep_exec_mode= LOCAL_COMMIT;
+ DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
+ /* Override XID iff it was generated by mysql */
+ if (thd->transaction.xid_state.xid.get_my_xid())
+ {
+ wsrep_xid_init(&thd->transaction.xid_state.xid,
+ &thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ }
+ DBUG_PRINT("wsrep", ("replicating commit success"));
+ break;
+ case WSREP_BF_ABORT:
+ DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
+ case WSREP_TRX_FAIL:
+ WSREP_DEBUG("commit failed for reason: %d %lu %s", rcode, thd->thread_id,
+ thd->query());
+ DBUG_PRINT("wsrep", ("replicating commit fail"));
+
+ thd->wsrep_query_state= QUERY_EXEC;
+
+ if (thd->wsrep_conflict_state == MUST_ABORT) {
+ thd->wsrep_conflict_state= ABORTED;
+ }
+ else
+ {
+ WSREP_DEBUG("conflict state: %d", thd->wsrep_conflict_state);
+ if (thd->wsrep_conflict_state == NO_CONFLICT)
+ {
+ thd->wsrep_conflict_state = CERT_FAILURE;
+ WSREP_LOG_CONFLICT(NULL, thd, FALSE);
+ }
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(WSREP_TRX_CERT_FAIL);
+
+ case WSREP_SIZE_EXCEEDED:
+ WSREP_ERROR("transaction size exceeded");
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED);
+ case WSREP_CONN_FAIL:
+ WSREP_ERROR("connection failure");
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ default:
+ WSREP_ERROR("unknown connection failure");
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ DBUG_RETURN(WSREP_TRX_ERROR);
+ }
+
+ thd->wsrep_query_state= QUERY_EXEC;
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_RETURN(WSREP_TRX_OK);
+}
+
+
+static int wsrep_hton_init(void *p)
+{
+ wsrep_hton= (handlerton *)p;
+ //wsrep_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
+ wsrep_hton->state= SHOW_OPTION_YES;
+ wsrep_hton->db_type=DB_TYPE_WSREP;
+ wsrep_hton->savepoint_offset= sizeof(my_off_t);
+ wsrep_hton->close_connection= wsrep_close_connection;
+ wsrep_hton->savepoint_set= wsrep_savepoint_set;
+ wsrep_hton->savepoint_rollback= wsrep_savepoint_rollback;
+ wsrep_hton->commit= wsrep_commit;
+ wsrep_hton->rollback= wsrep_rollback;
+ wsrep_hton->prepare= wsrep_prepare;
+ wsrep_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN; // todo: fix flags
+ wsrep_hton->slot= 0;
+ return 0;
+}
+
+
+struct st_mysql_storage_engine wsrep_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+
+mysql_declare_plugin(wsrep)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &wsrep_storage_engine,
+ "wsrep",
+ "Codership Oy",
+ "A pseudo storage engine to represent transactions in multi-master "
+ "synchornous replication",
+ PLUGIN_LICENSE_GPL,
+ wsrep_hton_init, /* Plugin Init */
+ NULL, /* Plugin Deinit */
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL, /* config options */
+ 0, /* flags */
+}
+mysql_declare_plugin_end;
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
new file mode 100644
index 00000000000..53d53c2c404
--- /dev/null
+++ b/sql/wsrep_mysqld.cc
@@ -0,0 +1,1585 @@
+/* Copyright 2008-2013 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <mysqld.h>
+#include <sql_class.h>
+#include <sql_parse.h>
+#include "wsrep_priv.h"
+#include "wsrep_thd.h"
+#include "wsrep_sst.h"
+#include "wsrep_utils.h"
+#include "wsrep_var.h"
+#include "wsrep_binlog.h"
+#include "wsrep_applier.h"
+#include <cstdio>
+#include <cstdlib>
+#include "log_event.h"
+#include <slave.h>
+
+wsrep_t *wsrep = NULL;
+my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
+
+/*
+ * 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;
+const wsrep_uuid_t* wsrep_cluster_uuid()
+{
+ return &cluster_uuid;
+}
+static char cluster_uuid_str[40]= { 0, };
+static const char* cluster_status_str[WSREP_VIEW_MAX] =
+{
+ "Primary",
+ "non-Primary",
+ "Disconnected"
+};
+
+static char provider_name[256]= { 0, };
+static char provider_version[256]= { 0, };
+static char provider_vendor[256]= { 0, };
+
+/*
+ * wsrep status variables
+ */
+my_bool wsrep_connected = FALSE;
+my_bool wsrep_ready = FALSE; // node can accept queries
+const char* wsrep_cluster_state_uuid = cluster_uuid_str;
+long long wsrep_cluster_conf_id = WSREP_SEQNO_UNDEFINED;
+const char* wsrep_cluster_status = cluster_status_str[WSREP_VIEW_DISCONNECTED];
+long wsrep_cluster_size = 0;
+long wsrep_local_index = -1;
+long long wsrep_local_bf_aborts = 0;
+const char* wsrep_provider_name = provider_name;
+const char* wsrep_provider_version = provider_version;
+const char* wsrep_provider_vendor = provider_vendor;
+/* End wsrep status variables */
+
+wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED;
+wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED;
+wsp::node_status local_status;
+long wsrep_protocol_version = 3;
+
+// Boolean denoting if server is in initial startup phase. This is needed
+// to make sure that main thread waiting in wsrep_sst_wait() is signaled
+// if there was no state gap on receiving first view event.
+static my_bool wsrep_startup = TRUE;
+
+
+static void wsrep_log_cb(wsrep_log_level_t level, const char *msg) {
+ switch (level) {
+ case WSREP_LOG_INFO:
+ sql_print_information("WSREP: %s", msg);
+ break;
+ case WSREP_LOG_WARN:
+ sql_print_warning("WSREP: %s", msg);
+ break;
+ case WSREP_LOG_ERROR:
+ case WSREP_LOG_FATAL:
+ sql_print_error("WSREP: %s", msg);
+ break;
+ case WSREP_LOG_DEBUG:
+ if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
+ default:
+ break;
+ }
+}
+
+static void wsrep_log_states (wsrep_log_level_t const level,
+ const wsrep_uuid_t* const group_uuid,
+ wsrep_seqno_t const group_seqno,
+ const wsrep_uuid_t* const node_uuid,
+ wsrep_seqno_t const node_seqno)
+{
+ char uuid_str[37];
+ char msg[256];
+
+ wsrep_uuid_print (group_uuid, uuid_str, sizeof(uuid_str));
+ snprintf (msg, 255, "WSREP: Group state: %s:%lld",
+ uuid_str, (long long)group_seqno);
+ wsrep_log_cb (level, msg);
+
+ wsrep_uuid_print (node_uuid, uuid_str, sizeof(uuid_str));
+ snprintf (msg, 255, "WSREP: Local state: %s:%lld",
+ uuid_str, (long long)node_seqno);
+ wsrep_log_cb (level, msg);
+}
+
+static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
+{
+ XID* xid= reinterpret_cast<XID*>(arg);
+ handlerton* hton= plugin_data(plugin, handlerton *);
+ if (hton->db_type == DB_TYPE_INNODB)
+ {
+ const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid));
+ char uuid_str[40] = {0, };
+ wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
+ WSREP_DEBUG("Set WSREPXid for InnoDB: %s:%lld",
+ uuid_str, (long long)wsrep_xid_seqno(xid));
+ hton->wsrep_set_checkpoint(hton, xid);
+ }
+ return FALSE;
+}
+
+void wsrep_set_SE_checkpoint(XID* xid)
+{
+ plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid);
+}
+
+static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
+{
+ XID* xid= reinterpret_cast<XID*>(arg);
+ handlerton* hton= plugin_data(plugin, handlerton *);
+ if (hton->db_type == DB_TYPE_INNODB)
+ {
+ hton->wsrep_get_checkpoint(hton, xid);
+ const wsrep_uuid_t* uuid(wsrep_xid_uuid(xid));
+ char uuid_str[40] = {0, };
+ wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
+ WSREP_DEBUG("Read WSREPXid from InnoDB: %s:%lld",
+ uuid_str, (long long)wsrep_xid_seqno(xid));
+
+ }
+ return FALSE;
+}
+
+void wsrep_get_SE_checkpoint(XID* xid)
+{
+ plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, xid);
+}
+
+void wsrep_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);
+}
+
+
+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;
+ wsrep_ready_set(FALSE);
+ WSREP_INFO("closing client connections for "
+ "protocol change %ld -> %d",
+ wsrep_protocol_version, view->proto_ver);
+ wsrep_close_client_connections(TRUE);
+ wsrep_protocol_version= view->proto_ver;
+ wsrep_ready_set(wsrep_ready_saved);
+ }
+ break;
+ default:
+ WSREP_ERROR("Unsupported application protocol version: %d",
+ view->proto_ver);
+ unireg_abort(1);
+ }
+
+ if (view->state_gap)
+ {
+ WSREP_WARN("Gap in state sequence. Need state transfer.");
+
+ /* After that wsrep will call wsrep_sst_prepare. */
+ /* keep ready flag 0 until we receive the snapshot */
+ wsrep_ready_set(FALSE);
+
+ /* Close client connections to ensure that they don't interfere
+ * with SST. Necessary only if storage engines are initialized
+ * before SST.
+ * TODO: Just killing all ongoing transactions should be enough
+ * since wsrep_ready is OFF and no new transactions can start.
+ */
+ if (!wsrep_before_SE())
+ {
+ WSREP_DEBUG("[debug]: closing client connections for PRIM");
+ wsrep_close_client_connections(TRUE);
+ }
+
+ ssize_t const req_len= wsrep_sst_prepare (sst_req);
+
+ if (req_len < 0)
+ {
+ WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len,
+ strerror(-req_len));
+ new_status= WSREP_MEMBER_UNDEFINED;
+ }
+ else
+ {
+ assert(sst_req != NULL);
+ *sst_req_len= req_len;
+ new_status= WSREP_MEMBER_JOINER;
+ }
+ }
+ else
+ {
+ /*
+ * NOTE: Initialize wsrep_group_uuid here only if it wasn't initialized
+ * before - OR - it was reinitilized on startup (lp:992840)
+ */
+ if (wsrep_startup)
+ {
+ if (wsrep_before_SE())
+ {
+ wsrep_SE_init_grab();
+ // Signal mysqld init thread to continue
+ wsrep_sst_complete (&cluster_uuid, view->state_id.seqno, false);
+ // and wait for SE initialization
+ wsrep_SE_init_wait();
+ }
+ else
+ {
+ local_uuid= cluster_uuid;
+ local_seqno= view->state_id.seqno;
+ }
+ /* Init storage engine XIDs from first view */
+ XID xid;
+ wsrep_xid_init(&xid, &local_uuid, local_seqno);
+ wsrep_set_SE_checkpoint(&xid);
+ new_status= WSREP_MEMBER_JOINED;
+ }
+
+ // just some sanity check
+ if (memcmp (&local_uuid, &cluster_uuid, sizeof (wsrep_uuid_t)))
+ {
+ WSREP_ERROR("Undetected state gap. Can't continue.");
+ wsrep_log_states(WSREP_LOG_FATAL, &cluster_uuid, view->state_id.seqno,
+ &local_uuid, -1);
+ unireg_abort(1);
+ }
+ }
+
+ if (wsrep_auto_increment_control)
+ {
+ global_system_variables.auto_increment_offset= view->my_idx + 1;
+ global_system_variables.auto_increment_increment= view->memb_num;
+ }
+
+ { /* capabilities may be updated on new configuration */
+ uint64_t const caps(wsrep->capabilities (wsrep));
+
+ my_bool const idc((caps & WSREP_CAP_INCREMENTAL_WRITESET) != 0);
+ if (TRUE == wsrep_incremental_data_collection && FALSE == idc)
+ {
+ WSREP_WARN("Unsupported protocol downgrade: "
+ "incremental data collection disabled. Expect abort.");
+ }
+ wsrep_incremental_data_collection = idc;
+ }
+
+out:
+ if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE;
+ local_status.set(new_status, view);
+
+ return WSREP_CB_SUCCESS;
+}
+
+void wsrep_ready_set (my_bool x)
+{
+ WSREP_DEBUG("Setting wsrep_ready to %d", x);
+ if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
+ if (wsrep_ready != x)
+ {
+ wsrep_ready= x;
+ mysql_cond_signal (&COND_wsrep_ready);
+ }
+ mysql_mutex_unlock (&LOCK_wsrep_ready);
+}
+
+// Wait until wsrep has reached ready state
+void wsrep_ready_wait ()
+{
+ if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
+ while (!wsrep_ready)
+ {
+ WSREP_INFO("Waiting to reach ready state");
+ mysql_cond_wait (&COND_wsrep_ready, &LOCK_wsrep_ready);
+ }
+ WSREP_INFO("ready state reached");
+ mysql_mutex_unlock (&LOCK_wsrep_ready);
+}
+
+static void wsrep_synced_cb(void* app_ctx)
+{
+ WSREP_INFO("Synchronized with group, ready for connections");
+ bool signal_main= false;
+ if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
+ if (!wsrep_ready)
+ {
+ wsrep_ready= TRUE;
+ mysql_cond_signal (&COND_wsrep_ready);
+ signal_main= true;
+
+ }
+ local_status.set(WSREP_MEMBER_SYNCED);
+ mysql_mutex_unlock (&LOCK_wsrep_ready);
+
+ if (signal_main)
+ {
+ wsrep_SE_init_grab();
+ // Signal mysqld init thread to continue
+ wsrep_sst_complete (&local_uuid, local_seqno, false);
+ // and wait for SE initialization
+ wsrep_SE_init_wait();
+ }
+ if (wsrep_restart_slave_activated)
+ {
+ int rcode;
+ WSREP_INFO("MySQL slave restart");
+ wsrep_restart_slave_activated= FALSE;
+
+ mysql_mutex_lock(&LOCK_active_mi);
+ if ((rcode = start_slave_threads(1 /* need mutex */,
+ 0 /* no wait for start*/,
+ active_mi,
+ 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 */
+ XID xid;
+ memset(&xid, 0, sizeof(xid));
+ xid.formatID= -1;
+ wsrep_get_SE_checkpoint(&xid);
+
+ if (xid.formatID == -1)
+ {
+ WSREP_INFO("Read nil XID from storage engines, skipping position init");
+ return;
+ }
+ else if (!wsrep_is_wsrep_xid(&xid))
+ {
+ WSREP_WARN("Read non-wsrep XID from storage engines, skipping position init");
+ return;
+ }
+
+ const wsrep_uuid_t* uuid= wsrep_xid_uuid(&xid);
+ const wsrep_seqno_t seqno= wsrep_xid_seqno(&xid);
+
+ char uuid_str[40] = {0, };
+ wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
+ WSREP_INFO("Initial position: %s:%lld", uuid_str, (long long)seqno);
+
+
+ if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(local_uuid)) &&
+ local_seqno == WSREP_SEQNO_UNDEFINED)
+ {
+ // Initial state
+ local_uuid= *uuid;
+ local_seqno= seqno;
+ }
+ else if (memcmp(&local_uuid, uuid, sizeof(local_uuid)) ||
+ local_seqno != seqno)
+ {
+ WSREP_WARN("Initial position was provided by configuration or SST, "
+ "avoiding override");
+ }
+}
+
+extern const 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
+ (void) wsrep_init();
+ return rcode;
+ }
+ else /* this is for recursive call above */
+ {
+ WSREP_ERROR("Could not revert to no provider: %s (%d). Need to abort.",
+ strerror(rcode), rcode);
+ unireg_abort(1);
+ }
+ }
+
+ if (!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)
+ {
+ const char* const colon= strrchr(node_addr, ':');
+ if (strchr(node_addr, ':') == colon) // 1 or 0 ':'
+ {
+ size_t const ip_len= colon ? colon - node_addr : node_addr_len;
+ if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
+ {
+ memcpy (inc_addr, node_addr, ip_len);
+ snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
+ (int)mysqld_port);
+ }
+ else
+ {
+ WSREP_WARN("Guessing address for incoming client connections: "
+ "address too long.");
+ inc_addr[0]= '\0';
+ }
+ }
+ else
+ {
+ WSREP_WARN("Guessing address for incoming client connections: "
+ "too many colons :) .");
+ inc_addr[0]= '\0';
+ }
+ }
+
+ if (!strlen(inc_addr))
+ {
+ WSREP_WARN("Guessing address for incoming client connections failed. "
+ "Try setting wsrep_node_incoming_address explicitly.");
+ }
+ }
+ }
+ else if (!strchr(wsrep_node_incoming_address, ':')) // no port included
+ {
+ if ((int)inc_addr_max <=
+ snprintf(inc_addr, inc_addr_max, "%s:%u",
+ wsrep_node_incoming_address,(int)mysqld_port))
+ {
+ WSREP_WARN("Guessing address for incoming client connections: "
+ "address too long.");
+ inc_addr[0]= '\0';
+ }
+ }
+ else
+ {
+ size_t const need = strlen (wsrep_node_incoming_address);
+ if (need >= inc_addr_max) {
+ WSREP_WARN("wsrep_node_incoming_address too long: %zu", need);
+ inc_addr[0]= '\0';
+ }
+ else {
+ memcpy (inc_addr, wsrep_node_incoming_address, need);
+ }
+ }
+
+ struct wsrep_init_args wsrep_args;
+
+ struct wsrep_gtid const state_id = { local_uuid, local_seqno };
+
+ wsrep_args.data_dir = wsrep_data_home_dir;
+ wsrep_args.node_name = (wsrep_node_name) ? wsrep_node_name : "";
+ wsrep_args.node_address = node_addr;
+ wsrep_args.node_incoming = inc_addr;
+ wsrep_args.options = (wsrep_provider_options) ?
+ wsrep_provider_options : "";
+ wsrep_args.proto_ver = wsrep_max_protocol_version;
+
+ wsrep_args.state_id = &state_id;
+
+ wsrep_args.logger_cb = wsrep_log_cb;
+ wsrep_args.view_handler_cb = wsrep_view_handler_cb;
+ wsrep_args.apply_cb = wsrep_apply_cb;
+ wsrep_args.commit_cb = wsrep_commit_cb;
+ wsrep_args.unordered_cb = wsrep_unordered_cb;
+ wsrep_args.sst_donate_cb = wsrep_sst_donate_cb;
+ wsrep_args.synced_cb = wsrep_synced_cb;
+
+ rcode = wsrep->init(wsrep, &wsrep_args);
+
+ if (rcode)
+ {
+ DBUG_PRINT("wsrep",("wsrep::init() failed: %d", rcode));
+ WSREP_ERROR("wsrep::init() failed: %d, must shutdown", rcode);
+ wsrep->free(wsrep);
+ free(wsrep);
+ wsrep = NULL;
+ } else {
+ wsrep_inited= 1;
+ }
+
+ return rcode;
+}
+
+extern "C" int wsrep_on(void *);
+
+void wsrep_init_startup (bool first)
+{
+ if (wsrep_init()) unireg_abort(1);
+
+ wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_abort_thd,
+ wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on);
+
+ /* Skip replication start if no cluster address */
+ if (!wsrep_cluster_address || strlen(wsrep_cluster_address) == 0) return;
+
+ if (first) wsrep_sst_grab(); // do it so we can wait for SST below
+
+ if (!wsrep_start_replication()) unireg_abort(1);
+
+ wsrep_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;
+ }
+ XID xid;
+ memset(&xid, 0, sizeof(xid));
+ xid.formatID= -1;
+ wsrep_get_SE_checkpoint(&xid);
+ char uuid_str[40];
+ wsrep_uuid_print(wsrep_xid_uuid(&xid), uuid_str, sizeof(uuid_str));
+ WSREP_INFO("Recovered position: %s:%lld", uuid_str,
+ (long long)wsrep_xid_seqno(&xid));
+}
+
+
+void wsrep_stop_replication(THD *thd)
+{
+ WSREP_INFO("Stop replication");
+ if (!wsrep)
+ {
+ WSREP_INFO("Provider was not loaded, in stop replication");
+ return;
+ }
+
+ /* disconnect from group first to get wsrep_ready == FALSE */
+ WSREP_DEBUG("Provider disconnect");
+ wsrep->disconnect(wsrep);
+
+ wsrep_connected= FALSE;
+
+ wsrep_close_client_connections(TRUE);
+
+ /* wait until appliers have stopped */
+ wsrep_wait_appliers_close(thd);
+
+ return;
+}
+
+/* This one is set to true when --wsrep-new-cluster is found in the command
+ * line arguments */
+static my_bool wsrep_new_cluster= FALSE;
+#define WSREP_NEW_CLUSTER "--wsrep-new-cluster"
+/* Finds and hides --wsrep-new-cluster from the arguments list
+ * by moving it to the end of the list and decrementing argument count */
+void wsrep_filter_new_cluster (int* argc, char* argv[])
+{
+ int i;
+ for (i= *argc - 1; i > 0; i--)
+ {
+ /* make a copy of the argument to convert possible underscores to hyphens.
+ * the copy need not to be longer than WSREP_NEW_CLUSTER option */
+ char arg[sizeof(WSREP_NEW_CLUSTER) + 1]= { 0, };
+ strncpy(arg, argv[i], sizeof(arg) - 1);
+ char* underscore(arg);
+ while (NULL != (underscore= strchr(underscore, '_'))) *underscore= '-';
+
+ if (!strcmp(arg, WSREP_NEW_CLUSTER))
+ {
+ wsrep_new_cluster= TRUE;
+ *argc -= 1;
+ /* preserve the order of remaining arguments AND
+ * preserve the original argument pointers - just in case */
+ char* wnc= argv[i];
+ memmove(&argv[i], &argv[i + 1], (*argc - i)*sizeof(argv[i]));
+ argv[*argc]= wnc; /* this will be invisible to the rest of the program */
+ }
+ }
+}
+
+bool wsrep_start_replication()
+{
+ wsrep_status_t rcode;
+
+ /*
+ if provider is trivial, don't even try to connect,
+ but resume local node operation
+ */
+ if (!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(TRUE == wsrep_new_cluster);
+ wsrep_new_cluster= FALSE;
+
+ WSREP_INFO("Start replication");
+
+ if ((rcode = wsrep->connect(wsrep,
+ wsrep_cluster_name,
+ wsrep_cluster_address,
+ wsrep_sst_donor,
+ bootstrap)))
+ {
+ 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;
+}
+
+/*
+ * Helpers to deal with TOI key arrays
+ */
+typedef struct wsrep_key_arr
+{
+ wsrep_key_t* keys;
+ size_t keys_len;
+} wsrep_key_arr_t;
+
+
+static void wsrep_keys_free(wsrep_key_arr_t* key_arr)
+{
+ for (size_t i= 0; i < key_arr->keys_len; ++i)
+ {
+ my_free((void*)key_arr->keys[i].key_parts);
+ }
+ my_free(key_arr->keys);
+ key_arr->keys= 0;
+ key_arr->keys_len= 0;
+}
+
+
+/*!
+ * @param db Database string
+ * @param table Table string
+ * @param key Array of wsrep_key_t
+ * @param key_len In: number of elements in key array, Out: number of
+ * elements populated
+ *
+ * @return true if preparation was successful, otherwise false.
+ */
+
+static bool wsrep_prepare_key_for_isolation(const char* db,
+ const char* table,
+ wsrep_buf_t* key,
+ size_t* key_len)
+{
+ if (*key_len < 2) return false;
+
+ switch (wsrep_protocol_version)
+ {
+ case 0:
+ *key_len= 0;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ {
+ *key_len= 0;
+ if (db)
+ {
+ // sql_print_information("%s.%s", db, table);
+ if (db)
+ {
+ key[*key_len].ptr= db;
+ key[*key_len].len= strlen(db);
+ ++(*key_len);
+ if (table)
+ {
+ key[*key_len].ptr= table;
+ key[*key_len].len= strlen(table);
+ ++(*key_len);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/* Prepare key list from db/table and table_list */
+static bool wsrep_prepare_keys_for_isolation(THD* thd,
+ const char* db,
+ const char* table,
+ const TABLE_LIST* table_list,
+ wsrep_key_arr_t* ka)
+{
+ ka->keys= 0;
+ ka->keys_len= 0;
+
+ extern TABLE* find_temporary_table(THD*, const TABLE_LIST*);
+
+ if (db || table)
+ {
+ TABLE_LIST tmp_table;
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.table_name= (char*)db;
+ tmp_table.db= (char*)table;
+ if (!table || !find_temporary_table(thd, &tmp_table))
+ {
+ if (!(ka->keys= (wsrep_key_t*)my_malloc(sizeof(wsrep_key_t), MYF(0))))
+ {
+ WSREP_ERROR("Can't allocate memory for key_array");
+ goto err;
+ }
+ ka->keys_len= 1;
+ if (!(ka->keys[0].key_parts= (wsrep_buf_t*)
+ my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
+ {
+ WSREP_ERROR("Can't allocate memory for key_parts");
+ goto err;
+ }
+ ka->keys[0].key_parts_num= 2;
+ if (!wsrep_prepare_key_for_isolation(
+ db, table,
+ (wsrep_buf_t*)ka->keys[0].key_parts,
+ &ka->keys[0].key_parts_num))
+ {
+ WSREP_ERROR("Preparing keys for isolation failed");
+ goto err;
+ }
+ }
+ }
+
+ for (const TABLE_LIST* table= table_list; table; table= table->next_global)
+ {
+ if (!find_temporary_table(thd, table))
+ {
+ wsrep_key_t* tmp;
+ tmp= (wsrep_key_t*)my_realloc(
+ ka->keys, (ka->keys_len + 1) * sizeof(wsrep_key_t), MYF(0));
+ if (!tmp)
+ {
+ WSREP_ERROR("Can't allocate memory for key_array");
+ goto err;
+ }
+ ka->keys= tmp;
+ if (!(ka->keys[ka->keys_len].key_parts= (wsrep_buf_t*)
+ my_malloc(sizeof(wsrep_buf_t)*2, MYF(0))))
+ {
+ WSREP_ERROR("Can't allocate memory for key_parts");
+ goto err;
+ }
+ ka->keys[ka->keys_len].key_parts_num= 2;
+ ++ka->keys_len;
+ if (!wsrep_prepare_key_for_isolation(
+ table->db, table->table_name,
+ (wsrep_buf_t*)ka->keys[ka->keys_len - 1].key_parts,
+ &ka->keys[ka->keys_len - 1].key_parts_num))
+ {
+ WSREP_ERROR("Preparing keys for isolation failed");
+ goto err;
+ }
+ }
+ }
+ return true;
+err:
+ wsrep_keys_free(ka);
+ return false;
+}
+
+
+bool wsrep_prepare_key_for_innodb(const uchar* cache_key,
+ size_t cache_key_len,
+ const uchar* row_id,
+ size_t row_id_len,
+ wsrep_buf_t* key,
+ size_t* key_len)
+{
+ if (*key_len < 3) return false;
+
+ *key_len= 0;
+ switch (wsrep_protocol_version)
+ {
+ case 0:
+ {
+ key[0].ptr = cache_key;
+ key[0].len = cache_key_len;
+
+ *key_len = 1;
+ break;
+ }
+ case 1:
+ case 2:
+ case 3:
+ {
+ key[0].ptr = cache_key;
+ key[0].len = strlen( (char*)cache_key );
+
+ key[1].ptr = cache_key + strlen( (char*)cache_key ) + 1;
+ key[1].len = strlen( (char*)(key[1].ptr) );
+
+ *key_len = 2;
+ break;
+ }
+ default:
+ return false;
+ }
+
+ key[*key_len].ptr = row_id;
+ key[*key_len].len = row_id_len;
+ ++(*key_len);
+
+ return true;
+}
+
+
+/*
+ * Construct Query_log_Event from thd query and serialize it
+ * into buffer.
+ *
+ * Return 0 in case of success, 1 in case of error.
+ */
+int wsrep_to_buf_helper(
+ THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len)
+{
+ IO_CACHE tmp_io_cache;
+ if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX,
+ 65536, MYF(MY_WME)))
+ return 1;
+
+ int ret(0);
+
+ 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;
+
+ /* if there is prepare query, add event for it */
+ if (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;
+ }
+
+ /* append the actual query */
+ Query_log_event ev(thd, query, query_len, FALSE, FALSE, FALSE, 0);
+ if (ev.write(&tmp_io_cache)) ret= 1;
+
+ if (!ret && wsrep_write_cache_buf(&tmp_io_cache, buf, buf_len)) ret= 1;
+
+ close_cached_file(&tmp_io_cache);
+ return ret;
+}
+
+#include "sql_show.h"
+static int
+create_view_query(THD *thd, uchar** buf, size_t* buf_len)
+{
+ LEX *lex= thd->lex;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ TABLE_LIST *first_table= select_lex->table_list.first;
+ TABLE_LIST *views = first_table;
+
+ String buff;
+ const LEX_STRING command[3]=
+ {{ C_STRING_WITH_LEN("CREATE ") },
+ { C_STRING_WITH_LEN("ALTER ") },
+ { C_STRING_WITH_LEN("CREATE OR REPLACE ") }};
+
+ buff.append(command[thd->lex->create_view_mode].str,
+ command[thd->lex->create_view_mode].length);
+
+ if (!lex->definer)
+ {
+ /*
+ DEFINER-clause is missing; we have to create default definer in
+ persistent arena to be PS/SP friendly.
+ If this is an ALTER VIEW then the current user should be set as
+ the definer.
+ */
+
+ if (!(lex->definer= create_default_definer(thd)))
+ {
+ WSREP_WARN("view default definer issue");
+ }
+ }
+
+ views->algorithm = lex->create_view_algorithm;
+ views->definer.user = lex->definer->user;
+ views->definer.host = lex->definer->host;
+ views->view_suid = lex->create_view_suid;
+ views->with_check = lex->create_view_check;
+
+ view_store_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);
+}
+
+static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
+ const TABLE_LIST* table_list)
+{
+ wsrep_status_t ret(WSREP_WARNING);
+ uchar* buf(0);
+ size_t buf_len(0);
+ int buf_err;
+
+ WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode, thd->query() );
+ switch (thd->lex->sql_command)
+ {
+ case SQLCOM_CREATE_VIEW:
+ buf_err= create_view_query(thd, &buf, &buf_len);
+ break;
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_CREATE_SPFUNCTION:
+ buf_err= wsrep_create_sp(thd, &buf, &buf_len);
+ break;
+ case SQLCOM_CREATE_TRIGGER:
+ buf_err= wsrep_create_trigger_query(thd, &buf, &buf_len);
+ break;
+ case SQLCOM_CREATE_EVENT:
+ buf_err= wsrep_create_event_query(thd, &buf, &buf_len);
+ break;
+ case SQLCOM_ALTER_EVENT:
+ buf_err= wsrep_alter_event_query(thd, &buf, &buf_len);
+ break;
+ default:
+ buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), &buf,
+ &buf_len);
+ break;
+ }
+
+ wsrep_key_arr_t key_arr= {0, 0};
+ struct wsrep_buf buff = { buf, buf_len };
+ if (!buf_err &&
+ wsrep_prepare_keys_for_isolation(thd, db_, table_, table_list, &key_arr)&&
+ WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
+ key_arr.keys, key_arr.keys_len,
+ &buff, 1,
+ &thd->wsrep_trx_meta)))
+ {
+ thd->wsrep_exec_mode= TOTAL_ORDER;
+ wsrep_to_isolation++;
+ if (buf) my_free(buf);
+ wsrep_keys_free(&key_arr);
+ WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode);
+ }
+ else {
+ /* jump to error handler in mysql_execute_command() */
+ WSREP_WARN("TO isolation failed for: %d, sql: %s. Check wsrep "
+ "connection state and retry the query.",
+ ret, (thd->query()) ? thd->query() : "void");
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
+ "your wsrep connection state and retry the query.");
+ if (buf) my_free(buf);
+ wsrep_keys_free(&key_arr);
+ return -1;
+ }
+ return 0;
+}
+
+static void wsrep_TOI_end(THD *thd) {
+ wsrep_status_t ret;
+ wsrep_to_isolation--;
+
+ WSREP_DEBUG("TO END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode, (thd->query()) ? thd->query() : "void");
+
+ XID xid;
+ wsrep_xid_init(&xid, &thd->wsrep_trx_meta.gtid.uuid,
+ thd->wsrep_trx_meta.gtid.seqno);
+ wsrep_set_SE_checkpoint(&xid);
+ WSREP_DEBUG("TO END: %lld, update seqno",
+ (long long)wsrep_thd_trx_seqno(thd));
+
+ if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) {
+ WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd));
+ }
+ else {
+ WSREP_WARN("TO isolation end failed for: %d, sql: %s",
+ ret, (thd->query()) ? thd->query() : "void");
+ }
+}
+
+static int wsrep_RSU_begin(THD *thd, char *db_, char *table_)
+{
+ wsrep_status_t ret(WSREP_WARNING);
+ WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode, thd->query() );
+
+ ret = wsrep->desync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("RSU desync failed %d for %s", ret, thd->query());
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ return(ret);
+ }
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ wsrep_replaying++;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+
+ if (wsrep_wait_committing_connections_close(5000))
+ {
+ /* no can do, bail out from DDL */
+ WSREP_WARN("RSU failed due to pending transactions, %s", thd->query());
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ wsrep_replaying--;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+
+ ret = wsrep->resync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resync failed %d for %s", ret, thd->query());
+ }
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ return(1);
+ }
+
+ wsrep_seqno_t seqno = wsrep->pause(wsrep);
+ if (seqno == WSREP_SEQNO_UNDEFINED)
+ {
+ WSREP_WARN("pause failed %lld for %s", (long long)seqno, thd->query());
+ return(1);
+ }
+ WSREP_DEBUG("paused at %lld", (long long)seqno);
+ thd->variables.wsrep_on = 0;
+ return 0;
+}
+
+static void wsrep_RSU_end(THD *thd)
+{
+ wsrep_status_t ret(WSREP_WARNING);
+ WSREP_DEBUG("RSU END: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_exec_mode, thd->query() );
+
+
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ wsrep_replaying--;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+
+ ret = wsrep->resume(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resume failed %d for %s", ret, thd->query());
+ }
+ ret = wsrep->resync(wsrep);
+ if (ret != WSREP_OK)
+ {
+ WSREP_WARN("resync failed %d for %s", ret, thd->query());
+ return;
+ }
+ thd->variables.wsrep_on = 1;
+}
+
+int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
+ const TABLE_LIST* table_list)
+{
+
+ /*
+ No isolation for applier or replaying threads.
+ */
+ if (thd->wsrep_exec_mode == REPL_RECV) return 0;
+
+ int ret= 0;
+ mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ if (thd->wsrep_conflict_state == MUST_ABORT)
+ {
+ WSREP_INFO("thread: %lu, %s has been aborted due to multi-master conflict",
+ thd->thread_id, thd->query());
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ return WSREP_TRX_FAIL;
+ }
+ mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+
+ DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
+ DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
+
+ if (thd->global_read_lock.can_acquire_protection())
+ {
+ WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lu",
+ thd->query(), thd->thread_id);
+ return -1;
+ }
+
+ if (wsrep_debug && thd->mdl_context.has_locks())
+ {
+ WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lu",
+ thd->query(), thd->thread_id);
+ }
+
+ /*
+ It makes sense to set auto_increment_* to defaults in TOI operations.
+ Must be done before wsrep_TOI_begin() since Query_log_event encapsulating
+ TOI statement and auto inc variables for wsrep replication is constructed
+ there. Variables are reset back in THD::reset_for_next_command() before
+ processing of next command.
+ */
+ if (wsrep_auto_increment_control)
+ {
+ thd->variables.auto_increment_offset = 1;
+ thd->variables.auto_increment_increment = 1;
+ }
+
+ if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE)
+ {
+ switch (wsrep_OSU_method_options) {
+ case WSREP_OSU_TOI: ret = wsrep_TOI_begin(thd, db_, table_,
+ table_list); break;
+ case WSREP_OSU_RSU: ret = wsrep_RSU_begin(thd, db_, table_); break;
+ }
+ if (!ret)
+ {
+ thd->wsrep_exec_mode= TOTAL_ORDER;
+ }
+ }
+ return ret;
+}
+
+void wsrep_to_isolation_end(THD *thd)
+{
+ if (thd->wsrep_exec_mode == TOTAL_ORDER)
+ {
+ switch(wsrep_OSU_method_options)
+ {
+ case WSREP_OSU_TOI: wsrep_TOI_end(thd); break;
+ case WSREP_OSU_RSU: wsrep_RSU_end(thd); break;
+ }
+ wsrep_cleanup_transaction(thd);
+ }
+}
+
+#define WSREP_MDL_LOG(severity, msg, req, gra) \
+ WSREP_##severity( \
+ "%s\n" \
+ "request: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n" \
+ "granted: (%lu \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)", \
+ msg, \
+ req->thread_id, (long long)wsrep_thd_trx_seqno(req), \
+ req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \
+ req->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->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
+) {
+ /* 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;
+
+ mysql_mutex_lock(&request_thd->LOCK_wsrep_thd);
+ if (request_thd->wsrep_exec_mode == TOTAL_ORDER ||
+ request_thd->wsrep_exec_mode == REPL_RECV)
+ {
+ mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
+ WSREP_MDL_LOG(DEBUG, "MDL conflict ", request_thd, granted_thd);
+ ticket->wsrep_report(wsrep_debug);
+
+ mysql_mutex_lock(&granted_thd->LOCK_wsrep_thd);
+ if (granted_thd->wsrep_exec_mode == TOTAL_ORDER ||
+ granted_thd->wsrep_exec_mode == REPL_RECV)
+ {
+ WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", request_thd, granted_thd);
+ ticket->wsrep_report(true);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ ret = TRUE;
+ }
+ else if (granted_thd->lex->sql_command == SQLCOM_FLUSH)
+ {
+ WSREP_DEBUG("mdl granted over FLUSH BF");
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ ret = TRUE;
+ }
+ else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
+ {
+ WSREP_DEBUG("DROP caused BF abort");
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
+ ret = FALSE;
+ }
+ else if (granted_thd->wsrep_query_state == QUERY_COMMITTING)
+ {
+ WSREP_DEBUG("mdl granted, but commiting thd abort scheduled");
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
+ ret = FALSE;
+ }
+ else
+ {
+ WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", request_thd, granted_thd);
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_wsrep_thd);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
+ ret = FALSE;
+ }
+ }
+ else
+ {
+ mysql_mutex_unlock(&request_thd->LOCK_wsrep_thd);
+ }
+ return ret;
+}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
new file mode 100644
index 00000000000..bd45399a948
--- /dev/null
+++ b/sql/wsrep_mysqld.h
@@ -0,0 +1,325 @@
+/* Copyright 2008-2013 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef WSREP_MYSQLD_H
+#define WSREP_MYSQLD_H
+
+#include "mysqld.h"
+typedef struct st_mysql_show_var SHOW_VAR;
+#include <sql_priv.h>
+#include "../wsrep/wsrep_api.h"
+
+#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX
+
+class set_var;
+class THD;
+
+enum wsrep_exec_mode {
+ LOCAL_STATE,
+ REPL_RECV,
+ TOTAL_ORDER,
+ LOCAL_COMMIT
+};
+
+enum wsrep_query_state {
+ QUERY_IDLE,
+ QUERY_EXEC,
+ QUERY_COMMITTING,
+ QUERY_EXITING,
+ QUERY_ROLLINGBACK,
+};
+
+enum wsrep_conflict_state {
+ NO_CONFLICT,
+ MUST_ABORT,
+ ABORTING,
+ ABORTED,
+ MUST_REPLAY,
+ REPLAYING,
+ RETRY_AUTOCOMMIT,
+ CERT_FAILURE,
+};
+
+enum wsrep_consistency_check_mode {
+ NO_CONSISTENCY_CHECK,
+ CONSISTENCY_CHECK_DECLARED,
+ CONSISTENCY_CHECK_RUNNING,
+};
+
+
+// Global wsrep parameters
+extern wsrep_t* wsrep;
+
+// MySQL wsrep options
+extern const char* wsrep_provider;
+extern const char* wsrep_provider_options;
+extern const char* wsrep_cluster_name;
+extern const char* wsrep_cluster_address;
+extern const char* wsrep_node_name;
+extern const char* wsrep_node_address;
+extern const char* wsrep_node_incoming_address;
+extern const char* wsrep_data_home_dir;
+extern const char* wsrep_dbug_option;
+extern long wsrep_slave_threads;
+extern int wsrep_slave_count_change;
+extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug;
+extern my_bool wsrep_convert_LOCK_to_trx;
+extern ulong wsrep_retry_autocommit;
+extern my_bool wsrep_auto_increment_control;
+extern my_bool wsrep_drupal_282555_workaround;
+extern my_bool wsrep_incremental_data_collection;
+extern 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 ulong wsrep_OSU_method_options;
+extern my_bool wsrep_desync;
+extern my_bool wsrep_recovery;
+extern my_bool wsrep_replicate_myisam;
+extern my_bool wsrep_log_conflicts;
+extern ulong wsrep_mysql_replication_bundle;
+extern my_bool wsrep_load_data_splitting;
+extern my_bool wsrep_restart_slave;
+extern my_bool wsrep_restart_slave_activated;
+extern my_bool wsrep_slave_FK_checks;
+extern my_bool wsrep_slave_UK_checks;
+extern my_bool wsrep_creating_startup_threads;
+
+enum enum_wsrep_OSU_method { WSREP_OSU_TOI, WSREP_OSU_RSU };
+enum enum_wsrep_sync_wait {
+ WSREP_SYNC_WAIT_NONE = 0x0,
+ // show, select, begin
+ WSREP_SYNC_WAIT_BEFORE_READ = 0x1,
+ WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE = 0x2,
+ WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE = 0x4,
+ WSREP_SYNC_WAIT_MAX = 0x7
+};
+
+// MySQL status variables
+extern my_bool wsrep_connected;
+extern my_bool wsrep_ready;
+extern const char* wsrep_cluster_state_uuid;
+extern long long wsrep_cluster_conf_id;
+extern const char* wsrep_cluster_status;
+extern long wsrep_cluster_size;
+extern long wsrep_local_index;
+extern long long wsrep_local_bf_aborts;
+extern const char* wsrep_provider_name;
+extern const char* wsrep_provider_version;
+extern const char* wsrep_provider_vendor;
+
+// Other wsrep global variables
+extern my_bool wsrep_inited; // whether wsrep is initialized ?
+
+int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
+void wsrep_free_status(THD *thd);
+
+/* Filters out --wsrep-new-cluster oprtion from argv[]
+ * should be called in the very beginning of main() */
+void wsrep_filter_new_cluster (int* argc, char* argv[]);
+
+int wsrep_init();
+void wsrep_deinit(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);
+
+
+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* bf_thd, THD *thd, my_bool signal);
+
+
+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);
+/* some inline functions are defined in wsrep_mysqld_inl.h */
+
+/* Other global variables */
+extern wsrep_seqno_t wsrep_locked_seqno;
+
+#define WSREP_ON \
+ (global_system_variables.wsrep_on)
+
+#define WSREP(thd) \
+ (WSREP_ON && wsrep && (thd && thd->variables.wsrep_on))
+
+#define WSREP_CLIENT(thd) \
+ (WSREP(thd) && thd->wsrep_client_thread)
+
+#define WSREP_EMULATE_BINLOG(thd) \
+ (WSREP(thd) && wsrep_emulate_bin_log)
+
+// MySQL logging functions don't seem to understand long long length modifer.
+// This is a workaround. It also prefixes all messages with "WSREP"
+#define WSREP_LOG(fun, ...) \
+ { \
+ char msg[1024] = {'\0'}; \
+ snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \
+ fun("WSREP: %s", msg); \
+ }
+
+#define WSREP_DEBUG(...) \
+ if (wsrep_debug) WSREP_LOG(sql_print_information, ##__VA_ARGS__)
+#define WSREP_INFO(...) WSREP_LOG(sql_print_information, ##__VA_ARGS__)
+#define WSREP_WARN(...) WSREP_LOG(sql_print_warning, ##__VA_ARGS__)
+#define WSREP_ERROR(...) WSREP_LOG(sql_print_error, ##__VA_ARGS__)
+
+#define WSREP_LOG_CONFLICT_THD(thd, role) \
+ WSREP_LOG(sql_print_information, \
+ "%s: \n " \
+ " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \
+ " SQL: %s", \
+ role, wsrep_thd_thread_id(thd), wsrep_thd_exec_mode_str(thd), \
+ wsrep_thd_query_state_str(thd), \
+ wsrep_thd_conflict_state_str(thd), (long long)wsrep_thd_trx_seqno(thd), \
+ wsrep_thd_query(thd) \
+ );
+
+#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \
+ if (wsrep_debug || wsrep_log_conflicts) \
+ { \
+ WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:",\
+ (bf_abort) ? "high priority abort" : "certification failure" \
+ ); \
+ if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
+ if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \
+ }
+
+#define WSREP_PROVIDER_EXISTS \
+ (wsrep_provider && strncasecmp(wsrep_provider, WSREP_NONE, FN_REFLEN))
+
+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 HAVE_PSI_INTERFACE
+extern PSI_mutex_key key_LOCK_wsrep_ready;
+extern PSI_mutex_key key_COND_wsrep_ready;
+extern PSI_mutex_key key_LOCK_wsrep_sst;
+extern PSI_cond_key key_COND_wsrep_sst;
+extern PSI_mutex_key key_LOCK_wsrep_sst_init;
+extern PSI_cond_key key_COND_wsrep_sst_init;
+extern PSI_mutex_key key_LOCK_wsrep_sst_thread;
+extern PSI_cond_key key_COND_wsrep_sst_thread;
+extern PSI_mutex_key key_LOCK_wsrep_rollback;
+extern PSI_cond_key key_COND_wsrep_rollback;
+extern PSI_mutex_key key_LOCK_wsrep_replaying;
+extern PSI_cond_key key_COND_wsrep_replaying;
+extern PSI_mutex_key key_LOCK_wsrep_slave_threads;
+extern PSI_mutex_key key_LOCK_wsrep_desync;
+#endif /* HAVE_PSI_INTERFACE */
+struct TABLE_LIST;
+int wsrep_to_isolation_begin(THD *thd, char *db_, char *table_,
+ const TABLE_LIST* table_list);
+void wsrep_to_isolation_end(THD *thd);
+void wsrep_cleanup_transaction(THD *thd);
+int wsrep_to_buf_helper(
+ THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len);
+int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
+int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
+int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len);
+int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len);
+
+struct xid_t;
+void wsrep_set_SE_checkpoint(xid_t*);
+void wsrep_get_SE_checkpoint(wsrep_uuid_t&, wsrep_seqno_t&);
+void wsrep_xid_init(xid_t*, const wsrep_uuid_t*, wsrep_seqno_t);
+const wsrep_uuid_t* wsrep_xid_uuid(const xid_t*);
+wsrep_seqno_t wsrep_xid_seqno(const xid_t*);
+extern "C" int wsrep_is_wsrep_xid(const void* xid);
+
+#endif /* WSREP_MYSQLD_H */
diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc
new file mode 100644
index 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..93640fbcc03
--- /dev/null
+++ b/sql/wsrep_priv.h
@@ -0,0 +1,51 @@
+/* Copyright 2010 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//! @file declares symbols private to wsrep integration layer
+
+#ifndef WSREP_PRIV_H
+#define WSREP_PRIV_H
+
+#include "wsrep_mysqld.h"
+#include "../wsrep/wsrep_api.h"
+
+#include <log.h>
+#include <pthread.h>
+#include <cstdio>
+
+void wsrep_ready_set (my_bool x);
+
+ssize_t wsrep_sst_prepare (void** msg);
+wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx,
+ void* recv_ctx,
+ const void* msg, size_t msg_len,
+ const wsrep_gtid_t* state_id,
+ const char* state, size_t state_len,
+ bool bypass);
+
+extern wsrep_uuid_t local_uuid;
+extern wsrep_seqno_t local_seqno;
+
+// a helper function
+void wsrep_sst_received(wsrep_t*, const wsrep_uuid_t*, wsrep_seqno_t,
+ const void*, size_t);
+/*! SST thread signals init thread about sst completion */
+void wsrep_sst_complete(const wsrep_uuid_t*, wsrep_seqno_t, bool);
+
+void wsrep_notify_status (wsrep_member_status_t new_status,
+ const wsrep_view_info_t* view = 0);
+
+#endif /* WSREP_PRIV_H */
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
new file mode 100644
index 00000000000..a5fe8a1e2d8
--- /dev/null
+++ b/sql/wsrep_sst.cc
@@ -0,0 +1,1121 @@
+/* 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 <my_config.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 <cstdio>
+#include <cstdlib>
+
+#include "wsrep_priv.h"
+#include "wsrep_utils.h"
+#include "wsrep_sst.h"
+
+extern const char wsrep_defaults_file[];
+
+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;
+}
+
+// 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* const uuid,
+ wsrep_seqno_t const seqno,
+ const void* const state,
+ size_t const state_len)
+{
+ int const rcode(seqno < 0 ? seqno : 0);
+ wsrep_gtid_t const state_id = {
+ *uuid, (rcode ? WSREP_SEQNO_UNDEFINED : seqno)
+ };
+ wsrep->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;
+}
+
+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;
+ }
+
+ int ret= snprintf (cmd_str(), cmd_len,
+ "wsrep_sst_%s "
+ WSREP_SST_OPT_ROLE" 'joiner' "
+ WSREP_SST_OPT_ADDR" '%s' "
+ WSREP_SST_OPT_DATA" '%s' "
+ WSREP_SST_OPT_CONF" '%s' "
+ WSREP_SST_OPT_PARENT" '%d'",
+ method, addr_in,
+ mysql_real_data_home,
+ wsrep_defaults_file, (int)getpid());
+
+ 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 ulong my_bind_addr;
+extern uint mysqld_port;
+
+/*! Just tells donor where to send mysqldump */
+static ssize_t sst_prepare_mysqldump (const char* addr_in,
+ const char** addr_out)
+{
+ ssize_t ret = strlen (addr_in);
+
+ if (!strrchr(addr_in, ':'))
+ {
+ ssize_t s = ret + 7;
+ char* tmp = (char*) malloc (s);
+
+ if (tmp)
+ {
+ ret= snprintf (tmp, s, "%s:%u", addr_in, mysqld_port);
+
+ if (ret > 0 && ret < s)
+ {
+ *addr_out= tmp;
+ return ret;
+ }
+ if (ret > 0) /* buffer too short */ ret = -EMSGSIZE;
+ free (tmp);
+ }
+ else {
+ ret= -ENOMEM;
+ }
+
+ WSREP_ERROR ("Could not prepare state transfer request: "
+ "adding default port failed: %zd.", ret);
+ }
+ else {
+ *addr_out= addr_in;
+ }
+
+ return ret;
+}
+
+static bool SE_initialized = false;
+
+ssize_t wsrep_sst_prepare (void** msg)
+{
+ const ssize_t ip_max= 256;
+ char ip_buf[ip_max];
+ const char* addr_in= NULL;
+ const char* addr_out= NULL;
+
+ if (!strcmp(wsrep_sst_method, WSREP_SST_SKIP))
+ {
+ ssize_t ret = strlen(WSREP_STATE_TRANSFER_TRIVIAL) + 1;
+ *msg = strdup(WSREP_STATE_TRANSFER_TRIVIAL);
+ if (!msg)
+ {
+ WSREP_ERROR("Could not allocate %zd bytes for state request", ret);
+ unireg_abort(1);
+ }
+ return ret;
+ }
+
+ // Figure out SST address. Common for all SST methods
+ if (wsrep_sst_receive_address &&
+ strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO))
+ {
+ addr_in= wsrep_sst_receive_address;
+ }
+ else if (wsrep_node_address && strlen(wsrep_node_address))
+ {
+ const char* const colon= strchr (wsrep_node_address, ':');
+ if (colon)
+ {
+ ptrdiff_t const len= colon - wsrep_node_address;
+ strncpy (ip_buf, wsrep_node_address, len);
+ ip_buf[len]= '\0';
+ addr_in= ip_buf;
+ }
+ else
+ {
+ addr_in= wsrep_node_address;
+ }
+ }
+ else
+ {
+ ssize_t ret= wsrep_guess_ip (ip_buf, ip_max);
+
+ if (ret && ret < ip_max)
+ {
+ addr_in= ip_buf;
+ }
+ else
+ {
+ WSREP_ERROR("Could not prepare state transfer request: "
+ "failed to guess address to accept state transfer at. "
+ "wsrep_sst_receive_address must be set manually.");
+ unireg_abort(1);
+ }
+ }
+
+ ssize_t addr_len= -ENOSYS;
+ if (!strcmp(wsrep_sst_method, WSREP_SST_MYSQLDUMP))
+ {
+ addr_len= sst_prepare_mysqldump (addr_in, &addr_out);
+ if (addr_len < 0) unireg_abort(1);
+ }
+ else
+ {
+ /*! A heuristic workaround until we learn how to stop and start engines */
+ if (SE_initialized)
+ {
+ // we already did SST at initializaiton, now engines are running
+ // sql_print_information() is here because the message is too long
+ // for WSREP_INFO.
+ sql_print_information ("WSREP: "
+ "You have configured '%s' state snapshot transfer method "
+ "which cannot be performed on a running server. "
+ "Wsrep provider won't be able to fall back to it "
+ "if other means of state transfer are unavailable. "
+ "In that case you will need to restart the server.",
+ wsrep_sst_method);
+ *msg = 0;
+ return 0;
+ }
+
+ addr_len = sst_prepare_other (wsrep_sst_method, 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
+{
+ size_t host_len;
+ const char* port = strchr (addr, ':');
+
+ if (port)
+ {
+ port += 1;
+ host_len = port - addr;
+ }
+ else
+ {
+ port = "";
+ host_len = strlen (addr) + 1;
+ }
+
+ char *host= (char *) alloca(host_len);
+
+ strncpy (host, addr, host_len - 1);
+ host[host_len - 1] = '\0';
+
+ 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);
+
+ int ret= snprintf (cmd_str(), cmd_len,
+ "wsrep_sst_mysqldump "
+ WSREP_SST_OPT_HOST" '%s' "
+ WSREP_SST_OPT_PORT" '%s' "
+ WSREP_SST_OPT_LPORT" '%u' "
+ WSREP_SST_OPT_SOCKET" '%s' "
+ WSREP_SST_OPT_DATA" '%s' "
+ WSREP_SST_OPT_CONF" '%s' "
+ WSREP_SST_OPT_GTID" '%s:%lld'"
+ "%s",
+ host, port, mysqld_port, mysqld_unix_port,
+ mysql_real_data_home, 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->stmt_da->sql_errno();
+ WSREP_WARN ("error executing '%s': %d (%s)%s",
+ query, err, thd->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,
+ (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);
+ locked= true;
+ goto wait_signal;
+ }
+ }
+ else if (!strcasecmp (out, magic_cont))
+ {
+ if (locked)
+ {
+ sst_disallow_writes (thd.ptr, false);
+ thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
+ locked= false;
+ }
+ err= 0;
+ goto wait_signal;
+ }
+ else if (!strncasecmp (out, magic_done, strlen(magic_done)))
+ {
+ err= sst_scan_uuid_seqno (out + strlen(magic_done) + 1,
+ &ret_uuid, &ret_seqno);
+ }
+ else
+ {
+ WSREP_WARN("Received unknown signal: '%s'", out);
+ }
+ }
+ else
+ {
+ WSREP_ERROR("Failed to read from: %s", proc.cmd());
+ proc.wait();
+ }
+ if (!err && proc.error()) err= proc.error();
+ }
+ else
+ {
+ WSREP_ERROR("Failed to execute: %s : %d (%s)",
+ proc.cmd(), err, strerror(err));
+ }
+
+ if (locked) // don't forget to unlock server before return
+ {
+ sst_disallow_writes (thd.ptr, false);
+ thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
+ }
+
+ // signal to donor that SST is over
+ struct wsrep_gtid const state_id = {
+ ret_uuid, err ? WSREP_SEQNO_UNDEFINED : ret_seqno
+ };
+ wsrep->sst_sent (wsrep, &state_id, -err);
+ proc.wait();
+
+ return NULL;
+}
+
+static int sst_donate_other (const char* method,
+ const char* addr,
+ const char* uuid,
+ wsrep_seqno_t seqno,
+ bool bypass,
+ 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;
+ }
+
+ int 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' "
+ WSREP_SST_OPT_CONF" '%s' "
+ WSREP_SST_OPT_GTID" '%s:%lld'"
+ "%s",
+ method, addr, mysqld_unix_port,
+ mysql_real_data_home, wsrep_defaults_file,
+ uuid, (long long) seqno,
+ bypass ? " " WSREP_SST_OPT_BYPASS : "");
+
+ 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? */
+// wsrep_notify_status(WSREP_MEMBER_DONOR);
+ local_status.set(WSREP_MEMBER_DONOR);
+
+ const char* method = (char*)msg;
+ size_t method_len = strlen (method);
+ const char* data = method + method_len + 1;
+
+ char uuid_str[37];
+ wsrep_uuid_print (&current_gtid->uuid, uuid_str, sizeof(uuid_str));
+
+ 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..ad02aa55114
--- /dev/null
+++ b/sql/wsrep_sst.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2013 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+#ifndef WSREP_SST_H
+#define WSREP_SST_H
+
+#include <mysql.h> // my_bool
+
+#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_PARENT "--parent"
+
+// 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..4d665775f2d
--- /dev/null
+++ b/sql/wsrep_thd.cc
@@ -0,0 +1,531 @@
+/* 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 "slave.h" // opt_log_slave_updates
+#include "sql_base.h" // close_thread_tables()
+#include "mysqld.h" // start_wsrep_THD();
+
+
+#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;
+}
+
+static Relay_log_info* wsrep_relay_log_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);
+ }
+
+ rli->sql_thd= current_thd;
+
+ if ((rli->deferred_events_collecting= rpl_filter->is_on()))
+ {
+ rli->deferred_events= new Deferred_log_events(rli);
+ }
+
+ return rli;
+}
+
+static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
+{
+ shadow->options = thd->variables.option_bits;
+ shadow->server_status = thd->server_status;
+ shadow->wsrep_exec_mode = thd->wsrep_exec_mode;
+ shadow->vio = thd->net.vio;
+
+ if (opt_log_slave_updates)
+ thd->variables.option_bits|= OPTION_BIN_LOG;
+ else
+ thd->variables.option_bits&= ~(OPTION_BIN_LOG);
+
+ if (!thd->wsrep_rli) thd->wsrep_rli= wsrep_relay_log_init("wsrep_relay");
+
+ thd->wsrep_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;
+ 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);
+
+ thd->wsrep_rli->cleanup_after_session();
+ delete thd->wsrep_rli;
+ thd->wsrep_rli= NULL;
+}
+
+void wsrep_replay_transaction(THD *thd)
+{
+ /* checking if BF trx must be replayed */
+ if (thd->wsrep_conflict_state== MUST_REPLAY) {
+ if (thd->wsrep_exec_mode!= REPL_RECV) {
+ if (thd->stmt_da->is_sent)
+ {
+ WSREP_ERROR("replay issue, thd has reported status already");
+ }
+ thd->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();
+
+ 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->stmt_da->is_sent)
+ {
+ WSREP_WARN("replay ok, thd has reported status");
+ }
+ else if (thd->stmt_da->is_set())
+ {
+ if (thd->stmt_da->status() != Diagnostics_area::DA_OK)
+ {
+ WSREP_WARN("replay ok, thd has error status %d",
+ thd->stmt_da->status());
+ }
+ }
+ else
+ {
+ my_ok(thd);
+ }
+ break;
+ case WSREP_TRX_FAIL:
+ if (thd->stmt_da->is_sent)
+ {
+ WSREP_ERROR("replay failed, thd has reported status");
+ }
+ else
+ {
+ WSREP_DEBUG("replay failed, rolling back");
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
+ }
+ thd->wsrep_conflict_state= ABORTED;
+ wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle);
+ break;
+ default:
+ WSREP_ERROR("trx_replay failed for: %d, query: %s",
+ rcode, thd->query() ? thd->query() : "void");
+ /* we're now in inconsistent state, must abort */
+ unireg_abort(1);
+ break;
+ }
+
+ wsrep_cleanup_transaction(thd);
+
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ wsrep_replaying--;
+ WSREP_DEBUG("replaying decreased: %d, thd: %lu",
+ wsrep_replaying, thd->thread_id);
+ mysql_cond_broadcast(&COND_wsrep_replaying);
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ }
+ }
+}
+
+static void wsrep_replication_process(THD *thd)
+{
+ int rcode;
+ DBUG_ENTER("wsrep_replication_process");
+
+ struct wsrep_thd_shadow shadow;
+ wsrep_prepare_bf_thd(thd, &shadow);
+
+ /* From trans_begin() */
+ thd->variables.option_bits|= OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+
+ rcode = wsrep->recv(wsrep, (void *)thd);
+ DBUG_PRINT("wsrep",("wsrep_repl returned: %d", rcode));
+
+ WSREP_INFO("applier thread exiting (code:%d)", rcode);
+
+ switch (rcode) {
+ case WSREP_OK:
+ case WSREP_NOT_IMPLEMENTED:
+ case WSREP_CONN_FAIL:
+ /* provider does not support slave operations / disconnected from group,
+ * just close applier thread */
+ break;
+ case WSREP_NODE_FAIL:
+ /* data inconsistency => SST is needed */
+ /* Note: we cannot just blindly restart replication here,
+ * SST might require server restart if storage engines must be
+ * initialized after SST */
+ WSREP_ERROR("node consistency compromised, aborting");
+ wsrep_kill_mysql(thd);
+ break;
+ case WSREP_WARNING:
+ case WSREP_TRX_FAIL:
+ case WSREP_TRX_MISSING:
+ /* these suggests a bug in provider code */
+ WSREP_WARN("bad return from recv() call: %d", rcode);
+ /* fall through to node shutdown */
+ case WSREP_FATAL:
+ /* Cluster connectivity is lost.
+ *
+ * If applier was killed on purpose (KILL_CONNECTION), we
+ * avoid mysql shutdown. This is because the killer will then handle
+ * shutdown processing (or replication restarting)
+ */
+ if (thd->killed != 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);
+
+ if (thd->temporary_tables)
+ {
+ WSREP_DEBUG("Applier %lu, has temporary tables at exit", thd->thread_id);
+ }
+ 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);
+
+ aborting->store_globals();
+
+ mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
+ wsrep_client_rollback(aborting);
+ WSREP_DEBUG("WSREP rollbacker aborted thd: (%lu %llu)",
+ aborting->thread_id, (long long)aborting->real_id);
+ mysql_mutex_unlock(&aborting->LOCK_wsrep_thd);
+
+ mysql_mutex_lock(&LOCK_wsrep_rollback);
+ }
+ }
+
+ mysql_mutex_unlock(&LOCK_wsrep_rollback);
+ sql_print_information("WSREP: rollbacker thread exiting");
+
+ DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting"));
+ DBUG_VOID_RETURN;
+}
+
+void wsrep_create_rollbacker()
+{
+ if (wsrep_provider && strcasecmp(wsrep_provider, "none"))
+ {
+ pthread_t hThread;
+ /* create rollbacker */
+ if (pthread_create( &hThread, &connection_attrib,
+ start_wsrep_THD, (void*)wsrep_rollback_process))
+ WSREP_WARN("Can't create thread to manage wsrep rollback");
+ }
+}
+
+
+extern "C"
+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;
+ }
+}
+
+extern "C"
+my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync)
+{
+ my_bool status = FALSE;
+ if (thd_ptr)
+ {
+ THD* thd = (THD*)thd_ptr;
+ if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ status = ((thd->wsrep_exec_mode == REPL_RECV) ||
+ (thd->wsrep_exec_mode == TOTAL_ORDER));
+ if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ return status;
+}
+
+extern "C"
+my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync)
+{
+ bool status = FALSE;
+ if (thd_ptr)
+ {
+ THD* thd = (THD*)thd_ptr;
+ if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ status = ((thd->wsrep_exec_mode == REPL_RECV) ||
+ (thd->wsrep_exec_mode == TOTAL_ORDER) ||
+ (thd->wsrep_exec_mode == LOCAL_COMMIT));
+ if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ return status;
+}
+
+extern "C"
+my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync)
+{
+ bool status = FALSE;
+ if (thd_ptr)
+ {
+ THD* thd = (THD*)thd_ptr;
+ if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ status = (thd->wsrep_exec_mode == LOCAL_STATE);
+ if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
+ }
+ return status;
+}
+
+extern "C"
+int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal)
+{
+ THD *victim_thd = (THD *) victim_thd_ptr;
+ THD *bf_thd = (THD *) bf_thd_ptr;
+ DBUG_ENTER("wsrep_abort_thd");
+
+ if ( (WSREP(bf_thd) ||
+ ( (WSREP_ON || wsrep_OSU_method_options == WSREP_OSU_RSU) &&
+ bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) &&
+ victim_thd)
+ {
+ 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;
+}
+
diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h
new file mode 100644
index 00000000000..597033a7c70
--- /dev/null
+++ b/sql/wsrep_thd.h
@@ -0,0 +1,35 @@
+/* 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();
+
+extern "C" my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync);
+extern "C" void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
+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_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
+ my_bool signal);
+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..951007c2660
--- /dev/null
+++ b/sql/wsrep_utils.cc
@@ -0,0 +1,611 @@
+/* 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 |
+ /* start a new process group */ POSIX_SPAWN_SETPGROUP |
+ POSIX_SPAWN_USEVFORK);
+ if (err_)
+ {
+ WSREP_ERROR ("posix_spawnattr_setflags() failed: %d (%s)",
+ err_, strerror(err_));
+ goto cleanup_attr;
+ }
+
+ posix_spawn_file_actions_t fact;
+ err_ = posix_spawn_file_actions_init (&fact);
+ if (err_)
+ {
+ WSREP_ERROR ("posix_spawn_file_actions_init() failed: %d (%s)",
+ err_, strerror(err_));
+ goto cleanup_attr;
+ }
+
+ // close child's stdout|stdin depending on what we returning
+ err_ = posix_spawn_file_actions_addclose (&fact, close_fd);
+ if (err_)
+ {
+ WSREP_ERROR ("posix_spawn_file_actions_addclose() failed: %d (%s)",
+ err_, strerror(err_));
+ goto cleanup_fact;
+ }
+
+ // substitute our pipe descriptor in place of the closed one
+ err_ = posix_spawn_file_actions_adddup2 (&fact,
+ pipe_fds[child_end], close_fd);
+ if (err_)
+ {
+ WSREP_ERROR ("posix_spawn_file_actions_addup2() failed: %d (%s)",
+ err_, strerror(err_));
+ goto cleanup_fact;
+ }
+
+ err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, 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;
+}
+
+/*
+ * WSREPXid
+ */
+
+#define WSREP_XID_PREFIX "WSREPXid"
+#define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN
+#define WSREP_XID_UUID_OFFSET 8
+#define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
+#define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
+
+void wsrep_xid_init(XID* xid, const wsrep_uuid_t* uuid, wsrep_seqno_t seqno)
+{
+ xid->formatID= 1;
+ xid->gtrid_length= WSREP_XID_GTRID_LEN;
+ xid->bqual_length= 0;
+ memset(xid->data, 0, sizeof(xid->data));
+ memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
+ memcpy(xid->data + WSREP_XID_UUID_OFFSET, uuid, sizeof(wsrep_uuid_t));
+ memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t));
+}
+
+const wsrep_uuid_t* wsrep_xid_uuid(const XID* xid)
+{
+ if (wsrep_is_wsrep_xid(xid))
+ return reinterpret_cast<const wsrep_uuid_t*>(xid->data
+ + WSREP_XID_UUID_OFFSET);
+ else
+ return &WSREP_UUID_UNDEFINED;
+}
+
+wsrep_seqno_t wsrep_xid_seqno(const XID* xid)
+{
+
+ if (wsrep_is_wsrep_xid(xid))
+ {
+ wsrep_seqno_t seqno;
+ memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t));
+ return seqno;
+ }
+ else
+ {
+ return WSREP_SEQNO_UNDEFINED;
+ }
+}
+
+extern "C"
+int wsrep_is_wsrep_xid(const void* xid_ptr)
+{
+ const XID* xid= reinterpret_cast<const XID*>(xid_ptr);
+ return (xid->formatID == 1 &&
+ xid->gtrid_length == WSREP_XID_GTRID_LEN &&
+ xid->bqual_length == 0 &&
+ !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN));
+}
diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
new file mode 100644
index 00000000000..7d864603c7f
--- /dev/null
+++ b/sql/wsrep_utils.h
@@ -0,0 +1,229 @@
+/* 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);
+
+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..6385fa926a2
--- /dev/null
+++ b/sql/wsrep_var.cc
@@ -0,0 +1,618 @@
+/* Copyright 2008 Codership Oy <http://www.codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "wsrep_var.h"
+
+#include <mysqld.h>
+#include <sql_class.h>
+#include <sql_plugin.h>
+#include <set_var.h>
+#include <sql_acl.h>
+#include "wsrep_priv.h"
+#include "wsrep_thd.h"
+#include <my_dir.h>
+#include <cstdio>
+#include <cstdlib>
+
+const char* wsrep_provider = 0;
+const char* wsrep_provider_options = 0;
+const char* wsrep_cluster_address = 0;
+const char* wsrep_cluster_name = 0;
+const char* wsrep_node_name = 0;
+const char* wsrep_node_address = 0;
+const char* wsrep_node_incoming_address = 0;
+const char* wsrep_start_position = 0;
+ulong wsrep_OSU_method_options;
+
+int wsrep_init_vars()
+{
+ wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME));
+ wsrep_provider_options= my_strdup("", MYF(MY_WME));
+ wsrep_cluster_address = my_strdup("", MYF(MY_WME));
+ wsrep_cluster_name = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME));
+ wsrep_node_name = my_strdup("", MYF(MY_WME));
+ wsrep_node_address = my_strdup("", MYF(MY_WME));
+ wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME));
+ wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME));
+
+ global_system_variables.binlog_format=BINLOG_FORMAT_ROW;
+ return 0;
+}
+
+bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type)
+{
+ if (var_type == OPT_GLOBAL) {
+ // FIXME: this variable probably should be changed only per session
+ thd->variables.wsrep_on = global_system_variables.wsrep_on;
+ }
+ return false;
+}
+
+bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type)
+{
+ // wsrep_sync_wait should also be updated.
+ if (var_type == OPT_GLOBAL) {
+ 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;
+ }
+ } else {
+ 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;
+ }
+ }
+
+ return false;
+}
+
+bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type)
+{
+ // wsrep_causal_reads should also be updated.
+ if (var_type == OPT_GLOBAL) {
+ global_system_variables.wsrep_causal_reads=
+ global_system_variables.wsrep_sync_wait & WSREP_SYNC_WAIT_BEFORE_READ;
+ } else {
+ thd->variables.wsrep_causal_reads=
+ thd->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;
+}
+
+void wsrep_set_local_position (const char* value)
+{
+ size_t value_len = strlen (value);
+ size_t uuid_len = wsrep_uuid_scan (value, value_len, &local_uuid);
+
+ local_seqno = strtoll (value + uuid_len + 1, NULL, 10);
+
+ XID xid;
+ wsrep_xid_init(&xid, &local_uuid, local_seqno);
+ wsrep_set_SE_checkpoint(&xid);
+ WSREP_INFO ("wsrep_start_position var submitted: '%s'", wsrep_start_position);
+}
+
+bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ // since this value passed wsrep_start_position_check, don't check anything
+ // here
+ wsrep_set_local_position (wsrep_start_position);
+
+ if (wsrep) {
+ wsrep_sst_received (wsrep, &local_uuid, local_seqno, NULL, 0);
+ }
+
+ return 0;
+}
+
+void wsrep_start_position_init (const char* val)
+{
+ if (NULL == val || wsrep_start_position_verify (val))
+ {
+ WSREP_ERROR("Bad initial value for wsrep_start_position: %s",
+ (val ? val : ""));
+ return;
+ }
+
+ wsrep_set_local_position (val);
+}
+
+static bool refresh_provider_options()
+{
+ WSREP_DEBUG("refresh_provider_options: %s",
+ (wsrep_provider_options) ? wsrep_provider_options : "null");
+ char* opts= wsrep->options_get(wsrep);
+ if (opts)
+ {
+ wsrep_provider_options_init(opts);
+ 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 */
+ bzero(&f_stat, 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
+ 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;
+}
+
+bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var)
+{
+ mysql_mutex_lock(&LOCK_wsrep_slave_threads);
+ wsrep_slave_count_change += (var->save_result.ulonglong_value -
+ wsrep_slave_threads);
+ mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
+
+ return 0;
+}
+
+bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ if (wsrep_slave_count_change > 0)
+ {
+ wsrep_create_appliers(wsrep_slave_count_change);
+ wsrep_slave_count_change = 0;
+ }
+ return false;
+}
+
+bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
+{
+ bool new_wsrep_desync= (bool) var->save_result.ulonglong_value;
+ if (wsrep_desync == new_wsrep_desync) {
+ if (new_wsrep_desync) {
+ push_warning (thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_VAR,
+ "'wsrep_desync' is already ON.");
+ } else {
+ push_warning (thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_VAR,
+ "'wsrep_desync' is already OFF.");
+ }
+ }
+ return 0;
+}
+
+bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type)
+{
+ wsrep_status_t ret(WSREP_WARNING);
+ if (wsrep_desync) {
+ ret = wsrep->desync (wsrep);
+ if (ret != WSREP_OK) {
+ WSREP_WARN ("SET desync failed %d for %s", ret, thd->query());
+ my_error (ER_CANNOT_USER, MYF(0), "'desync'", thd->query());
+ return true;
+ }
+ } else {
+ ret = wsrep->resync (wsrep);
+ if (ret != WSREP_OK) {
+ WSREP_WARN ("SET resync failed %d for %s", ret, thd->query());
+ my_error (ER_CANNOT_USER, MYF(0), "'resync'", thd->query());
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * Status variables stuff below
+ */
+static inline void
+wsrep_assign_to_mysql (SHOW_VAR* mysql, wsrep_stats_var* wsrep)
+{
+ mysql->name = wsrep->name;
+ switch (wsrep->type) {
+ case WSREP_VAR_INT64:
+ mysql->value = (char*) &wsrep->value._int64;
+ mysql->type = SHOW_LONGLONG;
+ break;
+ case WSREP_VAR_STRING:
+ mysql->value = (char*) &wsrep->value._string;
+ mysql->type = SHOW_CHAR_PTR;
+ break;
+ case WSREP_VAR_DOUBLE:
+ mysql->value = (char*) &wsrep->value._double;
+ mysql->type = SHOW_DOUBLE;
+ break;
+ }
+}
+
+#if DYNAMIC
+// somehow this mysql status thing works only with statically allocated arrays.
+static SHOW_VAR* mysql_status_vars = NULL;
+static int mysql_status_len = -1;
+#else
+static SHOW_VAR mysql_status_vars[512 + 1];
+static const int mysql_status_len = 512;
+#endif
+
+static void export_wsrep_status_to_mysql(THD* thd)
+{
+ int wsrep_status_len, i;
+
+ thd->wsrep_status_vars = wsrep->stats_get(wsrep);
+
+ if (!thd->wsrep_status_vars) {
+ return;
+ }
+
+ for (wsrep_status_len = 0;
+ thd->wsrep_status_vars[wsrep_status_len].name != NULL;
+ wsrep_status_len++) {
+ /* */
+ }
+
+#if DYNAMIC
+ if (wsrep_status_len != mysql_status_len) {
+ void* tmp = realloc (mysql_status_vars,
+ (wsrep_status_len + 1) * sizeof(SHOW_VAR));
+ if (!tmp) {
+
+ sql_print_error ("Out of memory for wsrep status variables."
+ "Number of variables: %d", wsrep_status_len);
+ return;
+ }
+
+ mysql_status_len = wsrep_status_len;
+ mysql_status_vars = (SHOW_VAR*)tmp;
+ }
+ /* @TODO: fix this: */
+#else
+ if (mysql_status_len < wsrep_status_len) wsrep_status_len= mysql_status_len;
+#endif
+
+ for (i = 0; i < wsrep_status_len; i++)
+ wsrep_assign_to_mysql (mysql_status_vars + i, thd->wsrep_status_vars + i);
+
+ mysql_status_vars[wsrep_status_len].name = NullS;
+ mysql_status_vars[wsrep_status_len].value = NullS;
+ mysql_status_vars[wsrep_status_len].type = SHOW_LONG;
+}
+
+int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff)
+{
+ export_wsrep_status_to_mysql(thd);
+ var->type= SHOW_ARRAY;
+ var->value= (char *) &mysql_status_vars;
+ return 0;
+}
+
+void wsrep_free_status (THD* thd)
+{
+ if (thd->wsrep_status_vars)
+ {
+ wsrep->stats_free (wsrep, thd->wsrep_status_vars);
+ thd->wsrep_status_vars = 0;
+ }
+}
diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h
new file mode 100644
index 00000000000..524dabfd9c0
--- /dev/null
+++ b/sql/wsrep_var.h
@@ -0,0 +1,86 @@
+/* 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;
+
+#endif /* WSREP_VAR_H */
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index cc494a7cd7a..603455196fc 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -119,12 +119,16 @@ IF(NOT CMAKE_CROSSCOMPILING)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_BUILTINS)
+IF(NOT WITH_WSREP)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1)
ENDIF()
+ENDIF()
IF(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
+IF(NOT WITH_WSREP)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_TEST_AND_SET=1)
ENDIF()
+ENDIF()
IF(HAVE_IB_GCC_SYNC_SYNCHRONISE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_SYNC_SYNCHRONISE=1)
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
index 588c2968b6a..17cf10412a8 100644
--- a/storage/innobase/dict/dict0dict.c
+++ b/storage/innobase/dict/dict0dict.c
@@ -2736,7 +2736,27 @@ next_rec:
return(NULL);
}
-
+#ifdef WITH_WSREP
+dict_index_t*
+wsrep_dict_foreign_find_index(
+/*====================*/
+ dict_table_t* table, /*!< in: table */
+ 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, columns, n_cols, types_idx,
+ check_charsets, check_null,
+ NULL, NULL, NULL);
+}
+#endif /* WITH_WSREP */
/**********************************************************************//**
Find an index that is equivalent to the one passed in and is not marked
for deletion.
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 780f3a6f82f..5261a50fdd6 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -93,6 +93,13 @@ extern "C" {
#include "ibuf0ibuf.h"
enum_tx_isolation thd_get_trx_isolation(const THD* thd);
+
+#ifdef WITH_WSREP
+#include "../storage/innobase/include/ut0byte.h"
+#ifndef EXTRA_DEBUG
+ //#include "../storage/innobase/include/ut0byte.ic"
+#endif /* EXTRA_DEBUG */
+#endif /* WITH_WSREP */
}
#include "ha_innodb.h"
@@ -102,6 +109,35 @@ enum_tx_isolation thd_get_trx_isolation(const THD* thd);
# define MYSQL_PLUGIN_IMPORT /* nothing */
# endif /* MYSQL_PLUGIN_IMPORT */
+#ifdef WITH_WSREP
+#include <wsrep_mysqld.h>
+#include <my_md5.h>
+extern my_bool wsrep_certify_nonPK;
+class binlog_trx_data;
+extern handlerton *binlog_hton;
+
+extern MYSQL_PLUGIN_IMPORT MYSQL_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 handlerton * binlog_hton;
+extern void wsrep_cleanup_transaction(THD *thd);
+#endif /* WITH_WSREP */
/** to protect innobase_open_files */
static mysql_mutex_t innobase_share_mutex;
/** to force correct commit order in binlog */
@@ -870,6 +906,15 @@ thd_to_trx(
{
return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr));
}
+#ifdef WITH_WSREP
+ulonglong
+thd_to_trx_id(
+/*=======*/
+ THD* thd) /*!< in: MySQL thread */
+{
+ return(thd_to_trx(thd)->id);
+}
+#endif
/********************************************************************//**
Call this function when mysqld passes control to the client. That is to
@@ -901,6 +946,15 @@ innobase_release_temporary_latches(
return(0);
}
+#ifdef WITH_WSREP
+static int
+wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
+ my_bool signal);
+static void
+wsrep_fake_trx_id(handlerton* hton, THD *thd);
+static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
+static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
+#endif
/********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used
@@ -1314,6 +1368,9 @@ int
innobase_mysql_tmpfile(void)
/*========================*/
{
+#ifdef WITH_INNODB_DISALLOW_WRITES
+ os_event_wait(srv_allow_writes_event);
+#endif /* WITH_INNODB_DISALLOW_WRITES */
int fd2 = -1;
File fd;
@@ -2264,6 +2321,12 @@ innobase_init(
innobase_hton->flags=HTON_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS;
innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
innobase_hton->alter_table_flags = innobase_alter_table_flags;
+#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;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -2728,10 +2791,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 */
}
/*****************************************************************//**
@@ -3395,7 +3478,14 @@ ha_innobase::max_supported_key_length() const
therefore set to slightly less than 1 / 4 of page size which
is 16 kB; but currently MySQL does not work with keys whose
size is > MAX_KEY_LENGTH */
+#ifdef WITH_WSREP
+ /* this may look like obsolete code, but this ifdef is here
+ just to make sure we will see bzr merge conflict, if Oracle
+ changes max key length */
+ return(3500);
+#else
return(3500);
+#endif
}
/****************************************************************//**
@@ -4481,7 +4571,119 @@ innobase_mysql_cmp(
return(0);
}
+#ifdef WITH_WSREP
+extern "C" 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];
+ uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN;
+
+ /* Use the charset number to pick the right charset struct for
+ the comparison. Since the MySQL function get_charset may be
+ slow before Bar removes the mutex operation there, we first
+ look at 2 common charsets directly. */
+
+ if (charset_number == default_charset_info->number) {
+ charset = default_charset_info;
+ } else if (charset_number == my_charset_latin1.number) {
+ charset = &my_charset_latin1;
+ } else {
+ charset = get_charset(charset_number, MYF(MY_WME));
+
+ if (charset == NULL) {
+ sql_print_error("InnoDB needs charset %lu for doing "
+ "a comparison, but MySQL cannot "
+ "find that charset.",
+ (ulong) charset_number);
+ ut_a(0);
+ }
+ }
+
+ ut_a(str_length <= tmp_length);
+ memcpy(tmp_str, str, str_length);
+
+ if (wsrep_protocol_version < 3) {
+ tmp_length = charset->coll->strnxfrm(
+ charset, str, str_length,
+ tmp_str, str_length);
+ 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
+ */
+ /* 5.5 strnxfrm pads the tail with spaces and
+ always returns the full destination buffer lenght
+ we cannot know how many characters were converted
+ using 2 * str length here as best guess
+ */
+ uint dst_length = (str_length * 2 < tmp_length) ?
+ (str_length * 2) : tmp_length;
+ tmp_length = charset->coll->strnxfrm(
+ charset, str, dst_length,
+ tmp_str, str_length);
+ 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
/**************************************************************//**
Converts a MySQL type to an InnoDB type. Note that this function returns
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
@@ -4600,6 +4802,268 @@ innobase_read_from_2_little_endian(
/*******************************************************************//**
Stores a key value for a row to a buffer.
@return key value length as stored in buff */
+#ifdef WITH_WSREP
+UNIV_INTERN
+uint
+wsrep_store_key_val_for_row(
+/*===============================*/
+ 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->key_parts;
+ char* buff_start = buff;
+ enum_field_types mysql_type;
+ Field* field;
+
+ DBUG_ENTER("store_key_val_for_row");
+
+ bzero(buff, 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 (record[key_part->null_offset] &
+ key_part->null_bit) {
+ *buff = 1;
+ part_is_null = TRUE;
+ } else {
+ *buff = 0;
+ }
+ buff++;
+ }
+ 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;
+ CHARSET_INFO* cs;
+ int error=0;
+
+ key_len = key_part->length;
+
+ if (part_is_null) {
+ buff += key_len + 2;
+
+ 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) {
+ memcpy(buff, sorted, true_len);
+ /* 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. */
+ buff += 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) {
+
+ 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) {
+ buff += key_len + 2;
+
+ 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);
+
+ memcpy(buff, sorted, true_len);
+
+ /* Note that we always reserve the maximum possible
+ length of the BLOB prefix in the key value. */
+ if (wsrep_protocol_version > 1) {
+ buff += true_len;
+ } else {
+ buff += key_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. */
+
+ CHARSET_INFO* cs;
+ 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) {
+ buff += key_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);
+
+ memcpy(buff, sorted, true_len);
+ } else {
+ memcpy(buff, src_start, true_len);
+ }
+ buff += true_len;
+
+ /* Pad the unused space with spaces. */
+
+#ifdef REMOVED
+ if (true_len < key_len) {
+ ulint pad_len = key_len - true_len;
+ ut_a(!(pad_len % cs->mbminlen));
+
+ cs->cset->fill(cs, buff, pad_len,
+ 0x20 /* space */);
+ buff += pad_len;
+ }
+#endif /* REMOVED */
+ }
+ }
+
+ ut_a(buff <= buff_start + buff_len);
+
+ DBUG_RETURN((uint)(buff - buff_start));
+}
+#endif /* WITH_WSREP */
UNIV_INTERN
uint
ha_innobase::store_key_val_for_row(
@@ -5208,6 +5672,9 @@ ha_innobase::write_row(
ulint error = 0;
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);
@@ -5238,8 +5705,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
@@ -5273,6 +5752,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. */
@@ -5283,6 +5784,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. */
@@ -5311,7 +5834,9 @@ no_commit:
/* Reset the error code before calling
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 = update_auto_increment())) {
/* We don't want to mask autoinc overflow errors. */
@@ -5394,6 +5919,38 @@ 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 &&
+ !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);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
+ /* jump straight to func exit over
+ * later wsrep hooks */
+ goto func_exit;
+ }
+ break;
+#endif
default:
break;
}
@@ -5442,6 +5999,21 @@ report_error:
error_result = convert_error_code_to_mysql((int) error,
prebuilt->table->flags,
user_thd);
+#ifdef WITH_WSREP
+ if (!error_result &&
+ wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd) &&
+ !wsrep_consistency_check(user_thd))
+ {
+ 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
func_exit:
innobase_active_small();
@@ -5597,7 +6169,84 @@ calc_row_difference(
return(0);
}
+#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;
+
+ my_MD5Context ctx;
+ my_MD5Init (&ctx);
+
+ 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)) {
+ my_MD5Update (&ctx, &null_byte, 1);
+ } else {
+ my_MD5Update (&ctx, &true_byte, 1);
+ my_MD5Update (&ctx, ptr, len);
+ }
+ }
+ my_MD5Final (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
@@ -5723,6 +6372,20 @@ ha_innobase::update_row(
innobase_active_small();
+#ifdef WITH_WSREP
+ if (!error && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd)) {
+
+ DBUG_PRINT("wsrep", ("update row key"));
+
+ if (wsrep_append_keys(user_thd, false, old_row, new_row)) {
+ DBUG_PRINT("wsrep", ("row key failed"));
+ error = HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif
DBUG_RETURN(error);
}
@@ -5766,6 +6429,18 @@ ha_innobase::delete_row(
innobase_active_small();
+#ifdef WITH_WSREP
+ if (!error && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd)) {
+
+ if (wsrep_append_keys(user_thd, false, record, NULL)) {
+ DBUG_PRINT("wsrep", ("delete fail"));
+ error = HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif
DBUG_RETURN(error);
}
@@ -6560,7 +7235,393 @@ ha_innobase::rnd_pos(
DBUG_RETURN(error);
}
+#ifdef WITH_WSREP
+extern "C" {
+dict_index_t*
+wsrep_dict_foreign_find_index(
+ dict_table_t* table,
+ const char** columns,
+ ulint n_cols,
+ dict_index_t* types_idx,
+ ibool check_charsets,
+ ulint check_null);
+
+ulint
+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, DICT_ERR_IGNORE_NONE);
+ if (foreign->referenced_table)
+ {
+ foreign->referenced_index =
+ wsrep_dict_foreign_find_index(
+ foreign->referenced_table,
+ 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, DICT_ERR_IGNORE_NONE);
+ if (foreign->foreign_table)
+ {
+ foreign->foreign_index =
+ wsrep_dict_foreign_find_index(
+ foreign->foreign_table,
+ 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 rcode;
+ }
+ 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,
+ &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), trx->id, key_len,
+ table_share->table_name.str, wsrep_thd_query(thd));
+ for (int i=0; i<key_len; i++) {
+ fprintf(stderr, "%hhX, ", key[i]);
+ }
+ fprintf(stderr, "\n");
+#endif
+ wsrep_buf_t wkey_part[3];
+ wsrep_key_t wkey = {wkey_part, 3};
+ if (!wsrep_prepare_key_for_innodb(
+ (const uchar*)table_share->table_cache_key.str,
+ table_share->table_cache_key.length,
+ (const uchar*)key, key_len,
+ wkey_part,
+ &wkey.key_parts_num)) {
+ WSREP_WARN("key prepare failed for: %s",
+ (wsrep_thd_query(thd)) ?
+ wsrep_thd_query(thd) : "void");
+ DBUG_RETURN(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(rcode);
+ }
+ DBUG_RETURN(0);
+}
+
+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 */
+{
+ 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(
+ table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record0, &is_null);
+
+ if (!is_null) {
+ int 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;
+ if (i != table->s->primary_key) {
+ wsrep_thd_set_PA_safe(thd, FALSE);
+ }
+ }
+ }
+
+ for (i=0; i<table->s->keys; ++i) {
+ uint len;
+ char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
+ char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
+ char* key0 = &keyval0[1];
+ char* key1 = &keyval1[1];
+ KEY* key_info = table->key_info + i;
+ ibool is_null;
+
+ dict_index_t* idx = innobase_get_index(i);
+ dict_table_t* tab = (idx) ? idx->table : NULL;
+
+ keyval0[0] = (char)i;
+ keyval1[0] = (char)i;
+
+ if (!tab) {
+ WSREP_WARN("MySQL-InnoDB key mismatch %s %s",
+ table->s->table_name.str,
+ key_info->name);
+ }
+ /* !hasPK == table with no PK, must append all non-unique keys */
+ if (!hasPK || key_info->flags & HA_NOSAME ||
+ ((tab &&
+ dict_table_get_referenced_constraint(tab, idx)) ||
+ (!tab && referenced_by_foreign_key()))) {
+
+ len = wsrep_store_key_val_for_row(
+ table, i, key0,
+ WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record0, &is_null);
+ if (!is_null) {
+ int 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(
+ table, i, key1,
+ WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record1, &is_null);
+ if (!is_null && memcmp(key0, key1, len)) {
+ int rcode = wsrep_append_key(
+ thd, trx, table_share,
+ table,
+ keyval1, len+1, shared);
+ if (rcode) DBUG_RETURN(rcode);
+ }
+ }
+ }
+ }
+ }
+
+ /* if no PK, calculate hash of full row, to be the key value */
+ if (!key_appended && wsrep_certify_nonPK) {
+ uchar digest[16];
+ int rcode;
+
+ wsrep_calc_row_hash(digest, record0, table, prebuilt, thd);
+ if ((rcode = wsrep_append_key(thd, trx, table_share, table,
+ (const char*) digest, 16,
+ shared))) {
+ DBUG_RETURN(rcode);
+ }
+
+ if (record1) {
+ wsrep_calc_row_hash(
+ digest, record1, table, prebuilt, thd);
+ if ((rcode = wsrep_append_key(thd, trx, table_share,
+ table,
+ (const char*) digest,
+ 16, shared))) {
+ DBUG_RETURN(rcode);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(0);
+}
+#endif
/*********************************************************************//**
Stores a reference to the current row to 'ref' field of the handle. Note
that in the case where we have generated the clustered index for the
@@ -9538,11 +10599,18 @@ ha_innobase::external_lock(
/* used by test case */
DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = 1;);
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 */
}
}
@@ -10497,7 +11565,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);
@@ -10795,6 +11876,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);
}
@@ -11653,6 +12737,304 @@ static SHOW_VAR innodb_status_variables_export[]= {
static struct st_mysql_storage_engine innobase_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+#ifdef WITH_WSREP
+void
+wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno)
+{
+ WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be "
+ "caused by:\n\t"
+ "1) unsupported configuration options combination, please check documentation.\n\t"
+ "2) a bug in the code.\n\t"
+ "3) a database corruption.\n Node consistency compromized, "
+ "need to abort. Restart the node to resync with cluster.",
+ (long long)bf_seqno, (long long)victim_seqno);
+ abort();
+}
+
+int
+wsrep_innobase_kill_one_trx(
+ void *bf_thd_ptr, /*!< in: BF thd */
+ trx_t *bf_trx, /*!< in: BF trx */
+ trx_t *victim_trx, /*!< in: victim trx */
+ ibool signal, /*!< in: signal to be used */
+ ibool have_kernel_mutex) /*!<in: do we own kernel mutex */
+{
+ DBUG_ENTER("wsrep_innobase_kill_one_trx");
+ THD *bf_thd = (THD *)bf_thd_ptr;
+ THD *thd = (THD *) victim_trx->mysql_thd;
+ int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0;
+
+ if (have_kernel_mutex) {
+ ut_ad(mutex_own(&kernel_mutex));
+ }
+
+ if (!bf_thd) bf_thd = (bf_trx) ? (THD *)bf_trx->mysql_thd : NULL;
+
+ if (!thd) {
+ DBUG_PRINT("wsrep", ("no thd for conflicting lock"));
+ WSREP_WARN("no THD for trx: %llu", victim_trx->id);
+ DBUG_RETURN(1);
+ }
+ if (!bf_thd) {
+ DBUG_PRINT("wsrep", ("no BF thd for conflicting lock"));
+ WSREP_WARN("no BF THD for trx: %llu", (bf_trx) ? bf_trx->id : 0);
+ DBUG_RETURN(1);
+ }
+
+ WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
+
+ WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %llu",
+ 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);
+
+ if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
+ WSREP_DEBUG("kill trx EXITING for %llu", victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ DBUG_RETURN(0);
+ }
+ if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
+ WSREP_DEBUG("withdraw for BF trx: %llu, state: %d",
+ victim_trx->id,
+ wsrep_thd_conflict_state(thd));
+ }
+
+ switch (wsrep_thd_conflict_state(thd)) {
+ case NO_CONFLICT:
+ wsrep_thd_set_conflict_state(thd, MUST_ABORT);
+ break;
+ case MUST_ABORT:
+ WSREP_DEBUG("victim %llu in MUST ABORT state",
+ victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ wsrep_thd_awake(bf_thd, thd, signal);
+ DBUG_RETURN(0);
+ break;
+ case ABORTED:
+ case ABORTING: // fall through
+ default:
+ WSREP_DEBUG("victim %llu 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_thd_awake(bf_thd, thd, signal);
+ WSREP_DEBUG("kill trx QUERY_COMMITTING for %llu",
+ 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: %llu",
+ victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ DBUG_RETURN(1);
+ break;
+ case WSREP_OK:
+ break;
+ default:
+ WSREP_ERROR(
+ "cancel commit bad exit: %d %llu",
+ rcode,
+ victim_trx->id);
+ /* unable to interrupt, must abort */
+ /* note: kill_mysql() will block, if we cannot.
+ * kill the lock holder first.
+ */
+ abort();
+ break;
+ }
+ }
+ break;
+ case QUERY_EXEC:
+ /* it is possible that victim trx is itself waiting for some
+ * other lock. We need to cancel this waiting
+ */
+ WSREP_DEBUG("kill trx QUERY_EXEC for %llu", victim_trx->id);
+
+ victim_trx->was_chosen_as_deadlock_victim= TRUE;
+ if (victim_trx->wait_lock) {
+ WSREP_DEBUG("victim has wait flag: %ld",
+ wsrep_thd_thread_id(thd));
+ lock_t* wait_lock = victim_trx->wait_lock;
+ if (wait_lock) {
+ WSREP_DEBUG("canceling wait lock");
+ victim_trx->was_chosen_as_deadlock_victim= TRUE;
+ if (!have_kernel_mutex) {
+ mutex_enter(&kernel_mutex);
+ }
+ lock_cancel_waiting_and_release(wait_lock);
+ /* If we already have kernel mutex when we
+ arrived to this function, do not yet release
+ it */
+ if (!have_kernel_mutex) {
+ mutex_exit(&kernel_mutex);
+ }
+ }
+
+ wsrep_thd_awake(bf_thd, thd, signal);
+ } else {
+ /* abort currently executing query */
+ DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld",
+ wsrep_thd_thread_id(thd)));
+ WSREP_DEBUG("kill query for: %ld",
+ wsrep_thd_thread_id(thd));
+ wsrep_thd_awake(bf_thd, thd, signal);
+
+ /* for BF thd, we need to prevent him from committing */
+ if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
+ wsrep_abort_slave_trx(bf_seqno,
+ wsrep_thd_trx_seqno(thd));
+ }
+ }
+ break;
+ case QUERY_IDLE:
+ {
+ bool skip_abort= false;
+ wsrep_aborting_thd_t abortees;
+
+ WSREP_DEBUG("kill IDLE for %llu", victim_trx->id);
+
+ if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
+ WSREP_DEBUG("kill BF IDLE, seqno: %lld",
+ (long long)wsrep_thd_trx_seqno(thd));
+ wsrep_thd_UNLOCK(thd);
+ wsrep_abort_slave_trx(bf_seqno,
+ wsrep_thd_trx_seqno(thd));
+ DBUG_RETURN(0);
+ }
+ /* This will lock thd from proceeding after net_read() */
+ wsrep_thd_set_conflict_state(thd, ABORTING);
+
+ mysql_mutex_lock(&LOCK_wsrep_rollback);
+
+ abortees = wsrep_aborting_thd;
+ while (abortees && !skip_abort) {
+ /* check if we have a kill message for this already */
+ if (abortees->aborting_thd == thd) {
+ skip_abort = true;
+ WSREP_WARN("duplicate thd aborter %lu",
+ wsrep_thd_thread_id(thd));
+ }
+ abortees = abortees->next;
+ }
+ if (!skip_abort) {
+ wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t)
+ my_malloc(sizeof(struct wsrep_aborting_thd),
+ MYF(0));
+ aborting->aborting_thd = thd;
+ aborting->next = wsrep_aborting_thd;
+ wsrep_aborting_thd = aborting;
+ DBUG_PRINT("wsrep",("enqueuing trx abort for %lu",
+ wsrep_thd_thread_id(thd)));
+ WSREP_DEBUG("enqueuing trx abort for (%lu)",
+ wsrep_thd_thread_id(thd));
+ }
+
+ DBUG_PRINT("wsrep",("signalling wsrep rollbacker"));
+ WSREP_DEBUG("signaling aborter");
+ mysql_cond_signal(&COND_wsrep_rollback);
+ mysql_mutex_unlock(&LOCK_wsrep_rollback);
+
+ break;
+ }
+ default:
+ WSREP_WARN("bad wsrep query state: %d",
+ wsrep_thd_query_state(thd));
+ break;
+ }
+ wsrep_thd_UNLOCK(thd);
+
+ DBUG_RETURN(0);
+}
+static int
+wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
+ my_bool signal)
+{
+ DBUG_ENTER("wsrep_innobase_abort_thd");
+ trx_t* victim_trx = thd_to_trx(victim_thd);
+ trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
+
+ ut_ad(!mutex_own(&kernel_mutex));
+
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s",
+ wsrep_thd_query(bf_thd),
+ wsrep_thd_query(victim_thd));
+
+ if (victim_trx)
+ {
+ int rcode = wsrep_innobase_kill_one_trx(
+ bf_thd, bf_trx, victim_trx, signal, FALSE);
+ 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(bf_thd, 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(&kernel_mutex);
+ trx_id_t trx_id = trx_sys_get_new_trx_id();
+ mutex_exit(&kernel_mutex);
+
+ (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
+}
+
+#endif /* WITH_WSREP */
/* plugin options */
static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
@@ -12015,6 +13397,40 @@ static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
NULL, NULL, 0, 0, 2, 0);
#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.",
@@ -12120,6 +13536,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
MYSQL_SYSVAR(change_buffering_debug),
#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(io_capacity),
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 42aae4dc20e..f9b6d6ff582 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -114,6 +114,10 @@ class ha_innobase: public handler
dict_index_t* innobase_get_index(uint keynr);
int info_low(uint flag, bool called_from_analyze);
+#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);
@@ -293,6 +297,40 @@ bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
*/
extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file);
+#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* bf_thd, THD *thd, my_bool signal);
+#endif
typedef struct trx_struct trx_t;
/********************************************************************//**
@file handler/ha_innodb.h
@@ -333,3 +371,6 @@ innobase_index_name_is_reserved(
ulint num_of_keys); /*!< in: Number of indexes to
be created. */
+#ifdef WITH_WSREP
+extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
+#endif
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index ecfda6d6264..9f0a0958912 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -36,6 +36,10 @@ extern "C" {
#include "handler0alter.h"
}
+#ifdef WITH_WSREP
+//#include "wsrep_api.h"
+#include <sql_acl.h> // PROCESS_ACL
+#endif
#include "ha_innodb.h"
/*************************************************************//**
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 1b12c8303bb..0bffc14f9dd 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -344,6 +344,9 @@ barracuda format, the length could be REC_VERSION_56_MAX_INDEX_COL_LEN
/** 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_struct{
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 83fa1d53f1e..add494d394f 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -285,6 +285,19 @@ thd_set_lock_wait_time(
void* thd, /*!< in: thread handle (THD*) */
ulint value); /*!< in: time waited for the lock */
+#ifdef WITH_WSREP
+UNIV_INTERN int wsrep_innobase_kill_one_trx(void *thd, trx_t *bf_trx, trx_t *victim_trx,
+ ibool signal, ibool have_kernel_mutex);
+my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync);
+//int64_t wsrep_thd_trx_seqno(THD *thd);
+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*);
+my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
+#endif /* WITH_WSREP */
/**********************************************************************//**
Get the current setting of the lower_case_table_names global parameter from
mysqld.cc. We do a dirty read because for one there is no synchronization
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index 01439835aa5..237e43b7882 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -799,9 +799,6 @@ lock_rec_get_page_no(
record */
#define LOCK_CONV_BY_OTHER 4096 /*!< this bit is set when the lock is created
by other transaction */
-#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_CONV_BY_OTHER)&LOCK_MODE_MASK
-# error
-#endif
#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_CONV_BY_OTHER)&LOCK_TYPE_MASK
# error
#endif
diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h
index 9dd96f609ea..7e76b4f40cb 100644
--- a/storage/innobase/include/rem0rec.h
+++ b/storage/innobase/include/rem0rec.h
@@ -836,6 +836,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 2b1a640ae8b..9a7cbcbe5c9 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -142,6 +142,10 @@ extern ulint srv_log_buffer_size;
extern ulong srv_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 */
@@ -580,6 +584,14 @@ srv_conc_enter_innodb(
/*==================*/
trx_t* trx); /*!< in: transaction object associated with the
thread */
+#ifdef WITH_WSREP
+UNIV_INTERN
+void
+wsrep_srv_conc_cancel_wait(
+/*==================*/
+ trx_t* trx); /*!< in: transaction object associated with the
+ thread */
+#endif /* WITH_WSREP */
/*********************************************************************//**
This lets a thread enter InnoDB regardless of the number of threads inside
InnoDB. This must be called when a thread ends a lock wait. */
diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
index 69b87e18010..b8f1973d9c5 100644
--- a/storage/innobase/include/trx0sys.h
+++ b/storage/innobase/include/trx0sys.h
@@ -41,6 +41,9 @@ Created 3/26/1996 Heikki Tuuri
#include "ut0bh.h"
#include "read0types.h"
#include "page0types.h"
+#ifdef WITH_WSREP
+#include "trx0xa.h"
+#endif /* WITH_WSREP */
/** In a MySQL replication slave, in crash recovery we store the master log
file name and position here. */
@@ -306,6 +309,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
@@ -314,6 +320,19 @@ UNIV_INTERN
void
trx_sys_print_mysql_binlog_offset(void);
/*===================================*/
+#ifdef WITH_WSREP
+/** Update WSREP checkpoint XID in sys header. */
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid, /*!< in: WSREP XID */
+ trx_sysf_t* sys_header, /*!< in: sys_header */
+ mtr_t* mtr); /*!< in: mtr */
+
+void
+/** Read WSREP checkpoint XID from sys header. */
+trx_sys_read_wsrep_checkpoint(
+ XID* xid); /*!< out: WSREP XID */
+#endif /* WITH_WSREP */
/*****************************************************************//**
Prints to stderr the MySQL master log offset info in the trx system header if
the magic number shows it valid. */
@@ -519,6 +538,22 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
within that file */
#define TRX_SYS_MYSQL_LOG_NAME 12 /*!< MySQL log file name */
+#ifdef WITH_WSREP
+/* We hijack TRX_SYS_MYSQL_MASTER_LOG_INFO, it seems to be completely unused
+ otherwise (see comments for MySQL bug #34058). */
+/** */
+#define TRX_SYS_WSREP_XID_INFO TRX_SYS_MYSQL_MASTER_LOG_INFO
+#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/trx0trx.h b/storage/innobase/include/trx0trx.h
index 4ade245f03e..0d23ede46b6 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -729,6 +729,9 @@ struct trx_struct{
/*------------------------------*/
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 */
};
#define TRX_MAX_N_THREADS 32 /* maximum number of
diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c
index 559b3687b79..3890a2c44ff 100644
--- a/storage/innobase/lock/lock0lock.c
+++ b/storage/innobase/lock/lock0lock.c
@@ -40,6 +40,10 @@ Created 5/7/1996 Heikki Tuuri
#include "trx0sys.h"
#include "btr0btr.h"
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+extern my_bool wsrep_log_conflicts;
+#endif
/* Restricts the length of search we will do in the waits-for
graph of transactions */
#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
@@ -794,7 +798,6 @@ lock_reset_lock_and_trx_wait(
/* Reset the back pointer in trx to this waiting lock request */
if (!(lock->type_mode & LOCK_CONV_BY_OTHER)) {
- ut_ad((lock->trx)->wait_lock == lock);
(lock->trx)->wait_lock = NULL;
} else {
ut_ad(lock_get_type_low(lock) == LOCK_REC);
@@ -905,6 +908,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
@@ -974,6 +980,52 @@ lock_rec_has_to_wait(
return(FALSE);
}
+#ifdef WITH_WSREP
+ /* if BF thread 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) {
+ /* exclusive lock conflicts are not
+ accepted */
+ fprintf(stderr,
+ "BF-BF X lock conflict\n");
+ lock_rec_print(stderr, lock2);
+ abort();
+ } else if (wsrep_debug) {
+ fprintf(stderr,
+ "BF-BF X lock conflict\n");
+ }
+ } 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);
}
@@ -1004,7 +1056,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)));
@@ -1454,6 +1510,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.
@@ -1503,6 +1564,53 @@ lock_rec_other_has_expl_req(
}
#endif /* UNIV_DEBUG */
+#ifdef WITH_WSREP
+static void
+wsrep_kill_victim(trx_t *trx, lock_t *lock) {
+ 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->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);
+ trx_print(stderr, trx, 3000);
+
+ if (bf_other)
+ fputs("\n*** Priority TRANSACTION:\n",
+ stderr);
+ else
+ fputs("\n*** Victim TRANSACTION:\n",
+ stderr);
+ trx_print(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);
+ }
+ }
+ wsrep_innobase_kill_one_trx(
+ trx->mysql_thd, trx, lock->trx, TRUE, TRUE);
+ }
+ }
+}
+#endif
/*********************************************************************//**
Checks if some other transaction has a conflicting explicit lock request
in the queue, so that we have to wait.
@@ -1530,8 +1638,15 @@ lock_rec_other_has_conflicting(
if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) {
do {
- if (lock_rec_has_to_wait(trx, mode, lock,
+#ifdef WITH_WSREP
+ if (lock_rec_has_to_wait(TRUE, trx, mode, lock,
+#else
+ if (lock_rec_has_to_wait(trx, mode, lock,
+#endif /* WITH_WSREP */
TRUE)) {
+#ifdef WITH_WSREP
+ wsrep_kill_victim(trx, lock);
+#endif
return(lock);
}
@@ -1540,8 +1655,15 @@ lock_rec_other_has_conflicting(
} else {
do {
- if (lock_rec_has_to_wait(trx, mode, lock,
+#ifdef WITH_WSREP
+ if (lock_rec_has_to_wait(TRUE, trx, mode, lock,
+#else
+ if (lock_rec_has_to_wait(trx, mode, lock,
+#endif /* WITH_WSREP */
FALSE)) {
+#ifdef WITH_WSREP
+ wsrep_kill_victim(trx, lock);
+#endif
return(lock);
}
@@ -1673,6 +1795,9 @@ static
lock_t*
lock_rec_create(
/*============*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /* conflicting lock */
+#endif
ulint type_mode,/*!< in: lock mode and wait
flag, type is ignored and
replaced by LOCK_REC */
@@ -1732,8 +1857,66 @@ lock_rec_create(
/* Set the bit corresponding to rec */
lock_rec_set_nth_bit(lock, heap_no);
+#ifdef WITH_WSREP
+ if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ lock_t *hash = c_lock->hash;
+ lock_t *prev = NULL;
+
+ while (hash &&
+ wsrep_thd_is_BF(hash->trx->mysql_thd, TRUE) &&
+ wsrep_trx_order_before(
+ hash->trx->mysql_thd, trx->mysql_thd))
+ {
+ prev = hash;
+ hash = 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
+ */
+ if (c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
+ c_lock->trx->was_chosen_as_deadlock_victim = TRUE;
+
+ if (wsrep_debug && c_lock->trx->wait_lock != c_lock) {
+ fprintf(stderr, "WSREP: c_lock != wait lock\n");
+ lock_rec_print(stderr, c_lock);
+ lock_rec_print(stderr, c_lock->trx->wait_lock);
+ }
+
+ trx->que_state = TRX_QUE_LOCK_WAIT;
+ lock_set_lock_and_trx_wait(lock, trx);
+
+ lock_cancel_waiting_and_release(c_lock->trx->wait_lock);
+
+ /* trx might not wait for c_lock, but some other lock
+ does not matter if wait_lock was released above
+ */
+ if (c_lock->trx->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);
+
+ /* have to bail out here to avoid lock_set_lock... */
+ return(lock);
+ }
+ } 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 (lock_is_wait_not_by_other(type_mode)) {
lock_set_lock_and_trx_wait(lock, trx);
@@ -1753,6 +1936,9 @@ static
enum db_err
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
@@ -1805,9 +1991,18 @@ lock_rec_enqueue_waiting(
}
if (lock == NULL) {
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) && trx->was_chosen_as_deadlock_victim) {
+ return(DB_DEADLOCK);
+ }
+ /* Enqueue the lock request that will wait to be granted */
+ lock = lock_rec_create(c_lock, type_mode | LOCK_WAIT,
+ block, heap_no, index, trx);
+#else
/* Enqueue the lock request that will wait to be granted */
lock = lock_rec_create(type_mode | LOCK_WAIT,
block, heap_no, index, trx);
+#endif /*WITH_WSREP */
} else {
ut_ad(lock->type_mode & LOCK_WAIT);
ut_ad(lock->type_mode & LOCK_CONV_BY_OTHER);
@@ -1892,7 +2087,19 @@ lock_rec_add_to_queue(
lock_t* other_lock
= lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT,
block, heap_no, trx);
+#ifdef WITH_WSREP
+ /* this can potentionally assert with wsrep */
+ if (wsrep_on(trx->mysql_thd)) {
+ if (wsrep_debug && other_lock) {
+ fprintf(stderr,
+ "WSREP: InnoDB assert ignored\n");
+ }
+ } else {
+ ut_a(!other_lock);
+ }
+#else
ut_a(!other_lock);
+#endif /* WITH_WSREP */
}
#endif /* UNIV_DEBUG */
@@ -1945,7 +2152,11 @@ lock_rec_add_to_queue(
}
somebody_waits:
+#ifdef WITH_WSREP
+ return(lock_rec_create(NULL, type_mode, block, heap_no, index, trx));
+#else
return(lock_rec_create(type_mode, block, heap_no, index, trx));
+#endif
}
/** Record locking request status */
@@ -2005,7 +2216,11 @@ lock_rec_lock_fast(
if (lock == NULL) {
if (!impl) {
+#ifdef WITH_WSREP
+ lock_rec_create(NULL, mode, block, heap_no, index, trx);
+#else
lock_rec_create(mode, block, heap_no, index, trx);
+#endif
}
return(LOCK_REC_SUCCESS_CREATED);
@@ -2061,6 +2276,9 @@ lock_rec_lock_slow(
que_thr_t* thr) /*!< in: query thread */
{
trx_t* trx;
+#ifdef WITH_WSREP
+ lock_t* c_lock = NULL;
+#endif
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
@@ -2102,7 +2320,12 @@ lock_rec_lock_slow(
/* The trx already has a strong enough lock on rec: do
nothing */
+#ifdef WITH_WSREP
+ } else if ((c_lock = lock_rec_other_has_conflicting(
+ mode, block, heap_no, trx))) {
+#else
} else if (lock_rec_other_has_conflicting(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
@@ -2110,8 +2333,16 @@ lock_rec_lock_slow(
ut_ad(lock == NULL);
enqueue_waiting:
+#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. */
+ return(lock_rec_enqueue_waiting(c_lock, mode, block, heap_no,
+ lock, index, thr));
+#else
return(lock_rec_enqueue_waiting(mode, block, heap_no,
lock, index, thr));
+#endif /* WITH_WSREP */
} else if (!impl) {
/* Set the requested lock on the record */
@@ -2158,7 +2389,6 @@ 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);
-
/* We try a simplified and faster subroutine for the most
common cases */
switch (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
@@ -3590,6 +3820,26 @@ lock_deadlock_recursive(
stderr);
}
#endif /* UNIV_DEBUG */
+#ifdef WITH_WSREP
+ if (wsrep_debug)
+ fputs("WSREP: Deadlock detected\n", stderr);
+ if ((start != wait_lock->trx) &&
+ wsrep_thd_is_BF(start->mysql_thd, TRUE) &&
+ wsrep_thd_is_BF(
+ wait_lock->trx->mysql_thd, TRUE))
+ {
+ if (wsrep_trx_order_before(
+ start->mysql_thd,
+ wait_lock->trx->mysql_thd)) {
+
+ wait_lock->trx->was_chosen_as_deadlock_victim = TRUE;
+ lock_cancel_waiting_and_release(wait_lock);
+ return(LOCK_VICTIM_IS_OTHER);
+ } else {
+ return(LOCK_VICTIM_IS_START);
+ }
+ }
+#endif
if (trx_weight_ge(wait_lock->trx, start)) {
/* Our recursion starting point
@@ -3597,8 +3847,23 @@ lock_deadlock_recursive(
choose 'start' as the victim and roll
back it */
+#ifdef WITH_WSREP
+ if (!wsrep_thd_is_BF(
+ start->mysql_thd, FALSE))
+ {
+ return(LOCK_VICTIM_IS_START);
+ }
+#else
+ return(LOCK_VICTIM_IS_START);
+#endif
+ }
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_BF(
+ wait_lock->trx->mysql_thd, TRUE))
+ {
return(LOCK_VICTIM_IS_START);
}
+#endif
lock_deadlock_found = TRUE;
@@ -3683,6 +3948,9 @@ UNIV_INLINE
lock_t*
lock_table_create(
/*==============*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /* conflicting lock */
+#endif
dict_table_t* table, /*!< in: database table in dictionary cache */
ulint type_mode,/*!< in: lock mode possibly ORed with
LOCK_WAIT */
@@ -3719,7 +3987,40 @@ lock_table_create(
lock->un_member.tab_lock.table = table;
+#ifdef WITH_WSREP
+ if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ UT_LIST_INSERT_AFTER(
+ un_member.tab_lock.locks, table->locks, c_lock, lock);
+ } else {
+ UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
+ }
+
+ if (c_lock && c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
+ if (wsrep_debug) {
+ fprintf(stderr,
+ "WSREP: table c_lock in wait: %llu new loc: %llu\n",
+ (ulonglong) c_lock->trx->id, lock->trx->id);
+ }
+
+ c_lock->trx->was_chosen_as_deadlock_victim = TRUE;
+ lock_cancel_waiting_and_release(c_lock->trx->wait_lock);
+
+ /* trx might not wait for c_lock, but some other lock
+ does not matter if wait_lock was released above
+ */
+ if (c_lock->trx->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);
+ }
+ }
+
+#else
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
+#endif
if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
@@ -3865,6 +4166,9 @@ static
ulint
lock_table_enqueue_waiting(
/*=======================*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /* conflicting lock */
+#endif
ulint mode, /*!< in: lock mode this transaction is
requesting */
dict_table_t* table, /*!< in: table */
@@ -3906,7 +4210,14 @@ lock_table_enqueue_waiting(
/* Enqueue the lock request that will wait to be granted */
+#ifdef WITH_WSREP
+ if (trx->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
/* Check if a deadlock occurs: if yes, remove the lock request and
return an error code */
@@ -3964,7 +4275,11 @@ lock_table_other_has_incompatible(
if ((lock->trx != trx)
&& (!lock_mode_compatible(lock_get_mode(lock), mode))
&& (wait || !(lock_get_wait(lock)))) {
-
+#ifdef WITH_WSREP
+ if (wsrep_debug)
+ fprintf(stderr, "WSREP: table lock abort");
+ wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
+#endif
return(lock);
}
@@ -3988,6 +4303,9 @@ lock_table(
enum lock_mode mode, /*!< in: lock mode */
que_thr_t* thr) /*!< in: query thread */
{
+#ifdef WITH_WSREP
+ lock_t *c_lock;
+#endif
trx_t* trx;
ulint err;
@@ -4016,19 +4334,32 @@ 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
+ if ((c_lock = (lock_t *)lock_table_other_has_incompatible(
+ trx, LOCK_WAIT, table, mode))) {
+#else
if (lock_table_other_has_incompatible(trx, LOCK_WAIT, table, mode)) {
+#endif
/* Another trx has a request on the table in an incompatible
mode: this trx may have to wait */
+#ifdef WITH_WSREP
+ err = lock_table_enqueue_waiting(c_lock, mode | flags, table, thr);
+#else
err = lock_table_enqueue_waiting(mode | flags, table, thr);
+#endif
lock_mutex_exit_kernel();
return(err);
}
+#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);
@@ -4946,6 +5277,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) {
@@ -4955,6 +5287,7 @@ lock_rec_queue_validate(
}
ut_a(!lock_rec_other_has_expl_req(
mode, 0, 0, block, heap_no, lock->trx));
+#endif /* WITH_WSREP */
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
@@ -5231,6 +5564,9 @@ lock_rec_insert_check_and_lock(
lock_t* lock;
ulint err;
ulint next_rec_heap_no;
+#ifdef WITH_WSREP
+ lock_t *c_lock;
+#endif
ut_ad(block->frame == page_align(rec));
@@ -5283,15 +5619,28 @@ lock_rec_insert_check_and_lock(
had to wait for their insert. Both had waiting gap type lock requests
on the successor, which produced an unnecessary deadlock. */
+#ifdef WITH_WSREP
+ if ((c_lock = lock_rec_other_has_conflicting(
+ LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
+ block, next_rec_heap_no, trx))) {
+#else
if (lock_rec_other_has_conflicting(
LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
block, next_rec_heap_no, trx)) {
+#endif
/* Note that we may get DB_SUCCESS also here! */
+#ifdef WITH_WSREP
+ err = lock_rec_enqueue_waiting(c_lock, LOCK_X | LOCK_GAP
+ | LOCK_INSERT_INTENTION,
+ block, next_rec_heap_no,
+ NULL, index, thr);
+#else
err = lock_rec_enqueue_waiting(LOCK_X | LOCK_GAP
| LOCK_INSERT_INTENTION,
block, next_rec_heap_no,
NULL, index, thr);
+#endif /* WITH_WSREP */
} else {
err = DB_SUCCESS;
}
@@ -5375,6 +5724,11 @@ lock_rec_convert_impl_to_expl(
implicit lock. Because cannot lock at this moment.*/
if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))
+#ifdef WITH_WSREP
+ && !wsrep_thd_is_BF(impl_trx->mysql_thd, FALSE)
+ /* BF-BF conflict is possible if advancing into
+ lock_rec_other_has_conflicting*/
+#endif /* WITH_WSREP */
&& lock_rec_other_has_conflicting(
LOCK_X | LOCK_REC_NOT_GAP, block,
heap_no, impl_trx)) {
diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c
index 90bebdb2374..a6156e555b5 100644
--- a/storage/innobase/os/os0file.c
+++ b/storage/innobase/os/os0file.c
@@ -90,6 +90,12 @@ UNIV_INTERN os_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:
@@ -727,7 +733,9 @@ os_file_create_tmpfile(void)
/*========================*/
{
FILE* file = NULL;
- int fd = innobase_mysql_tmpfile();
+ int fd;
+ WAIT_ALLOW_WRITES();
+ fd = innobase_mysql_tmpfile();
if (fd >= 0) {
file = fdopen(fd, "w+b");
@@ -1046,6 +1054,7 @@ os_file_create_directory(
return (TRUE);
#else
int rcode;
+ WAIT_ALLOW_WRITES();
rcode = mkdir(pathname, 0770);
@@ -1147,6 +1156,8 @@ try_again:
os_file_t file;
int create_flag;
ibool retry;
+ if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
+ WAIT_ALLOW_WRITES();
try_again:
ut_a(name);
@@ -1280,6 +1291,8 @@ os_file_create_simple_no_error_handling_func(
const char* mode_str = NULL;
ut_a(name);
+ if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
+ WAIT_ALLOW_WRITES();
if (create_mode == OS_FILE_OPEN) {
mode_str = "OPEN";
@@ -1573,6 +1586,8 @@ try_again:
int create_flag;
ibool retry;
const char* mode_str = NULL;
+ if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
+ WAIT_ALLOW_WRITES();
DBUG_EXECUTE_IF(
"ib_create_table_fail_disk_full",
@@ -1741,6 +1756,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -1804,6 +1820,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -1844,6 +1861,7 @@ os_file_rename_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = rename(oldpath, newpath);
@@ -2106,6 +2124,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__ */
}
@@ -2200,6 +2219,7 @@ os_file_flush_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
#if defined(HAVE_DARWIN_THREADS)
# ifndef F_FULLFSYNC
@@ -2892,6 +2912,7 @@ retry:
return(FALSE);
#else
ssize_t ret;
+ WAIT_ALLOW_WRITES();
ret = os_file_pwrite(file, buf, n, offset, offset_high);
diff --git a/storage/innobase/rem/rem0rec.c b/storage/innobase/rem/rem0rec.c
index 7f435a92489..84f04beb61d 100644
--- a/storage/innobase/rem/rem0rec.c
+++ b/storage/innobase/rem/rem0rec.c
@@ -31,6 +31,9 @@ Created 5/30/1994 Heikki Tuuri
#include "mtr0mtr.h"
#include "mtr0log.h"
+#ifdef WITH_WSREP
+#include <ha_prototypes.h>
+#endif /* WITH_WSREP */
/* PHYSICAL RECORD (OLD STYLE)
===========================
@@ -1896,3 +1899,133 @@ 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
diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
index 5bdaf4b722b..c380390d62a 100644
--- a/storage/innobase/row/row0ins.c
+++ b/storage/innobase/row/row0ins.c
@@ -759,6 +759,14 @@ row_ins_invalidate_query_cache(
innobase_invalidate_query_cache(thr_get_trx(thr), buf, len);
mem_free(buf);
}
+#ifdef WITH_WSREP
+ulint 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
@@ -1072,6 +1080,18 @@ row_ins_foreign_check_on_constraint(
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
+#ifdef WITH_WSREP
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ clust_rec,
+ clust_index,
+ FALSE, FALSE);
+ if (err != DB_SUCCESS) {
+ fprintf(stderr,
+ "WSREP: foreign key append failed: %lu\n", err);
+ } else
+#endif
err = row_update_cascade_for_mysql(thr, cascade,
foreign->foreign_table);
@@ -1405,7 +1425,14 @@ run_again:
if (check_ref) {
err = DB_SUCCESS;
-
+#ifdef WITH_WSREP
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ check_ref, TRUE);
+#endif /* WITH_WSREP */
goto end_scan;
} else if (foreign->type != 0) {
/* There is an ON UPDATE or ON DELETE
diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c
index 4b23165cc59..40e9fbfde23 100644
--- a/storage/innobase/row/row0upd.c
+++ b/storage/innobase/row/row0upd.c
@@ -51,6 +51,10 @@ Created 12/27/1996 Heikki Tuuri
#include "pars0sym.h"
#include "eval0eval.h"
#include "buf0lru.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h"
+extern my_bool wsrep_debug;
+#endif
/* What kind of latch and lock can we assume when the control comes to
@@ -170,6 +174,50 @@ func_exit:
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 (!UT_LIST_GET_FIRST(table->foreign_list)) {
+
+ return(FALSE);
+ }
+
+ if (trx->dict_operation_lock_mode == 0) {
+ row_mysql_freeze_data_dictionary(trx);
+ froze_data_dict = TRUE;
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ if (foreign->foreign_index == index) {
+
+ is_referenced = TRUE;
+ goto func_exit;
+ }
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+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,127 @@ row_upd_check_references_constraints(
}
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
+ulint
+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;
+ ulint err;
+ ibool got_s_lock = FALSE;
+
+ if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) {
+
+ return(DB_SUCCESS);
+ }
+
+ trx = thr_get_trx(thr);
+ if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+
+ return(DB_SUCCESS);
+ }
+
+ /* 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(ROW_COPY_DATA, 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);
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ /* 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) {
+ dict_table_get(foreign->referenced_table_name_lookup,
+ FALSE, DICT_ERR_IGNORE_NONE);
+ }
+
+ if (foreign->referenced_table) {
+ mutex_enter(&(dict_sys->mutex));
+
+ (foreign->referenced_table
+ ->n_foreign_key_checks_running)++;
+
+ mutex_exit(&(dict_sys->mutex));
+ }
+
+ /* 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) {
+ mutex_enter(&(dict_sys->mutex));
+
+ ut_a(foreign->referenced_table
+ ->n_foreign_key_checks_running > 0);
+
+ (foreign->referenced_table
+ ->n_foreign_key_checks_running)--;
+
+ mutex_exit(&(dict_sys->mutex));
+ }
+
+ if (err != DB_SUCCESS) {
+
+ goto func_exit;
+ }
+ }
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+ err = DB_SUCCESS;
func_exit:
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
@@ -294,6 +462,7 @@ func_exit:
return(err);
}
+#endif /* WITH_WSREP */
/*********************************************************************//**
Creates an update node for a query graph.
@@ -1560,10 +1729,16 @@ row_upd_sec_index_entry(
trx_t* trx = thr_get_trx(thr);
ulint mode = BTR_MODIFY_LEAF;
enum row_search_result search_result;
+#ifdef WITH_WSREP
+ ibool foreign;
+#endif /* WITH_WSREP */
index = node->index;
referenced = row_upd_index_is_referenced(index, trx);
+#ifdef WITH_WSREP
+ foreign = wsrep_row_upd_index_is_foreign(index, trx);
+#endif /* WITH_WSREP */
heap = mem_heap_create(1024);
@@ -1626,6 +1801,9 @@ row_upd_sec_index_entry(
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);
@@ -1643,6 +1821,38 @@ row_upd_sec_index_entry(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced &&
+ !(parent && que_node_get_type(parent) ==
+ QUE_NODE_UPDATE &&
+ ((upd_node_t*)parent)->cascade_node == node) &&
+ foreign
+ ) {
+ ulint* offsets =
+ rec_get_offsets(
+ rec, index, NULL,
+ ULINT_UNDEFINED, &heap);
+ err = wsrep_row_upd_check_foreign_constraints(
+ node, &pcur, index->table,
+ index, offsets, thr, &mtr);
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_NO_REFERENCED_ROW:
+ err = DB_SUCCESS;
+ break;
+ case DB_DEADLOCK:
+ if (wsrep_debug)
+ fprintf (stderr,
+ "WSREP: sec index FK check fail for deadlock");
+ break;
+ default:
+ fprintf (stderr,
+ "WSREP: referenced FK check fail: %lu",
+ err);
+ break;
+ }
+ }
+#endif /* WITH_WSREP */
}
break;
}
@@ -1793,6 +2003,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;
@@ -1806,6 +2019,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));
@@ -1888,6 +2104,34 @@ err_exit:
goto err_exit;
}
}
+#ifdef WITH_WSREP
+ if (!referenced &&
+ !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
+ ((upd_node_t*)parent)->cascade_node == node) &&
+ foreign
+ ) {
+ err = wsrep_row_upd_check_foreign_constraints(
+ node, pcur, table, index, offsets, thr, mtr);
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_NO_REFERENCED_ROW:
+ err = DB_SUCCESS;
+ break;
+ case DB_DEADLOCK:
+ if (wsrep_debug) fprintf (stderr,
+ "WSREP: insert FK check fail for deadlock");
+ break;
+ default:
+ fprintf (stderr,
+ "WSREP: referenced FK check fail: %lu",
+ err);
+ break;
+ }
+ if (err != DB_SUCCESS) {
+ goto err_exit;
+ }
+ }
+#endif /* WITH_WSREP */
}
mtr_commit(mtr);
@@ -2056,11 +2300,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;
ulint 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));
@@ -2077,15 +2328,49 @@ 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(
BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
+#ifdef WITH_WSREP
+ rec, index, offsets, TRUE, thr, mtr);
+#else
btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
+#endif /* WITH_WSREP */
if (err == DB_SUCCESS && referenced) {
/* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced &&
+ !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
+ ((upd_node_t*)parent)->cascade_node == node) &&
+ thr_get_trx(thr) &&
+ foreign
+ ) {
+ err = wsrep_row_upd_check_foreign_constraints(
+ node, pcur, index->table, index, offsets, thr, mtr);
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_NO_REFERENCED_ROW:
+ err = DB_SUCCESS;
+ break;
+ case DB_DEADLOCK:
+ if (wsrep_debug) fprintf (stderr,
+ "WSREP: clust rec FK check fail for deadlock");
+ break;
+ default:
+ fprintf (stderr,
+ "WSREP: clust rec referenced FK check fail: %lu",
+ err);
+ break;
+ }
+ }
+#endif /* WITH_WSREP */
mtr_commit(mtr);
@@ -2114,11 +2399,17 @@ row_upd_clust_step(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets;
ibool referenced;
+#ifdef WITH_WSREP
+ ibool foreign;
+#endif /* WITH_WSREP */
rec_offs_init(offsets_);
index = dict_table_get_first_index(node->table);
referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
+#ifdef WITH_WSREP
+ foreign = wsrep_row_upd_index_is_foreign(index, thr_get_trx(thr));
+#endif /* WITH_WSREP */
pcur = node->pcur;
@@ -2188,7 +2479,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;
@@ -2239,7 +2534,11 @@ exit_func:
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/srv0srv.c b/storage/innobase/srv/srv0srv.c
index d5b0208382f..98f7134abe7 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -90,6 +90,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 counter is incremented whenever there is some user activity
in the server */
UNIV_INTERN ulint srv_activity_count = 0;
@@ -202,6 +206,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;
@@ -375,6 +383,9 @@ struct srv_conc_slot_struct{
free to proceed; but
reserved may still be
TRUE at that point */
+#ifdef WITH_WSREP
+ void *thd; /*!< to see priority */
+#endif
UT_LIST_NODE_T(srv_conc_slot_t) srv_conc_queue; /*!< queue node */
};
@@ -1101,8 +1112,20 @@ srv_init(void)
conc_slot->reserved = FALSE;
conc_slot->event = os_event_create(NULL);
ut_a(conc_slot->event);
+#ifdef WITH_WSREP
+ conc_slot->thd = NULL;
+#endif /* WITH_WSREP */
}
+#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(NULL);
+ 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);
}
@@ -1151,6 +1174,23 @@ srv_general_init(void)
/* Maximum allowable purge history length. <=0 means 'infinite'. */
UNIV_INTERN ulong srv_max_purge_lag = 0;
+#ifdef WITH_WSREP
+UNIV_INTERN
+void
+wsrep_srv_conc_cancel_wait(
+/*==================*/
+ trx_t* trx) /*!< in: transaction object associated with the
+ thread */
+{
+ 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 /* WITH_WSREP */
/*********************************************************************//**
Puts an OS thread to wait if there are too many concurrent threads
(>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */
@@ -1188,6 +1228,18 @@ srv_conc_enter_innodb(
return;
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ srv_conc_force_enter_innodb(trx);
+ return;
+ }
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_trx_is_aborting(trx->mysql_thd)) {
+ srv_conc_force_enter_innodb(trx);
+ return;
+ }
+#endif
os_fast_mutex_lock(&srv_conc_mutex);
retry:
if (trx->declared_to_be_inside_innodb) {
@@ -1280,6 +1332,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);
@@ -1287,6 +1342,19 @@ retry:
srv_conc_n_waiting_threads++;
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_trx_is_aborting(trx->mysql_thd)) {
+ srv_conc_n_waiting_threads--;
+ 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_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
@@ -1301,6 +1369,9 @@ retry:
thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK);
os_event_wait(slot->event);
thd_wait_end(trx->mysql_thd);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
trx->op_info = "";
@@ -1312,6 +1383,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);
@@ -1382,6 +1456,9 @@ srv_conc_force_exit_innodb(
trx->n_tickets_to_enter_innodb = 0;
if (srv_conc_n_threads < (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 */
@@ -1391,6 +1468,19 @@ srv_conc_force_exit_innodb(
slot = UT_LIST_GET_NEXT(srv_conc_queue, slot);
}
+#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;
@@ -1768,7 +1858,20 @@ srv_suspend_mysql_thread(
if (lock_wait_timeout < 100000000
&& wait_time > (double) lock_wait_timeout) {
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_thd_is_BF(trx->mysql_thd, TRUE)) {
+ fprintf(stderr,
+ "WSREP: BF long lock wait ended after %.f sec\n",
+ wait_time);
+ srv_print_innodb_monitor = FALSE;
+ srv_print_innodb_lock_monitor = FALSE;
+ } else {
+#endif
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
+#ifdef WITH_WSREP
+ }
+#endif
}
if (trx_is_interrupted(trx)) {
@@ -2323,6 +2426,27 @@ exit_func:
OS_THREAD_DUMMY_RETURN;
}
+#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(
+/*====================*/
+ srv_slot_t* slot) /* in: lock slot to check for lock priority */
+{
+ if (wsrep_on(thr_get_trx(slot->thr)->mysql_thd) &&
+ wsrep_thd_is_BF((thr_get_trx(slot->thr))->mysql_thd, TRUE)) {
+ fprintf(stderr, "WSREP: BF lock wait long\n");
+ srv_print_innodb_monitor = TRUE;
+ srv_print_innodb_lock_monitor = TRUE;
+ os_event_set(srv_lock_timeout_thread_event);
+ return TRUE;
+ }
+ return FALSE;
+ }
+#endif /* WITH_WSREP */
/*********************************************************************//**
A thread which wakes up threads whose lock wait may have lasted too long.
@return a dummy parameter */
@@ -2391,8 +2515,14 @@ loop:
granted: in that case do nothing */
if (trx->wait_lock) {
+#ifdef WITH_WSREP
+ if (!wsrep_is_BF_lock_timeout(slot)) {
+#endif
lock_cancel_waiting_and_release(
trx->wait_lock);
+#ifdef WITH_WSREP
+ }
+#endif
}
}
}
@@ -2510,7 +2640,20 @@ loop:
if (sync_array_print_long_waits(&waiter, &sema)
&& sema == old_sema && os_thread_eq(waiter, old_waiter)) {
+#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES)
+ if (srv_allow_writes_event->is_set) {
+#endif /* WITH_WSREP */
fatal_cnt++;
+#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES)
+ } else {
+ fprintf(stderr,
+ "WSREP: avoiding InnoDB self crash due to long "
+ "semaphore wait of > %lu seconds\n"
+ "Server is processing SST donor operation, "
+ "fatal_cnt now: %lu",
+ (ulong) srv_fatal_semaphore_wait_threshold, fatal_cnt);
+ }
+#endif /* WITH_WSREP */
if (fatal_cnt > 10) {
fprintf(stderr,
diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c
index 638e06191bc..b393dfda85d 100644
--- a/storage/innobase/trx/trx0roll.c
+++ b/storage/innobase/trx/trx0roll.c
@@ -43,6 +43,9 @@ Created 3/26/1996 Heikki Tuuri
#include "row0mysql.h"
#include "lock0lock.h"
#include "pars0pars.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h"
+#endif /* WITH_WSREP */
/** This many pages must be undone before a truncate is tried within
rollback */
@@ -148,6 +151,12 @@ trx_rollback_for_mysql(
trx->op_info = "";
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
return(err);
}
@@ -175,6 +184,12 @@ trx_rollback_last_sql_stat_for_mysql(
trx->op_info = "";
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
return(err);
}
@@ -1127,6 +1142,12 @@ trx_rollback(
srv_que_task_enqueue_low(thr);
/* srv_que_task_enqueue_low(thr2); */
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
}
/****************************************************************//**
@@ -1285,6 +1306,12 @@ trx_finish_rollback_off_kernel(
sig = next_sig;
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
}
/*********************************************************************//**
diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c
index 256e22d1b50..a0fcc2b2370 100644
--- a/storage/innobase/trx/trx0sys.c
+++ b/storage/innobase/trx/trx0sys.c
@@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri
#include "os0file.h"
#include "read0read.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */
+#endif /* */
+
/** The file format tag structure with id and name. */
struct file_format_struct {
ulint id; /*!< id of the file format */
@@ -691,10 +695,14 @@ trx_sys_update_mysql_binlog_offset(
ib_int64_t offset, /*!< in: position in that log file */
ulint field, /*!< in: offset of the MySQL log info field in
the trx sys header */
+#ifdef WITH_WSREP
+ trx_sysf_t* sys_header, /*!< in: trx sys header */
+#endif /* WITH_WSREP */
mtr_t* mtr) /*!< in: mtr */
{
+#ifndef WITH_WSREP
trx_sysf_t* sys_header;
-
+#endif /* !WITH_WSREP */
if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
/* We cannot fit the name to the 512 bytes we have reserved */
@@ -702,7 +710,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)
@@ -789,6 +799,125 @@ trx_sys_print_mysql_binlog_offset(void)
mtr_commit(&mtr);
}
+#ifdef WITH_WSREP
+
+#ifdef UNIV_DEBUG
+static long long trx_sys_cur_xid_seqno = -1;
+static unsigned char trx_sys_cur_xid_uuid[16];
+
+long long read_wsrep_xid_seqno(const XID* xid)
+{
+ long long seqno;
+ memcpy(&seqno, xid->data + 24, sizeof(long long));
+ return seqno;
+}
+
+void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
+{
+ memcpy(buf, xid->data + 8, 16);
+}
+
+#endif /* UNIV_DEBUG */
+
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid, /*!< in: transaction XID */
+ trx_sysf_t* sys_header, /*!< in: sys_header */
+ mtr_t* mtr) /*!< in: mtr */
+{
+
+#ifdef UNIV_DEBUG
+ {
+ /* Check that seqno is monotonically increasing */
+ unsigned char xid_uuid[16];
+ long long xid_seqno = read_wsrep_xid_seqno(xid);
+ read_wsrep_xid_uuid(xid, xid_uuid);
+ if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8))
+ {
+ ut_ad(xid_seqno > trx_sys_cur_xid_seqno);
+ trx_sys_cur_xid_seqno = xid_seqno;
+ }
+ else
+ {
+ memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16);
+ }
+ trx_sys_cur_xid_seqno = xid_seqno;
+ }
+#endif /* UNIV_DEBUG */
+
+ ut_ad(xid && mtr && sys_header);
+ ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid));
+
+ if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
+ != TRX_SYS_WSREP_XID_MAGIC_N) {
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD,
+ TRX_SYS_WSREP_XID_MAGIC_N,
+ MLOG_4BYTES, mtr);
+ }
+
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_FORMAT,
+ (int)xid->formatID,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_GTRID_LEN,
+ (int)xid->gtrid_length,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_BQUAL_LEN,
+ (int)xid->bqual_length,
+ MLOG_4BYTES, mtr);
+ mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_DATA,
+ (const unsigned char*) xid->data,
+ XIDDATASIZE, mtr);
+
+}
+
+void
+trx_sys_read_wsrep_checkpoint(XID* xid)
+/*===================================*/
+{
+ trx_sysf_t* sys_header;
+ mtr_t mtr;
+ ulint magic;
+
+ ut_ad(xid);
+
+ mtr_start(&mtr);
+
+ sys_header = trx_sysf_get(&mtr);
+
+ if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD))
+ != TRX_SYS_WSREP_XID_MAGIC_N) {
+ memset(xid, 0, sizeof(*xid));
+ xid->formatID = -1;
+ trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
+ mtr_commit(&mtr);
+ return;
+ }
+
+ xid->formatID = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT);
+ xid->gtrid_length = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN);
+ xid->bqual_length = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN);
+ ut_memcpy(xid->data,
+ sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA,
+ XIDDATASIZE);
+
+ mtr_commit(&mtr);
+}
+
+#endif /* WITH_WSREP */
+
/*****************************************************************//**
Prints to stderr the MySQL master log offset info in the trx system header if
the magic number shows it valid. */
diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
index 151e70013f9..558cd74cfca 100644
--- a/storage/innobase/trx/trx0trx.c
+++ b/storage/innobase/trx/trx0trx.c
@@ -192,6 +192,9 @@ trx_create(
/* Remember to free the vector explicitly. */
trx->autoinc_locks = ib_vector_create(
mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
return(trx);
}
@@ -713,6 +716,11 @@ trx_start_low(
trx->id = trx_sys_get_new_trx_id();
+#ifdef WITH_WSREP
+ memset(&trx->xid, 0, sizeof(trx->xid));
+ trx->xid.formatID = -1;
+#endif /* WITH_WSREP */
+
/* The initial value for trx->no: IB_ULONGLONG_MAX is used in
read_view_open_now: */
@@ -817,6 +825,9 @@ trx_write_serialisation_history(
/*============================*/
trx_t* trx) /*!< in: transaction */
{
+#ifdef WITH_WSREP
+ trx_sysf_t* sys_header;
+#endif /* WITH_WSREP */
mtr_t mtr;
trx_rseg_t* rseg;
@@ -866,6 +877,15 @@ trx_write_serialisation_history(
mutex_exit(&rseg->mutex);
+#ifdef WITH_WSREP
+ sys_header = trx_sysf_get(&mtr);
+ /* Update latest MySQL wsrep XID in trx sys header. */
+ if (wsrep_is_wsrep_xid(&trx->xid))
+ {
+ trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, &mtr);
+ }
+#endif /* WITH_WSREP */
+
/* Update the latest MySQL binlog name and offset info
in trx sys header if MySQL binlogging is on or the database
server is a MySQL replication slave */
@@ -876,7 +896,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;
}
@@ -1063,6 +1087,12 @@ trx_commit_off_kernel(
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
trx->error_state = DB_SUCCESS;
diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c
index 699af1fcaa1..8b9501ee8bc 100644
--- a/storage/innobase/ut/ut0ut.c
+++ b/storage/innobase/ut/ut0ut.c
@@ -554,7 +554,7 @@ ut_print_namel(
trx ? trx->mysql_thd : NULL,
table_id);
- fwrite(buf, 1, bufend - buf, f);
+ (void) fwrite(buf, 1, bufend - buf, f);
}
/**********************************************************************//**
@@ -575,7 +575,7 @@ ut_copy_file(
? (size_t) len
: sizeof buf;
size_t size = fread(buf, 1, maxs, src);
- fwrite(buf, 1, size, dest);
+ (void) fwrite(buf, 1, size, dest);
len -= (long) size;
if (size < maxs) {
break;
diff --git a/storage/tokudb/CMakeLists.txt b/storage/tokudb/CMakeLists.txt
index 2052d448a43..9b743e47aec 100644
--- a/storage/tokudb/CMakeLists.txt
+++ b/storage/tokudb/CMakeLists.txt
@@ -26,7 +26,7 @@ ENDIF()
############################################
SET(TOKUDB_VERSION "tokudb-7.5.7")
-SET(TOKUDB_DEB_FILES "usr/lib/mysql/plugin/ha_tokudb.so\netc/mysql/conf.d/tokudb.cnf\nusr/bin/tokuftdump\nusr/share/doc/mariadb-server-5.5/README-TOKUDB\nusr/share/doc/mariadb-server-5.5/README.md" PARENT_SCOPE)
+SET(TOKUDB_DEB_FILES "usr/lib/mysql/plugin/ha_tokudb.so\netc/mysql/conf.d/tokudb.cnf\nusr/bin/tokuftdump\nusr/share/doc/mariadb-galera-server-5.5/README-TOKUDB\nusr/share/doc/mariadb-galera-server-5.5/README.md" PARENT_SCOPE)
SET(USE_BDB OFF CACHE BOOL "")
MARK_AS_ADVANCED(BUILDNAME)
MARK_AS_ADVANCED(BUILD_TESTING)
diff --git a/storage/tokudb/mysql-test/tokudb_bugs/disabled.def b/storage/tokudb/mysql-test/tokudb_bugs/disabled.def
index b6fa575522b..81f9c69f9bc 100644
--- a/storage/tokudb/mysql-test/tokudb_bugs/disabled.def
+++ b/storage/tokudb/mysql-test/tokudb_bugs/disabled.def
@@ -12,4 +12,4 @@ xa-2: Not for 5.5
6053: N/A
checkpoint_lock_2: test can not work when the checkpoint_safe_lock is a fair rwlock
-
+xa-3 : failed in 5.5.56-galera
diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c
index 0b0a00cd1ed..73cfc62d960 100644
--- a/storage/xtradb/buf/buf0buf.c
+++ b/storage/xtradb/buf/buf0buf.c
@@ -2541,7 +2541,7 @@ loop:
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
loop2:
-#endif
+#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
if (block && buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
mutex_exit(block_mutex);
block = NULL;
diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c
index 5da4509599e..a6970c20831 100644
--- a/storage/xtradb/dict/dict0dict.c
+++ b/storage/xtradb/dict/dict0dict.c
@@ -2870,7 +2870,27 @@ next_rec:
return(NULL);
}
-
+#ifdef WITH_WSREP
+dict_index_t*
+wsrep_dict_foreign_find_index(
+/*====================*/
+ dict_table_t* table, /*!< in: table */
+ 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, columns, n_cols, types_idx,
+ check_charsets, check_null,
+ NULL, NULL, NULL);
+}
+#endif /* WITH_WSREP */
/**********************************************************************//**
Find an index that is equivalent to the one passed in and is not marked
for deletion.
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 66fcc2799bb..805b28d9d21 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -102,6 +102,13 @@ extern "C" {
#include "ibuf0ibuf.h"
enum_tx_isolation thd_get_trx_isolation(const THD* thd);
+
+#ifdef WITH_WSREP
+#include "../storage/innobase/include/ut0byte.h"
+#ifndef EXTRA_DEBUG
+ //#include "../storage/innobase/include/ut0byte.ic"
+#endif /* EXTRA_DEBUG */
+#endif /* WITH_WSREP */
}
#include "ha_innodb.h"
@@ -119,6 +126,35 @@ extern ib_int64_t trx_sys_mysql_relay_log_pos;
# define MYSQL_PLUGIN_IMPORT /* nothing */
# endif /* MYSQL_PLUGIN_IMPORT */
+#ifdef WITH_WSREP
+#include <wsrep_mysqld.h>
+#include <my_md5.h>
+extern my_bool wsrep_certify_nonPK;
+class binlog_trx_data;
+extern handlerton *binlog_hton;
+
+extern MYSQL_PLUGIN_IMPORT MYSQL_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 handlerton * binlog_hton;
+extern void wsrep_cleanup_transaction(THD *thd);
+#endif /* WITH_WSREP */
/** to protect innobase_open_files */
static mysql_mutex_t innobase_share_mutex;
static ulong commit_threads = 0;
@@ -1125,6 +1161,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
my_bool
ha_innobase::is_fake_change_enabled(THD* thd)
@@ -1165,6 +1210,15 @@ innobase_release_temporary_latches(
return(0);
}
+#ifdef WITH_WSREP
+static int
+wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
+ my_bool signal);
+static void
+wsrep_fake_trx_id(handlerton* hton, THD *thd);
+static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
+static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
+#endif
/********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used
@@ -1581,6 +1635,9 @@ int
innobase_mysql_tmpfile(void)
/*========================*/
{
+#ifdef WITH_INNODB_DISALLOW_WRITES
+ os_event_wait(srv_allow_writes_event);
+#endif /* WITH_INNODB_DISALLOW_WRITES */
int fd2 = -1;
File fd;
@@ -2706,6 +2763,12 @@ innobase_init(
innobase_hton->flags=HTON_EXTENDED_KEYS;
innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
innobase_hton->alter_table_flags = innobase_alter_table_flags;
+#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;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -3453,6 +3516,23 @@ 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)) {
/* Save the current replication position for write to trx sys
@@ -3463,6 +3543,9 @@ innobase_commit_low(
trx_commit_for_mysql(trx);
}
+#ifdef WITH_WSREP
+ if (wsrep_on((void*)thd)) { thd_proc_info(thd, tmp); }
+#endif /* WITH_WSREP */
}
/*****************************************************************//**
@@ -4146,7 +4229,14 @@ ha_innobase::max_supported_key_length() const
therefore set to slightly less than 1 / 4 of page size which
is 16 kB; but currently MySQL does not work with keys whose
size is > MAX_KEY_LENGTH */
+#ifdef WITH_WSREP
+ /* this may look like obsolete code, but this ifdef is here
+ just to make sure we will see bzr merge conflict, if Oracle
+ changes max key length */
+ return(3500);
+#else
return(3500);
+#endif
}
/****************************************************************//**
@@ -5254,7 +5344,119 @@ innobase_mysql_cmp(
return(0);
}
+#ifdef WITH_WSREP
+extern "C" 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];
+ uint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN;
+
+ /* Use the charset number to pick the right charset struct for
+ the comparison. Since the MySQL function get_charset may be
+ slow before Bar removes the mutex operation there, we first
+ look at 2 common charsets directly. */
+
+ if (charset_number == default_charset_info->number) {
+ charset = default_charset_info;
+ } else if (charset_number == my_charset_latin1.number) {
+ charset = &my_charset_latin1;
+ } else {
+ charset = get_charset(charset_number, MYF(MY_WME));
+
+ if (charset == NULL) {
+ sql_print_error("InnoDB needs charset %lu for doing "
+ "a comparison, but MySQL cannot "
+ "find that charset.",
+ (ulong) charset_number);
+ ut_a(0);
+ }
+ }
+
+ ut_a(str_length <= tmp_length);
+ memcpy(tmp_str, str, str_length);
+
+ if (wsrep_protocol_version < 3) {
+ tmp_length = charset->coll->strnxfrm(
+ charset, str, str_length,
+ tmp_str, str_length);
+ 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
+ */
+ /* 5.5 strnxfrm pads the tail with spaces and
+ always returns the full destination buffer lenght
+ we cannot know how many characters were converted
+ using 2 * str length here as best guess
+ */
+ uint dst_length = (str_length * 2 < tmp_length) ?
+ (str_length * 2) : tmp_length;
+ tmp_length = charset->coll->strnxfrm(
+ charset, str, dst_length,
+ tmp_str, str_length);
+ 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
/**************************************************************//**
Converts a MySQL type to an InnoDB type. Note that this function returns
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
@@ -5408,6 +5610,268 @@ innobase_read_from_2_little_endian(
/*******************************************************************//**
Stores a key value for a row to a buffer.
@return key value length as stored in buff */
+#ifdef WITH_WSREP
+UNIV_INTERN
+uint
+wsrep_store_key_val_for_row(
+/*===============================*/
+ 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->key_parts;
+ char* buff_start = buff;
+ enum_field_types mysql_type;
+ Field* field;
+
+ DBUG_ENTER("store_key_val_for_row");
+
+ bzero(buff, 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 (record[key_part->null_offset] &
+ key_part->null_bit) {
+ *buff = 1;
+ part_is_null = TRUE;
+ } else {
+ *buff = 0;
+ }
+ buff++;
+ }
+ 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;
+ CHARSET_INFO* cs;
+ int error=0;
+
+ key_len = key_part->length;
+
+ if (part_is_null) {
+ buff += key_len + 2;
+
+ 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) {
+ memcpy(buff, sorted, true_len);
+ /* 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. */
+ buff += 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) {
+
+ 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) {
+ buff += key_len + 2;
+
+ 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);
+
+ memcpy(buff, sorted, true_len);
+
+ /* Note that we always reserve the maximum possible
+ length of the BLOB prefix in the key value. */
+ if (wsrep_protocol_version > 1) {
+ buff += true_len;
+ } else {
+ buff += key_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. */
+
+ CHARSET_INFO* cs;
+ 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) {
+ buff += key_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);
+
+ memcpy(buff, sorted, true_len);
+ } else {
+ memcpy(buff, src_start, true_len);
+ }
+ buff += true_len;
+
+ /* Pad the unused space with spaces. */
+
+#ifdef REMOVED
+ if (true_len < key_len) {
+ ulint pad_len = key_len - true_len;
+ ut_a(!(pad_len % cs->mbminlen));
+
+ cs->cset->fill(cs, buff, pad_len,
+ 0x20 /* space */);
+ buff += pad_len;
+ }
+#endif /* REMOVED */
+ }
+ }
+
+ ut_a(buff <= buff_start + buff_len);
+
+ DBUG_RETURN((uint)(buff - buff_start));
+}
+#endif /* WITH_WSREP */
UNIV_INTERN
uint
ha_innobase::store_key_val_for_row(
@@ -6223,6 +6687,9 @@ ha_innobase::write_row(
ulint error = 0;
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);
@@ -6257,8 +6724,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
@@ -6292,6 +6771,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. */
@@ -6302,6 +6803,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. */
@@ -6330,7 +6853,9 @@ no_commit:
/* Reset the error code before calling
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 = update_auto_increment())) {
/* We don't want to mask autoinc overflow errors. */
@@ -6419,6 +6944,38 @@ 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 &&
+ !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);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
+ /* jump straight to func exit over
+ * later wsrep hooks */
+ goto func_exit;
+ }
+ break;
+#endif
default:
break;
}
@@ -6467,6 +7024,21 @@ report_error:
error_result = convert_error_code_to_mysql((int) error,
prebuilt->table->flags,
user_thd);
+#ifdef WITH_WSREP
+ if (!error_result &&
+ wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd) &&
+ !wsrep_consistency_check(user_thd))
+ {
+ 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
func_exit:
innobase_active_small();
@@ -6630,7 +7202,84 @@ calc_row_difference(
return(0);
}
+#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;
+
+ my_MD5Context ctx;
+ my_MD5Init (&ctx);
+
+ 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)) {
+ my_MD5Update (&ctx, &null_byte, 1);
+ } else {
+ my_MD5Update (&ctx, &true_byte, 1);
+ my_MD5Update (&ctx, ptr, len);
+ }
+ }
+ my_MD5Final (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
@@ -6770,6 +7419,20 @@ ha_innobase::update_row(
DBUG_RETURN(HA_ERR_CRASHED);
}
+#ifdef WITH_WSREP
+ if (!error && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd)) {
+
+ DBUG_PRINT("wsrep", ("update row key"));
+
+ if (wsrep_append_keys(user_thd, false, old_row, new_row)) {
+ DBUG_PRINT("wsrep", ("row key failed"));
+ error = HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif
DBUG_RETURN(error);
}
@@ -6827,6 +7490,18 @@ ha_innobase::delete_row(
DBUG_RETURN(HA_ERR_CRASHED);
}
+#ifdef WITH_WSREP
+ if (!error && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE &&
+ wsrep_on(user_thd)) {
+
+ if (wsrep_append_keys(user_thd, false, record, NULL)) {
+ DBUG_PRINT("wsrep", ("delete fail"));
+ error = HA_ERR_INTERNAL_ERROR;
+ goto wsrep_error;
+ }
+ }
+wsrep_error:
+#endif
DBUG_RETURN(error);
}
@@ -7668,7 +8343,393 @@ ha_innobase::rnd_pos(
DBUG_RETURN(error);
}
+#ifdef WITH_WSREP
+extern "C" {
+dict_index_t*
+wsrep_dict_foreign_find_index(
+ dict_table_t* table,
+ const char** columns,
+ ulint n_cols,
+ dict_index_t* types_idx,
+ ibool check_charsets,
+ ulint check_null);
+
+ulint
+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, DICT_ERR_IGNORE_NONE);
+ if (foreign->referenced_table)
+ {
+ foreign->referenced_index =
+ wsrep_dict_foreign_find_index(
+ foreign->referenced_table,
+ 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, DICT_ERR_IGNORE_NONE);
+ if (foreign->foreign_table)
+ {
+ foreign->foreign_index =
+ wsrep_dict_foreign_find_index(
+ foreign->foreign_table,
+ 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 rcode;
+ }
+ 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,
+ &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), trx->id, key_len,
+ table_share->table_name.str, wsrep_thd_query(thd));
+ for (int i=0; i<key_len; i++) {
+ fprintf(stderr, "%hhX, ", key[i]);
+ }
+ fprintf(stderr, "\n");
+#endif
+ wsrep_buf_t wkey_part[3];
+ wsrep_key_t wkey = {wkey_part, 3};
+ if (!wsrep_prepare_key_for_innodb(
+ (const uchar*)table_share->table_cache_key.str,
+ table_share->table_cache_key.length,
+ (const uchar*)key, key_len,
+ wkey_part,
+ &wkey.key_parts_num)) {
+ WSREP_WARN("key prepare failed for: %s",
+ (wsrep_thd_query(thd)) ?
+ wsrep_thd_query(thd) : "void");
+ DBUG_RETURN(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(rcode);
+ }
+ DBUG_RETURN(0);
+}
+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 */
+{
+ 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(
+ table, 0, key, WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record0, &is_null);
+
+ if (!is_null) {
+ int 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;
+ if (i != table->s->primary_key) {
+ wsrep_thd_set_PA_safe(thd, FALSE);
+ }
+ }
+ }
+
+ for (i=0; i<table->s->keys; ++i) {
+ uint len;
+ char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
+ char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
+ char* key0 = &keyval0[1];
+ char* key1 = &keyval1[1];
+ KEY* key_info = table->key_info + i;
+ ibool is_null;
+
+ dict_index_t* idx = innobase_get_index(i);
+ dict_table_t* tab = (idx) ? idx->table : NULL;
+
+ keyval0[0] = (char)i;
+ keyval1[0] = (char)i;
+
+ if (!tab) {
+ WSREP_WARN("MySQL-InnoDB key mismatch %s %s",
+ table->s->table_name.str,
+ key_info->name);
+ }
+ /* !hasPK == table with no PK, must append all non-unique keys */
+ if (!hasPK || key_info->flags & HA_NOSAME ||
+ ((tab &&
+ dict_table_get_referenced_constraint(tab, idx)) ||
+ (!tab && referenced_by_foreign_key()))) {
+
+ len = wsrep_store_key_val_for_row(
+ table, i, key0,
+ WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record0, &is_null);
+ if (!is_null) {
+ int 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(
+ table, i, key1,
+ WSREP_MAX_SUPPORTED_KEY_LENGTH,
+ record1, &is_null);
+ if (!is_null && memcmp(key0, key1, len)) {
+ int rcode = wsrep_append_key(
+ thd, trx, table_share,
+ table,
+ keyval1, len+1, shared);
+ if (rcode) DBUG_RETURN(rcode);
+ }
+ }
+ }
+ }
+ }
+
+ /* if no PK, calculate hash of full row, to be the key value */
+ if (!key_appended && wsrep_certify_nonPK) {
+ uchar digest[16];
+ int rcode;
+
+ wsrep_calc_row_hash(digest, record0, table, prebuilt, thd);
+ if ((rcode = wsrep_append_key(thd, trx, table_share, table,
+ (const char*) digest, 16,
+ shared))) {
+ DBUG_RETURN(rcode);
+ }
+
+ if (record1) {
+ wsrep_calc_row_hash(
+ digest, record1, table, prebuilt, thd);
+ if ((rcode = wsrep_append_key(thd, trx, table_share,
+ table,
+ (const char*) digest,
+ 16, shared))) {
+ DBUG_RETURN(rcode);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+
+ DBUG_RETURN(0);
+}
+#endif
/*********************************************************************//**
Stores a reference to the current row to 'ref' field of the handle. Note
that in the case where we have generated the clustered index for the
@@ -10793,11 +11854,18 @@ ha_innobase::external_lock(
/* used by test case */
DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = 1;);
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 */
}
}
@@ -11767,7 +12835,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);
@@ -12065,6 +13146,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);
}
@@ -13139,6 +14223,304 @@ static SHOW_VAR innodb_status_variables_export[]= {
static struct st_mysql_storage_engine innobase_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+#ifdef WITH_WSREP
+void
+wsrep_abort_slave_trx(wsrep_seqno_t bf_seqno, wsrep_seqno_t victim_seqno)
+{
+ WSREP_ERROR("Trx %lld tries to abort slave trx %lld. This could be "
+ "caused by:\n\t"
+ "1) unsupported configuration options combination, please check documentation.\n\t"
+ "2) a bug in the code.\n\t"
+ "3) a database corruption.\n Node consistency compromized, "
+ "need to abort. Restart the node to resync with cluster.",
+ (long long)bf_seqno, (long long)victim_seqno);
+ abort();
+}
+
+int
+wsrep_innobase_kill_one_trx(
+ void *bf_thd_ptr, /*!< in: BF thd */
+ trx_t *bf_trx, /*!< in: BF trx */
+ trx_t *victim_trx, /*!< in: victim trx */
+ ibool signal, /*!< in: signal to be used */
+ ibool have_kernel_mutex) /*!<in: do we own kernel mutex */
+{
+ DBUG_ENTER("wsrep_innobase_kill_one_trx");
+ THD *bf_thd = (THD *)bf_thd_ptr;
+ THD *thd = (THD *) victim_trx->mysql_thd;
+ int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0;
+
+ if (have_kernel_mutex) {
+ ut_ad(mutex_own(&kernel_mutex));
+ }
+
+ if (!bf_thd) bf_thd = (bf_trx) ? (THD *)bf_trx->mysql_thd : NULL;
+
+ if (!thd) {
+ DBUG_PRINT("wsrep", ("no thd for conflicting lock"));
+ WSREP_WARN("no THD for trx: %llu", victim_trx->id);
+ DBUG_RETURN(1);
+ }
+ if (!bf_thd) {
+ DBUG_PRINT("wsrep", ("no BF thd for conflicting lock"));
+ WSREP_WARN("no BF THD for trx: %llu", (bf_trx) ? bf_trx->id : 0);
+ DBUG_RETURN(1);
+ }
+
+ WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
+
+ WSREP_DEBUG("BF kill (%lu, seqno: %lld), victim: (%lu) trx: %llu",
+ 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);
+
+ if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
+ WSREP_DEBUG("kill trx EXITING for %llu", victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ DBUG_RETURN(0);
+ }
+ if(wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
+ WSREP_DEBUG("withdraw for BF trx: %llu, state: %d",
+ victim_trx->id,
+ wsrep_thd_conflict_state(thd));
+ }
+
+ switch (wsrep_thd_conflict_state(thd)) {
+ case NO_CONFLICT:
+ wsrep_thd_set_conflict_state(thd, MUST_ABORT);
+ break;
+ case MUST_ABORT:
+ WSREP_DEBUG("victim %llu in MUST ABORT state",
+ victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ wsrep_thd_awake(bf_thd, thd, signal);
+ DBUG_RETURN(0);
+ break;
+ case ABORTED:
+ case ABORTING: // fall through
+ default:
+ WSREP_DEBUG("victim %llu 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_thd_awake(bf_thd, thd, signal);
+ WSREP_DEBUG("kill trx QUERY_COMMITTING for %llu",
+ 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: %llu",
+ victim_trx->id);
+ wsrep_thd_UNLOCK(thd);
+ DBUG_RETURN(1);
+ break;
+ case WSREP_OK:
+ break;
+ default:
+ WSREP_ERROR(
+ "cancel commit bad exit: %d %llu",
+ rcode,
+ victim_trx->id);
+ /* unable to interrupt, must abort */
+ /* note: kill_mysql() will block, if we cannot.
+ * kill the lock holder first.
+ */
+ abort();
+ break;
+ }
+ }
+ break;
+ case QUERY_EXEC:
+ /* it is possible that victim trx is itself waiting for some
+ * other lock. We need to cancel this waiting
+ */
+ WSREP_DEBUG("kill trx QUERY_EXEC for %llu", victim_trx->id);
+
+ victim_trx->was_chosen_as_deadlock_victim= TRUE;
+ if (victim_trx->wait_lock) {
+ WSREP_DEBUG("victim has wait flag: %ld",
+ wsrep_thd_thread_id(thd));
+ lock_t* wait_lock = victim_trx->wait_lock;
+ if (wait_lock) {
+ WSREP_DEBUG("canceling wait lock");
+ victim_trx->was_chosen_as_deadlock_victim= TRUE;
+ if (!have_kernel_mutex) {
+ mutex_enter(&kernel_mutex);
+ }
+ lock_cancel_waiting_and_release(wait_lock);
+ /* If we already have kernel mutex when we
+ arrived to this function, do not yet release
+ it */
+ if (!have_kernel_mutex) {
+ mutex_exit(&kernel_mutex);
+ }
+ }
+
+ wsrep_thd_awake(bf_thd, thd, signal);
+ } else {
+ /* abort currently executing query */
+ DBUG_PRINT("wsrep",("sending KILL_QUERY to: %ld",
+ wsrep_thd_thread_id(thd)));
+ WSREP_DEBUG("kill query for: %ld",
+ wsrep_thd_thread_id(thd));
+ wsrep_thd_awake(bf_thd, thd, signal);
+
+ /* for BF thd, we need to prevent him from committing */
+ if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
+ wsrep_abort_slave_trx(bf_seqno,
+ wsrep_thd_trx_seqno(thd));
+ }
+ }
+ break;
+ case QUERY_IDLE:
+ {
+ bool skip_abort= false;
+ wsrep_aborting_thd_t abortees;
+
+ WSREP_DEBUG("kill IDLE for %llu", victim_trx->id);
+
+ if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
+ WSREP_DEBUG("kill BF IDLE, seqno: %lld",
+ (long long)wsrep_thd_trx_seqno(thd));
+ wsrep_thd_UNLOCK(thd);
+ wsrep_abort_slave_trx(bf_seqno,
+ wsrep_thd_trx_seqno(thd));
+ DBUG_RETURN(0);
+ }
+ /* This will lock thd from proceeding after net_read() */
+ wsrep_thd_set_conflict_state(thd, ABORTING);
+
+ mysql_mutex_lock(&LOCK_wsrep_rollback);
+
+ abortees = wsrep_aborting_thd;
+ while (abortees && !skip_abort) {
+ /* check if we have a kill message for this already */
+ if (abortees->aborting_thd == thd) {
+ skip_abort = true;
+ WSREP_WARN("duplicate thd aborter %lu",
+ wsrep_thd_thread_id(thd));
+ }
+ abortees = abortees->next;
+ }
+ if (!skip_abort) {
+ wsrep_aborting_thd_t aborting = (wsrep_aborting_thd_t)
+ my_malloc(sizeof(struct wsrep_aborting_thd),
+ MYF(0));
+ aborting->aborting_thd = thd;
+ aborting->next = wsrep_aborting_thd;
+ wsrep_aborting_thd = aborting;
+ DBUG_PRINT("wsrep",("enqueuing trx abort for %lu",
+ wsrep_thd_thread_id(thd)));
+ WSREP_DEBUG("enqueuing trx abort for (%lu)",
+ wsrep_thd_thread_id(thd));
+ }
+
+ DBUG_PRINT("wsrep",("signalling wsrep rollbacker"));
+ WSREP_DEBUG("signaling aborter");
+ mysql_cond_signal(&COND_wsrep_rollback);
+ mysql_mutex_unlock(&LOCK_wsrep_rollback);
+
+ break;
+ }
+ default:
+ WSREP_WARN("bad wsrep query state: %d",
+ wsrep_thd_query_state(thd));
+ break;
+ }
+ wsrep_thd_UNLOCK(thd);
+
+ DBUG_RETURN(0);
+}
+static int
+wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
+ my_bool signal)
+{
+ DBUG_ENTER("wsrep_innobase_abort_thd");
+ trx_t* victim_trx = thd_to_trx(victim_thd);
+ trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
+
+ ut_ad(!mutex_own(&kernel_mutex));
+
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s",
+ wsrep_thd_query(bf_thd),
+ wsrep_thd_query(victim_thd));
+
+ if (victim_trx)
+ {
+ int rcode = wsrep_innobase_kill_one_trx(
+ bf_thd, bf_trx, victim_trx, signal, FALSE);
+ 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(bf_thd, 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(&kernel_mutex);
+ trx_id_t trx_id = trx_sys_get_new_trx_id();
+ mutex_exit(&kernel_mutex);
+
+ (void *)wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
+}
+
+#endif /* WITH_WSREP */
/* plugin options */
static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
@@ -13646,6 +15028,40 @@ static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
NULL, NULL, 0, 0, 2, 0);
#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.",
@@ -13985,6 +15401,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
MYSQL_SYSVAR(change_buffering_debug),
#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(io_capacity),
diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h
index 914055a9271..69a28905f22 100644
--- a/storage/xtradb/handler/ha_innodb.h
+++ b/storage/xtradb/handler/ha_innodb.h
@@ -115,6 +115,10 @@ class ha_innobase: public handler
dict_index_t* innobase_get_index(uint keynr);
int info_low(uint flag, bool called_from_analyze);
+#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);
@@ -372,6 +376,40 @@ bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
*/
extern void mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file);
+#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* bf_thd, THD *thd, my_bool signal);
+#endif
typedef struct trx_struct trx_t;
/********************************************************************//**
@file handler/ha_innodb.h
@@ -435,3 +473,6 @@ innobase_build_index_translation(
where index translation table
will be constructed in. */
+#ifdef WITH_WSREP
+extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
+#endif
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 82902db8412..bdb4fa0c1b6 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -37,6 +37,10 @@ extern "C" {
#include "handler0alter.h"
}
+#ifdef WITH_WSREP
+//#include "wsrep_api.h"
+#include <sql_acl.h> // PROCESS_ACL
+#endif
#include "ha_innodb.h"
/*************************************************************//**
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index 07ecc42f045..81d5923a5fb 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -344,6 +344,9 @@ barracuda format, the length could be REC_VERSION_56_MAX_INDEX_COL_LEN
/** 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_struct{
diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h
index c430d7cc590..73741ed911e 100644
--- a/storage/xtradb/include/ha_prototypes.h
+++ b/storage/xtradb/include/ha_prototypes.h
@@ -310,6 +310,19 @@ thd_flush_log_at_trx_commit(
/*================================*/
void* thd);
+#ifdef WITH_WSREP
+UNIV_INTERN int wsrep_innobase_kill_one_trx(void *thd, trx_t *bf_trx, trx_t *victim_trx,
+ ibool signal, ibool have_kernel_mutex);
+my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync);
+//int64_t wsrep_thd_trx_seqno(THD *thd);
+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*);
+my_bool wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
+#endif /* WITH_WSREP */
/**********************************************************************//**
Get the current setting of the lower_case_table_names global parameter from
mysqld.cc. We do a dirty read because for one there is no synchronization
diff --git a/storage/xtradb/include/lock0lock.h b/storage/xtradb/include/lock0lock.h
index c6684f36300..a196c51651f 100644
--- a/storage/xtradb/include/lock0lock.h
+++ b/storage/xtradb/include/lock0lock.h
@@ -810,9 +810,6 @@ lock_rec_get_page_no(
record */
#define LOCK_CONV_BY_OTHER 4096 /*!< this bit is set when the lock is created
by other transaction */
-#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_CONV_BY_OTHER)&LOCK_MODE_MASK
-# error
-#endif
#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_CONV_BY_OTHER)&LOCK_TYPE_MASK
# error
#endif
diff --git a/storage/xtradb/include/rem0rec.h b/storage/xtradb/include/rem0rec.h
index 18e89eacccd..239a02a83f8 100644
--- a/storage/xtradb/include/rem0rec.h
+++ b/storage/xtradb/include/rem0rec.h
@@ -835,6 +835,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 6eee44c93d7..6ffd5c195e7 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -175,6 +175,10 @@ extern ulint srv_log_buffer_size;
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 */
@@ -674,6 +678,14 @@ srv_conc_enter_innodb(
/*==================*/
trx_t* trx); /*!< in: transaction object associated with the
thread */
+#ifdef WITH_WSREP
+UNIV_INTERN
+void
+wsrep_srv_conc_cancel_wait(
+/*==================*/
+ trx_t* trx); /*!< in: transaction object associated with the
+ thread */
+#endif /* WITH_WSREP */
/*********************************************************************//**
This lets a thread enter InnoDB regardless of the number of threads inside
InnoDB. This must be called when a thread ends a lock wait. */
diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h
index f284790630c..69457a4c9b1 100644
--- a/storage/xtradb/include/trx0sys.h
+++ b/storage/xtradb/include/trx0sys.h
@@ -41,6 +41,9 @@ Created 3/26/1996 Heikki Tuuri
#include "ut0bh.h"
#include "read0types.h"
#include "page0types.h"
+#ifdef WITH_WSREP
+#include "trx0xa.h"
+#endif /* WITH_WSREP */
/** In a MySQL replication slave, in crash recovery we store the master log
file name and position here. */
@@ -352,6 +355,19 @@ UNIV_INTERN
void
trx_sys_print_mysql_binlog_offset(void);
/*===================================*/
+#ifdef WITH_WSREP
+/** Update WSREP checkpoint XID in sys header. */
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid, /*!< in: WSREP XID */
+ trx_sysf_t* sys_header, /*!< in: sys_header */
+ mtr_t* mtr); /*!< in: mtr */
+
+void
+/** Read WSREP checkpoint XID from sys header. */
+trx_sys_read_wsrep_checkpoint(
+ XID* xid); /*!< out: WSREP XID */
+#endif /* WITH_WSREP */
/*****************************************************************//**
Prints to stderr the MySQL master log offset info in the trx system header
COMMIT set of fields if the magic number shows it valid and stores it
@@ -552,6 +568,22 @@ We must remember this limit in order to keep file compatibility. */
//#if UNIV_PAGE_SIZE < 4096
//# error "UNIV_PAGE_SIZE < 4096"
//#endif
+
+
+/* The offset to WSREP XID headers */
+#ifdef WITH_WSREP
+#define TRX_SYS_WSREP_XID_INFO (UNIV_PAGE_SIZE - 3500)
+#define TRX_SYS_WSREP_XID_MAGIC_N_FLD 0
+#define TRX_SYS_WSREP_XID_MAGIC_N 0x77737265
+
+/* XID field: formatID, gtrid_len, bqual_len, xid_data */
+#define TRX_SYS_WSREP_XID_LEN (4 + 4 + 4 + XIDDATASIZE)
+#define TRX_SYS_WSREP_XID_FORMAT 4
+#define TRX_SYS_WSREP_XID_GTRID_LEN 8
+#define TRX_SYS_WSREP_XID_BQUAL_LEN 12
+#define TRX_SYS_WSREP_XID_DATA 16
+#endif /* WITH_WSREP*/
+
/** The offset of the MySQL replication info in the trx system header;
this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below. These are
written at prepare time and are the main copy. */
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index fcfcb14ae3b..5d0f85f1c18 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -779,6 +779,9 @@ struct trx_struct{
/*------------------------------*/
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.c b/storage/xtradb/lock/lock0lock.c
index 4d7587af288..b6cee714dec 100644
--- a/storage/xtradb/lock/lock0lock.c
+++ b/storage/xtradb/lock/lock0lock.c
@@ -40,6 +40,10 @@ Created 5/7/1996 Heikki Tuuri
#include "trx0sys.h"
#include "btr0btr.h"
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+extern my_bool wsrep_log_conflicts;
+#endif
/* Restricts the length of search we will do in the waits-for
graph of transactions */
#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
@@ -795,7 +799,6 @@ lock_reset_lock_and_trx_wait(
/* Reset the back pointer in trx to this waiting lock request */
if (!(lock->type_mode & LOCK_CONV_BY_OTHER)) {
- ut_ad((lock->trx)->wait_lock == lock);
(lock->trx)->wait_lock = NULL;
} else {
ut_ad(lock_get_type_low(lock) == LOCK_REC);
@@ -906,6 +909,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
@@ -975,6 +981,52 @@ lock_rec_has_to_wait(
return(FALSE);
}
+#ifdef WITH_WSREP
+ /* if BF thread 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) {
+ /* exclusive lock conflicts are not
+ accepted */
+ fprintf(stderr,
+ "BF-BF X lock conflict\n");
+ lock_rec_print(stderr, lock2);
+ abort();
+ } else if (wsrep_debug) {
+ fprintf(stderr,
+ "BF-BF X lock conflict\n");
+ }
+ } 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);
}
@@ -1005,7 +1057,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)));
@@ -1455,6 +1511,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.
@@ -1504,6 +1565,53 @@ lock_rec_other_has_expl_req(
}
#endif /* UNIV_DEBUG */
+#ifdef WITH_WSREP
+static void
+wsrep_kill_victim(trx_t *trx, lock_t *lock) {
+ 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->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);
+ trx_print(stderr, trx, 3000);
+
+ if (bf_other)
+ fputs("\n*** Priority TRANSACTION:\n",
+ stderr);
+ else
+ fputs("\n*** Victim TRANSACTION:\n",
+ stderr);
+ trx_print(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);
+ }
+ }
+ wsrep_innobase_kill_one_trx(
+ trx->mysql_thd, trx, lock->trx, TRUE, TRUE);
+ }
+ }
+}
+#endif
/*********************************************************************//**
Checks if some other transaction has a conflicting explicit lock request
in the queue, so that we have to wait.
@@ -1531,8 +1639,15 @@ lock_rec_other_has_conflicting(
if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) {
do {
- if (lock_rec_has_to_wait(trx, mode, lock,
+#ifdef WITH_WSREP
+ if (lock_rec_has_to_wait(TRUE, trx, mode, lock,
+#else
+ if (lock_rec_has_to_wait(trx, mode, lock,
+#endif /* WITH_WSREP */
TRUE)) {
+#ifdef WITH_WSREP
+ wsrep_kill_victim(trx, lock);
+#endif
return(lock);
}
@@ -1541,8 +1656,15 @@ lock_rec_other_has_conflicting(
} else {
do {
- if (lock_rec_has_to_wait(trx, mode, lock,
+#ifdef WITH_WSREP
+ if (lock_rec_has_to_wait(TRUE, trx, mode, lock,
+#else
+ if (lock_rec_has_to_wait(trx, mode, lock,
+#endif /* WITH_WSREP */
FALSE)) {
+#ifdef WITH_WSREP
+ wsrep_kill_victim(trx, lock);
+#endif
return(lock);
}
@@ -1674,6 +1796,9 @@ static
lock_t*
lock_rec_create(
/*============*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /* conflicting lock */
+#endif
ulint type_mode,/*!< in: lock mode and wait
flag, type is ignored and
replaced by LOCK_REC */
@@ -1733,9 +1858,66 @@ lock_rec_create(
/* Set the bit corresponding to rec */
lock_rec_set_nth_bit(lock, heap_no);
+#ifdef WITH_WSREP
+ if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ lock_t *hash = c_lock->hash;
+ lock_t *prev = NULL;
+
+ while (hash &&
+ wsrep_thd_is_BF(hash->trx->mysql_thd, TRUE) &&
+ wsrep_trx_order_before(
+ hash->trx->mysql_thd, trx->mysql_thd))
+ {
+ prev = hash;
+ hash = 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
+ */
+ if (c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
+ c_lock->trx->was_chosen_as_deadlock_victim = TRUE;
+
+ if (wsrep_debug && c_lock->trx->wait_lock != c_lock) {
+ fprintf(stderr, "WSREP: c_lock != wait lock\n");
+ lock_rec_print(stderr, c_lock);
+ lock_rec_print(stderr, c_lock->trx->wait_lock);
+ }
+
+ trx->que_state = TRX_QUE_LOCK_WAIT;
+ lock_set_lock_and_trx_wait(lock, trx);
+
+ lock_cancel_waiting_and_release(c_lock->trx->wait_lock);
+
+ /* trx might not wait for c_lock, but some other lock
+ does not matter if wait_lock was released above
+ */
+ if (c_lock->trx->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);
+
+ /* have to bail out here to avoid lock_set_lock... */
+ return(lock);
+ }
+ } 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++;
if (lock_is_wait_not_by_other(type_mode)) {
lock_set_lock_and_trx_wait(lock, trx);
@@ -1755,6 +1937,9 @@ static
enum db_err
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
@@ -1809,9 +1994,18 @@ lock_rec_enqueue_waiting(
}
if (lock == NULL) {
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) && trx->was_chosen_as_deadlock_victim) {
+ return(DB_DEADLOCK);
+ }
+ /* Enqueue the lock request that will wait to be granted */
+ lock = lock_rec_create(c_lock, type_mode | LOCK_WAIT,
+ block, heap_no, index, trx);
+#else
/* Enqueue the lock request that will wait to be granted */
lock = lock_rec_create(type_mode | LOCK_WAIT,
block, heap_no, index, trx);
+#endif /*WITH_WSREP */
} else {
ut_ad(lock->type_mode & LOCK_WAIT);
ut_ad(lock->type_mode & LOCK_CONV_BY_OTHER);
@@ -1900,7 +2094,19 @@ lock_rec_add_to_queue(
lock_t* other_lock
= lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT,
block, heap_no, trx);
+#ifdef WITH_WSREP
+ /* this can potentionally assert with wsrep */
+ if (wsrep_on(trx->mysql_thd)) {
+ if (wsrep_debug && other_lock) {
+ fprintf(stderr,
+ "WSREP: InnoDB assert ignored\n");
+ }
+ } else {
+ ut_a(!other_lock);
+ }
+#else
ut_a(!other_lock);
+#endif /* WITH_WSREP */
}
#endif /* UNIV_DEBUG */
@@ -1953,7 +2159,11 @@ lock_rec_add_to_queue(
}
somebody_waits:
+#ifdef WITH_WSREP
+ return(lock_rec_create(NULL, type_mode, block, heap_no, index, trx));
+#else
return(lock_rec_create(type_mode, block, heap_no, index, trx));
+#endif
}
/** Record locking request status */
@@ -2013,7 +2223,11 @@ lock_rec_lock_fast(
if (lock == NULL) {
if (!impl) {
+#ifdef WITH_WSREP
+ lock_rec_create(NULL, mode, block, heap_no, index, trx);
+#else
lock_rec_create(mode, block, heap_no, index, trx);
+#endif
}
return(LOCK_REC_SUCCESS_CREATED);
@@ -2069,6 +2283,9 @@ lock_rec_lock_slow(
que_thr_t* thr) /*!< in: query thread */
{
trx_t* trx;
+#ifdef WITH_WSREP
+ lock_t* c_lock = NULL;
+#endif
lock_t* lock;
ut_ad(mutex_own(&kernel_mutex));
@@ -2110,7 +2327,12 @@ lock_rec_lock_slow(
/* The trx already has a strong enough lock on rec: do
nothing */
+#ifdef WITH_WSREP
+ } else if ((c_lock = lock_rec_other_has_conflicting(
+ mode, block, heap_no, trx))) {
+#else
} else if (lock_rec_other_has_conflicting(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
@@ -2118,8 +2340,16 @@ lock_rec_lock_slow(
ut_ad(lock == NULL);
enqueue_waiting:
+#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. */
+ return(lock_rec_enqueue_waiting(c_lock, mode, block, heap_no,
+ lock, index, thr));
+#else
return(lock_rec_enqueue_waiting(mode, block, heap_no,
lock, index, thr));
+#endif /* WITH_WSREP */
} else if (!impl) {
/* Set the requested lock on the record */
@@ -2166,7 +2396,6 @@ 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);
-
/* We try a simplified and faster subroutine for the most
common cases */
switch (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
@@ -3601,6 +3830,26 @@ lock_deadlock_recursive(
stderr);
}
#endif /* UNIV_DEBUG */
+#ifdef WITH_WSREP
+ if (wsrep_debug)
+ fputs("WSREP: Deadlock detected\n", stderr);
+ if ((start != wait_lock->trx) &&
+ wsrep_thd_is_BF(start->mysql_thd, TRUE) &&
+ wsrep_thd_is_BF(
+ wait_lock->trx->mysql_thd, TRUE))
+ {
+ if (wsrep_trx_order_before(
+ start->mysql_thd,
+ wait_lock->trx->mysql_thd)) {
+
+ wait_lock->trx->was_chosen_as_deadlock_victim = TRUE;
+ lock_cancel_waiting_and_release(wait_lock);
+ return(LOCK_VICTIM_IS_OTHER);
+ } else {
+ return(LOCK_VICTIM_IS_START);
+ }
+ }
+#endif
if (trx_weight_ge(wait_lock->trx, start)) {
/* Our recursion starting point
@@ -3608,8 +3857,23 @@ lock_deadlock_recursive(
choose 'start' as the victim and roll
back it */
+#ifdef WITH_WSREP
+ if (!wsrep_thd_is_BF(
+ start->mysql_thd, FALSE))
+ {
+ return(LOCK_VICTIM_IS_START);
+ }
+#else
+ return(LOCK_VICTIM_IS_START);
+#endif
+ }
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_BF(
+ wait_lock->trx->mysql_thd, TRUE))
+ {
return(LOCK_VICTIM_IS_START);
}
+#endif
lock_deadlock_found = TRUE;
@@ -3694,6 +3958,9 @@ UNIV_INLINE
lock_t*
lock_table_create(
/*==============*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /* conflicting lock */
+#endif
dict_table_t* table, /*!< in: database table in dictionary cache */
ulint type_mode,/*!< in: lock mode possibly ORed with
LOCK_WAIT */
@@ -3730,7 +3997,40 @@ lock_table_create(
lock->un_member.tab_lock.table = table;
+#ifdef WITH_WSREP
+ if (c_lock && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ UT_LIST_INSERT_AFTER(
+ un_member.tab_lock.locks, table->locks, c_lock, lock);
+ } else {
+ UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
+ }
+
+ if (c_lock && c_lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
+ if (wsrep_debug) {
+ fprintf(stderr,
+ "WSREP: table c_lock in wait: %llu new loc: %llu\n",
+ (ulonglong) c_lock->trx->id, lock->trx->id);
+ }
+
+ c_lock->trx->was_chosen_as_deadlock_victim = TRUE;
+ lock_cancel_waiting_and_release(c_lock->trx->wait_lock);
+
+ /* trx might not wait for c_lock, but some other lock
+ does not matter if wait_lock was released above
+ */
+ if (c_lock->trx->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);
+ }
+ }
+
+#else
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
+#endif
if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
@@ -3878,6 +4178,9 @@ static
ulint
lock_table_enqueue_waiting(
/*=======================*/
+#ifdef WITH_WSREP
+ lock_t* c_lock, /* conflicting lock */
+#endif
ulint mode, /*!< in: lock mode this transaction is
requesting */
dict_table_t* table, /*!< in: table */
@@ -3921,7 +4224,14 @@ lock_table_enqueue_waiting(
/* Enqueue the lock request that will wait to be granted */
+#ifdef WITH_WSREP
+ if (trx->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
/* Check if a deadlock occurs: if yes, remove the lock request and
return an error code */
@@ -3983,7 +4293,11 @@ lock_table_other_has_incompatible(
if ((lock->trx != trx)
&& (!lock_mode_compatible(lock_get_mode(lock), mode))
&& (wait || !(lock_get_wait(lock)))) {
-
+#ifdef WITH_WSREP
+ if (wsrep_debug)
+ fprintf(stderr, "WSREP: table lock abort");
+ wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
+#endif
return(lock);
}
@@ -4007,6 +4321,9 @@ lock_table(
enum lock_mode mode, /*!< in: lock mode */
que_thr_t* thr) /*!< in: query thread */
{
+#ifdef WITH_WSREP
+ lock_t *c_lock;
+#endif
trx_t* trx;
ulint err;
@@ -4039,19 +4356,32 @@ 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
+ if ((c_lock = (lock_t *)lock_table_other_has_incompatible(
+ trx, LOCK_WAIT, table, mode))) {
+#else
if (lock_table_other_has_incompatible(trx, LOCK_WAIT, table, mode)) {
+#endif
/* Another trx has a request on the table in an incompatible
mode: this trx may have to wait */
+#ifdef WITH_WSREP
+ err = lock_table_enqueue_waiting(c_lock, mode | flags, table, thr);
+#else
err = lock_table_enqueue_waiting(mode | flags, table, thr);
+#endif
lock_mutex_exit_kernel();
return(err);
}
+#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);
@@ -4975,6 +5305,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) {
@@ -4984,6 +5315,7 @@ lock_rec_queue_validate(
}
ut_a(!lock_rec_other_has_expl_req(
mode, 0, 0, block, heap_no, lock->trx));
+#endif /* WITH_WSREP */
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
@@ -5260,6 +5592,9 @@ lock_rec_insert_check_and_lock(
lock_t* lock;
ulint err;
ulint next_rec_heap_no;
+#ifdef WITH_WSREP
+ lock_t *c_lock;
+#endif
ut_ad(block->frame == page_align(rec));
@@ -5317,15 +5652,28 @@ lock_rec_insert_check_and_lock(
had to wait for their insert. Both had waiting gap type lock requests
on the successor, which produced an unnecessary deadlock. */
+#ifdef WITH_WSREP
+ if ((c_lock = lock_rec_other_has_conflicting(
+ LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
+ block, next_rec_heap_no, trx))) {
+#else
if (lock_rec_other_has_conflicting(
LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
block, next_rec_heap_no, trx)) {
+#endif
/* Note that we may get DB_SUCCESS also here! */
+#ifdef WITH_WSREP
+ err = lock_rec_enqueue_waiting(c_lock, LOCK_X | LOCK_GAP
+ | LOCK_INSERT_INTENTION,
+ block, next_rec_heap_no,
+ NULL, index, thr);
+#else
err = lock_rec_enqueue_waiting(LOCK_X | LOCK_GAP
| LOCK_INSERT_INTENTION,
block, next_rec_heap_no,
NULL, index, thr);
+#endif /* WITH_WSREP */
} else {
err = DB_SUCCESS;
}
@@ -5409,6 +5757,11 @@ lock_rec_convert_impl_to_expl(
implicit lock. Because cannot lock at this moment.*/
if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))
+#ifdef WITH_WSREP
+ && !wsrep_thd_is_BF(impl_trx->mysql_thd, FALSE)
+ /* BF-BF conflict is possible if advancing into
+ lock_rec_other_has_conflicting*/
+#endif /* WITH_WSREP */
&& lock_rec_other_has_conflicting(
LOCK_X | LOCK_REC_NOT_GAP, block,
heap_no, impl_trx)) {
diff --git a/storage/xtradb/os/os0file.c b/storage/xtradb/os/os0file.c
index e48f65956bb..8e5cc9a6ba6 100644
--- a/storage/xtradb/os/os0file.c
+++ b/storage/xtradb/os/os0file.c
@@ -104,6 +104,12 @@ UNIV_INTERN os_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:
@@ -864,7 +870,9 @@ os_file_create_tmpfile(void)
/*========================*/
{
FILE* file = NULL;
- int fd = innobase_mysql_tmpfile();
+ int fd;
+ WAIT_ALLOW_WRITES();
+ fd = innobase_mysql_tmpfile();
if (fd >= 0) {
file = fdopen(fd, "w+b");
@@ -1148,6 +1156,7 @@ os_file_create_directory(
return (TRUE);
#else
int rcode;
+ WAIT_ALLOW_WRITES();
rcode = mkdir(pathname, 0770);
@@ -1249,6 +1258,8 @@ try_again:
os_file_t file;
int create_flag;
ibool retry;
+ if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
+ WAIT_ALLOW_WRITES();
try_again:
ut_a(name);
@@ -1384,6 +1395,8 @@ os_file_create_simple_no_error_handling_func(
const char* mode_str = NULL;
ut_a(name);
+ if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
+ WAIT_ALLOW_WRITES();
if (create_mode == OS_FILE_OPEN) {
mode_str = "OPEN";
@@ -1694,6 +1707,8 @@ try_again:
int create_flag;
ibool retry;
const char* mode_str = NULL;
+ if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
+ WAIT_ALLOW_WRITES();
DBUG_EXECUTE_IF(
"ib_create_table_fail_disk_full",
@@ -1873,6 +1888,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -1936,6 +1952,7 @@ loop:
goto loop;
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = unlink(name);
@@ -1976,6 +1993,7 @@ os_file_rename_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
ret = rename(oldpath, newpath);
@@ -2236,6 +2254,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__ */
}
@@ -2365,6 +2384,7 @@ os_file_flush_func(
return(FALSE);
#else
int ret;
+ WAIT_ALLOW_WRITES();
#if defined(HAVE_DARWIN_THREADS)
# ifndef F_FULLFSYNC
@@ -3049,6 +3069,7 @@ retry:
return(FALSE);
#else
ssize_t ret;
+ WAIT_ALLOW_WRITES();
ret = os_file_pwrite(file, buf, n, offset, offset_high);
diff --git a/storage/xtradb/os/os0proc.c b/storage/xtradb/os/os0proc.c
index 7b52dd2a28f..535bb308e34 100644
--- a/storage/xtradb/os/os0proc.c
+++ b/storage/xtradb/os/os0proc.c
@@ -57,6 +57,9 @@ UNIV_INTERN ibool os_use_large_pages;
/* Large page size. This may be a boot-time option on some platforms */
UNIV_INTERN ulint os_large_page_size;
+#ifdef WITH_WSREP
+extern my_bool wsrep_recovery;
+#endif /* WITH_WSREP */
/****************************************************************//**
Converts the current process id to a number. It is not guaranteed that the
number is unique. In Linux returns the 'process number' of the current
@@ -183,6 +186,12 @@ skip:
# else
size = UNIV_PAGE_SIZE;
# endif
+#ifdef WITH_WSREP
+ /* Don't populate if wsrep_recovery is ON */
+ if (wsrep_recovery) {
+ populate = FALSE;
+ }
+#endif /* WITH_WSREP */
/* Align block size to system page size */
ut_ad(ut_is_2pow(size));
size = *n = ut_2pow_round(*n + (size - 1), size);
diff --git a/storage/xtradb/rem/rem0rec.c b/storage/xtradb/rem/rem0rec.c
index a43085fe89e..232033a3f23 100644
--- a/storage/xtradb/rem/rem0rec.c
+++ b/storage/xtradb/rem/rem0rec.c
@@ -31,6 +31,9 @@ Created 5/30/1994 Heikki Tuuri
#include "mtr0mtr.h"
#include "mtr0log.h"
+#ifdef WITH_WSREP
+#include <ha_prototypes.h>
+#endif /* WITH_WSREP */
/* PHYSICAL RECORD (OLD STYLE)
===========================
@@ -1896,3 +1899,133 @@ 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
diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c
index 6de9a95a694..a4309612377 100644
--- a/storage/xtradb/row/row0ins.c
+++ b/storage/xtradb/row/row0ins.c
@@ -760,6 +760,14 @@ row_ins_invalidate_query_cache(
innobase_invalidate_query_cache(thr_get_trx(thr), buf, len);
mem_free(buf);
}
+#ifdef WITH_WSREP
+ulint 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
@@ -1073,6 +1081,18 @@ row_ins_foreign_check_on_constraint(
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
+#ifdef WITH_WSREP
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ clust_rec,
+ clust_index,
+ FALSE, FALSE);
+ if (err != DB_SUCCESS) {
+ fprintf(stderr,
+ "WSREP: foreign key append failed: %lu\n", err);
+ } else
+#endif
err = row_update_cascade_for_mysql(thr, cascade,
foreign->foreign_table);
@@ -1412,7 +1432,14 @@ run_again:
if (check_ref) {
err = DB_SUCCESS;
-
+#ifdef WITH_WSREP
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ check_ref, TRUE);
+#endif /* WITH_WSREP */
goto end_scan;
} else if (foreign->type != 0) {
/* There is an ON UPDATE or ON DELETE
diff --git a/storage/xtradb/row/row0upd.c b/storage/xtradb/row/row0upd.c
index 64ae0e3f1d0..a2eabc347d6 100644
--- a/storage/xtradb/row/row0upd.c
+++ b/storage/xtradb/row/row0upd.c
@@ -51,6 +51,10 @@ Created 12/27/1996 Heikki Tuuri
#include "pars0sym.h"
#include "eval0eval.h"
#include "buf0lru.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h"
+extern my_bool wsrep_debug;
+#endif
/* What kind of latch and lock can we assume when the control comes to
@@ -170,6 +174,50 @@ func_exit:
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 (!UT_LIST_GET_FIRST(table->foreign_list)) {
+
+ return(FALSE);
+ }
+
+ if (trx->dict_operation_lock_mode == 0) {
+ row_mysql_freeze_data_dictionary(trx);
+ froze_data_dict = TRUE;
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ if (foreign->foreign_index == index) {
+
+ is_referenced = TRUE;
+ goto func_exit;
+ }
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+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,127 @@ row_upd_check_references_constraints(
}
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
+ulint
+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;
+ ulint err;
+ ibool got_s_lock = FALSE;
+
+ if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) {
+
+ return(DB_SUCCESS);
+ }
+
+ trx = thr_get_trx(thr);
+ if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+
+ return(DB_SUCCESS);
+ }
+
+ /* 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(ROW_COPY_DATA, 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);
+ }
+
+ foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ /* 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) {
+ dict_table_get(foreign->referenced_table_name_lookup,
+ FALSE, DICT_ERR_IGNORE_NONE);
+ }
+
+ if (foreign->referenced_table) {
+ mutex_enter(&(dict_sys->mutex));
+
+ (foreign->referenced_table
+ ->n_foreign_key_checks_running)++;
+
+ mutex_exit(&(dict_sys->mutex));
+ }
+
+ /* 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) {
+ mutex_enter(&(dict_sys->mutex));
+
+ ut_a(foreign->referenced_table
+ ->n_foreign_key_checks_running > 0);
+
+ (foreign->referenced_table
+ ->n_foreign_key_checks_running)--;
+
+ mutex_exit(&(dict_sys->mutex));
+ }
+
+ if (err != DB_SUCCESS) {
+
+ goto func_exit;
+ }
+ }
+
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+
+ err = DB_SUCCESS;
func_exit:
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
@@ -294,6 +462,7 @@ func_exit:
return(err);
}
+#endif /* WITH_WSREP */
/*********************************************************************//**
Creates an update node for a query graph.
@@ -1578,10 +1747,16 @@ row_upd_sec_index_entry(
trx_t* trx = thr_get_trx(thr);
ulint mode = BTR_MODIFY_LEAF;
enum row_search_result search_result;
+#ifdef WITH_WSREP
+ ibool foreign;
+#endif /* WITH_WSREP */
index = node->index;
referenced = row_upd_index_is_referenced(index, trx);
+#ifdef WITH_WSREP
+ foreign = wsrep_row_upd_index_is_foreign(index, trx);
+#endif /* WITH_WSREP */
heap = mem_heap_create(1024);
@@ -1646,6 +1821,9 @@ row_upd_sec_index_entry(
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);
@@ -1663,6 +1841,38 @@ row_upd_sec_index_entry(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced &&
+ !(parent && que_node_get_type(parent) ==
+ QUE_NODE_UPDATE &&
+ ((upd_node_t*)parent)->cascade_node == node) &&
+ foreign
+ ) {
+ ulint* offsets =
+ rec_get_offsets(
+ rec, index, NULL,
+ ULINT_UNDEFINED, &heap);
+ err = wsrep_row_upd_check_foreign_constraints(
+ node, &pcur, index->table,
+ index, offsets, thr, &mtr);
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_NO_REFERENCED_ROW:
+ err = DB_SUCCESS;
+ break;
+ case DB_DEADLOCK:
+ if (wsrep_debug)
+ fprintf (stderr,
+ "WSREP: sec index FK check fail for deadlock");
+ break;
+ default:
+ fprintf (stderr,
+ "WSREP: referenced FK check fail: %lu",
+ err);
+ break;
+ }
+ }
+#endif /* WITH_WSREP */
}
break;
}
@@ -1813,6 +2023,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;
@@ -1826,6 +2039,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));
@@ -1911,6 +2127,34 @@ err_exit:
goto err_exit;
}
}
+#ifdef WITH_WSREP
+ if (!referenced &&
+ !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
+ ((upd_node_t*)parent)->cascade_node == node) &&
+ foreign
+ ) {
+ err = wsrep_row_upd_check_foreign_constraints(
+ node, pcur, table, index, offsets, thr, mtr);
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_NO_REFERENCED_ROW:
+ err = DB_SUCCESS;
+ break;
+ case DB_DEADLOCK:
+ if (wsrep_debug) fprintf (stderr,
+ "WSREP: insert FK check fail for deadlock");
+ break;
+ default:
+ fprintf (stderr,
+ "WSREP: referenced FK check fail: %lu",
+ err);
+ break;
+ }
+ if (err != DB_SUCCESS) {
+ goto err_exit;
+ }
+ }
+#endif /* WITH_WSREP */
}
mtr_commit(mtr);
@@ -2086,11 +2330,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;
ulint 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));
@@ -2107,15 +2358,49 @@ 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(
BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
+#ifdef WITH_WSREP
+ rec, index, offsets, TRUE, thr, mtr);
+#else
btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
+#endif /* WITH_WSREP */
if (err == DB_SUCCESS && referenced) {
/* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced &&
+ !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
+ ((upd_node_t*)parent)->cascade_node == node) &&
+ thr_get_trx(thr) &&
+ foreign
+ ) {
+ err = wsrep_row_upd_check_foreign_constraints(
+ node, pcur, index->table, index, offsets, thr, mtr);
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_NO_REFERENCED_ROW:
+ err = DB_SUCCESS;
+ break;
+ case DB_DEADLOCK:
+ if (wsrep_debug) fprintf (stderr,
+ "WSREP: clust rec FK check fail for deadlock");
+ break;
+ default:
+ fprintf (stderr,
+ "WSREP: clust rec referenced FK check fail: %lu",
+ err);
+ break;
+ }
+ }
+#endif /* WITH_WSREP */
mtr_commit(mtr);
@@ -2144,11 +2429,17 @@ row_upd_clust_step(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets;
ibool referenced;
+#ifdef WITH_WSREP
+ ibool foreign;
+#endif /* WITH_WSREP */
rec_offs_init(offsets_);
index = dict_table_get_first_index(node->table);
referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
+#ifdef WITH_WSREP
+ foreign = wsrep_row_upd_index_is_foreign(index, thr_get_trx(thr));
+#endif /* WITH_WSREP */
pcur = node->pcur;
@@ -2221,7 +2512,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;
@@ -2272,7 +2567,11 @@ exit_func:
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/srv0srv.c b/storage/xtradb/srv/srv0srv.c
index 6d7327c187f..9e863765dc0 100644
--- a/storage/xtradb/srv/srv0srv.c
+++ b/storage/xtradb/srv/srv0srv.c
@@ -100,6 +100,10 @@ ulong innobase_thd_get_thread_id(const void* thd);
/* prototypes for new functions added to ha_innodb.cc */
ibool innobase_get_slow_log();
+#ifdef WITH_WSREP
+extern int 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;
@@ -236,6 +240,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;
@@ -383,6 +391,9 @@ struct srv_conc_slot_struct{
free to proceed; but
reserved may still be
TRUE at that point */
+#ifdef WITH_WSREP
+ void *thd; /*!< to see priority */
+#endif
UT_LIST_NODE_T(srv_conc_slot_t) srv_conc_queue; /*!< queue node */
};
@@ -1211,8 +1222,20 @@ srv_init(void)
conc_slot->reserved = FALSE;
conc_slot->event = os_event_create(NULL);
ut_a(conc_slot->event);
+#ifdef WITH_WSREP
+ conc_slot->thd = NULL;
+#endif /* WITH_WSREP */
}
+#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(NULL);
+ 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);
}
@@ -1261,6 +1284,23 @@ srv_general_init(void)
/* Maximum allowable purge history length. <=0 means 'infinite'. */
UNIV_INTERN ulong srv_max_purge_lag = 0;
+#ifdef WITH_WSREP
+UNIV_INTERN
+void
+wsrep_srv_conc_cancel_wait(
+/*==================*/
+ trx_t* trx) /*!< in: transaction object associated with the
+ thread */
+{
+ 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 /* WITH_WSREP */
/*********************************************************************//**
Puts an OS thread to wait if there are too many concurrent threads
(>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */
@@ -1382,6 +1422,18 @@ srv_conc_enter_innodb(
}
#endif
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ srv_conc_force_enter_innodb(trx);
+ return;
+ }
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_trx_is_aborting(trx->mysql_thd)) {
+ srv_conc_force_enter_innodb(trx);
+ return;
+ }
+#endif
os_fast_mutex_lock(&srv_conc_mutex);
retry:
if (trx->declared_to_be_inside_innodb) {
@@ -1475,6 +1527,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);
@@ -1482,6 +1537,19 @@ retry:
srv_conc_n_waiting_threads++;
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_trx_is_aborting(trx->mysql_thd)) {
+ srv_conc_n_waiting_threads--;
+ 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_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
@@ -1505,6 +1573,9 @@ retry:
thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK);
os_event_wait(slot->event);
thd_wait_end(trx->mysql_thd);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
trx->op_info = "";
@@ -1522,6 +1593,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);
@@ -1609,6 +1683,9 @@ srv_conc_force_exit_innodb(
trx->n_tickets_to_enter_innodb = 0;
if (srv_conc_n_threads < (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 */
@@ -1618,6 +1695,19 @@ srv_conc_force_exit_innodb(
slot = UT_LIST_GET_NEXT(srv_conc_queue, slot);
}
+#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;
@@ -2001,7 +2091,20 @@ srv_suspend_mysql_thread(
if (lock_wait_timeout < 100000000
&& wait_time > (double) lock_wait_timeout) {
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ wsrep_thd_is_BF(trx->mysql_thd, TRUE)) {
+ fprintf(stderr,
+ "WSREP: BF long lock wait ended after %.f sec\n",
+ wait_time);
+ srv_print_innodb_monitor = FALSE;
+ srv_print_innodb_lock_monitor = FALSE;
+ } else {
+#endif
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
+#ifdef WITH_WSREP
+ }
+#endif
}
if (trx_is_interrupted(trx)) {
@@ -2800,6 +2903,27 @@ exit_func:
OS_THREAD_DUMMY_RETURN;
}
+#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(
+/*====================*/
+ srv_slot_t* slot) /* in: lock slot to check for lock priority */
+{
+ if (wsrep_on(thr_get_trx(slot->thr)->mysql_thd) &&
+ wsrep_thd_is_BF((thr_get_trx(slot->thr))->mysql_thd, TRUE)) {
+ fprintf(stderr, "WSREP: BF lock wait long\n");
+ srv_print_innodb_monitor = TRUE;
+ srv_print_innodb_lock_monitor = TRUE;
+ os_event_set(srv_lock_timeout_thread_event);
+ return TRUE;
+ }
+ return FALSE;
+ }
+#endif /* WITH_WSREP */
/*********************************************************************//**
A thread which wakes up threads whose lock wait may have lasted too long.
@return a dummy parameter */
@@ -2868,8 +2992,14 @@ loop:
granted: in that case do nothing */
if (trx->wait_lock) {
+#ifdef WITH_WSREP
+ if (!wsrep_is_BF_lock_timeout(slot)) {
+#endif
lock_cancel_waiting_and_release(
trx->wait_lock);
+#ifdef WITH_WSREP
+ }
+#endif
}
}
}
@@ -2987,7 +3117,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.c b/storage/xtradb/srv/srv0start.c
index 331382d2438..d8710eab82c 100644
--- a/storage/xtradb/srv/srv0start.c
+++ b/storage/xtradb/srv/srv0start.c
@@ -91,7 +91,10 @@ Created 2/16/1996 Heikki Tuuri
# include "buf0lru.h" /* for buf_LRU_file_restore() */
# include "os0stacktrace.h"
-/** Log sequence number immediately after startup */
+#ifdef WITH_WSREP
+extern my_bool wsrep_recovery;
+#endif /* WITH_WSREP */
+ /** Log sequence number immediately after startup */
UNIV_INTERN ib_uint64_t srv_start_lsn;
/** Log sequence number at shutdown */
UNIV_INTERN ib_uint64_t srv_shutdown_lsn;
@@ -2115,6 +2118,10 @@ innobase_start_or_create_for_mysql(void)
os_thread_create(&srv_monitor_thread, NULL,
thread_ids + 4 + SRV_MAX_N_IO_THREADS);
+#ifdef WITH_WSREP
+ /* Don't start the LRU thread when recovery is on */
+ if (!wsrep_recovery) {
+#endif /* WITH_WSREP */
/* Create the thread which automaticaly dumps/restore buffer pool */
os_thread_create(&srv_LRU_dump_restore_thread, NULL,
thread_ids + 5 + SRV_MAX_N_IO_THREADS);
@@ -2123,6 +2130,9 @@ innobase_start_or_create_for_mysql(void)
synchronously */
if (srv_auto_lru_dump && srv_blocking_lru_restore)
buf_LRU_file_restore();
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
srv_is_being_started = FALSE;
diff --git a/storage/xtradb/trx/trx0roll.c b/storage/xtradb/trx/trx0roll.c
index 8c0438ab975..f2a3a2cc4c7 100644
--- a/storage/xtradb/trx/trx0roll.c
+++ b/storage/xtradb/trx/trx0roll.c
@@ -43,6 +43,9 @@ Created 3/26/1996 Heikki Tuuri
#include "row0mysql.h"
#include "lock0lock.h"
#include "pars0pars.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h"
+#endif /* WITH_WSREP */
/** This many pages must be undone before a truncate is tried within
rollback */
@@ -148,6 +151,12 @@ trx_rollback_for_mysql(
trx->op_info = "";
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
return(err);
}
@@ -175,6 +184,12 @@ trx_rollback_last_sql_stat_for_mysql(
trx->op_info = "";
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
return(err);
}
@@ -1127,6 +1142,12 @@ trx_rollback(
srv_que_task_enqueue_low(thr);
/* srv_que_task_enqueue_low(thr2); */
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
}
/****************************************************************//**
@@ -1285,6 +1306,12 @@ trx_finish_rollback_off_kernel(
sig = next_sig;
}
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
}
/*********************************************************************//**
diff --git a/storage/xtradb/trx/trx0sys.c b/storage/xtradb/trx/trx0sys.c
index a56e55c0e19..7d9397b8e2c 100644
--- a/storage/xtradb/trx/trx0sys.c
+++ b/storage/xtradb/trx/trx0sys.c
@@ -44,6 +44,10 @@ Created 3/26/1996 Heikki Tuuri
#include "os0file.h"
#include "read0read.h"
+#ifdef WITH_WSREP
+#include "ha_prototypes.h" /* wsrep_is_wsrep_xid() */
+#endif /* */
+
/** The file format tag structure with id and name. */
struct file_format_struct {
ulint id; /*!< id of the file format */
@@ -960,6 +964,125 @@ trx_sys_print_mysql_binlog_offset(void)
mtr_commit(&mtr);
}
+#ifdef WITH_WSREP
+
+#ifdef UNIV_DEBUG
+static long long trx_sys_cur_xid_seqno = -1;
+static unsigned char trx_sys_cur_xid_uuid[16];
+
+long long read_wsrep_xid_seqno(const XID* xid)
+{
+ long long seqno;
+ memcpy(&seqno, xid->data + 24, sizeof(long long));
+ return seqno;
+}
+
+void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
+{
+ memcpy(buf, xid->data + 8, 16);
+}
+
+#endif /* UNIV_DEBUG */
+
+void
+trx_sys_update_wsrep_checkpoint(
+ const XID* xid, /*!< in: transaction XID */
+ trx_sysf_t* sys_header, /*!< in: sys_header */
+ mtr_t* mtr) /*!< in: mtr */
+{
+
+#ifdef UNIV_DEBUG
+ {
+ /* Check that seqno is monotonically increasing */
+ unsigned char xid_uuid[16];
+ long long xid_seqno = read_wsrep_xid_seqno(xid);
+ read_wsrep_xid_uuid(xid, xid_uuid);
+ if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 8))
+ {
+ ut_ad(xid_seqno > trx_sys_cur_xid_seqno);
+ trx_sys_cur_xid_seqno = xid_seqno;
+ }
+ else
+ {
+ memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16);
+ }
+ trx_sys_cur_xid_seqno = xid_seqno;
+ }
+#endif /* UNIV_DEBUG */
+
+ ut_ad(xid && mtr && sys_header);
+ ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid));
+
+ if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
+ != TRX_SYS_WSREP_XID_MAGIC_N) {
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD,
+ TRX_SYS_WSREP_XID_MAGIC_N,
+ MLOG_4BYTES, mtr);
+ }
+
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_FORMAT,
+ (int)xid->formatID,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_GTRID_LEN,
+ (int)xid->gtrid_length,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_BQUAL_LEN,
+ (int)xid->bqual_length,
+ MLOG_4BYTES, mtr);
+ mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_DATA,
+ (const unsigned char*) xid->data,
+ XIDDATASIZE, mtr);
+
+}
+
+void
+trx_sys_read_wsrep_checkpoint(XID* xid)
+/*===================================*/
+{
+ trx_sysf_t* sys_header;
+ mtr_t mtr;
+ ulint magic;
+
+ ut_ad(xid);
+
+ mtr_start(&mtr);
+
+ sys_header = trx_sysf_get(&mtr);
+
+ if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD))
+ != TRX_SYS_WSREP_XID_MAGIC_N) {
+ memset(xid, 0, sizeof(*xid));
+ xid->formatID = -1;
+ trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
+ mtr_commit(&mtr);
+ return;
+ }
+
+ xid->formatID = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT);
+ xid->gtrid_length = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN);
+ xid->bqual_length = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN);
+ ut_memcpy(xid->data,
+ sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA,
+ XIDDATASIZE);
+
+ mtr_commit(&mtr);
+}
+
+#endif /* WITH_WSREP */
+
/*****************************************************************//**
Reads the log coordinates at the given offset in the trx sys header. */
static
diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c
index dd7b8bfdd1d..fbdf11f378d 100644
--- a/storage/xtradb/trx/trx0trx.c
+++ b/storage/xtradb/trx/trx0trx.c
@@ -332,6 +332,9 @@ trx_create(
/* Remember to free the vector explicitly. */
trx->autoinc_locks = ib_vector_create(
mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 4), 4);
+#ifdef WITH_WSREP
+ trx->wsrep_event = NULL;
+#endif /* WITH_WSREP */
return(trx);
}
@@ -874,6 +877,11 @@ trx_start_low(
trx->id = trx_sys_get_new_trx_id();
+#ifdef WITH_WSREP
+ memset(&trx->xid, 0, sizeof(trx->xid));
+ trx->xid.formatID = -1;
+#endif /* WITH_WSREP */
+
/* The initial value for trx->no: IB_ULONGLONG_MAX is used in
read_view_open_now: */
@@ -1045,6 +1053,15 @@ trx_write_serialisation_history(
mutex_exit(&rseg->mutex);
+#ifdef WITH_WSREP
+ sys_header = trx_sysf_get(&mtr);
+ /* Update latest MySQL wsrep XID in trx sys header. */
+ if (wsrep_is_wsrep_xid(&trx->xid))
+ {
+ trx_sys_update_wsrep_checkpoint(&trx->xid, sys_header, &mtr);
+ }
+#endif /* WITH_WSREP */
+
/* Update the latest MySQL binlog name and offset info
in trx sys header if MySQL binlogging is on or the database
server is a MySQL replication slave */
@@ -1059,7 +1076,8 @@ trx_write_serialisation_history(
sys_header,
trx->mysql_log_file_name,
trx->mysql_log_offset,
- TRX_SYS_MYSQL_LOG_INFO, &mtr);
+ TRX_SYS_MYSQL_LOG_INFO,
+ &mtr);
trx->mysql_log_file_name = NULL;
}
@@ -1287,6 +1305,12 @@ trx_commit_off_kernel(
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0);
+#ifdef WITH_WSREP
+ if (wsrep_on(trx->mysql_thd) &&
+ trx->was_chosen_as_deadlock_victim) {
+ trx->was_chosen_as_deadlock_victim = FALSE;
+ }
+#endif
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
ut_ad(trx_sys->descr_n_used <= UT_LIST_GET_LEN(trx_sys->trx_list));
diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt
index 5e9fd081a09..b48abde4fe8 100644
--- a/support-files/CMakeLists.txt
+++ b/support-files/CMakeLists.txt
@@ -41,7 +41,7 @@ ELSE()
SET(inst_location ${INSTALL_SUPPORTFILESDIR})
ENDIF()
-FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small)
+FOREACH(inifile my-huge my-innodb-heavy-4G my-large my-medium my-small wsrep)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${inifile}.cnf.sh
${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension} @ONLY)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${inifile}.${ini_file_extension}
@@ -94,6 +94,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 7a6154a1af5..a1b43d99a05 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -24,6 +24,14 @@
# Short-Description: start and stop MySQL
# Description: MySQL is a very fast and reliable SQL database engine.
### END INIT INFO
+
+# Prevent OpenSUSE's init scripts from calling systemd, so that
+# both 'bootstrap' and 'start' are handled entirely within this
+# script
+SYSTEMD_NO_WRAP=1
+
+# Prevent Debian's init scripts from calling systemctl
+_SYSTEMCTL_SKIP_REDIRECT=true
# If you install MySQL on some other places than @prefix@, then you
# have to do one of the following things for this script to work:
@@ -52,6 +60,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'
@@ -244,6 +253,10 @@ wait_for_gone () {
wait_for_ready () {
+ test -n "$socket" && sockopt="--socket=$socket"
+
+ sst_progress_file=$datadir/sst_in_progress
+
i=0
while test $i -ne $service_startup_timeout ; do
@@ -257,9 +270,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
@@ -345,7 +363,10 @@ case "$mode" in
# Stop the service and regardless of whether it was
# running or not, start it again.
if $0 stop $other_args; then
- $0 start $other_args
+ if ! $0 start $other_args; then
+ log_failure_msg "Failed to restart server."
+ exit 1
+ fi
else
log_failure_msg "Failed to stop running server, so refusing to try to start."
exit 1
@@ -422,10 +443,17 @@ 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} [ MySQL server options ]"
+ echo "Usage: $basename {start|stop|restart|reload|force-reload|status|configtest|bootstrap} [ MySQL server options ]"
exit 1
;;
esac
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 5af4783f919..0d6348c6031 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -20,15 +20,15 @@
# NOTE: "vendor" is used in upgrade/downgrade check, so you can't
# change these, has to be exactly as is.
-%global mysql_old_vendor MySQL AB
-%global mysql_vendor_2 Sun Microsystems, Inc.
-%global mysql_vendor Oracle and/or its affiliates
+%define mysql_old_vendor MySQL AB
+%define mysql_vendor_2 Sun Microsystems, Inc.
+%define mysql_vendor Oracle and/or its affiliates
-%global mysql_version @VERSION@
+%define mysql_version @VERSION@
-%global mysqld_user mysql
-%global mysqld_group mysql
-%global mysqldatadir /var/lib/mysql
+%define mysqld_user mysql
+%define mysqld_group mysql
+%define mysqldatadir /var/lib/mysql
%global release 1
@@ -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}
@@ -127,13 +142,13 @@
%if "%oelver" == "4"
%define distro_description Oracle Enterprise Linux 4
%define distro_releasetag oel4
- %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel
%define distro_requires chkconfig coreutils grep procps shadow-utils net-tools
%else
%if "%oelver" == "5"
%define distro_description Oracle Enterprise Linux 5
%define distro_releasetag oel5
- %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel
%define distro_requires chkconfig coreutils grep procps shadow-utils net-tools
%else
%{error:Oracle Enterprise Linux %{oelver} is unsupported}
@@ -156,19 +171,19 @@
%if "%rhelver" == "4"
%define distro_description Red Hat Enterprise Linux 4
%define distro_releasetag rhel4
- %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel
%define distro_requires chkconfig coreutils grep procps shadow-utils net-tools
%else
%if "%rhelver" == "5"
%define distro_description Red Hat Enterprise Linux 5
%define distro_releasetag rhel5
- %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel
%define distro_requires chkconfig coreutils grep procps shadow-utils net-tools
%else
%if "%rhelver" == "6"
%define distro_description Red Hat Enterprise Linux 6
%define distro_releasetag rhel6
- %define distro_buildreq gcc-c++ ncurses-devel perl readline-devel time zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ ncurses-devel perl readline-devel time zlib-devel
%define distro_requires chkconfig coreutils grep procps shadow-utils net-tools
%else
%{error:Red Hat Enterprise Linux %{rhelver} is unsupported}
@@ -181,13 +196,13 @@
%if "%susever" == "10"
%define distro_description SUSE Linux Enterprise Server 10
%define distro_releasetag sles10
- %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client readline-devel zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client readline-devel zlib-devel
%define distro_requires aaa_base coreutils grep procps pwdutils
%else
%if "%susever" == "11"
%define distro_description SUSE Linux Enterprise Server 11
%define distro_releasetag sles11
- %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client procps pwdutils readline-devel zlib-devel cmake libaio-devel
+ %define distro_buildreq gcc-c++ gdbm-devel gperf ncurses-devel openldap2-client procps pwdutils readline-devel zlib-devel
%define distro_requires aaa_base coreutils grep procps pwdutils
%else
%{error:SuSE %{susever} is unsupported}
@@ -284,16 +299,27 @@ 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
-Requires: %{distro_requires}
-%if 0%{?commercial}
-Obsoletes: MySQL-server
+%if %{defined with_wsrep}
+Requires: %{distro_requires} rsync lsof
%else
-Obsoletes: MySQL-server-advanced
+Requires: %{distro_requires}
%endif
Obsoletes: mysql-server < %{version}-%{release}
Obsoletes: mysql-server-advanced
+Conflicts: mysql mysql-server mysql-advanced mysql-server-advanced
+Obsoletes: MySQL MySQL-server
+Obsoletes: MySQL-server-classic MySQL-server-community MySQL-server-enterprise
+Obsoletes: MySQL-server-advanced MySQL-server-advanced-gpl MySQL-server-enterprise-gpl
+%else
+Obsoletes: MySQL < %{version}-%{release}
+Obsoletes: MySQL-server < %{version}-%{release}
+Obsoletes: MySQL-server-advanced < %{version}-%{release}
+Obsoletes: mysql mysql-server mysql-advanced mysql-server-advanced
Obsoletes: MySQL-server-classic MySQL-server-community MySQL-server-enterprise
Obsoletes: MySQL-server-advanced-gpl MySQL-server-enterprise-gpl
Provides: mysql-server = %{version}-%{release}
@@ -320,6 +346,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!
@@ -327,17 +356,21 @@ package "MySQL-client%{product_suffix}" as well!
%package -n MySQL-client%{product_suffix}
Summary: MySQL - Client
Group: Applications/Databases
-%if 0%{?commercial}
+%if %{defined susever}
+Provides: MySQL-client
+Conflicts: mysql mysql-advanced
Obsoletes: MySQL-client
+Obsoletes: MySQL-client-classic MySQL-client-community MySQL-client-enterprise
+Obsoletes: MySQL-client-advanced MySQL-client-advanced-gpl MySQL-client-enterprise-gpl
%else
-Obsoletes: MySQL-client-advanced
-%endif
-Obsoletes: mysql < %{version}-%{release}
-Obsoletes: mysql-advanced < %{version}-%{release}
+Obsoletes: mysql mysql-advanced
+Obsoletes: MySQL-client < %{version}-%{release}
+Obsoletes: MySQL-client-advanced < %{version}-%{release}
Obsoletes: MySQL-client-classic MySQL-client-community MySQL-client-enterprise
Obsoletes: MySQL-client-advanced-gpl MySQL-client-enterprise-gpl
-Provides: mysql = %{version}-%{release}
+Provides: MySQL-client MySQL-client-advanced
Provides: mysql%{?_isa} = %{version}-%{release}
+%endif
%description -n MySQL-client%{product_suffix}
This package contains the standard MySQL clients and administration tools.
@@ -348,21 +381,29 @@ For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
%package -n MySQL-test%{product_suffix}
Summary: MySQL - Test suite
Group: Applications/Databases
-%if 0%{?commercial}
-Requires: MySQL-client-advanced perl
+%if %{defined susever}
+Requires: MySQL-client perl
+Provides: MySQL-test
+Conflicts: mysql-test mysql-test-advanced
Obsoletes: MySQL-test
+Obsoletes: mysql-bench MySQL-bench
+Obsoletes: MySQL-test-classic MySQL-test-community MySQL-test-enterprise
+Obsoletes: MySQL-test-advanced MySQL-test-advanced-gpl MySQL-test-enterprise-gpl
+AutoReqProv: no
%else
Requires: MySQL-client perl
-Obsoletes: MySQL-test-advanced
-%endif
+Conflicts: mysql-test mysql-test-advanced
Obsoletes: mysql-test < %{version}-%{release}
Obsoletes: mysql-test-advanced
Obsoletes: mysql-bench MySQL-bench
+Obsoletes: MySQL-test < %{version}-%{release}
+Obsoletes: MySQL-test-advanced < %{version}-%{release}
Obsoletes: MySQL-test-classic MySQL-test-community MySQL-test-enterprise
Obsoletes: MySQL-test-advanced-gpl MySQL-test-enterprise-gpl
Provides: mysql-test = %{version}-%{release}
Provides: mysql-test%{?_isa} = %{version}-%{release}
AutoReqProv: no
+%endif
%description -n MySQL-test%{product_suffix}
This package contains the MySQL regression test suite.
@@ -373,11 +414,15 @@ For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
%package -n MySQL-devel%{product_suffix}
Summary: MySQL - Development header files and libraries
Group: Applications/Databases
-%if 0%{?commercial}
+%if %{defined susever}
+Provides: MySQL-devel
+Conflicts: mysql-devel mysql-embedded-devel mysql-devel-advanced mysql-embedded-devel-advanced
Obsoletes: MySQL-devel
+Obsoletes: MySQL-devel-classic MySQL-devel-community MySQL-devel-enterprise
+Obsoletes: MySQL-devel-advanced MySQL-devel-advanced-gpl MySQL-devel-enterprise-gpl
%else
-Obsoletes: MySQL-devel-advanced
-%endif
+Conflicts: mysql-devel mysql-embedded-devel mysql-devel-advanced mysql-embedded-devel-advanced
+Obsoletes: MySQL-devel < %{version}-%{release}
Obsoletes: mysql-devel < %{version}-%{release}
Obsoletes: mysql-embedded-devel mysql-devel-advanced mysql-embedded-devel-advanced
Obsoletes: MySQL-devel-classic MySQL-devel-community MySQL-devel-enterprise
@@ -395,35 +440,49 @@ For a description of MySQL see the base MySQL RPM or http://www.mysql.com/
%package -n MySQL-shared%{product_suffix}
Summary: MySQL - Shared libraries
Group: Applications/Databases
-%if 0%{?commercial}
-Obsoletes: MySQL-shared
+%if %{defined susever}
+Provides: MySQL-shared
+Obsoletes: MySQL-shared-standard MySQL-shared-pro
+Obsoletes: MySQL-shared-pro-cert MySQL-shared-pro-gpl
+Obsoletes: MySQL-shared-pro-gpl-cert MySQL-shared
+Obsoletes: MySQL-shared-classic MySQL-shared-community MySQL-shared-enterprise
+Obsoletes: MySQL-shared-advanced MySQL-shared-advanced-gpl MySQL-shared-enterprise-gpl
%else
-Obsoletes: MySQL-shared-advanced
-%endif
Obsoletes: MySQL-shared-standard MySQL-shared-pro
Obsoletes: MySQL-shared-pro-cert MySQL-shared-pro-gpl
+Obsoletes: MySQL-shared < %{version}-%{release}
+Obsoletes: MySQL-shared-advanced < %{version}-%{release}
Obsoletes: MySQL-shared-pro-gpl-cert
Obsoletes: MySQL-shared-classic MySQL-shared-community MySQL-shared-enterprise
Obsoletes: MySQL-shared-advanced-gpl MySQL-shared-enterprise-gpl
+Provides: MySQL-shared MySQL-shared-advanced
+%endif
%description -n MySQL-shared%{product_suffix}
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
-%if 0%{?commercial}
-Requires: MySQL-devel-advanced
+%if %{defined susever}
+Requires: MySQL-devel
+Provides: MySQL-embedded
+Conflicts: mysql-embedded mysql-embedded-advanced
Obsoletes: MySQL-embedded
+Obsoletes: MySQL-embedded-pro
+Obsoletes: MySQL-embedded-classic MySQL-embedded-community MySQL-embedded-enterprise
+Obsoletes: MySQL-embedded-advanced MySQL-embedded-advanced-gpl MySQL-embedded-enterprise-gpl
%else
Requires: MySQL-devel
-Obsoletes: MySQL-embedded-advanced
-%endif
+Conflicts: mysql-embedded mysql-embedded-advanced
Obsoletes: mysql-embedded < %{version}-%{release}
Obsoletes: mysql-embedded-advanced
Obsoletes: MySQL-embedded-pro
+Obsoletes: MySQL-embedded < %{version}-%{release}
+Obsoletes: MySQL-embedded-advanced < %{version}-%{release}
Obsoletes: MySQL-embedded-classic MySQL-embedded-community MySQL-embedded-enterprise
Obsoletes: MySQL-embedded-advanced-gpl MySQL-embedded-enterprise-gpl
Provides: mysql-embedded = %{version}-%{release}
@@ -440,6 +499,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 +579,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 +598,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 +665,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 +1140,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*
@@ -1102,6 +1182,10 @@ echo "=====" >> $STATUS_HISTORY
%ghost %config(noreplace,missingok) %{_sysconfdir}/my.cnf
%dir %{_sysconfdir}/my.cnf.d
+%if %{defined with_wsrep}
+%ghost %config(noreplace,missingok) %{_sysconfdir}/wsrep.cnf
+%endif
+
%attr(755, root, root) %{_bindir}/innochecksum
%attr(755, root, root) %{_bindir}/my_print_defaults
%attr(755, root, root) %{_bindir}/myisam_ftdump
@@ -1127,6 +1211,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 +1297,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 +1308,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
@@ -1238,9 +1334,6 @@ echo "=====" >> $STATUS_HISTORY
* Fri Aug 16 2013 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
- Added provides lowercase mysql tags
-* Wed Jun 26 2013 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com>
-- Cleaned up spec file to resolve rpm dependencies.
-
* Tue Jul 24 2012 Joerg Bruehe <joerg.bruehe@oracle.com>
- Add a macro "runselftest":
@@ -1252,6 +1345,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 +1402,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 2025a8b811a..ee66a3149e9 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..11d0e34d1b0
--- /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_uuid.c wsrep_loader.c wsrep_dummy.c)
+
+ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES})
+DTRACE_INSTRUMENT(wsrep)
+
+#ADD_EXECUTABLE(listener wsrep_listener.c ${WSREP_SOURCES})
+#TARGET_LINK_LIBRARIES(listener ${LIBDL})
diff --git a/wsrep/Makefile.am b/wsrep/Makefile.am
new file mode 100644
index 00000000000..a748ece92e9
--- /dev/null
+++ b/wsrep/Makefile.am
@@ -0,0 +1,7 @@
+noinst_LIBRARIES = libwsrep.a
+libwsrep_a_SOURCES = wsrep_api.h wsrep_loader.c wsrep_dummy.c wsrep_uuid.c wsrep_gtid.c
+noinst_PROGRAMS = wsrep_listener
+wsrep_listener_SOURCES = wsrep_listener.c
+wsrep_listener_LDADD = $(noinst_LIBRARIES)
+wsrep_listener_LDFLAGS = -static -ldl
+
diff --git a/wsrep/wsrep_api.h b/wsrep/wsrep_api.h
new file mode 100644
index 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..ff9b0b0ea92
--- /dev/null
+++ b/wsrep/wsrep_dummy.c
@@ -0,0 +1,409 @@
+/* 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 * opt;
+ WSREP_DBUG_ENTER(w);
+ opt= WSREP_DUMMY(w)->options;
+ return opt ? strdup(opt) : NULL;
+}
+
+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;
+ }
+}