summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt4
-rw-r--r--cmake/cpack_rpm.cmake2
-rw-r--r--cmake/make_dist.cmake.in8
-rw-r--r--cmake/submodules.cmake6
-rw-r--r--cmake/wsrep.cmake15
-rw-r--r--debian/control2
-rw-r--r--extra/mariabackup/CMakeLists.txt3
-rw-r--r--include/mysql/service_wsrep.h305
-rw-r--r--include/thr_lock.h6
-rw-r--r--include/wsrep.h27
-rw-r--r--mysql-test/include/check-testcase.test51
-rw-r--r--mysql-test/include/galera_cluster.inc6
-rw-r--r--mysql-test/include/galera_have_debug_sync.inc (renamed from mysql-test/suite/galera/include/galera_have_debug_sync.inc)0
-rw-r--r--mysql-test/include/galera_wait_sync_point.inc11
-rw-r--r--mysql-test/include/have_wsrep_enabled.inc1
-rw-r--r--mysql-test/include/kill_galera.inc20
-rw-r--r--mysql-test/include/wsrep_wait_disconnect.inc20
-rwxr-xr-xmysql-test/mysql-test-run.pl154
-rw-r--r--mysql-test/suite/galera/disabled.def13
-rw-r--r--mysql-test/suite/galera/galera_2nodes.cnf26
-rw-r--r--mysql-test/suite/galera/galera_2nodes_as_master.cnf18
-rw-r--r--mysql-test/suite/galera/galera_2nodes_as_slave.cnf51
-rw-r--r--mysql-test/suite/galera/galera_3nodes_as_slave.cnf62
-rw-r--r--mysql-test/suite/galera/galera_4nodes.cnf30
-rw-r--r--mysql-test/suite/galera/include/galera_base_port.inc8
-rw-r--r--mysql-test/suite/galera/include/galera_concurrent_test.inc90
-rw-r--r--mysql-test/suite/galera/include/galera_dump_sr_table.inc28
-rw-r--r--mysql-test/suite/galera/include/galera_load_provider.inc68
-rw-r--r--mysql-test/suite/galera/include/galera_sst_restore.inc2
-rw-r--r--mysql-test/suite/galera/include/galera_st_disconnect_slave.inc8
-rw-r--r--mysql-test/suite/galera/include/galera_unload_provider.inc8
-rw-r--r--mysql-test/suite/galera/r/GAL-382.result2
-rw-r--r--mysql-test/suite/galera/r/GAL-401.result2
-rw-r--r--mysql-test/suite/galera/r/GAL-480.result2
-rw-r--r--mysql-test/suite/galera/r/GCF-1081.result47
-rw-r--r--mysql-test/suite/galera/r/GCF-939.result13
-rw-r--r--mysql-test/suite/galera/r/MDEV-15443.result2
-rw-r--r--mysql-test/suite/galera/r/MW-252.result2
-rw-r--r--mysql-test/suite/galera/r/MW-258.result2
-rw-r--r--mysql-test/suite/galera/r/MW-259.result2
-rw-r--r--mysql-test/suite/galera/r/MW-284.result4
-rw-r--r--mysql-test/suite/galera/r/MW-285.result2
-rw-r--r--mysql-test/suite/galera/r/MW-286.result21
-rw-r--r--mysql-test/suite/galera/r/MW-292.result27
-rw-r--r--mysql-test/suite/galera/r/MW-309.result2
-rw-r--r--mysql-test/suite/galera/r/MW-313.result2
-rw-r--r--mysql-test/suite/galera/r/MW-328A.result25
-rw-r--r--mysql-test/suite/galera/r/MW-328B.result2
-rw-r--r--mysql-test/suite/galera/r/MW-328C.result2
-rw-r--r--mysql-test/suite/galera/r/MW-328D.result2
-rw-r--r--mysql-test/suite/galera/r/MW-328E.result2
-rw-r--r--mysql-test/suite/galera/r/MW-329.result9
-rw-r--r--mysql-test/suite/galera/r/MW-336.result2
-rw-r--r--mysql-test/suite/galera/r/MW-357.result2
-rw-r--r--mysql-test/suite/galera/r/MW-360.result41
-rw-r--r--mysql-test/suite/galera/r/MW-369.result149
-rw-r--r--mysql-test/suite/galera/r/MW-388.result6
-rw-r--r--mysql-test/suite/galera/r/MW-402.result76
-rw-r--r--mysql-test/suite/galera/r/MW-416.result5
-rw-r--r--mysql-test/suite/galera/r/MW-86-wait1.result17
-rw-r--r--mysql-test/suite/galera/r/MW-86-wait8.result16
-rw-r--r--mysql-test/suite/galera/r/MW-86.result78
-rw-r--r--mysql-test/suite/galera/r/basic.result2
-rw-r--r--mysql-test/suite/galera/r/binlog_checksum.result2
-rw-r--r--mysql-test/suite/galera/r/create.result2
-rw-r--r--mysql-test/suite/galera/r/enforce_storage_engine.result2
-rw-r--r--mysql-test/suite/galera/r/enforce_storage_engine2.result2
-rw-r--r--mysql-test/suite/galera/r/ev51914.result2
-rw-r--r--mysql-test/suite/galera/r/fk.result2
-rw-r--r--mysql-test/suite/galera/r/galera#414.result2
-rw-r--r--mysql-test/suite/galera/r/galera#500.result8
-rw-r--r--mysql-test/suite/galera/r/galera#505.result2
-rw-r--r--mysql-test/suite/galera/r/galera_FK_duplicate_client_insert.result2
-rw-r--r--mysql-test/suite/galera/r/galera_admin.result2
-rw-r--r--mysql-test/suite/galera/r/galera_alter_engine_innodb.result2
-rw-r--r--mysql-test/suite/galera/r/galera_alter_engine_myisam.result2
-rw-r--r--mysql-test/suite/galera/r/galera_alter_table_force.result2
-rw-r--r--mysql-test/suite/galera/r/galera_applier_ftwrl_table.result2
-rw-r--r--mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result2
-rw-r--r--mysql-test/suite/galera/r/galera_as_master.result4
-rw-r--r--mysql-test/suite/galera/r/galera_as_master_gtid.result44
-rw-r--r--mysql-test/suite/galera/r/galera_as_master_large.result2
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave.result12
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_autoinc.result12
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_gtid.result12
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result159
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result315
-rw-r--r--mysql-test/suite/galera/r/galera_as_slave_nonprim.result16
-rw-r--r--mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result2
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort.result4
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result2
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_for_update.result6
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result2
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_get_lock.result4
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_group_commit.result685
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_lock_table.result2
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_shutdown.result12
-rw-r--r--mysql-test/suite/galera/r/galera_bf_abort_sleep.result4
-rw-r--r--mysql-test/suite/galera/r/galera_bf_background_statistics.result4
-rw-r--r--mysql-test/suite/galera/r/galera_bf_lock_wait.result2
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_cache_size.result2
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_checksum.result2
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result2
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result2
-rw-r--r--mysql-test/suite/galera/r/galera_binlog_row_image.result2
-rw-r--r--mysql-test/suite/galera/r/galera_commit_empty.result15
-rw-r--r--mysql-test/suite/galera/r/galera_concurrent_ctas.result2
-rw-r--r--mysql-test/suite/galera/r/galera_create_function.result2
-rw-r--r--mysql-test/suite/galera/r/galera_create_procedure.result2
-rw-r--r--mysql-test/suite/galera/r/galera_create_table_as_select.result103
-rw-r--r--mysql-test/suite/galera/r/galera_create_table_like.result2
-rw-r--r--mysql-test/suite/galera/r/galera_create_trigger.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ddl_multiline.result2
-rw-r--r--mysql-test/suite/galera/r/galera_defaults.result12
-rw-r--r--mysql-test/suite/galera/r/galera_delete_limit.result2
-rw-r--r--mysql-test/suite/galera/r/galera_desync_overlapped.result2
-rw-r--r--mysql-test/suite/galera/r/galera_drop_multi.result2
-rw-r--r--mysql-test/suite/galera/r/galera_encrypt_tmp_files.result2
-rw-r--r--mysql-test/suite/galera/r/galera_enum.result4
-rw-r--r--mysql-test/suite/galera/r/galera_events.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_cascade_delete.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_cascade_update.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_conflict.result4
-rw-r--r--mysql-test/suite/galera/r/galera_fk_mismatch.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_multicolumn.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_multitable.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_no_pk.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_selfreferential.result2
-rw-r--r--mysql-test/suite/galera/r/galera_fk_setnull.result2
-rw-r--r--mysql-test/suite/galera/r/galera_flush_local.result2
-rw-r--r--mysql-test/suite/galera/r/galera_forced_binlog_format.result20
-rw-r--r--mysql-test/suite/galera/r/galera_ftwrl.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ftwrl_drain.result4
-rw-r--r--mysql-test/suite/galera/r/galera_fulltext.result2
-rw-r--r--mysql-test/suite/galera/r/galera_gcache_recover.result2
-rw-r--r--mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result4
-rw-r--r--mysql-test/suite/galera/r/galera_gcs_fc_limit.result2
-rw-r--r--mysql-test/suite/galera/r/galera_gcs_fragment.result15
-rw-r--r--mysql-test/suite/galera/r/galera_gcs_max_packet_size.result2
-rw-r--r--mysql-test/suite/galera/r/galera_gra_log.result2
-rw-r--r--mysql-test/suite/galera/r/galera_gtid.result2
-rw-r--r--mysql-test/suite/galera/r/galera_gtid_slave.result26
-rw-r--r--mysql-test/suite/galera/r/galera_gtid_slave_sst_rsync.result106
-rw-r--r--mysql-test/suite/galera/r/galera_insert_ignore.result2
-rw-r--r--mysql-test/suite/galera/r/galera_insert_multi.result4
-rw-r--r--mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ist_mariabackup,debug.rdiff6
-rw-r--r--mysql-test/suite/galera/r/galera_ist_mariabackup.result5
-rw-r--r--mysql-test/suite/galera/r/galera_ist_mariabackup_innodb_flush_logs.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ist_mysqldump.result3
-rw-r--r--mysql-test/suite/galera/r/galera_ist_progress.result9
-rw-r--r--mysql-test/suite/galera/r/galera_ist_recv_bind.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ist_restart_joiner.result3
-rw-r--r--mysql-test/suite/galera/r/galera_ist_rsync.result5
-rw-r--r--mysql-test/suite/galera/r/galera_kill_ddl.result2
-rw-r--r--mysql-test/suite/galera/r/galera_kill_largechanges.result2
-rw-r--r--mysql-test/suite/galera/r/galera_kill_smallchanges.result2
-rw-r--r--mysql-test/suite/galera/r/galera_lock_table.result2
-rw-r--r--mysql-test/suite/galera/r/galera_log_bin.result4
-rw-r--r--mysql-test/suite/galera/r/galera_log_output_csv.result2
-rw-r--r--mysql-test/suite/galera/r/galera_many_columns.result4
-rw-r--r--mysql-test/suite/galera/r/galera_many_indexes.result4
-rw-r--r--mysql-test/suite/galera/r/galera_many_rows.result6
-rw-r--r--mysql-test/suite/galera/r/galera_many_tables_nopk.result4
-rw-r--r--mysql-test/suite/galera/r/galera_many_tables_pk.result4
-rw-r--r--mysql-test/suite/galera/r/galera_mdev_10812.result2
-rw-r--r--mysql-test/suite/galera/r/galera_mdev_13787.result2
-rw-r--r--mysql-test/suite/galera/r/galera_mdev_15611.result2
-rw-r--r--mysql-test/suite/galera/r/galera_mdl_race.result4
-rw-r--r--mysql-test/suite/galera/r/galera_multi_database.result2
-rw-r--r--mysql-test/suite/galera/r/galera_myisam_autocommit.result2
-rw-r--r--mysql-test/suite/galera/r/galera_myisam_transactions.result2
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_bit.result4
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_blob.result4
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_large_varchar.result4
-rw-r--r--mysql-test/suite/galera/r/galera_nopk_unicode.result4
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result8
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result20
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result4
-rw-r--r--mysql-test/suite/galera/r/galera_parallel_simple.result2
-rw-r--r--mysql-test/suite/galera/r/galera_pc_recovery.result37
-rw-r--r--mysql-test/suite/galera/r/galera_pk_bigint_signed.result4
-rw-r--r--mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result4
-rw-r--r--mysql-test/suite/galera/r/galera_prepared_statement.result2
-rw-r--r--mysql-test/suite/galera/r/galera_query_cache.result2
-rw-r--r--mysql-test/suite/galera/r/galera_query_cache_sync_wait.result2
-rw-r--r--mysql-test/suite/galera/r/galera_read_only.result2
-rw-r--r--mysql-test/suite/galera/r/galera_repl_key_format_flat16.result2
-rw-r--r--mysql-test/suite/galera/r/galera_repl_max_ws_size.result4
-rw-r--r--mysql-test/suite/galera/r/galera_restart_nochanges.result2
-rw-r--r--mysql-test/suite/galera/r/galera_restart_on_unknown_option.result2
-rw-r--r--mysql-test/suite/galera/r/galera_roles.result2
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_add_pk.result2
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_drop_pk.result2
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_error.result2
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_simple.result2
-rw-r--r--mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sbr.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sbr_binlog.result2
-rw-r--r--mysql-test/suite/galera/r/galera_schema_dirty_reads.result2
-rw-r--r--mysql-test/suite/galera/r/galera_serializable.result8
-rw-r--r--mysql-test/suite/galera/r/galera_server.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sql_log_bin_zero.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ssl.result2
-rw-r--r--mysql-test/suite/galera/r/galera_ssl_compression.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mariabackup.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mariabackup_data_dir.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mariabackup_encrypt_with_key.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff22
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mysqldump,release.rdiff18
-rw-r--r--mysql-test/suite/galera/r/galera_sst_mysqldump.result1
-rw-r--r--mysql-test/suite/galera/r/galera_sst_rsync.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sst_rsync2,debug.rdiff12
-rw-r--r--mysql-test/suite/galera/r/galera_sst_rsync_data_dir.result2
-rw-r--r--mysql-test/suite/galera/r/galera_status_cluster.result2
-rw-r--r--mysql-test/suite/galera/r/galera_status_local_index.result2
-rw-r--r--mysql-test/suite/galera/r/galera_status_local_state.result2
-rw-r--r--mysql-test/suite/galera/r/galera_suspend_slave.result2
-rw-r--r--mysql-test/suite/galera/r/galera_sync_wait_show.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_error.result5
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_locking.result33
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ddl_sequential.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_drop_database.result6
-rw-r--r--mysql-test/suite/galera/r/galera_toi_ftwrl.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_lock_exclusive.result4
-rw-r--r--mysql-test/suite/galera/r/galera_toi_lock_shared.result2
-rw-r--r--mysql-test/suite/galera/r/galera_toi_truncate.result4
-rw-r--r--mysql-test/suite/galera/r/galera_transaction_read_only.result2
-rw-r--r--mysql-test/suite/galera/r/galera_transaction_replay.result96
-rw-r--r--mysql-test/suite/galera/r/galera_truncate.result2
-rw-r--r--mysql-test/suite/galera/r/galera_truncate_temporary.result2
-rw-r--r--mysql-test/suite/galera/r/galera_unicode_identifiers.result2
-rw-r--r--mysql-test/suite/galera/r/galera_unicode_pk.result6
-rw-r--r--mysql-test/suite/galera/r/galera_update_limit.result2
-rw-r--r--mysql-test/suite/galera/r/galera_v1_row_events.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_OSU_method.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_OSU_method2.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result4
-rw-r--r--mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_cluster_address.result8
-rw-r--r--mysql-test/suite/galera/r/galera_var_desync_on.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_dirty_reads.result5
-rw-r--r--mysql-test/suite/galera/r/galera_var_fkchecks.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_gtid_domain_id.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result186
-rw-r--r--mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_load_data_splitting.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_log_bin.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_max_ws_rows.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_max_ws_size.result4
-rw-r--r--mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_node_address.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_reject_queries.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_retry_autocommit.result28
-rw-r--r--mysql-test/suite/galera/r/galera_var_slave_threads.result60
-rw-r--r--mysql-test/suite/galera/r/galera_var_sst_auth.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_sync_wait.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_wsrep_on_off.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wan.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wan_restart_ist.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wan_restart_sst.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_log_conficts.result4
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_new_cluster.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result2
-rw-r--r--mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result2
-rw-r--r--mysql-test/suite/galera/r/galera_zero_length_column.result2
-rw-r--r--mysql-test/suite/galera/r/grant.result2
-rw-r--r--mysql-test/suite/galera/r/lp1276424.result2
-rw-r--r--mysql-test/suite/galera/r/lp1347768.result2
-rw-r--r--mysql-test/suite/galera/r/lp1376747-2.result2
-rw-r--r--mysql-test/suite/galera/r/lp1376747-3.result2
-rw-r--r--mysql-test/suite/galera/r/lp1376747-4.result2
-rw-r--r--mysql-test/suite/galera/r/lp1376747.result2
-rw-r--r--mysql-test/suite/galera/r/lp1438990.result2
-rw-r--r--mysql-test/suite/galera/r/lp959512.result2
-rw-r--r--mysql-test/suite/galera/r/mdev_10518.result2
-rw-r--r--mysql-test/suite/galera/r/mdev_9290.result2
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#110.result2
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#198.result2
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#201.result2
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#216.result11
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#237.result4
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#247.result2
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#31.result2
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#33.result6
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#332.result42
-rw-r--r--mysql-test/suite/galera/r/mysql-wsrep#90.result2
-rw-r--r--mysql-test/suite/galera/r/partition.result6
-rw-r--r--mysql-test/suite/galera/r/pxc-421.result2
-rw-r--r--mysql-test/suite/galera/r/query_cache.result2
-rw-r--r--mysql-test/suite/galera/r/rename.result2
-rw-r--r--mysql-test/suite/galera/r/rpl_row_annotate.result8
-rw-r--r--mysql-test/suite/galera/r/sql_log_bin.result2
-rw-r--r--mysql-test/suite/galera/r/unique_key.result2
-rw-r--r--mysql-test/suite/galera/r/versioning_trx_id.result2
-rw-r--r--mysql-test/suite/galera/r/view.result2
-rw-r--r--mysql-test/suite/galera/r/wsrep_trx_fragment_size_sr.result15
-rw-r--r--mysql-test/suite/galera/suite.pm6
-rw-r--r--mysql-test/suite/galera/t/GAL-419.test4
-rw-r--r--mysql-test/suite/galera/t/GCF-1081.test72
-rw-r--r--mysql-test/suite/galera/t/GCF-939.test31
-rw-r--r--mysql-test/suite/galera/t/MW-284.test2
-rw-r--r--mysql-test/suite/galera/t/MW-286.test50
-rw-r--r--mysql-test/suite/galera/t/MW-292.test50
-rw-r--r--mysql-test/suite/galera/t/MW-328A.test40
-rw-r--r--mysql-test/suite/galera/t/MW-329.test28
-rw-r--r--mysql-test/suite/galera/t/MW-336.test9
-rw-r--r--mysql-test/suite/galera/t/MW-360-master.opt2
-rw-r--r--mysql-test/suite/galera/t/MW-360.test100
-rw-r--r--mysql-test/suite/galera/t/MW-369.inc7
-rw-r--r--mysql-test/suite/galera/t/MW-369.test100
-rw-r--r--mysql-test/suite/galera/t/MW-388.test5
-rw-r--r--mysql-test/suite/galera/t/MW-402.test56
-rw-r--r--mysql-test/suite/galera/t/MW-416.test8
-rw-r--r--mysql-test/suite/galera/t/MW-86-wait1.test13
-rw-r--r--mysql-test/suite/galera/t/MW-86-wait8.test11
-rw-r--r--mysql-test/suite/galera/t/galera#500.test6
-rw-r--r--mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt2
-rw-r--r--mysql-test/suite/galera/t/galera_as_master.test2
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid.cnf2
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid.test24
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf2
-rw-r--r--mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test2
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave.test17
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_autoinc.test18
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_gtid.test21
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf17
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test150
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test176
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_nonprim.test26
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_preordered.test19
-rw-r--r--mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test13
-rw-r--r--mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.cnf4
-rw-r--r--mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test3
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_group_commit.cnf15
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_group_commit.test77
-rw-r--r--mysql-test/suite/galera/t/galera_bf_abort_shutdown.test33
-rw-r--r--mysql-test/suite/galera/t/galera_commit_empty.test35
-rw-r--r--mysql-test/suite/galera/t/galera_create_table_as_select.test145
-rw-r--r--mysql-test/suite/galera/t/galera_defaults.test2
-rw-r--r--mysql-test/suite/galera/t/galera_forced_binlog_format.test5
-rw-r--r--mysql-test/suite/galera/t/galera_ftwrl_drain.test4
-rw-r--r--mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test12
-rw-r--r--mysql-test/suite/galera/t/galera_gcs_fragment.test4
-rw-r--r--mysql-test/suite/galera/t/galera_gtid-master.opt2
-rw-r--r--mysql-test/suite/galera/t/galera_gtid_slave.test33
-rw-r--r--mysql-test/suite/galera/t/galera_gtid_slave_sst_rsync.test111
-rw-r--r--mysql-test/suite/galera/t/galera_ist_progress.test4
-rw-r--r--mysql-test/suite/galera/t/galera_ist_restart_joiner.test4
-rw-r--r--mysql-test/suite/galera/t/galera_kill_applier.test1
-rw-r--r--mysql-test/suite/galera/t/galera_log_bin.test2
-rw-r--r--mysql-test/suite/galera/t/galera_many_rows.cnf10
-rw-r--r--mysql-test/suite/galera/t/galera_many_rows.test7
-rw-r--r--mysql-test/suite/galera/t/galera_migrate.cnf2
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test6
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test11
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test2
-rw-r--r--mysql-test/suite/galera/t/galera_parallel_simple.test2
-rw-r--r--mysql-test/suite/galera/t/galera_pc_recovery.test102
-rw-r--r--mysql-test/suite/galera/t/galera_split_brain.test6
-rw-r--r--mysql-test/suite/galera/t/galera_ssl_upgrade.test4
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump.cnf4
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump.test2
-rw-r--r--mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf4
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_error.test5
-rw-r--r--mysql-test/suite/galera/t/galera_toi_ddl_locking.test54
-rw-r--r--mysql-test/suite/galera/t/galera_transaction_replay.test201
-rw-r--r--mysql-test/suite/galera/t/galera_var_cluster_address.test11
-rw-r--r--mysql-test/suite/galera/t/galera_var_dirty_reads.test12
-rw-r--r--mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test235
-rw-r--r--mysql-test/suite/galera/t/galera_var_log_bin.cnf5
-rw-r--r--mysql-test/suite/galera/t/galera_var_retry_autocommit.test24
-rw-r--r--mysql-test/suite/galera/t/galera_var_slave_threads.cnf7
-rw-r--r--mysql-test/suite/galera/t/galera_var_slave_threads.test139
-rw-r--r--mysql-test/suite/galera/t/galera_vote_drop_temporary-master.opt1
-rw-r--r--mysql-test/suite/galera/t/galera_wsrep_new_cluster.test1
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#198-master.opt1
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#237.test4
-rw-r--r--mysql-test/suite/galera/t/mysql-wsrep#332.test2
-rw-r--r--mysql-test/suite/galera/t/partition.test16
-rw-r--r--mysql-test/suite/galera/t/rpl_row_annotate.test5
-rw-r--r--mysql-test/suite/galera/t/wsrep_trx_fragment_size_sr.test22
-rw-r--r--mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf22
-rw-r--r--mysql-test/suite/galera_3nodes/galera_3nodes.cnf14
-rw-r--r--mysql-test/suite/galera_3nodes/include/galera_resume.inc (renamed from mysql-test/suite/galera/include/galera_resume.inc)2
-rw-r--r--mysql-test/suite/galera_3nodes/include/galera_suspend.inc2
-rw-r--r--mysql-test/suite/galera_3nodes/include/have_ipv6.inc15
-rw-r--r--mysql-test/suite/galera_3nodes/r/GAL-501.result6
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result2
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result5
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result8
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_garbd.result14
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result11
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result18
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result5
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result18
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result2
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result4
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result13
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_pc_weight.result24
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result23
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result7
-rw-r--r--mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result82
-rw-r--r--mysql-test/suite/galera_3nodes/suite.pm4
-rw-r--r--mysql-test/suite/galera_3nodes/t/GAL-501.test8
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test2
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test6
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_garbd.test22
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test58
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt1
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test15
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test2
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf26
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test62
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test2
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test2
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf8
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_pc_weight.test9
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test26
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test1
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test3
-rw-r--r--mysql-test/suite/galera_3nodes/t/galera_wsrep_schema.test83
-rw-r--r--mysql-test/suite/galera_3nodes_sr/galera_3nodes.cnf1
-rw-r--r--mysql-test/suite/galera_3nodes_sr/my.cnf1
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-336.result26
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-582.result23
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-606.result38
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-609.result20
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-810A.result256
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-810B.result100
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-810C.result177
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-817.result54
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/GCF-832.result26
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_isolate_master.result80
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_join_slave.result39
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_master.result33
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply.result53
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback.result58
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback2.result31
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_before_apply.result44
-rw-r--r--mysql-test/suite/galera_3nodes_sr/r/galera_sr_threeway_split.result117
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-336.test47
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-582.test39
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-606.test80
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-609.test30
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-810A.test137
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-810B.test49
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-810C.test70
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-817.test109
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/GCF-832.test43
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/disabled.def7
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_isolate_master.test127
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_join_slave.test59
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_master.test58
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply.test81
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback.test80
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback2.test56
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_before_apply.test73
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.cnf5
-rw-r--r--mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.test177
-rw-r--r--mysql-test/suite/galera_sr/galera_2nodes.cnf1
-rw-r--r--mysql-test/suite/galera_sr/my.cnf1
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1008.result70
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1018.result24
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1018B.result12
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1043A.result21
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1043B.result21
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1051.result46
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-1060.result21
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-437.result12
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-561.result50
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-571.result67
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-572.result37
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-574.result11
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-580.result13
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-585.result28
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-597.result21
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-620.result18
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-623.result29
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-627.result26
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-845.result21
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-851.result30
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-867.result4
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-889.result25
-rw-r--r--mysql-test/suite/galera_sr/r/GCF-900.result21
-rw-r--r--mysql-test/suite/galera_sr/r/galera-features#56.result32
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_bf_abort.result555
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_blob.result23
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_cc_master.result65
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result59
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_concurrent.result36
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_conflict.result21
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit.result31
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit2.result28
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_conflict_with_rollback_master.result29
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_ddl_master.result48
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_ddl_schema.result23
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_ddl_slave.result50
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_ddl_unrelated.result42
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_dupkey_error.result46
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_fk_conflict.result39
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_gtid.result57
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_insert_select.result18
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_kill_all_nobootstrap.result29
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result30
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_kill_all_pcrecovery.result30
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_kill_connection.result32
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_kill_query.result31
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result53
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_large_fragment.result33
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_load_data.result13
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result9
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_log_bin.result124
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_many_fragments.result33
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_myisam.result16
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_mysqldump_sst.result58
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_parallel_apply.result37
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_rollback.result42
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result33
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_rollback_savepoint.result42
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_rollback_statement.result22
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_sbr.result16
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_shutdown_master.result31
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_shutdown_slave.result43
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_small_gcache.result15
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_table_contents.result198
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_transaction_replay.result121
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_unit_statements.result54
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_v1_row_events.result20
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_ws_size.result36
-rw-r--r--mysql-test/suite/galera_sr/r/galera_sr_ws_size2.result34
-rw-r--r--mysql-test/suite/galera_sr/r/galera_var_ignore_apply_errors_sr.result29
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep#215.result137
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#136.result65
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#138.result24
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#14.result12
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result42
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#15.result11
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#165.result752
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#22.result35
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#27.result23
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result14
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#32.result27
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#35.result41
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#8.result39
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#9.result20
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#93.result18
-rw-r--r--mysql-test/suite/galera_sr/r/mysql-wsrep-features#96.result33
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1008.inc36
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1008.test18
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1018.test38
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1018B.test40
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1043A.test13
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1043B.test13
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1051.test51
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-1060.test9
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-437.test21
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-561.test65
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-571.test54
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-572.test54
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-574.test27
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-580.test27
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-585.test44
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-597.test29
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-620.test22
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-623.test31
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-627.test30
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-845.test30
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-851.test24
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-867.test42
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-889.test29
-rw-r--r--mysql-test/suite/galera_sr/t/GCF-900.test28
-rw-r--r--mysql-test/suite/galera_sr/t/disabled.def3
-rw-r--r--mysql-test/suite/galera_sr/t/galera-features#56.test55
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_bf_abort.inc145
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_bf_abort.test50
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_blob.test38
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_cc_master.test98
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test97
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_concurrent.test45
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_conflict.test45
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit.test45
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit2.test46
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_conflict_with_rollback_master.test44
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_ddl_master.test63
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_ddl_schema.test43
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_ddl_slave.test65
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_ddl_unrelated.test53
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_dupkey_error.test59
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_fk_conflict.test62
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_gtid-master.opt1
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_gtid.test46
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_insert_select.test33
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_all_nobootstrap.test52
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf4
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test53
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_all_pcrecovery.test54
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_connection.test59
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_query.test48
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_slave.cnf4
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test80
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_large_fragment-master.opt1
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_large_fragment.test58
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_load_data.test39
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_load_data_splitting.test50
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_log_bin-master.opt1
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_log_bin.test70
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_many_fragments.test53
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_myisam.test29
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.cnf11
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.test79
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_parallel_apply.test59
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_rollback.test76
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test55
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_rollback_savepoint.test51
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_rollback_statement.test61
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_sbr.test31
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_shutdown_master.test53
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_shutdown_slave.test63
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_small_gcache.cnf6
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_small_gcache.test21
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_table_contents.test49
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_transaction_replay.test260
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_unit_statements.test54
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_v1_row_events-master.opt1
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_v1_row_events.test27
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_ws_size.test70
-rw-r--r--mysql-test/suite/galera_sr/t/galera_sr_ws_size2.test62
-rw-r--r--mysql-test/suite/galera_sr/t/galera_var_ignore_apply_errors_sr.test38
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep#215.test175
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#136-master.opt1
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#136.test41
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#138.test25
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#14.test21
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test60
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#15.test17
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.inc104
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.test41
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#22.test47
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#27.test29
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test23
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#32-master.opt1
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#32.test44
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#35.test48
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#8.test63
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#9.test44
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#93.test29
-rw-r--r--mysql-test/suite/galera_sr/t/mysql-wsrep-features#96.test45
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_wsrep.result58
-rw-r--r--mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result15
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test16
-rw-r--r--mysql-test/suite/wsrep/disabled.def1
-rw-r--r--mysql-test/suite/wsrep/my.cnf4
-rw-r--r--mysql-test/suite/wsrep/r/wsrep-recover,binlogon.rdiff28
-rw-r--r--mysql-test/suite/wsrep/r/wsrep-recover.result66
-rw-r--r--mysql-test/suite/wsrep/suite.pm4
-rw-r--r--mysql-test/suite/wsrep/t/binlog_format.cnf8
-rw-r--r--mysql-test/suite/wsrep/t/binlog_format.opt1
-rw-r--r--mysql-test/suite/wsrep/t/binlog_format.test1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_10186.cnf6
-rw-r--r--mysql-test/suite/wsrep/t/mdev_10186.opt1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_10186.test1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_6832.cnf7
-rw-r--r--mysql-test/suite/wsrep/t/mdev_6832.opt1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_6832.test1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_7798.cnf7
-rw-r--r--mysql-test/suite/wsrep/t/mdev_7798.opt1
-rw-r--r--mysql-test/suite/wsrep/t/mdev_7798.test1
-rw-r--r--mysql-test/suite/wsrep/t/pool_of_threads.cnf8
-rw-r--r--mysql-test/suite/wsrep/t/pool_of_threads.opt1
-rw-r--r--mysql-test/suite/wsrep/t/wsrep-recover-step.inc41
-rw-r--r--mysql-test/suite/wsrep/t/wsrep-recover.cnf9
-rw-r--r--mysql-test/suite/wsrep/t/wsrep-recover.combinations4
-rw-r--r--mysql-test/suite/wsrep/t/wsrep-recover.test204
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/my.cnf7
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result10
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/suite.pm4
-rw-r--r--plugin/wsrep_info/plugin.cc87
-rw-r--r--scripts/mysqld_safe.sh11
-rwxr-xr-xscripts/wsrep_sst_common.sh2
-rw-r--r--scripts/wsrep_sst_mysqldump.sh5
-rw-r--r--scripts/wsrep_sst_rsync.sh10
-rw-r--r--sql/CMakeLists.txt19
-rw-r--r--sql/event_data_objects.cc12
-rw-r--r--sql/handler.cc339
-rw-r--r--sql/handler.h7
-rw-r--r--sql/item_create.cc101
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_strfunc.cc99
-rw-r--r--sql/item_strfunc.h51
-rw-r--r--sql/lock.cc76
-rw-r--r--sql/log.cc122
-rw-r--r--sql/log.h5
-rw-r--r--sql/log_event.cc35
-rw-r--r--sql/mdl.cc134
-rw-r--r--sql/mysqld.cc94
-rw-r--r--sql/protocol.cc22
-rw-r--r--sql/rpl_record.cc3
-rw-r--r--sql/service_wsrep.cc255
-rw-r--r--sql/slave.cc115
-rw-r--r--sql/sp_head.cc30
-rw-r--r--sql/sql_acl.cc2
-rw-r--r--sql/sql_alter.cc2
-rw-r--r--sql/sql_base.cc15
-rw-r--r--sql/sql_class.cc161
-rw-r--r--sql/sql_class.h154
-rw-r--r--sql/sql_connect.cc30
-rw-r--r--sql/sql_insert.cc66
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_load.cc11
-rw-r--r--sql/sql_parse.cc703
-rw-r--r--sql/sql_plugin_services.ic46
-rw-r--r--sql/sql_prepare.cc48
-rw-r--r--sql/sql_repl.cc11
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/sql_trigger.cc3
-rw-r--r--sql/sql_truncate.cc2
-rw-r--r--sql/sys_vars.cc38
-rw-r--r--sql/table.cc7
-rw-r--r--sql/transaction.cc54
-rw-r--r--sql/wsrep_applier.cc320
-rw-r--r--sql/wsrep_applier.h67
-rw-r--r--sql/wsrep_binlog.cc334
-rw-r--r--sql/wsrep_binlog.h35
-rw-r--r--sql/wsrep_check_opts.cc4
-rw-r--r--sql/wsrep_client_service.cc307
-rw-r--r--sql/wsrep_client_service.h63
-rw-r--r--sql/wsrep_client_state.h47
-rw-r--r--sql/wsrep_condition_variable.h54
-rw-r--r--sql/wsrep_dummy.cc112
-rw-r--r--sql/wsrep_high_priority_service.cc649
-rw-r--r--sql/wsrep_high_priority_service.h118
-rw-r--r--sql/wsrep_hton.cc658
-rw-r--r--sql/wsrep_mutex.h50
-rw-r--r--sql/wsrep_mysqld.cc2438
-rw-r--r--sql/wsrep_mysqld.h394
-rw-r--r--sql/wsrep_notify.cc77
-rw-r--r--sql/wsrep_plugin.cc53
-rw-r--r--sql/wsrep_priv.h24
-rw-r--r--sql/wsrep_schema.cc1360
-rw-r--r--sql/wsrep_schema.h161
-rw-r--r--sql/wsrep_server_service.cc318
-rw-r--r--sql/wsrep_server_service.h81
-rw-r--r--sql/wsrep_server_state.cc82
-rw-r--r--sql/wsrep_server_state.h66
-rw-r--r--sql/wsrep_sst.cc595
-rw-r--r--sql/wsrep_sst.h30
-rw-r--r--sql/wsrep_storage_service.cc238
-rw-r--r--sql/wsrep_storage_service.h48
-rw-r--r--sql/wsrep_thd.cc787
-rw-r--r--sql/wsrep_thd.h216
-rw-r--r--sql/wsrep_trans_observer.h423
-rw-r--r--sql/wsrep_types.h29
-rw-r--r--sql/wsrep_utils.cc104
-rw-r--r--sql/wsrep_utils.h76
-rw-r--r--sql/wsrep_var.cc321
-rw-r--r--sql/wsrep_var.h11
-rw-r--r--sql/wsrep_xid.cc118
-rw-r--r--sql/wsrep_xid.h14
-rw-r--r--storage/innobase/buf/buf0dump.cc4
-rw-r--r--storage/innobase/handler/ha_innodb.cc490
-rw-r--r--storage/innobase/handler/ha_innodb.h33
-rw-r--r--storage/innobase/include/trx0trx.h5
-rw-r--r--storage/innobase/lock/lock0lock.cc55
-rw-r--r--storage/innobase/row/row0ins.cc30
-rw-r--r--storage/innobase/row/row0sel.cc10
-rw-r--r--storage/innobase/row/row0upd.cc6
-rw-r--r--storage/innobase/srv/srv0conc.cc8
-rw-r--r--storage/innobase/srv/srv0srv.cc4
-rw-r--r--storage/innobase/srv/srv0start.cc2
-rw-r--r--storage/innobase/trx/trx0roll.cc11
-rw-r--r--storage/innobase/trx/trx0rseg.cc69
-rw-r--r--storage/innobase/trx/trx0trx.cc7
-rw-r--r--support-files/compiler_warnings.supp1
m---------wsrep-lib0
-rw-r--r--wsrep/CMakeLists.txt26
-rw-r--r--wsrep/wsrep_api.h1117
-rw-r--r--wsrep/wsrep_dummy.c413
-rw-r--r--wsrep/wsrep_gtid.c74
-rw-r--r--wsrep/wsrep_loader.c226
-rw-r--r--wsrep/wsrep_uuid.c83
791 files changed, 27577 insertions, 8408 deletions
diff --git a/.gitmodules b/.gitmodules
index 6419657e501..61d4c06dd4e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,7 @@
[submodule "storage/rocksdb/rocksdb"]
path = storage/rocksdb/rocksdb
url = https://github.com/facebook/rocksdb.git
+[submodule "wsrep-lib"]
+ path = wsrep-lib
+ url = https://github.com/codership/wsrep-lib.git
+ branch = master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a139c9e5fa4..b7cf8d23308 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -143,6 +143,7 @@ INCLUDE(misc)
INCLUDE(mysql_version)
INCLUDE(cpack_source_ignore_files)
INCLUDE(install_layout)
+INCLUDE(submodules)
INCLUDE(wsrep)
INCLUDE(cpack_rpm)
INCLUDE(cpack_deb)
@@ -377,7 +378,6 @@ ENDIF()
SET (MYSQLD_STATIC_PLUGIN_LIBS "" CACHE INTERNAL "")
-INCLUDE(submodules)
INCLUDE(mariadb_connector_c) # this does ADD_SUBDIRECTORY(libmariadb)
# Add storage engines and plugins.
@@ -405,7 +405,7 @@ IF(NOT WITHOUT_SERVER)
ENDIF(WITH_EMBEDDED_SERVER)
IF(WITH_WSREP)
- ADD_SUBDIRECTORY(wsrep)
+ ADD_SUBDIRECTORY(wsrep-lib)
ENDIF()
ADD_SUBDIRECTORY(mysql-test)
diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake
index 36d426257ea..19293e9a176 100644
--- a/cmake/cpack_rpm.cmake
+++ b/cmake/cpack_rpm.cmake
@@ -171,7 +171,7 @@ SETA(CPACK_RPM_server_PACKAGE_REQUIRES
IF(WITH_WSREP)
SETA(CPACK_RPM_server_PACKAGE_REQUIRES
- "galera" "rsync" "lsof" "grep" "gawk" "iproute"
+ "galera-4" "rsync" "lsof" "grep" "gawk" "iproute"
"coreutils" "findutils" "tar")
ENDIF()
diff --git a/cmake/make_dist.cmake.in b/cmake/make_dist.cmake.in
index 6fad17137fd..8e77b700eb7 100644
--- a/cmake/make_dist.cmake.in
+++ b/cmake/make_dist.cmake.in
@@ -50,6 +50,14 @@ IF(GIT_EXECUTABLE)
IF(NOT RESULT EQUAL 0)
SET(GIT_EXECUTABLE)
ENDIF()
+ EXECUTE_PROCESS(
+ COMMAND "${GIT_EXECUTABLE}" submodule foreach "${GIT_EXECUTABLE} checkout-index --all --prefix=${PACKAGE_DIR}/wsrep-lib/$path/"
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/wsrep-lib
+ RESULT_VARIABLE RESULT
+ )
+ IF(NOT RESULT EQUAL 0)
+ SET(GIT_EXECUTABLE)
+ ENDIF()
ENDIF()
CONFIGURE_FILE(${CMAKE_BINARY_DIR}/include/source_revision.h
diff --git a/cmake/submodules.cmake b/cmake/submodules.cmake
index 4181f4cd01e..c2a415c6063 100644
--- a/cmake/submodules.cmake
+++ b/cmake/submodules.cmake
@@ -14,16 +14,16 @@ IF(GIT_EXECUTABLE AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
SET(update_result 0)
ELSEIF (cmake_update_submodules MATCHES force)
MESSAGE(STATUS "Updating submodules (forced)")
- EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --force
+ EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --force --recursive
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE update_result)
ELSEIF (cmake_update_submodules MATCHES yes)
- EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init
+ EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --recursive
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE update_result)
ELSE()
MESSAGE(STATUS "Updating submodules")
- EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init
+ EXECUTE_PROCESS(COMMAND "${GIT_EXECUTABLE}" submodule update --init --recursive
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE update_result)
ENDIF()
diff --git a/cmake/wsrep.cmake b/cmake/wsrep.cmake
index 9fa127380a4..44e00649993 100644
--- a/cmake/wsrep.cmake
+++ b/cmake/wsrep.cmake
@@ -24,12 +24,15 @@ ELSE()
ENDIF()
OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ${with_wsrep_default})
+OPTION(WITH_WSREP_ALL
+ "Build all components of WSREP (unit tests, sample programs)"
+ OFF)
# Set the patch version
-SET(WSREP_PATCH_VERSION "23")
+SET(WSREP_PATCH_VERSION "22")
# Obtain wsrep API version
-FILE(STRINGS "${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h" WSREP_API_VERSION
+FILE(STRINGS "${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26/wsrep_api.h" WSREP_API_VERSION
LIMIT_COUNT 1 REGEX "WSREP_INTERFACE_VERSION")
STRING(REGEX MATCH "([0-9]+)" WSREP_API_VERSION "${WSREP_API_VERSION}")
@@ -40,4 +43,12 @@ SET(WSREP_PROC_INFO ${WITH_WSREP})
IF(WITH_WSREP)
SET(WSREP_PATCH_VERSION "wsrep_${WSREP_VERSION}")
+ if (NOT WITH_WSREP_ALL)
+ SET(WSREP_LIB_WITH_UNIT_TESTS OFF CACHE BOOL
+ "Disable unit tests for wsrep-lib")
+ SET(WSREP_LIB_WITH_DBSIM OFF CACHE BOOL
+ "Disable building dbsim for wsrep-lib")
+ endif()
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/wsrep-lib/include)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/wsrep-lib/wsrep-API/v26)
ENDIF()
diff --git a/debian/control b/debian/control
index 1588ade9153..2d3f0eb4aef 100644
--- a/debian/control
+++ b/debian/control
@@ -430,7 +430,7 @@ Recommends: libhtml-template-perl
Pre-Depends: adduser (>= 3.40),
debconf,
mariadb-common (>= ${source:Version})
-Depends: galera-3 (>=25.3),
+Depends: galera-4 (>=26.4),
gawk,
iproute | iproute2,
libdbi-perl,
diff --git a/extra/mariabackup/CMakeLists.txt b/extra/mariabackup/CMakeLists.txt
index 02f2d1a3690..623e7460ee4 100644
--- a/extra/mariabackup/CMakeLists.txt
+++ b/extra/mariabackup/CMakeLists.txt
@@ -40,9 +40,6 @@ IF(NOT HAVE_SYSTEM_REGEX)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pcre)
ENDIF()
-IF(WITH_WSREP)
- INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/wsrep)
-ENDIF()
ADD_DEFINITIONS(-UMYSQL_SERVER)
########################################################################
diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h
index cefba6303fe..5aa97cdb47e 100644
--- a/include/mysql/service_wsrep.h
+++ b/include/mysql/service_wsrep.h
@@ -1,5 +1,20 @@
#ifndef MYSQL_SERVICE_WSREP_INCLUDED
+#define MYSQL_SERVICE_WSREP_INCLUDED
+
+enum Wsrep_service_key_type
+{
+ WSREP_SERVICE_KEY_SHARED,
+ WSREP_SERVICE_KEY_REFERENCE,
+ WSREP_SERVICE_KEY_UPDATE,
+ WSREP_SERVICE_KEY_EXCLUSIVE
+};
+
+#if (defined (MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED)) || (!defined(MYSQL_DYNAMIC_PLUGIN) && defined(MYSQL_SERVICE_WSREP_STATIC_INCLUDED))
+
+#else
+
/* Copyright (c) 2015 MariaDB Corporation Ab
+ 2018 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
@@ -21,153 +36,92 @@
Interface to WSREP functionality in the server.
For engines that want to support galera.
*/
-
+#include <my_pthread.h>
#ifdef __cplusplus
-extern "C" {
#endif
-enum wsrep_conflict_state {
- NO_CONFLICT,
- MUST_ABORT,
- ABORTING,
- ABORTED,
- MUST_REPLAY,
- REPLAYING,
- RETRY_AUTOCOMMIT,
- CERT_FAILURE,
-};
-
-enum wsrep_exec_mode {
- /* Transaction processing before replication. */
- LOCAL_STATE,
- /* Slave thread applying write sets from other nodes or replaying thread. */
- REPL_RECV,
- /* Total-order-isolation mode. */
- TOTAL_ORDER,
- /*
- Transaction procession after it has been replicated in prepare stage and
- has passed certification.
- */
- LOCAL_COMMIT
-};
-
-enum wsrep_query_state {
- QUERY_IDLE,
- QUERY_EXEC,
- QUERY_COMMITTING,
- QUERY_EXITING,
- QUERY_ROLLINGBACK,
-};
-
-enum wsrep_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 */
-};
-
struct xid_t;
-struct wsrep;
struct wsrep_ws_handle;
struct wsrep_buf;
+/* Must match to definition in sql/mysqld.h */
+typedef int64 query_id_t;
+
+
extern struct wsrep_service_st {
- struct wsrep * (*get_wsrep_func)();
- my_bool (*get_wsrep_certify_nonPK_func)();
- my_bool (*get_wsrep_debug_func)();
- my_bool (*get_wsrep_drupal_282555_workaround_func)();
my_bool (*get_wsrep_recovery_func)();
- my_bool (*get_wsrep_load_data_splitting_func)();
- my_bool (*get_wsrep_log_conflicts_func)();
- long (*get_wsrep_protocol_version_func)();
- my_bool (*wsrep_aborting_thd_contains_func)(THD *thd);
- void (*wsrep_aborting_thd_enqueue_func)(THD *thd);
- bool (*wsrep_consistency_check_func)(THD *thd);
- int (*wsrep_is_wsrep_xid_func)(const struct xid_t *xid);
+ bool (*wsrep_consistency_check_func)(MYSQL_THD thd);
+ int (*wsrep_is_wsrep_xid_func)(const void *xid);
long long (*wsrep_xid_seqno_func)(const struct xid_t *xid);
const unsigned char* (*wsrep_xid_uuid_func)(const struct xid_t *xid);
- void (*wsrep_lock_rollback_func)();
- int (*wsrep_on_func)(MYSQL_THD);
- void (*wsrep_post_commit_func)(THD* thd, bool all);
- bool (*wsrep_prepare_key_func)(const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
- enum wsrep_trx_status (*wsrep_run_wsrep_commit_func)(THD *thd, bool all);
- void (*wsrep_thd_LOCK_func)(THD *thd);
- void (*wsrep_thd_UNLOCK_func)(THD *thd);
- void (*wsrep_thd_awake_func)(THD *thd, my_bool signal);
- enum wsrep_conflict_state (*wsrep_thd_conflict_state_func)(MYSQL_THD, my_bool);
- const char * (*wsrep_thd_conflict_state_str_func)(THD *thd);
- enum wsrep_exec_mode (*wsrep_thd_exec_mode_func)(THD *thd);
- const char * (*wsrep_thd_exec_mode_str_func)(THD *thd);
- enum wsrep_conflict_state (*wsrep_thd_get_conflict_state_func)(MYSQL_THD);
- my_bool (*wsrep_thd_is_BF_func)(MYSQL_THD , my_bool);
- my_bool (*wsrep_thd_is_wsrep_func)(MYSQL_THD thd);
- char * (*wsrep_thd_query_func)(THD *thd);
- enum wsrep_query_state (*wsrep_thd_query_state_func)(THD *thd);
- const char * (*wsrep_thd_query_state_str_func)(THD *thd);
- int (*wsrep_thd_retry_counter_func)(THD *thd);
- void (*wsrep_thd_set_conflict_state_func)(THD *thd, enum wsrep_conflict_state state);
- bool (*wsrep_thd_ignore_table_func)(THD *thd);
- long long (*wsrep_thd_trx_seqno_func)(THD *thd);
- struct wsrep_ws_handle * (*wsrep_thd_ws_handle_func)(THD *thd);
- int (*wsrep_trx_is_aborting_func)(MYSQL_THD thd);
- int (*wsrep_trx_order_before_func)(MYSQL_THD, MYSQL_THD);
- void (*wsrep_unlock_rollback_func)();
+ my_bool (*wsrep_on_func)(const MYSQL_THD thd);
+ bool (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
+ void (*wsrep_thd_LOCK_func)(const MYSQL_THD thd);
+ void (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd);
+ const char * (*wsrep_thd_query_func)(const MYSQL_THD thd);
+ int (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd);
+ bool (*wsrep_thd_ignore_table_func)(MYSQL_THD thd);
+ long long (*wsrep_thd_trx_seqno_func)(const MYSQL_THD thd);
+ my_bool (*wsrep_thd_is_aborting_func)(const MYSQL_THD thd);
void (*wsrep_set_data_home_dir_func)(const char *data_dir);
+ my_bool (*wsrep_thd_is_BF_func)(const MYSQL_THD thd, my_bool sync);
+ my_bool (*wsrep_thd_is_local_func)(const MYSQL_THD thd);
+ void (*wsrep_thd_self_abort_func)(MYSQL_THD thd);
+ int (*wsrep_thd_append_key_func)(MYSQL_THD thd, const struct wsrep_key* key,
+ int n_keys, enum Wsrep_service_key_type);
+ const char* (*wsrep_thd_client_state_str_func)(const MYSQL_THD thd);
+ const char* (*wsrep_thd_client_mode_str_func)(const MYSQL_THD thd);
+ const char* (*wsrep_thd_transaction_state_str_func)(const MYSQL_THD thd);
+ query_id_t (*wsrep_thd_transaction_id_func)(const MYSQL_THD thd);
+ my_bool (*wsrep_thd_bf_abort_func)(const MYSQL_THD bf_thd,
+ MYSQL_THD victim_thd,
+ my_bool signal);
+ my_bool (*wsrep_thd_order_before_func)(const MYSQL_THD left, const MYSQL_THD right);
+ void (*wsrep_handle_SR_rollback_func)(MYSQL_THD BF_thd, MYSQL_THD victim_thd);
+ my_bool (*wsrep_thd_skip_locking_func)(const MYSQL_THD thd);
+ const char* (*wsrep_get_sr_table_name_func)();
+ my_bool (*wsrep_get_debug_func)();
} *wsrep_service;
+#define MYSQL_SERVICE_WSREP_INCLUDED
+#endif
+
#ifdef MYSQL_DYNAMIC_PLUGIN
-#define get_wsrep() wsrep_service->get_wsrep_func()
-#define get_wsrep_certify_nonPK() wsrep_service->get_wsrep_certify_nonPK_func()
-#define get_wsrep_debug() wsrep_service->get_wsrep_debug_func()
-#define get_wsrep_drupal_282555_workaround() wsrep_service->get_wsrep_drupal_282555_workaround_func()
+
+#define MYSQL_SERVICE_WSREP_DYNAMIC_INCLUDED
#define get_wsrep_recovery() wsrep_service->get_wsrep_recovery_func()
-#define get_wsrep_load_data_splitting() wsrep_service->get_wsrep_load_data_splitting_func()
-#define get_wsrep_log_conflicts() wsrep_service->get_wsrep_log_conflicts_func()
-#define get_wsrep_protocol_version() wsrep_service->get_wsrep_protocol_version_func()
-#define wsrep_aborting_thd_contains(T) wsrep_service->wsrep_aborting_thd_contains_func(T)
-#define wsrep_aborting_thd_enqueue(T) wsrep_service->wsrep_aborting_thd_enqueue_func(T)
#define wsrep_consistency_check(T) wsrep_service->wsrep_consistency_check_func(T)
#define wsrep_is_wsrep_xid(X) wsrep_service->wsrep_is_wsrep_xid_func(X)
#define wsrep_xid_seqno(X) wsrep_service->wsrep_xid_seqno_func(X)
#define wsrep_xid_uuid(X) wsrep_service->wsrep_xid_uuid_func(X)
-#define wsrep_lock_rollback() wsrep_service->wsrep_lock_rollback_func()
#define wsrep_on(X) wsrep_service->wsrep_on_func(X)
-#define wsrep_post_commit(T,A) wsrep_service->wsrep_post_commit_func(T,A)
-#define wsrep_prepare_key(A,B,C,D,E,F) wsrep_service->wsrep_prepare_key_func(A,B,C,D,E,F)
-#define wsrep_run_wsrep_commit(T,A) wsrep_service->wsrep_run_wsrep_commit_func(T,A)
+#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G)
#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T)
#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T)
-#define wsrep_thd_awake(T,S) wsrep_service->wsrep_thd_awake_func(T,S)
-#define wsrep_thd_conflict_state(T,S) wsrep_service->wsrep_thd_conflict_state_func(T,S)
-#define wsrep_thd_conflict_state_str(T) wsrep_service->wsrep_thd_conflict_state_str_func(T)
-#define wsrep_thd_exec_mode(T) wsrep_service->wsrep_thd_exec_mode_func(T)
-#define wsrep_thd_exec_mode_str(T) wsrep_service->wsrep_thd_exec_mode_str_func(T)
-#define wsrep_thd_get_conflict_state(T) wsrep_service->wsrep_thd_get_conflict_state_func(T)
-#define wsrep_thd_is_BF(T,S) wsrep_service->wsrep_thd_is_BF_func(T,S)
-#define wsrep_thd_is_wsrep(T) wsrep_service->wsrep_thd_is_wsrep_func(T)
#define wsrep_thd_query(T) wsrep_service->wsrep_thd_query_func(T)
-#define wsrep_thd_query_state(T) wsrep_service->wsrep_thd_query_state_func(T)
-#define wsrep_thd_query_state_str(T) wsrep_service->wsrep_thd_query_state_str_func(T)
#define wsrep_thd_retry_counter(T) wsrep_service->wsrep_thd_retry_counter_func(T)
-#define wsrep_thd_set_conflict_state(T,S) wsrep_service->wsrep_thd_set_conflict_state_func(T,S)
#define wsrep_thd_ignore_table(T) wsrep_service->wsrep_thd_ignore_table_func(T)
#define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T)
-#define wsrep_thd_ws_handle(T) wsrep_service->wsrep_thd_ws_handle_func(T)
-#define wsrep_trx_is_aborting(T) wsrep_service->wsrep_trx_is_aborting_func(T)
-#define wsrep_trx_order_before(T1,T2) wsrep_service->wsrep_trx_order_before_func(T1,T2)
-#define wsrep_unlock_rollback() wsrep_service->wsrep_unlock_rollback_func()
#define wsrep_set_data_home_dir(A) wsrep_service->wsrep_set_data_home_dir_func(A)
-
-#define wsrep_debug get_wsrep_debug()
-#define wsrep_log_conflicts get_wsrep_log_conflicts()
-#define wsrep_certify_nonPK get_wsrep_certify_nonPK()
-#define wsrep_load_data_splitting get_wsrep_load_data_splitting()
-#define wsrep_drupal_282555_workaround get_wsrep_drupal_282555_workaround()
-#define wsrep_recovery get_wsrep_recovery()
-#define wsrep_protocol_version get_wsrep_protocol_version()
+#define wsrep_thd_is_BF(T,S) wsrep_service->wsrep_thd_is_BF_func(T,S)
+#define wsrep_thd_is_aborting(T) wsrep_service->wsrep_thd_is_aborting_func(T)
+#define wsrep_thd_is_local(T) wsrep_service->wsrep_thd_is_local_func(T)
+#define wsrep_thd_self_abort(T) wsrep_service->wsrep_thd_self_abort_func(T)
+#define wsrep_thd_append_key(T,W,N,K) wsrep_service->wsrep_thd_append_key_func(T,W,N,K)
+#define wsrep_thd_client_state_str(T) wsrep_service->wsrep_thd_client_state_str_func(T)
+#define wsrep_thd_client_mode_str(T) wsrep_service->wsrep_thd_client_mode_str_func(T)
+#define wsrep_thd_transaction_state_str(T) wsrep_service->wsrep_thd_transaction_state_str_func(T)
+#define wsrep_thd_transaction_id(T) wsrep_service->wsrep_thd_transaction_id_func(T)
+#define wsrep_thd_bf_abort(T,T2,S) wsrep_service->wsrep_thd_bf_abort_func(T,T2,S)
+#define wsrep_thd_order_before(L,R) wsrep_service->wsrep_thd_order_before_func(L,R)
+#define wsrep_handle_SR_rollback(B,V) wsrep_service->wsrep_handle_SR_rollback_func(B,V)
+#define wsrep_thd_skip_locking(T) wsrep_service->wsrep_thd_skip_locking_func(T)
+#define wsrep_get_sr_table_name() wsrep_service->wsrep_get_sr_table_name_func()
+#define wsrep_get_debug() wsrep_service->wsrep_get_debug_func()
#else
+#define MYSQL_SERVICE_WSREP_STATIC_INCLUDED
extern my_bool wsrep_debug;
extern my_bool wsrep_log_conflicts;
extern my_bool wsrep_certify_nonPK;
@@ -176,54 +130,81 @@ extern my_bool wsrep_drupal_282555_workaround;
extern my_bool wsrep_recovery;
extern long wsrep_protocol_version;
-bool wsrep_consistency_check(THD *thd);
-bool wsrep_prepare_key(const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len);
-char *wsrep_thd_query(THD *thd);
-const char *wsrep_thd_conflict_state_str(THD *thd);
-const char *wsrep_thd_exec_mode_str(THD *thd);
-const char *wsrep_thd_query_state_str(THD *thd);
-enum wsrep_conflict_state wsrep_thd_conflict_state(MYSQL_THD thd, my_bool sync);
-enum wsrep_conflict_state wsrep_thd_get_conflict_state(MYSQL_THD thd);
-enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
-enum wsrep_query_state wsrep_thd_query_state(THD *thd);
-enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, bool all);
-int wsrep_is_wsrep_xid(const struct xid_t* xid);
-long long wsrep_xid_seqno(const struct xid_t* xid);
+extern "C" bool wsrep_consistency_check(MYSQL_THD thd);
+bool wsrep_prepare_key_for_innodb(MYSQL_THD thd, const unsigned char* cache_key, size_t cache_key_len, const unsigned char* row_id, size_t row_id_len, struct wsrep_buf* key, size_t* key_len);
+extern "C" const char *wsrep_thd_query(const MYSQL_THD thd);
+extern "C" int wsrep_is_wsrep_xid(const void* xid);
+extern "C" long long wsrep_xid_seqno(const struct xid_t* xid);
const unsigned char* wsrep_xid_uuid(const struct xid_t* xid);
-int wsrep_on(MYSQL_THD thd);
-int wsrep_thd_retry_counter(THD *thd);
-int wsrep_trx_is_aborting(MYSQL_THD thd);
-int wsrep_trx_order_before(MYSQL_THD thd1, MYSQL_THD thd2);
-long get_wsrep_protocol_version();
-long long wsrep_thd_trx_seqno(THD *thd);
-my_bool get_wsrep_certify_nonPK();
-my_bool get_wsrep_debug();
-my_bool get_wsrep_drupal_282555_workaround();
+extern "C" long long wsrep_thd_trx_seqno(const MYSQL_THD thd);
my_bool get_wsrep_recovery();
-my_bool get_wsrep_load_data_splitting();
-my_bool get_wsrep_log_conflicts();
-my_bool wsrep_aborting_thd_contains(THD *thd);
-my_bool wsrep_thd_is_BF(MYSQL_THD thd, my_bool sync);
-my_bool wsrep_thd_is_wsrep(MYSQL_THD thd);
-struct wsrep *get_wsrep();
-struct wsrep_ws_handle *wsrep_thd_ws_handle(THD *thd);
-void wsrep_aborting_thd_enqueue(THD *thd);
-void wsrep_lock_rollback();
-void wsrep_post_commit(THD* thd, bool all);
-void wsrep_thd_LOCK(THD *thd);
-void wsrep_thd_UNLOCK(THD *thd);
-void wsrep_thd_awake(THD *thd, my_bool signal);
-void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state);
-bool wsrep_thd_ignore_table(THD *thd);
-void wsrep_unlock_rollback();
+bool wsrep_thd_ignore_table(MYSQL_THD thd);
void wsrep_set_data_home_dir(const char *data_dir);
+/* from mysql wsrep-lib */
+#include "my_global.h"
+#include "my_pthread.h"
+
+/* Return true if wsrep is enabled for a thd. This means that
+ wsrep is enabled globally and the thd has wsrep on */
+extern "C" my_bool wsrep_on(const MYSQL_THD thd);
+/* Lock thd wsrep lock */
+extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd);
+/* Unlock thd wsrep lock */
+extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd);
+
+/* Return thd client state string */
+extern "C" const char* wsrep_thd_client_state_str(const MYSQL_THD thd);
+/* Return thd client mode string */
+extern "C" const char* wsrep_thd_client_mode_str(const MYSQL_THD thd);
+/* Return thd transaction state string */
+extern "C" const char* wsrep_thd_transaction_state_str(const MYSQL_THD thd);
+
+/* Return current transaction id */
+extern "C" query_id_t wsrep_thd_transaction_id(const MYSQL_THD thd);
+/* Mark thd own transaction as aborted */
+extern "C" void wsrep_thd_self_abort(MYSQL_THD thd);
+/* Return true if thd is in replicating mode */
+extern "C" my_bool wsrep_thd_is_local(const MYSQL_THD thd);
+/* Return true if thd is in high priority mode */
+/* todo: rename to is_high_priority() */
+extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
+/* Return true if thd is in TOI mode */
+extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd);
+/* Return true if thd is in replicating TOI mode */
+extern "C" my_bool wsrep_thd_is_local_toi(const MYSQL_THD thd);
+/* Return true if thd is in RSU mode */
+extern "C" my_bool wsrep_thd_is_in_rsu(const MYSQL_THD thd);
+/* Return true if thd is in BF mode, either high_priority or TOI */
+extern "C" my_bool wsrep_thd_is_BF(const MYSQL_THD thd, my_bool sync);
+/* Return true if thd is streaming */
+extern "C" my_bool wsrep_thd_is_SR(const MYSQL_THD thd);
+extern "C" void wsrep_handle_SR_rollback(MYSQL_THD BF_thd, MYSQL_THD victim_thd);
+/* Return thd retry counter */
+extern "C" int wsrep_thd_retry_counter(const MYSQL_THD thd);
+/* BF abort victim_thd */
+extern "C" my_bool wsrep_thd_bf_abort(const MYSQL_THD bf_thd,
+ MYSQL_THD victim_thd,
+ my_bool signal);
+/* Return true if left thd is ordered before right thd */
+extern "C" my_bool wsrep_thd_order_before(const MYSQL_THD left, const MYSQL_THD right);
+/* Return true if thd should skip locking. This means that the thd
+ is operating on shared resource inside commit order critical section. */
+extern "C" my_bool wsrep_thd_skip_locking(const MYSQL_THD thd);
+/* Return true if thd is aborting */
+extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd);
+
+struct wsrep_key;
+struct wsrep_key_array;
+extern "C" int wsrep_thd_append_key(MYSQL_THD thd,
+ const struct wsrep_key* key,
+ int n_keys,
+ enum Wsrep_service_key_type);
+
+extern const char* wsrep_sr_table_name_full;
+
+extern "C" const char* wsrep_get_sr_table_name();
+
+extern "C" my_bool wsrep_get_debug();
#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#define MYSQL_SERVICE_WSREP_INCLUDED
-#endif
-
+#endif /* MYSQL_SERVICE_WSREP_INCLUDED */
diff --git a/include/thr_lock.h b/include/thr_lock.h
index e6451bf21c4..ee15fd7315d 100644
--- a/include/thr_lock.h
+++ b/include/thr_lock.h
@@ -168,9 +168,9 @@ void thr_set_lock_wait_callback(void (*before_wait)(void),
void (*after_wait)(void));
#ifdef WITH_WSREP
- 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 *);
+ typedef my_bool (* wsrep_thd_is_brute_force_fun)(const MYSQL_THD, my_bool);
+ typedef my_bool(* wsrep_abort_thd_fun)(const MYSQL_THD, MYSQL_THD, my_bool);
+ typedef my_bool (* wsrep_on_fun)(const MYSQL_THD);
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);
diff --git a/include/wsrep.h b/include/wsrep.h
index f7a9b6b0231..df8a88e1c69 100644
--- a/include/wsrep.h
+++ b/include/wsrep.h
@@ -13,11 +13,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
-#include <my_config.h>
-
#ifndef WSREP_INCLUDED
#define WSREP_INCLUDED
+#include <my_config.h>
+
#ifdef WITH_WSREP
#define IF_WSREP(A,B) A
#define DBUG_ASSERT_IF_WSREP(A) DBUG_ASSERT(A)
@@ -28,12 +28,14 @@
goto wsrep_error_label;
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_) \
- if (WSREP_ON && WSREP(thd) && wsrep_to_isolation_begin(thd, db_, table_, \
- table_list_, alter_info_)) \
+ if (WSREP(thd) && wsrep_thd_is_local(thd) && \
+ wsrep_to_isolation_begin(thd, db_, table_, \
+ table_list_, alter_info_)) \
goto wsrep_error_label;
-#define WSREP_TO_ISOLATION_END \
- if (WSREP_ON && (WSREP(thd) || (thd && thd->wsrep_exec_mode==TOTAL_ORDER))) \
+#define WSREP_TO_ISOLATION_END \
+ if ((WSREP(thd) && wsrep_thd_is_local_toi(thd)) || \
+ wsrep_thd_is_in_rsu(thd)) \
wsrep_to_isolation_end(thd);
/*
@@ -54,19 +56,22 @@
{ if (WSREP_CLIENT(thd_) && \
wsrep_sync_wait(thd_, before_)) goto wsrep_error_label; }
-#else
+#else /* !WITH_WSREP */
+
+/* These macros are needed to compile MariaDB without WSREP support
+ * (e.g. embedded) */
+
#define IF_WSREP(A,B) B
-#define DBUG_ASSERT_IF_WSREP(A)
+//#define DBUG_ASSERT_IF_WSREP(A)
#define WSREP_DEBUG(...)
-#define WSREP_INFO(...)
-#define WSREP_WARN(...)
+//#define WSREP_INFO(...)
+//#define WSREP_WARN(...)
#define WSREP_ERROR(...)
#define WSREP_TO_ISOLATION_BEGIN(db_, table_, table_list_) do { } while(0)
#define WSREP_TO_ISOLATION_BEGIN_ALTER(db_, table_, table_list_, alter_info_)
#define WSREP_TO_ISOLATION_END
#define WSREP_TO_ISOLATION_BEGIN_WRTCHK(db_, table_, table_list_)
#define WSREP_SYNC_WAIT(thd_, before_)
-
#endif /* WITH_WSREP */
#endif /* WSREP_INCLUDED */
diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test
index a9c8e13fa7c..39aa3d49d68 100644
--- a/mysql-test/include/check-testcase.test
+++ b/mysql-test/include/check-testcase.test
@@ -103,5 +103,56 @@ cat_file $datadir.tempfiles.txt;
remove_file $datadir.tempfiles.txt;
list_files $datadir/mysql #sql*;
+#
+# Check that SHOW ENGINE INNODB STATUS does not show any active transactions
+# We do this only if wsrep provider is loaded, to avoid disturbing any non-Galera MTR tests
+#
+if (`SELECT COUNT(*)=1 FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'wsrep' AND PLUGIN_STATUS='ACTIVE'`) {
+ if (`SELECT @@wsrep_on`) {
+ if (`SELECT COUNT(*) FROM information_schema.innodb_trx WHERE trx_mysql_thread_id != 0`) {
+ if ($before) {
+ --echo Before test start.
+ }
+ if (!$before) {
+ --echo After test end.
+ }
+ --echo There is one or more active InnoDB transaction(s) when there should be none. Dumping some diagnostics.
+
+ --let $status_locks = `SELECT @@innodb_status_output_locks`
+ --let $status_output = `SELECT @@innodb_status_output`
+ --enable_query_log
+ SET GLOBAL innodb_status_output_locks=ON;
+ SHOW ENGINE INNODB STATUS;
+ --disable_query_log
+ --eval SET GLOBAL innodb_status_output_locks=$status_locks;
+ --eval SET GLOBAL innodb_status_output=$status_output;
+ --enable_query_log
+
+ --vertical_results
+ if ($before) {
+ --replace_regex /$/ /
+ }
+ SELECT * FROM information_schema.processlist;
+
+ if ($before) {
+ --replace_regex /$/ /
+ }
+ SELECT * FROM information_schema.innodb_trx;
+
+ if ($before) {
+ --replace_regex /$/ /
+ }
+ SELECT * FROM information_schema.innodb_locks;
+
+ if ($before) {
+ --replace_regex /$/ /
+ }
+ SELECT * FROM information_schema.innodb_lock_waits;
+ --horizontal_results
+ --disable_query_log
+ }
+ }
+}
+
--enable_query_log
diff --git a/mysql-test/include/galera_cluster.inc b/mysql-test/include/galera_cluster.inc
index c1834c3c26f..7f76ea59c7f 100644
--- a/mysql-test/include/galera_cluster.inc
+++ b/mysql-test/include/galera_cluster.inc
@@ -8,5 +8,11 @@
--let $galera_cluster_size = 2
--source include/galera_init.inc
+--source include/have_innodb.inc
+--source include/galera_wait_ready.inc
+--connection node_2
+--source include/galera_wait_ready.inc
--source include/have_innodb.inc
+
+--connection node_1
diff --git a/mysql-test/suite/galera/include/galera_have_debug_sync.inc b/mysql-test/include/galera_have_debug_sync.inc
index 7c0156052d8..7c0156052d8 100644
--- a/mysql-test/suite/galera/include/galera_have_debug_sync.inc
+++ b/mysql-test/include/galera_have_debug_sync.inc
diff --git a/mysql-test/include/galera_wait_sync_point.inc b/mysql-test/include/galera_wait_sync_point.inc
index cf3a4980186..c0951b220b4 100644
--- a/mysql-test/include/galera_wait_sync_point.inc
+++ b/mysql-test/include/galera_wait_sync_point.inc
@@ -1,6 +1,17 @@
--let $wait_timeout = 10
--let $wsrep_on_orig = `SELECT @@wsrep_on`
SET SESSION wsrep_on = 0;
+
+#
+# following is only for debugging purposes
+# should be commented out when test wporks as planned
+#
+#--sleep 1
+# SHOW PROCESSLIST;
+#SHOW STATUS LIKE 'wsrep_%';
+#--echo $galera_sync_point
+
--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_wsrep_enabled.inc b/mysql-test/include/have_wsrep_enabled.inc
index 9287369c87c..7eb8b4372cf 100644
--- a/mysql-test/include/have_wsrep_enabled.inc
+++ b/mysql-test/include/have_wsrep_enabled.inc
@@ -1,7 +1,6 @@
# 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
--source include/have_innodb.inc
if (`SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_on' AND VARIABLE_VALUE='ON'`)
diff --git a/mysql-test/include/kill_galera.inc b/mysql-test/include/kill_galera.inc
new file mode 100644
index 00000000000..d7f665df6c7
--- /dev/null
+++ b/mysql-test/include/kill_galera.inc
@@ -0,0 +1,20 @@
+--echo Killing server ...
+
+# Write file to make mysql-test-run.pl expect the crash, but don't start it
+--let $_server_id= `SELECT @@server_id`
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
+--exec echo "wait" > $_expect_file_name
+
+# Kill the connected server
+--disable_reconnect
+--let KILL_NODE_PIDFILE = `SELECT @@pid_file`
+
+--perl
+ my $pid_filename = $ENV{'KILL_NODE_PIDFILE'};
+ my $mysqld_pid = `cat $pid_filename`;
+ chomp($mysqld_pid);
+ system("kill -9 $mysqld_pid");
+ exit(0);
+EOF
+
+--source include/wait_until_disconnected.inc
diff --git a/mysql-test/include/wsrep_wait_disconnect.inc b/mysql-test/include/wsrep_wait_disconnect.inc
new file mode 100644
index 00000000000..740fc0d9426
--- /dev/null
+++ b/mysql-test/include/wsrep_wait_disconnect.inc
@@ -0,0 +1,20 @@
+let $wait_condition = SELECT 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready' AND VARIABLE_VALUE = 'OFF';
+# since this is called until AFTER provider disconnects,we need to allow
+# queries in non-prim
+#
+# We are also forced to use a hard-coded value for wsrep_sync_wait here because
+# we can not issue a SELECT query to obtain the original value and then restore
+# it
+disable_query_log;
+SET SESSION wsrep_sync_wait = 7;
+--let $restore_wsrep_on = `SHOW VARIABLES WHERE Variable_name = 'wsrep_on' AND Value = 'ON'`
+SET SESSION wsrep_on = OFF;
+
+--source include/wait_condition.inc
+
+if ($restore_wsrep_on != "")
+{
+ --eval SET SESSION wsrep_on = ON
+}
+SET SESSION wsrep_sync_wait = 15;
+enable_query_log;
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index b5b8a92f1ec..428092a355a 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -2896,15 +2896,44 @@ sub mysql_server_start($) {
# Save this test case information, so next can examine it
$mysqld->{'started_tinfo'}= $tinfo;
}
+
+ # If wsrep is on, we need to wait until the first
+ # server starts and bootstraps the cluster before
+ # starting other servers. The bootsrap server in the
+ # configuration should always be the first which has
+ # wsrep_on=ON
+ if (wsrep_on($mysqld) && wsrep_is_bootstrap_server($mysqld))
+ {
+ mtr_verbose("Waiting for wsrep bootstrap server to start");
+ if ($mysqld->{WAIT}->($mysqld))
+ {
+ return 1;
+ }
+ }
}
sub mysql_server_wait {
- my ($mysqld) = @_;
+ my ($mysqld, $tinfo) = @_;
- return not sleep_until_file_created($mysqld->value('pid-file'),
- $opt_start_timeout,
- $mysqld->{'proc'},
- $warn_seconds);
+ if (!sleep_until_file_created($mysqld->value('pid-file'),
+ $opt_start_timeout,
+ $mysqld->{'proc'},
+ $warn_seconds))
+ {
+ $tinfo->{comment}= "Failed to start ".$mysqld->name() . "\n";
+ return 1;
+ }
+
+ if (wsrep_on($mysqld))
+ {
+ mtr_verbose("Waiting for wsrep server " . $mysqld->name() . " to be ready");
+ if (!wait_wsrep_ready($tinfo, $mysqld))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
}
sub create_config_file_for_extern {
@@ -5408,6 +5437,118 @@ sub stop_servers($$) {
}
}
+#
+# run_query_output
+#
+# Run a query against a server using mysql client. The output of
+# the query will be written into outfile.
+#
+sub run_query_output {
+ my ($mysqld, $query, $outfile)= @_;
+ my $args;
+
+ mtr_init_args(\$args);
+ mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
+ mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
+ mtr_add_arg($args, "--silent");
+ mtr_add_arg($args, "--execute=%s", $query);
+
+ my $res= My::SafeProcess->run
+ (
+ name => "run_query_output -> ".$mysqld->name(),
+ path => $exe_mysql,
+ args => \$args,
+ output => $outfile,
+ error => $outfile
+ );
+
+ return $res
+}
+
+
+#
+# wsrep_wait_ready
+#
+# Wait until the server has been joined to the cluster and is
+# ready for operation.
+#
+# RETURN
+# 1 Server is ready
+# 0 Server didn't transition to ready state within start timeout
+#
+sub wait_wsrep_ready($$) {
+ my ($tinfo, $mysqld)= @_;
+
+ my $sleeptime= 100; # Milliseconds
+ my $loops= ($opt_start_timeout * 1000) / $sleeptime;
+
+ my $name= $mysqld->name();
+ my $outfile= "$opt_vardir/tmp/$name.wsrep_ready";
+ my $query= "SET SESSION wsrep_sync_wait = 0;
+ SELECT VARIABLE_NAME, VARIABLE_VALUE
+ FROM INFORMATION_SCHEMA.GLOBAL_STATUS
+ WHERE VARIABLE_NAME = 'wsrep_ready'";
+
+ for (my $loop= 1; $loop <= $loops; $loop++)
+ {
+ # Careful... if MTR runs with option 'verbose' then the
+ # file contains also SafeProcess verbose output
+ if (run_query_output($mysqld, $query, $outfile) == 0 &&
+ mtr_grab_file($outfile) =~ /WSREP_READY\s+ON/)
+ {
+ unlink($outfile);
+ return 1;
+ }
+ mtr_milli_sleep($sleeptime);
+ }
+
+ $tinfo->{logfile}= "WSREP did not transition to state READY";
+ return 0;
+}
+
+#
+# wsrep_is_bootstrap_server
+#
+# Check if the server is the first one to be started in the
+# cluster.
+#
+# RETURN
+# 1 The server is a bootstrap server
+# 0 The server is not a bootstrap server
+#
+sub wsrep_is_bootstrap_server($) {
+ my $mysqld= shift;
+
+ my $cluster_address= $mysqld->if_exist('wsrep-cluster-address') ||
+ $mysqld->if_exist('wsrep_cluster_address');
+ if (defined $cluster_address)
+ {
+ return $cluster_address eq "gcomm://" || $cluster_address eq "'gcomm://'";
+ }
+ return 0;
+}
+
+#
+# wsrep_on
+#
+# Check if wsrep has been enabled for a server.
+#
+# RETURN
+# 1 Wsrep has been enabled
+# 0 Wsrep is not enabled
+#
+sub wsrep_on($) {
+ my $mysqld= shift;
+ #check if wsrep_on= is set in configuration
+ if ($mysqld->if_exist('wsrep-on')) {
+ my $on= "".$mysqld->value('wsrep-on');
+ if ($on eq "1" || $on eq "ON") {
+ return 1;
+ }
+ }
+ return 0;
+}
+
#
# start_servers
@@ -5427,8 +5568,7 @@ sub start_servers($) {
for (all_servers()) {
next unless $_->{WAIT} and started($_);
- if ($_->{WAIT}->($_)) {
- $tinfo->{comment}= "Failed to start ".$_->name() . "\n";
+ if ($_->{WAIT}->($_, $tinfo)) {
return 1;
}
}
diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def
index 7064df982dd..b179c9d2a63 100644
--- a/mysql-test/suite/galera/disabled.def
+++ b/mysql-test/suite/galera/disabled.def
@@ -9,13 +9,14 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
-
+MW-360 : needs rewrite to be MariaDB gtid compatible
galera_flush : MariaDB does not have global.thread_statistics
galera_account_management : MariaDB 10.0 does not support ALTER USER
galera_binlog_rows_query_log_events: MariaDB does not support binlog_rows_query_log_events
galera_migrate : MariaDB does not support START SLAVE USER
galera_as_master_gtid : Requires MySQL GTID
galera_as_master_gtid_change_master : Requires MySQL GTID
+galera_as_slave_gtid_replicate_do_db_cc : Requires MySQL GTID
galera_as_slave_preordered : wsrep-preordered feature not merged to MariaDB
GAL-419 : MDEV-13549 Galera test failures
galera_var_notify_cmd : MDEV-13549 Galera test failures
@@ -52,3 +53,13 @@ galera.galera_var_reject_queries : assertion in inline_mysql_socket_send
query_cache : MDEV-18137: Galera test failure on query_cache
galera.galera_autoinc_sst_mariabackup : MDEV-18177 Galera test failure on galera_autoinc_sst_mariabackup
galera_gcache_recover_manytrx : MDEV-15740
+galera.galera_ist_mariabackup : Leaves port open
+galera.galera_sst_rsync2 : MDEV-18178 Galera test failure on galera_sst_rsync2
+galera.galera_kill_largechanges : MDEV-18179 Galera test failure on galera.galera_kill_largechanges
+galera.galera_concurrent_ctas : MDEV-18180 Galera test failure on galera.galera_concurrent_ctas
+galera.galera_var_retry_autocommit: MDEV-18181 Galera test failure on galera.galera_var_retry_autocommit
+galera.galera_many_tables_nopk : MDEV-18182 Galera test failure on galera.galera_many_tables_nopk
+galera.galera_kill_nochanges : MDEV-18280 Galera test failure on galera_split_brain and galera_kill_nochanges
+galera.galera_split_brain : MDEV-18280 Galera test failure on galera_split_brain and galera_kill_nochanges
+galera.galera_bf_abort_group_commit : MDEV-18282 Galera test failure on galera.galera_bf_abort_group_commit
+galera.GCF-1081 : MDEV-18283 Galera test failure on galera.GCF-1081
diff --git a/mysql-test/suite/galera/galera_2nodes.cnf b/mysql-test/suite/galera/galera_2nodes.cnf
index b24f3603894..ef8a17a77be 100644
--- a/mysql-test/suite/galera/galera_2nodes.cnf
+++ b/mysql-test/suite/galera/galera_2nodes.cnf
@@ -2,7 +2,7 @@
!include include/default_mysqld.cnf
[mysqld]
-wsrep-on=1
+loose-innodb
binlog-format=row
innodb-autoinc-lock-mode=2
default-storage-engine=innodb
@@ -10,20 +10,35 @@ wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
# enforce read-committed characteristics across the cluster
wsrep-sync-wait=15
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.1]
+loose-innodb
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep-cluster-address=gcomm://
wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;gcache.size=10M'
wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+# enforce read-committed characteristics across the cluster
+wsrep_causal_reads=ON
+wsrep_sync_wait = 15
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
+
[mysqld.2]
+loose-innodb
+# debug=d:t:i:o,/tmp/mysqld.2.trace
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
@@ -34,8 +49,14 @@ wsrep_sync_wait = 15
wsrep_node_address=127.0.0.1
wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port
wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
-wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_sst_receive_address='127.0.0.2:@mysqld.2.#sst_port'
+# enforce read-committed characteristics across the cluster
+wsrep_causal_reads=ON
+wsrep_sync_wait = 15
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[ENV]
NODE_MYPORT_1= @mysqld.1.port
@@ -43,4 +64,3 @@ NODE_MYSOCK_1= @mysqld.1.socket
NODE_MYPORT_2= @mysqld.2.port
NODE_MYSOCK_2= @mysqld.2.socket
-
diff --git a/mysql-test/suite/galera/galera_2nodes_as_master.cnf b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
index 33bfc475721..4403416b033 100644
--- a/mysql-test/suite/galera/galera_2nodes_as_master.cnf
+++ b/mysql-test/suite/galera/galera_2nodes_as_master.cnf
@@ -11,6 +11,9 @@ log-bin=mysqld-bin
binlog-format=row
innodb-autoinc-lock-mode=2
default-storage-engine=innodb
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.1]
#galera_port=@OPT.port
@@ -30,6 +33,9 @@ wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.2]
#galera_port=@OPT.port
@@ -49,9 +55,15 @@ wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.3]
server-id=3
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[ENV]
NODE_MYPORT_1= @mysqld.1.port
@@ -62,9 +74,3 @@ NODE_MYSOCK_2= @mysqld.2.socket
NODE_MYPORT_3= @mysqld.3.port
NODE_MYSOCK_3= @mysqld.3.socket
-
-NODE_GALERAPORT_1= @mysqld.1.#galera_port
-NODE_GALERAPORT_2= @mysqld.2.#galera_port
-
-NODE_SSTPORT_1= @mysqld.1.#sst_port
-NODE_SSTPORT_2= @mysqld.2.#sst_port
diff --git a/mysql-test/suite/galera/galera_2nodes_as_slave.cnf b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
index 4d9e39d2aae..d1fa7bfbfca 100644
--- a/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
+++ b/mysql-test/suite/galera/galera_2nodes_as_slave.cnf
@@ -9,17 +9,13 @@
binlog-format=row
[mysqld.1]
-log-bin
-server-id=1
-
-[mysqld.2]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
-
wsrep-on=1
-log-bin
+log-bin=master-bin
+log-bin-index=master-bin
log-slave-updates
innodb-autoinc-lock-mode=2
@@ -27,38 +23,53 @@ default-storage-engine=innodb
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
wsrep-cluster-address=gcomm://
-wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M'
-wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
-wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
-server-id=2
+server-id=1
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
-[mysqld.3]
+[mysqld.2]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
-
wsrep-on=1
-log-bin
+log-bin=master-bin
+log-bin-index=master-bin
log-slave-updates
innodb-autoinc-lock-mode=2
default-storage-engine=innodb
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
-wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
-wsrep_provider_options='base_port=@mysqld.3.#galera_port;gcache.size=10M'
-wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
-wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
+server-id=2
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
+
+[mysqld.3]
+log-bin=master-bin
+log-bin-index=master-bin
server-id=3
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
+
[ENV]
NODE_MYPORT_1= @mysqld.1.port
@@ -69,9 +80,3 @@ NODE_MYSOCK_2= @mysqld.2.socket
NODE_MYPORT_3= @mysqld.3.port
NODE_MYSOCK_3= @mysqld.3.socket
-
-NODE_GALERAPORT_2= @mysqld.2.#galera_port
-NODE_GALERAPORT_3= @mysqld.3.#galera_port
-
-NODE_SSTPORT_2= @mysqld.2.#sst_port
-NODE_SSTPORT_3= @mysqld.3.#sst_port
diff --git a/mysql-test/suite/galera/galera_3nodes_as_slave.cnf b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
index ac1ca34e242..c84c4b25d2a 100644
--- a/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
+++ b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf
@@ -8,14 +8,15 @@
[mysqld]
log-bin
binlog-format=row
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.1]
-server-id=1
-
-[mysqld.2]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
log-slave-updates
@@ -24,19 +25,23 @@ default-storage-engine=innodb
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
wsrep-cluster-address=gcomm://
-wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.install_timeout = PT15S;evs.max_install_timeouts=1;gcache.size=10M'
-wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
-wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;evs.install_timeout = PT15S;evs.max_install_timeouts=1;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
-server-id=2
+server-id=1
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
-[mysqld.3]
+[mysqld.2]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
log-slave-updates
@@ -44,20 +49,24 @@ innodb-autoinc-lock-mode=2
default-storage-engine=innodb
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
-wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
-wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M'
-wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
-wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
-server-id=3
+server-id=2
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
-[mysqld.4]
+[mysqld.3]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
log-slave-updates
@@ -65,15 +74,24 @@ innodb-autoinc-lock-mode=2
default-storage-engine=innodb
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
-wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port'
-wsrep_provider_options='base_port=@mysqld.4.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M'
-wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port
-wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port'
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M'
+wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
+wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
+server-id=3
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
+
+[mysqld.4]
server-id=4
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[ENV]
NODE_MYPORT_1= @mysqld.1.port
@@ -87,11 +105,3 @@ NODE_MYSOCK_3= @mysqld.3.socket
NODE_MYPORT_4= @mysqld.4.port
NODE_MYSOCK_4= @mysqld.4.socket
-
-NODE_GALERAPORT_2= @mysqld.2.#galera_port
-NODE_GALERAPORT_3= @mysqld.3.#galera_port
-NODE_GALERAPORT_4= @mysqld.4.#galera_port
-
-NODE_SSTPORT_2= @mysqld.2.#sst_port
-NODE_SSTPORT_3= @mysqld.3.#sst_port
-NODE_SSTPORT_4= @mysqld.4.#sst_port
diff --git a/mysql-test/suite/galera/galera_4nodes.cnf b/mysql-test/suite/galera/galera_4nodes.cnf
index 1c195afd54b..7f59f75b2dc 100644
--- a/mysql-test/suite/galera/galera_4nodes.cnf
+++ b/mysql-test/suite/galera/galera_4nodes.cnf
@@ -5,50 +5,68 @@
binlog-format=row
innodb-autoinc-lock-mode=2
default-storage-engine=innodb
-wsrep-on=1
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
# enforce read-committed characteristics across the cluster
wsrep-causal-reads=ON
wsrep-sync-wait=15
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.1]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep-cluster-address=gcomm://
wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M'
wsrep_node_incoming_address=127.0.0.1:@mysqld.1.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.2]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M'
wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.3]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.3.#galera_port;gcache.size=10M'
wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port'
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[mysqld.4]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.4.#galera_port;gcache.size=10M'
wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port
wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port'
+# lock schedule alg appears to be VATS by default, and it is not
+# yet compatible with galera
+innodb_lock_schedule_algorithm=FCFS
[ENV]
NODE_MYPORT_1= @mysqld.1.port
@@ -62,13 +80,3 @@ NODE_MYSOCK_3= @mysqld.3.socket
NODE_MYPORT_4= @mysqld.4.port
NODE_MYSOCK_4= @mysqld.4.socket
-
-NODE_GALERAPORT_1= @mysqld.1.#galera_port
-NODE_GALERAPORT_2= @mysqld.2.#galera_port
-NODE_GALERAPORT_3= @mysqld.3.#galera_port
-NODE_GALERAPORT_4= @mysqld.4.#galera_port
-
-NODE_SSTPORT_1= @mysqld.1.#sst_port
-NODE_SSTPORT_2= @mysqld.2.#sst_port
-NODE_SSTPORT_3= @mysqld.3.#sst_port
-NODE_SSTPORT_4= @mysqld.4.#sst_port
diff --git a/mysql-test/suite/galera/include/galera_base_port.inc b/mysql-test/suite/galera/include/galera_base_port.inc
new file mode 100644
index 00000000000..caf986ee950
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_base_port.inc
@@ -0,0 +1,8 @@
+#
+# Extract base_port from galera node.
+#
+
+# Convert "... base_port = N; ..." to "N; ..."
+--let $s1 = `SELECT SUBSTR(@@wsrep_provider_options, LOCATE('base_port =', @@wsrep_provider_options) + LENGTH('base_port = '))`
+# Convert "N; ..." to "N"
+--let $_NODE_GALERAPORT = `SELECT SUBSTR('$s1', 1, LOCATE(';', '$s1') - 1)`
diff --git a/mysql-test/suite/galera/include/galera_concurrent_test.inc b/mysql-test/suite/galera/include/galera_concurrent_test.inc
new file mode 100644
index 00000000000..3d1bc7674a1
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_concurrent_test.inc
@@ -0,0 +1,90 @@
+#
+# Perform a quick concurrent test on two nodes using a set of predefined statements.
+#
+# Such tests are not deterministic, so we are hoping to catch assertions, slave apply errors
+# and cases where the two nodes diverge
+#
+# Parameters:
+# - $wsrep_trx_fragment_size
+# - $count
+# - $query_node_1
+# - $query_node_1a (optional)
+# - $query_node_2
+#
+
+if (!$count) {
+ --let $count = 50;
+}
+
+if (!$node_1a_connected) {
+ --connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+ --let $node_1a_connected = 1
+}
+
+--echo Running a concurrent test with the following queries:
+--echo $query_node_1
+--echo $query_node_1a
+--echo $query_node_2
+
+--connection node_1
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+
+SET SESSION wsrep_sync_wait = 0;
+--eval SET SESSION wsrep_trx_fragment_size = $wsrep_trx_fragment_size;
+
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--eval SET SESSION wsrep_trx_fragment_size = $wsrep_trx_fragment_size;
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--eval SET SESSION wsrep_trx_fragment_size = $wsrep_trx_fragment_size;
+
+--disable_query_log
+--let $i = `SELECT $count`
+while ($i)
+{
+ --connection node_1
+ --send_eval $query_node_1
+
+ --connection node_1a
+ if ($query_node_1a) {
+ --send_eval $query_node_1a
+ }
+
+ --connection node_2
+ --send_eval $query_node_2
+
+ --connection node_1
+ --error 0,ER_QUERY_INTERRUPTED,ER_LOCK_DEADLOCK,ER_DUP_ENTRY
+ --reap
+
+ --connection node_1a
+ if ($query_node_1a) {
+ --error 0,ER_QUERY_INTERRUPTED,ER_LOCK_DEADLOCK,ER_DUP_ENTRY
+ --reap
+ }
+
+ --connection node_2
+ --error 0,ER_QUERY_INTERRUPTED,ER_LOCK_DEADLOCK,ER_DUP_ENTRY
+ --reap
+ --dec $i
+}
+
+SET SESSION wsrep_sync_wait = 15;
+--enable_query_log
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+DROP TABLE t1;
+
+--let $query_node_1 = ""
+--let $query_node_1a = ""
+--let $query_node_2 = ""
+
+--echo Concurrent test end
diff --git a/mysql-test/suite/galera/include/galera_dump_sr_table.inc b/mysql-test/suite/galera/include/galera_dump_sr_table.inc
new file mode 100644
index 00000000000..48a55006eae
--- /dev/null
+++ b/mysql-test/suite/galera/include/galera_dump_sr_table.inc
@@ -0,0 +1,28 @@
+#
+# Dump the contents of the SR table using mysqldump
+#
+
+--let $sr_min = `SELECT MIN(seqno) FROM mysql.wsrep_streaming_log`
+--let $sr_max = `SELECT MAX(seqno) FROM mysql.wsrep_streaming_log`
+
+--let $seqno = $sr_min
+while ($seqno <= $sr_max)
+{
+ --let $sr_fragment_file = $MYSQLTEST_VARDIR/tmp/sr_fragment.log
+ --exec rm -rf $sr_fragment_file
+ --disable_query_log
+ --eval SELECT frag FROM mysql.wsrep_streaming_log WHERE seqno = $seqno INTO DUMPFILE '$sr_fragment_file'
+ --enable_query_log
+
+ --let $sr_binlog_file = $MYSQLTEST_VARDIR/tmp/sr_binlog.log
+ --exec rm -rf $sr_binlog_file
+
+ --exec cp std_data/binlog-header.log $sr_binlog_file
+ --exec cat $sr_fragment_file >> $sr_binlog_file
+
+ --replace_regex /SET TIMESTAMP=[0-9]+/SET TIMESTAMP=<TIMESTAMP>/ /#[0-9]+ +[0-9]+:[0-9]+:[0-9]+/<ISO TIMESTAMP>/ /pseudo_thread_id=[0-9]+/pseudo_thread_id=<PSEUDO_THREAD_ID>/ /thread_id=[0-9]+/thread_id=<QUERY_THREAD_ID>/ /table id [0-9]+/table id <TABLE_ID>/ /mapped to number [0-9]+/mapped to number <TABLE_ID>/ /auto_increment_increment=[0-9]+/auto_increment_increment=<AUTO_INCREMENT_INCREMENT>/ /auto_increment_offset=[0-9]+/auto_increment_offset=<AUTO_INCREMENT_OFFSET>/ /exec_time=[0-9]+/exec_time=<EXEC_TIME>/
+ --exec $MYSQL_BINLOG --skip-gtids $sr_binlog_file --base64-output=decode-rows --start-position=120 | grep -v 'SET @' 2>&1
+
+ --inc $seqno
+}
+
diff --git a/mysql-test/suite/galera/include/galera_load_provider.inc b/mysql-test/suite/galera/include/galera_load_provider.inc
index aeab7e6ea19..0f843597d9c 100644
--- a/mysql-test/suite/galera/include/galera_load_provider.inc
+++ b/mysql-test/suite/galera/include/galera_load_provider.inc
@@ -2,7 +2,75 @@
--disable_query_log
--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
+
+#
+# count occurences of successful node starts in error log
+#
+perl;
+ use strict;
+ my $test_log=$ENV{'LOG_FILE'} or die "LOG_FILE not set";
+ my $test_log_copy=$test_log . '.copy';
+ if (-e $test_log_copy) {
+ unlink $test_log_copy;
+ }
+
+EOF
+--copy_file $LOG_FILE $LOG_FILE.copy
+
+#
+# now join to the cluster
+#
--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig';
+
+--enable_query_log
+
+#
+# Cluster address change above, will launch SST/IST
+# if mysqldump ST has been configured, mysqld will close all
+# client connections, and it will be hard for us to poll for
+# cluster status during SST process, therefore wait_until_connected_again.inc
+# and wait_until_ready.inc may fail in this phase
+# To workaround this, we do first lazy polling here just to see when
+# client connections will be possible, and after that check for node readyness
+#
+--disable_result_log
+--disable_query_log
+
+--error 0,1
+perl;
+ use strict;
+ my $logfile = $ENV{'LOG_FILE'} or die ("no error log file set");
+
+ my $counter = 1000;
+ #my $found = false
+
+ while ($counter > 0) {
+
+ open(FILE, "$logfile") or die("Unable to open $logfile : $!\n");
+ my $new_sync_count = () = grep(/Synchronized with group/g,<FILE>);
+ close(FILE);
+
+ open(FILEN, "$logfile.copy") or die("Unable to open $logfile.copy : $!\n");
+ my $old_sync_count = () = grep(/Synchronized with group/g,<FILEN>);
+ close(FILEN);
+
+ if ($new_sync_count > $old_sync_count ) {
+ exit(0);
+ }
+ $counter--;
+ sleep(5);
+ }
+ exit(1);
+EOF
+if ($errno)
+{
+--echo "SST failed $errno"
+}
+
+--remove_file $LOG_FILE.copy
+
--enable_query_log
+--enable_result_log
+#--eval SET GLOBAL log_error = $log_error_;
--source include/galera_wait_ready.inc
diff --git a/mysql-test/suite/galera/include/galera_sst_restore.inc b/mysql-test/suite/galera/include/galera_sst_restore.inc
index 7c9a08090ad..83d07f086d1 100644
--- a/mysql-test/suite/galera/include/galera_sst_restore.inc
+++ b/mysql-test/suite/galera/include/galera_sst_restore.inc
@@ -20,7 +20,7 @@ CALL mtr.add_suppression("Can't open and lock time zone table");
CALL mtr.add_suppression("Can't open and lock privilege tables");
CALL mtr.add_suppression("Info table is not ready to be used");
CALL mtr.add_suppression("Native table .* has the wrong structure");
-
+CALL mtr.add_suppression("Table \'mysql.gtid_slave_pos\' doesn\'t exist");
--disable_query_log
--eval SET GLOBAL wsrep_sst_method = '$wsrep_sst_method_orig';
--eval SET GLOBAL wsrep_sst_receive_address = '$wsrep_sst_receive_address_orig';
diff --git a/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc b/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc
index c8869746bd1..d6d7552f7b6 100644
--- a/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc
+++ b/mysql-test/suite/galera/include/galera_st_disconnect_slave.inc
@@ -55,6 +55,14 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
--connection node_2
--source suite/galera/include/galera_load_provider.inc
+#
+# client connections were killed by provider load, so have to re-open here
+#
+--disconnect node_2
+--connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2
+--enable_reconnect
+
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
diff --git a/mysql-test/suite/galera/include/galera_unload_provider.inc b/mysql-test/suite/galera/include/galera_unload_provider.inc
index edc7eb31e0e..cd841f51fbc 100644
--- a/mysql-test/suite/galera/include/galera_unload_provider.inc
+++ b/mysql-test/suite/galera/include/galera_unload_provider.inc
@@ -3,5 +3,13 @@
--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
--let $wsrep_provider_orig = `SELECT @@wsrep_provider`
--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+--let $wsrep_error_log_orig = `SELECT @@log_error`
+if(!$wsrep_log_error_orig)
+{
+ # MySQL Server on windows is started with --console and thus
+ # does not know the location of its .err log, use default location
+ let $wsrep_log_error_orig = $MYSQLTEST_VARDIR/log/mysqld.2.err;
+}
+--let LOG_FILE= $wsrep_log_error_orig
SET GLOBAL wsrep_provider = 'none';
diff --git a/mysql-test/suite/galera/r/GAL-382.result b/mysql-test/suite/galera/r/GAL-382.result
index fb7c229bd56..137efe4efba 100644
--- a/mysql-test/suite/galera/r/GAL-382.result
+++ b/mysql-test/suite/galera/r/GAL-382.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
create table t1 (i int, j int, k int, primary key pk(i)) engine=innodb;
insert into t1 values (1, 1, 1), (2, 2, 2), (3, 3, 3);
diff --git a/mysql-test/suite/galera/r/GAL-401.result b/mysql-test/suite/galera/r/GAL-401.result
index 3b55b7589b7..3dfc32ffb8c 100644
--- a/mysql-test/suite/galera/r/GAL-401.result
+++ b/mysql-test/suite/galera/r/GAL-401.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
connection node_2;
SET @@global.wsrep_desync = 1;
diff --git a/mysql-test/suite/galera/r/GAL-480.result b/mysql-test/suite/galera/r/GAL-480.result
index 143f48a69e3..8a4f8edcdd6 100644
--- a/mysql-test/suite/galera/r/GAL-480.result
+++ b/mysql-test/suite/galera/r/GAL-480.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 CHAR(10), f0 integer) ENGINE=InnoDB;
FLUSH TABLE t1 FOR EXPORT;
diff --git a/mysql-test/suite/galera/r/GCF-1081.result b/mysql-test/suite/galera/r/GCF-1081.result
new file mode 100644
index 00000000000..ede512ec6b1
--- /dev/null
+++ b/mysql-test/suite/galera/r/GCF-1081.result
@@ -0,0 +1,47 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 0), (3, 0);
+CREATE PROCEDURE proc_update ()
+BEGIN
+UPDATE t1 SET f2 = 1 where f1 > 0;
+END|
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+connection node_1;
+CALL proc_update ();;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+connection node_1a;
+SET GLOBAL DEBUG = 'd,sync.wsrep_before_BF_victim_unlock';
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+connection node_2;
+INSERT INTO t1 VALUES (2, 2);;
+connection node_1a;
+SET SESSION DEBUG_SYNC = 'now WAIT_FOR sync.wsrep_before_BF_victim_unlock_reached';
+SET GLOBAL DEBUG = '';
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+connection node_2;
+SELECT * FROM t1;
+f1 f2
+1 1
+2 2
+3 1
+connection node_1;
+SELECT * FROM t1;
+f1 f2
+1 1
+2 2
+3 1
+wsrep_local_replays
+1
+DROP PROCEDURE proc_update;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/GCF-939.result b/mysql-test/suite/galera/r/GCF-939.result
new file mode 100644
index 00000000000..24d4eab67e5
--- /dev/null
+++ b/mysql-test/suite/galera/r/GCF-939.result
@@ -0,0 +1,13 @@
+connection node_2;
+connection node_1;
+connection node_1;
+DROP TABLE t1;
+ERROR 42S02: Unknown table 'test.t1'
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+GRA_.log
+GRA_.log
+DROP TABLE t1;
+CALL mtr.add_suppression("Ignoring error 'Unknown table 'test.t1'' on query");
+connection node_2;
+CALL mtr.add_suppression("Error 'Unknown table 'test.t1'' on query");
diff --git a/mysql-test/suite/galera/r/MDEV-15443.result b/mysql-test/suite/galera/r/MDEV-15443.result
index 618e5459878..21332b372e8 100644
--- a/mysql-test/suite/galera/r/MDEV-15443.result
+++ b/mysql-test/suite/galera/r/MDEV-15443.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/MW-252.result b/mysql-test/suite/galera/r/MW-252.result
index 795d3fff670..4d458802614 100644
--- a/mysql-test/suite/galera/r/MW-252.result
+++ b/mysql-test/suite/galera/r/MW-252.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
FLUSH TABLES WITH READ LOCK;
diff --git a/mysql-test/suite/galera/r/MW-258.result b/mysql-test/suite/galera/r/MW-258.result
index 1c2a1744c98..22963557daf 100644
--- a/mysql-test/suite/galera/r/MW-258.result
+++ b/mysql-test/suite/galera/r/MW-258.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER);
LOCK TABLE t1 WRITE;
diff --git a/mysql-test/suite/galera/r/MW-259.result b/mysql-test/suite/galera/r/MW-259.result
index 5256a95c52c..9a0f2ccfa23 100644
--- a/mysql-test/suite/galera/r/MW-259.result
+++ b/mysql-test/suite/galera/r/MW-259.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1;
diff --git a/mysql-test/suite/galera/r/MW-284.result b/mysql-test/suite/galera/r/MW-284.result
index 0f6c0be25fe..11a0a7df387 100644
--- a/mysql-test/suite/galera/r/MW-284.result
+++ b/mysql-test/suite/galera/r/MW-284.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
@@ -24,7 +26,9 @@ RESET SLAVE ALL;
CALL mtr.add_suppression('failed registering on master');
CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
connection node_1;
+set global wsrep_on=OFF;
RESET MASTER;
+set global wsrep_on=ON;
CALL mtr.add_suppression('WSREP: Last Applied Action message in non-primary configuration from member');
connection node_2;
CALL mtr.add_suppression('WSREP: Last Applied Action message in non-primary configuration from member');
diff --git a/mysql-test/suite/galera/r/MW-285.result b/mysql-test/suite/galera/r/MW-285.result
index 8c5a21fcbee..762f22d5d25 100644
--- a/mysql-test/suite/galera/r/MW-285.result
+++ b/mysql-test/suite/galera/r/MW-285.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE parent1 ( id INT PRIMARY KEY, KEY (id) ) ENGINE=InnoDB;
CREATE TABLE parent2 ( id INT PRIMARY KEY, KEY (id) ) ENGINE=InnoDB;
CREATE TABLE child (
diff --git a/mysql-test/suite/galera/r/MW-286.result b/mysql-test/suite/galera/r/MW-286.result
index f3bef6f7516..b3accb1cd9b 100644
--- a/mysql-test/suite/galera/r/MW-286.result
+++ b/mysql-test/suite/galera/r/MW-286.result
@@ -1,15 +1,24 @@
+connection node_2;
+connection node_1;
connection node_1;
-CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
-INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
-INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
-INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;;
+INSERT INTO t1 (f1) VALUES (1), (2), (3);
connection node_2;
SET GLOBAL wsrep_desync = TRUE;
SET wsrep_on = FALSE;
-ALTER TABLE t1 ADD PRIMARY KEY (f1);
+SET SESSION debug_sync = "alter_table_inplace_after_lock_upgrade SIGNAL mdl_locked WAIT_FOR mdl_continue";
+ALTER TABLE t1 ADD PRIMARY KEY (f1);;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2a;
+SET SESSION debug_sync = "now WAIT_FOR mdl_locked";
+connection node_1;
+INSERT INTO t1(f1) VALUES (11);
+connection node_2a;
+SET debug_sync = "now SIGNAL mdl_continue";
+SET debug_sync='RESET';
+connection node_2;
+ERROR 70100: Query execution was interrupted
SET wsrep_on = TRUE;
SET GLOBAL wsrep_desync = FALSE;
connection node_1;
DROP TABLE t1;
-DROP TABLE ten;
diff --git a/mysql-test/suite/galera/r/MW-292.result b/mysql-test/suite/galera/r/MW-292.result
index 5b9214ace2a..81e5a316b63 100644
--- a/mysql-test/suite/galera/r/MW-292.result
+++ b/mysql-test/suite/galera/r/MW-292.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE rand_table (f1 FLOAT);
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
INSERT INTO t1 VALUES (1, 'a');
@@ -10,19 +12,28 @@ SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
f1 f2
2 a
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
-SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
-connection node_1;
-COMMIT;;
-connection node_1a;
-SET SESSION wsrep_sync_wait = 0;
-SET SESSION wsrep_on = 0;
-SET SESSION wsrep_on = 1;
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
connection node_1;
SELECT TIMEDIFF(SYSDATE(), NOW()) < 2;
TIMEDIFF(SYSDATE(), NOW()) < 2
diff --git a/mysql-test/suite/galera/r/MW-309.result b/mysql-test/suite/galera/r/MW-309.result
index 3dd49a041ee..0169b56e3e1 100644
--- a/mysql-test/suite/galera/r/MW-309.result
+++ b/mysql-test/suite/galera/r/MW-309.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
INSERT INTO t1 SELECT * FROM t1;
diff --git a/mysql-test/suite/galera/r/MW-313.result b/mysql-test/suite/galera/r/MW-313.result
index dc605ffc370..909caf77f1d 100644
--- a/mysql-test/suite/galera/r/MW-313.result
+++ b/mysql-test/suite/galera/r/MW-313.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
INSERT INTO t1 SELECT * FROM t1;
diff --git a/mysql-test/suite/galera/r/MW-328A.result b/mysql-test/suite/galera/r/MW-328A.result
index db0301b6bf2..f4bb018b442 100644
--- a/mysql-test/suite/galera/r/MW-328A.result
+++ b/mysql-test/suite/galera/r/MW-328A.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES (1);
CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
@@ -14,10 +16,6 @@ connection node_1X;
CALL proc_update();;
connection node_2;
SET SESSION wsrep_retry_autocommit = 0;
-have_successes
-1
-have_deadlocks
-1
connection node_1;
connection node_1X;
Got one of the listed errors
@@ -25,3 +23,22 @@ connection node_1;
DROP PROCEDURE proc_update;
DROP TABLE t1, t2;
CALL mtr.add_suppression("conflict state 3 after post commit");
+connection node_1;
+CREATE TABLE t1 (i int primary key, j int) engine=innodb;
+INSERT INTO t1 values (1,0);
+BEGIN;
+UPDATE t1 SET j=1 WHERE i=1;
+connection node_2;
+UPDATE t1 SET j=2 WHERE i=1;
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+i j
+1 2
+connection node_2;
+SELECT * FROM t1;
+i j
+1 2
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/MW-328B.result b/mysql-test/suite/galera/r/MW-328B.result
index e898e315ca8..d29c3a50f3d 100644
--- a/mysql-test/suite/galera/r/MW-328B.result
+++ b/mysql-test/suite/galera/r/MW-328B.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES (1);
CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/MW-328C.result b/mysql-test/suite/galera/r/MW-328C.result
index d8e164e7b4a..748f9420764 100644
--- a/mysql-test/suite/galera/r/MW-328C.result
+++ b/mysql-test/suite/galera/r/MW-328C.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES (1);
CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/MW-328D.result b/mysql-test/suite/galera/r/MW-328D.result
index 6562136ec27..43e1cefe08f 100644
--- a/mysql-test/suite/galera/r/MW-328D.result
+++ b/mysql-test/suite/galera/r/MW-328D.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (i INT) ENGINE = InnoDB;
INSERT INTO t1 (i) VALUES(1);
CREATE TABLE t2 (i INT) ENGINE = InnoDB;
diff --git a/mysql-test/suite/galera/r/MW-328E.result b/mysql-test/suite/galera/r/MW-328E.result
index 89654ec066a..729fdea1a63 100644
--- a/mysql-test/suite/galera/r/MW-328E.result
+++ b/mysql-test/suite/galera/r/MW-328E.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
create table t1 (i int primary key, j int) engine=innodb;
create table t2 (i int primary key, j int) engine=innodb;
insert into t1 values (1,0);
diff --git a/mysql-test/suite/galera/r/MW-329.result b/mysql-test/suite/galera/r/MW-329.result
index a3cb7277a9c..334ff9f80fb 100644
--- a/mysql-test/suite/galera/r/MW-329.result
+++ b/mysql-test/suite/galera/r/MW-329.result
@@ -1,10 +1,6 @@
CALL mtr.add_suppression("WSREP: .*conflict state . after post commit .*");
CREATE TABLE t1 (f1 INTEGER, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
INSERT INTO t1 (f1) VALUES (1),(65535);
-FLUSH STATUS;
-SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
-VARIABLE_VALUE = 0
-1
CREATE PROCEDURE proc_insert ()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
@@ -16,10 +12,7 @@ END|
connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1b;
CALL proc_insert();;
-connection node_2;
-CALL mtr.add_suppression("WSREP: Failed to report last committed .*");
-SELECT VARIABLE_VALUE > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
-VARIABLE_VALUE > 0
+wsrep_local_replays
1
connection node_1;
connection node_1b;
diff --git a/mysql-test/suite/galera/r/MW-336.result b/mysql-test/suite/galera/r/MW-336.result
index e35044d872b..5961d1f3e24 100644
--- a/mysql-test/suite/galera/r/MW-336.result
+++ b/mysql-test/suite/galera/r/MW-336.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
INSERT INTO t1 values(0);
connection node_1;
diff --git a/mysql-test/suite/galera/r/MW-357.result b/mysql-test/suite/galera/r/MW-357.result
index 35855e21233..dc391be4dd3 100644
--- a/mysql-test/suite/galera/r/MW-357.result
+++ b/mysql-test/suite/galera/r/MW-357.result
@@ -1,4 +1,6 @@
connection node_2;
+connection node_1;
+connection node_2;
SET GLOBAL wsrep_slave_threads = 0;
Warnings:
Warning 1292 Truncated incorrect wsrep_slave_threads value: '0'
diff --git a/mysql-test/suite/galera/r/MW-360.result b/mysql-test/suite/galera/r/MW-360.result
new file mode 100644
index 00000000000..f20d5be2135
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-360.result
@@ -0,0 +1,41 @@
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+DROP TABLE t1;
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+DROP TABLE t1, t2;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+DROP TABLE t1, t2;
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+CREATE TEMPORARY TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (3);
+DROP TABLE t1, t2, t3;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (3);
+DROP TABLE t1, t2, t3;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (2);
+DROP TABLE t1;
+DROP TABLE t1;
+gtid_executed_equal
+1
diff --git a/mysql-test/suite/galera/r/MW-369.result b/mysql-test/suite/galera/r/MW-369.result
index 516904d1b2a..9f0a77edbbc 100644
--- a/mysql-test/suite/galera/r/MW-369.result
+++ b/mysql-test/suite/galera/r/MW-369.result
@@ -1,25 +1,36 @@
+connection node_2;
+connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
DELETE FROM p WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
INSERT INTO c VALUES (1, 1);
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
SELECT * FROM p;
f1 f2
1 0
@@ -29,6 +40,7 @@ f1 p_id
1 1
DROP TABLE c;
DROP TABLE p;
+connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
f2 INTEGER,
@@ -36,22 +48,30 @@ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1, 0);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
UPDATE p SET f2 = 1 WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
UPDATE c SET f2 = 1 WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
+connection node_2;
SELECT * FROM p;
f1 f2
1 1
@@ -61,28 +81,37 @@ f1 p_id f2
1 1 1
DROP TABLE c;
DROP TABLE p;
+connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1)) ;
INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
UPDATE p SET f2 = 1 WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
DELETE FROM c WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
+connection node_2;
SELECT * FROM p;
f1 f2
1 1
@@ -95,23 +124,31 @@ CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER UNIQUE KEY) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f2)) ;
INSERT INTO p VALUES (1, 0);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
UPDATE p SET f2 = 1 WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
INSERT INTO c VALUES (1, 0);;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
SELECT * FROM p;
f1 f2
1 0
@@ -127,23 +164,31 @@ ON DELETE CASCADE) ;
INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1, 0);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
DELETE FROM p WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
UPDATE c SET f2 = 1 WHERE f1 = 1;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
SELECT * FROM p;
f1 f2
1 0
@@ -153,3 +198,87 @@ f1 p_id f2
1 1 1
DROP TABLE c;
DROP TABLE p;
+#
+# Start of 10.4 tests
+#
+connection node_1;
+CREATE TABLE pf (f1 INTEGER PRIMARY KEY) ENGINE=INNODB;
+CREATE TABLE cf (
+f1 INTEGER PRIMARY KEY,
+p_id INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES pf (f1)
+);
+INSERT INTO pf VALUES (1);
+connection node_1;
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+INSERT INTO cf (f1, p_id) VALUES (10, 1);
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+INSERT INTO cf (f1, p_id) VALUES (20, 1);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
+connection node_2;
+SELECT * FROM pf;
+f1
+1
+SELECT * FROM cf;
+f1 p_id
+10 1
+20 1
+DROP TABLE cf;
+DROP TABLE pf;
+connection node_1;
+CREATE TABLE pg (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE cg (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES pg (f1)) ;
+INSERT INTO pg VALUES (1, 0);
+INSERT INTO pg VALUES (2, 0);
+connection node_1;
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+UPDATE pg SET f2 = 1 WHERE f1 = 1;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+INSERT INTO cg VALUES (1, 1, 0);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
+connection node_2;
+SELECT * FROM pg;
+f1 f2
+1 1
+2 0
+SELECT * FROM cg;
+f1 p_id f2
+1 1 0
+DROP TABLE cg;
+DROP TABLE pg;
diff --git a/mysql-test/suite/galera/r/MW-388.result b/mysql-test/suite/galera/r/MW-388.result
index a2cf02712bb..3e532b3e12d 100644
--- a/mysql-test/suite/galera/r/MW-388.result
+++ b/mysql-test/suite/galera/r/MW-388.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB;
CREATE PROCEDURE insert_proc ()
@@ -18,7 +20,7 @@ connection node_1a;
SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
connection node_1;
SET SESSION wsrep_sync_wait = 0;
-SET SESSION DEBUG_SYNC = 'wsrep_after_replication SIGNAL wsrep_after_replication_reached WAIT_FOR wsrep_after_replication_continue';
+SET SESSION DEBUG_SYNC = 'wsrep_after_certification SIGNAL wsrep_after_certification_reached WAIT_FOR wsrep_after_certification_continue';
CALL insert_proc ();;
connection node_1a;
SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_replication_reached";
@@ -29,7 +31,7 @@ connection node_2;
connection node_1;
SELECT @errno = 1213;
@errno = 1213
-0
+1
SELECT * FROM t1;
f1 f2
1 node 2
diff --git a/mysql-test/suite/galera/r/MW-402.result b/mysql-test/suite/galera/r/MW-402.result
index 9be98d629fb..f692c90d611 100644
--- a/mysql-test/suite/galera/r/MW-402.result
+++ b/mysql-test/suite/galera/r/MW-402.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
@@ -20,14 +22,14 @@ connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
connection node_1;
COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
@@ -60,14 +62,14 @@ connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
connection node_1;
COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
@@ -102,14 +104,14 @@ connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
connection node_1;
COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
@@ -135,14 +137,14 @@ connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
connection node_1;
COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
@@ -159,8 +161,10 @@ DROP TABLE p;
connection node_1;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
-CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER, f2 INTEGER,
-CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1) ON DELETE CASCADE,
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ON DELETE CASCADE,
CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1));
INSERT INTO p1 VALUES (1, 0);
INSERT INTO p2 VALUES (1, 0);
@@ -179,14 +183,14 @@ connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
connection node_1;
COMMIT;
connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
connection node_1;
connection node_2;
@@ -197,4 +201,52 @@ f1 f2
1 2
SELECT * FROM c;
f1 p1_id p2_id f2
+DROP TABLE c;
+DROP TABLE p1;
+DROP TABLE p2;
+connection node_1;
+CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+f2 INTEGER,
+CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ON DELETE CASCADE,
+CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
+ON DELETE CASCADE);
+INSERT INTO p1 VALUES (1, 0);
+INSERT INTO p2 VALUES (1, 0);
+INSERT INTO c VALUES (1, 1, 1, 0);
+connection node_1a;
+connection node_1;
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+DELETE FROM p2 WHERE f1=1;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+DELETE FROM p1 WHERE f1=1;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
+SELECT * FROM p1;
+f1 f2
+SELECT * FROM p2;
+f1 f2
+1 0
+SELECT * FROM c;
+f1 p1_id p2_id f2
DROP TABLE c,p1,p2;
diff --git a/mysql-test/suite/galera/r/MW-416.result b/mysql-test/suite/galera/r/MW-416.result
index 05399b213a8..537e648df6b 100644
--- a/mysql-test/suite/galera/r/MW-416.result
+++ b/mysql-test/suite/galera/r/MW-416.result
@@ -109,6 +109,5 @@ mtr
mysql
performance_schema
test
-SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
-Variable_name Value
-wsrep_replicated 3
+wsrep_replicated_after_diff
+1
diff --git a/mysql-test/suite/galera/r/MW-86-wait1.result b/mysql-test/suite/galera/r/MW-86-wait1.result
index 00010eaedcb..36cbfadf302 100644
--- a/mysql-test/suite/galera/r/MW-86-wait1.result
+++ b/mysql-test/suite/galera/r/MW-86-wait1.result
@@ -1,11 +1,13 @@
connection node_2;
+connection node_1;
+SET @orig_debug=@@debug;
+connection node_2;
SELECT @@debug_sync;
@@debug_sync
ON - current signal: ''
+set debug_sync='RESET';
SET SESSION wsrep_sync_wait = 1;
-SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb";
connection node_1;
CREATE TABLE t_wait1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t_wait1 VALUES (1);
@@ -36,16 +38,11 @@ SHOW TABLES;
SHOW TRIGGERS;
SHOW GLOBAL VARIABLES LIKE 'foo_bar';
SHOW WARNINGS;
-SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET GLOBAL debug_dbug = @orig_debug;
SET SESSION debug_sync = "now SIGNAL signal.wsrep_apply_cb";
+SET debug_sync='RESET';
SET SESSION wsrep_sync_wait = default;
DROP TABLE t_wait1;
-SET GLOBAL debug = NULL;
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
-SET debug_sync='RESET';
SELECT @@debug_sync;
@@debug_sync
ON - current signal: ''
diff --git a/mysql-test/suite/galera/r/MW-86-wait8.result b/mysql-test/suite/galera/r/MW-86-wait8.result
index 47e0ebc1342..6ac2c5f5e1f 100644
--- a/mysql-test/suite/galera/r/MW-86-wait8.result
+++ b/mysql-test/suite/galera/r/MW-86-wait8.result
@@ -1,11 +1,12 @@
connection node_2;
+connection node_1;
+SET @orig_debug=@@debug;
+connection node_2;
SELECT @@debug_sync;
@@debug_sync
ON - current signal: ''
SET SESSION wsrep_sync_wait = 8;
-SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb";
connection node_1;
CREATE TABLE t_wait8 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t_wait8 VALUES (1);
@@ -38,16 +39,11 @@ SHOW TABLES;
SHOW TRIGGERS;
SHOW GLOBAL VARIABLES LIKE 'foo_bar';
SHOW WARNINGS;
-SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET GLOBAL debug_dbug = @orig_debug;
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+SET debug_sync='RESET';
SET SESSION wsrep_sync_wait = default;
DROP TABLE t_wait8;
-SET GLOBAL debug = NULL;
-Warnings:
-Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
-SET debug_sync='RESET';
SELECT @@debug_sync;
@@debug_sync
ON - current signal: ''
diff --git a/mysql-test/suite/galera/r/MW-86.result b/mysql-test/suite/galera/r/MW-86.result
new file mode 100644
index 00000000000..bca9be93191
--- /dev/null
+++ b/mysql-test/suite/galera/r/MW-86.result
@@ -0,0 +1,78 @@
+connection node_2;
+connection node_1;
+connection node_2;
+SET SESSION wsrep_sync_wait = 1;
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+connection node_1;
+CREATE DATABASE db1;
+CREATE TABLE bar (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO bar VALUES (1);
+connection node_2;
+SHOW BINARY LOGS;
+SHOW BINLOG EVENTS;
+SHOW COLUMNS FROM t1;
+SHOW CREATE DATABASE db1;
+SHOW CREATE EVENT e1;
+SHOW CREATE FUNCTION f1;
+SHOW CREATE PROCEDURE p1;
+SHOW CREATE TABLE t1;
+SHOW CREATE TRIGGER tr1;
+SHOW CREATE VIEW v1;
+SHOW DATABASES;
+SHOW ENGINE InnoDB STATUS;
+SHOW FUNCTION CODE f1;
+SHOW FUNCTION STATUS;
+SHOW GRANTS FOR 'root'@'localhost';
+SHOW INDEX FROM t1;
+SHOW OPEN TABLES;
+SHOW PROCEDURE CODE p1;
+SHOW PROCEDURE STATUS;
+SHOW PRIVILEGES;
+SHOW STATUS LIKE 'wsrep_cluster_size';
+SHOW TABLE STATUS;
+SHOW TABLES;
+SHOW TRIGGERS;
+SHOW GLOBAL VARIABLES LIKE 'foo_bar';
+SHOW WARNINGS;
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+SET SESSION wsrep_sync_wait = 8;
+DROP DATABASE db1;
+connection node_2;
+SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT0.1S";
+SET SESSION wsrep_sync_wait = 8;
+SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
+connection node_1;
+CREATE TABLE q (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO q VALUES (1);
+connection node_2;
+SHOW BINARY LOGS;
+SHOW BINLOG EVENTS;
+SHOW COLUMNS FROM t1;
+SHOW CREATE DATABASE db1;
+SHOW CREATE EVENT e1;
+SHOW CREATE FUNCTION f1;
+SHOW CREATE PROCEDURE p1;
+SHOW CREATE TABLE t1;
+SHOW CREATE TRIGGER tr1;
+SHOW CREATE VIEW v1;
+SHOW DATABASES;
+SHOW ENGINE InnoDB STATUS;
+SHOW FUNCTION CODE f1;
+SHOW FUNCTION STATUS;
+SHOW GRANTS FOR 'root'@'localhost';
+SHOW INDEX FROM t1;
+SHOW OPEN TABLES;
+SHOW PROCEDURE CODE p1;
+SHOW PROCEDURE STATUS;
+SHOW PRIVILEGES;
+SHOW STATUS LIKE 'wsrep_cluster_size';
+SHOW TABLE STATUS;
+SHOW TABLES;
+SHOW TRIGGERS;
+SHOW GLOBAL VARIABLES LIKE 'foo_bar';
+SHOW WARNINGS;
+SET GLOBAL DEBUG = "";
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
diff --git a/mysql-test/suite/galera/r/basic.result b/mysql-test/suite/galera/r/basic.result
index e85c805253f..10f180e7a94 100644
--- a/mysql-test/suite/galera/r/basic.result
+++ b/mysql-test/suite/galera/r/basic.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
USE test;
CREATE TABLE t1(c1 INT PRIMARY KEY) ENGINE=INNODB;
INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
diff --git a/mysql-test/suite/galera/r/binlog_checksum.result b/mysql-test/suite/galera/r/binlog_checksum.result
index e86f3892ac7..4106354eb7d 100644
--- a/mysql-test/suite/galera/r/binlog_checksum.result
+++ b/mysql-test/suite/galera/r/binlog_checksum.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
# On node_1
connection node_1;
SET @binlog_checksum_saved= @@GLOBAL.BINLOG_CHECKSUM;
diff --git a/mysql-test/suite/galera/r/create.result b/mysql-test/suite/galera/r/create.result
index a445b32e8bf..6ad94dd3d43 100644
--- a/mysql-test/suite/galera/r/create.result
+++ b/mysql-test/suite/galera/r/create.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-6924 : Server crashed on CREATE TABLE ... SELECT
#
diff --git a/mysql-test/suite/galera/r/enforce_storage_engine.result b/mysql-test/suite/galera/r/enforce_storage_engine.result
index 746aa22bf20..1a453241427 100644
--- a/mysql-test/suite/galera/r/enforce_storage_engine.result
+++ b/mysql-test/suite/galera/r/enforce_storage_engine.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-8831 : enforce_storage_engine doesn't block table creation on
# other nodes (galera cluster)
diff --git a/mysql-test/suite/galera/r/enforce_storage_engine2.result b/mysql-test/suite/galera/r/enforce_storage_engine2.result
index 128994ed221..8b174139eae 100644
--- a/mysql-test/suite/galera/r/enforce_storage_engine2.result
+++ b/mysql-test/suite/galera/r/enforce_storage_engine2.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-9312: storage engine not enforced during galera cluster
# replication
diff --git a/mysql-test/suite/galera/r/ev51914.result b/mysql-test/suite/galera/r/ev51914.result
index 3f3d67d01ef..b9d8a82bfa0 100644
--- a/mysql-test/suite/galera/r/ev51914.result
+++ b/mysql-test/suite/galera/r/ev51914.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SAVEPOINT in a stored function should be forbidden
CREATE FUNCTION f1 () RETURNS INT BEGIN
diff --git a/mysql-test/suite/galera/r/fk.result b/mysql-test/suite/galera/r/fk.result
index ab8e1c8f680..17fc99a904e 100644
--- a/mysql-test/suite/galera/r/fk.result
+++ b/mysql-test/suite/galera/r/fk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
USE test;
# On node_1
diff --git a/mysql-test/suite/galera/r/galera#414.result b/mysql-test/suite/galera/r/galera#414.result
index 34dcb6242d3..2c1dccfd131 100644
--- a/mysql-test/suite/galera/r/galera#414.result
+++ b/mysql-test/suite/galera/r/galera#414.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera#500.result b/mysql-test/suite/galera/r/galera#500.result
index 6a07d0359a4..a5ab0b19718 100644
--- a/mysql-test/suite/galera/r/galera#500.result
+++ b/mysql-test/suite/galera/r/galera#500.result
@@ -1,10 +1,18 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options="gmcast.isolate=2";
+connection node_1;
SET SESSION wsrep_sync_wait = 0;
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
wsrep_cluster_status non-Primary
SET SESSION wsrep_sync_wait = default;
SET GLOBAL wsrep_provider_options="pc.bootstrap=1";
+connection node_2;
SET SESSION wsrep_on=0;
+connection node_2;
CALL mtr.add_suppression("WSREP: exception from gcomm, backend must be restarted: Gcomm backend termination was requested by setting gmcast.isolate=2.");
diff --git a/mysql-test/suite/galera/r/galera#505.result b/mysql-test/suite/galera/r/galera#505.result
index 8d3e3ec072a..bc7eb3b9ed4 100644
--- a/mysql-test/suite/galera/r/galera#505.result
+++ b/mysql-test/suite/galera/r/galera#505.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET SESSION wsrep_sync_wait=0;
SET SESSION wsrep_sync_wait=DEFAULT;
diff --git a/mysql-test/suite/galera/r/galera_FK_duplicate_client_insert.result b/mysql-test/suite/galera/r/galera_FK_duplicate_client_insert.result
index 3eb638ca49a..5ae577a6323 100644
--- a/mysql-test/suite/galera/r/galera_FK_duplicate_client_insert.result
+++ b/mysql-test/suite/galera/r/galera_FK_duplicate_client_insert.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE user(id int primary key, j int) ENGINE=InnoDB;
CREATE TABLE user_session(id int primary key, fk1 int, fk2 int) ENGINE=InnoDB;
alter table user_session add foreign key (fk1) references user(id);
diff --git a/mysql-test/suite/galera/r/galera_admin.result b/mysql-test/suite/galera/r/galera_admin.result
index e52bf8ccca3..01e2aac16b2 100644
--- a/mysql-test/suite/galera/r/galera_admin.result
+++ b/mysql-test/suite/galera/r/galera_admin.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
DROP TABLE IF EXISTS t1, t2;
DROP TABLE IF EXISTS x1, x2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_alter_engine_innodb.result b/mysql-test/suite/galera/r/galera_alter_engine_innodb.result
index ff6ab792c0e..dfa30441f85 100644
--- a/mysql-test/suite/galera/r/galera_alter_engine_innodb.result
+++ b/mysql-test/suite/galera/r/galera_alter_engine_innodb.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_alter_engine_myisam.result b/mysql-test/suite/galera/r/galera_alter_engine_myisam.result
index 389383858ac..b3a9bdd30df 100644
--- a/mysql-test/suite/galera/r/galera_alter_engine_myisam.result
+++ b/mysql-test/suite/galera/r/galera_alter_engine_myisam.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET GLOBAL wsrep_replicate_myisam = TRUE;
CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1);
diff --git a/mysql-test/suite/galera/r/galera_alter_table_force.result b/mysql-test/suite/galera/r/galera_alter_table_force.result
index d0a2f81b631..271796422cd 100644
--- a/mysql-test/suite/galera/r/galera_alter_table_force.result
+++ b/mysql-test/suite/galera/r/galera_alter_table_force.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
ALTER TABLE t1 FORCE;
diff --git a/mysql-test/suite/galera/r/galera_applier_ftwrl_table.result b/mysql-test/suite/galera/r/galera_applier_ftwrl_table.result
index a6607906661..11fda5d8aab 100644
--- a/mysql-test/suite/galera/r/galera_applier_ftwrl_table.result
+++ b/mysql-test/suite/galera/r/galera_applier_ftwrl_table.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET SESSION wsrep_sync_wait = 0;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result b/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result
index 9711100d155..a5aeb6eb366 100644
--- a/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result
+++ b/mysql-test/suite/galera/r/galera_applier_ftwrl_table_alter.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET SESSION wsrep_sync_wait = 0;
SET SESSION lock_wait_timeout = 60;
diff --git a/mysql-test/suite/galera/r/galera_as_master.result b/mysql-test/suite/galera/r/galera_as_master.result
index 2a7262359fa..4aca328be56 100644
--- a/mysql-test/suite/galera/r/galera_as_master.result
+++ b/mysql-test/suite/galera/r/galera_as_master.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
START SLAVE;
connection node_1;
@@ -54,4 +56,6 @@ STOP SLAVE;
RESET SLAVE ALL;
CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
connection node_1;
+set global wsrep_on=OFF;
RESET MASTER;
+set global wsrep_on=ON;
diff --git a/mysql-test/suite/galera/r/galera_as_master_gtid.result b/mysql-test/suite/galera/r/galera_as_master_gtid.result
index 8dfe462d495..4f5c38b607a 100644
--- a/mysql-test/suite/galera/r/galera_as_master_gtid.result
+++ b/mysql-test/suite/galera/r/galera_as_master_gtid.result
@@ -5,55 +5,19 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
uuids_do_not_match
1
-SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 120;
-Log_name Pos Event_type Server_id End_log_pos Info
-mysqld-bin.000002 120 Previous_gtids 1 151
-mysqld-bin.000002 151 Gtid 1 199 SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
-mysqld-bin.000002 199 Query 1 327 use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
-mysqld-bin.000002 327 Gtid 1 375 SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
-mysqld-bin.000002 375 Query 1 452 BEGIN
-mysqld-bin.000002 452 Table_map 1 497 table_id: # (test.t1)
-mysqld-bin.000002 497 Write_rows 1 537 table_id: # flags: STMT_END_F
-mysqld-bin.000002 537 Xid 1 568 COMMIT /* xid=# */
INSERT INTO t1 VALUES(2);
uuids_do_not_match
1
uuids_match
1
-SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 120;
-Log_name Pos Event_type Server_id End_log_pos Info
-mysqld-bin.000003 120 Previous_gtids 2 151
-mysqld-bin.000003 151 Gtid 1 199 SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
-mysqld-bin.000003 199 Query 1 327 use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
-mysqld-bin.000003 327 Gtid 1 375 SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
-mysqld-bin.000003 375 Query 1 443 BEGIN
-mysqld-bin.000003 443 Table_map 1 488 table_id: # (test.t1)
-mysqld-bin.000003 488 Write_rows 1 528 table_id: # flags: STMT_END_F
-mysqld-bin.000003 528 Xid 1 559 COMMIT /* xid=# */
-mysqld-bin.000003 559 Gtid 2 607 SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
-mysqld-bin.000003 607 Query 2 684 BEGIN
-mysqld-bin.000003 684 Table_map 2 729 table_id: # (test.t1)
-mysqld-bin.000003 729 Write_rows 2 769 table_id: # flags: STMT_END_F
-mysqld-bin.000003 769 Xid 2 800 COMMIT /* xid=# */
uuids_do_not_match
1
uuids_match
1
-SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
-Log_name Pos Event_type Server_id End_log_pos Info
-mysqld-bin.000001 120 Previous_gtids 3 151
-mysqld-bin.000001 151 Gtid 1 199 SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
-mysqld-bin.000001 199 Query 1 327 use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
-mysqld-bin.000001 327 Gtid 1 375 SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
-mysqld-bin.000001 375 Query 1 443 BEGIN
-mysqld-bin.000001 443 Table_map 1 488 table_id: # (test.t1)
-mysqld-bin.000001 488 Write_rows 1 528 table_id: # flags: STMT_END_F
-mysqld-bin.000001 528 Xid 1 559 COMMIT /* xid=# */
-mysqld-bin.000001 559 Gtid 2 607 SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
-mysqld-bin.000001 607 Query 2 675 BEGIN
-mysqld-bin.000001 675 Table_map 2 720 table_id: # (test.t1)
-mysqld-bin.000001 720 Write_rows 2 760 table_id: # flags: STMT_END_F
-mysqld-bin.000001 760 Xid 2 791 COMMIT /* xid=# */
DROP TABLE t1;
+gtid_executed_equal
+1
+gtid_executed_equal
+1
STOP SLAVE;
RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/r/galera_as_master_large.result b/mysql-test/suite/galera/r/galera_as_master_large.result
index dad74211af9..826d2f32057 100644
--- a/mysql-test/suite/galera/r/galera_as_master_large.result
+++ b/mysql-test/suite/galera/r/galera_as_master_large.result
@@ -2,6 +2,8 @@
# MDEV-9044 : Getting binlog corruption on my Galera cluster (10.1.8)
# making it impossible to async slave.
#
+connection node_2;
+connection node_1;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
START SLAVE;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_as_slave.result b/mysql-test/suite/galera/r/galera_as_slave.result
index 9ccb5106234..391ceecd509 100644
--- a/mysql-test/suite/galera/r/galera_as_slave.result
+++ b/mysql-test/suite/galera/r/galera_as_slave.result
@@ -1,12 +1,14 @@
-connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2;
-START SLAVE;
connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_2;
+START SLAVE;
+connection node_3;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
connection node_2;
INSERT INTO t1 VALUES (2);
-connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
SELECT COUNT(*) = 2 FROM t1;
COUNT(*) = 2
1
@@ -15,10 +17,10 @@ connection node_2;
SELECT COUNT(*) = 3 FROM t1;
COUNT(*) = 3
1
-connection node_1;
+connection node_3;
DROP TABLE t1;
connection node_2;
STOP SLAVE;
RESET SLAVE ALL;
-connection node_1;
+connection node_3;
RESET MASTER;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_autoinc.result b/mysql-test/suite/galera/r/galera_as_slave_autoinc.result
index 60f3216aa9c..6ac51f44950 100644
--- a/mysql-test/suite/galera/r/galera_as_slave_autoinc.result
+++ b/mysql-test/suite/galera/r/galera_as_slave_autoinc.result
@@ -1,7 +1,9 @@
-connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2;
-START SLAVE;
connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_2;
+START SLAVE;
+connection node_3;
SET SESSION binlog_format='STATEMENT';
CREATE TABLE t1 (
i int(11) NOT NULL AUTO_INCREMENT,
@@ -60,7 +62,7 @@ binlog_format ROW
show variables like 'auto_increment_increment';
Variable_name Value
auto_increment_increment 2
-connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
select * from t1;
i c
1 dummy_text
@@ -79,10 +81,10 @@ binlog_format ROW
show variables like 'auto_increment_increment';
Variable_name Value
auto_increment_increment 2
-connection node_1;
+connection node_3;
DROP TABLE t1;
connection node_2;
STOP SLAVE;
RESET SLAVE ALL;
-connection node_1;
+connection node_3;
RESET MASTER;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_gtid.result b/mysql-test/suite/galera/r/galera_as_slave_gtid.result
index 0ef9d208bf4..180b72bf729 100644
--- a/mysql-test/suite/galera/r/galera_as_slave_gtid.result
+++ b/mysql-test/suite/galera/r/galera_as_slave_gtid.result
@@ -1,7 +1,9 @@
-connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2;
-START SLAVE;
connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_2;
+START SLAVE;
+connection node_3;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
SELECT LENGTH(@@global.gtid_binlog_state) > 1;
@@ -10,15 +12,15 @@ LENGTH(@@global.gtid_binlog_state) > 1
connection node_2;
gtid_binlog_state_equal
1
-connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
1
gtid_binlog_state_equal
1
-connection node_1;
-DROP TABLE t1;
connection node_3;
+DROP TABLE t1;
+connection node_1;
connection node_2;
STOP SLAVE;
RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result b/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result
new file mode 100644
index 00000000000..9589d319991
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result
@@ -0,0 +1,159 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+connection node_3;
+RESET MASTER;
+connection node_2;
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+START SLAVE;
+connection node_3;
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+UPDATE test2.t1 SET test2.t1.f2 = 'cde';
+UPDATE test1.t1, test2.t1 SET test1.t1.f2 = 'klm', test2.t1.f2 = 'xyz';
+DELETE test1.t1, test2.t1 FROM test1.t1 INNER JOIN test2.t1 WHERE test1.t1.f1 = test2.t1.f1 AND test1.t1.f1 = 3;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO test2.t1 (f1) VALUES (999);
+INSERT INTO test2.t1 (f1) VALUES (9999);
+COMMIT;
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (111);
+INSERT INTO test1.t1 (f1) VALUES (222);
+COMMIT;
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (333);
+INSERT INTO test2.t1 (f1) VALUES (99999);
+COMMIT;
+connection node_2;
+SHOW BINLOG EVENTS IN 'master-bin.000001' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 256 Gtid_list 2 285 []
+master-bin.000001 285 Binlog_checkpoint 2 329 master-bin.000001
+master-bin.000001 329 Gtid 3 371 GTID 0-3-1
+master-bin.000001 371 Query 3 458 CREATE SCHEMA test1
+master-bin.000001 458 Gtid 3 500 GTID 0-3-3
+master-bin.000001 500 Query 3 647 use `test1`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB
+master-bin.000001 647 Gtid 3 689 BEGIN GTID 0-3-5
+master-bin.000001 689 Annotate_rows 3 748 INSERT INTO test1.t1 (f1) VALUES (1)
+master-bin.000001 748 Table_map 3 797 table_id: ### (test1.t1)
+master-bin.000001 797 Write_rows_v1 3 839 table_id: ### flags: STMT_END_F
+master-bin.000001 839 Xid 3 870 COMMIT /* xid=### */
+master-bin.000001 870 Gtid 3 912 BEGIN GTID 0-3-7
+master-bin.000001 912 Annotate_rows 3 971 INSERT INTO test1.t1 (f1) VALUES (2)
+master-bin.000001 971 Table_map 3 1020 table_id: ### (test1.t1)
+master-bin.000001 1020 Write_rows_v1 3 1062 table_id: ### flags: STMT_END_F
+master-bin.000001 1062 Xid 3 1093 COMMIT /* xid=### */
+master-bin.000001 1093 Gtid 3 1135 BEGIN GTID 0-3-9
+master-bin.000001 1135 Annotate_rows 3 1194 INSERT INTO test1.t1 (f1) VALUES (3)
+master-bin.000001 1194 Table_map 3 1243 table_id: ### (test1.t1)
+master-bin.000001 1243 Write_rows_v1 3 1285 table_id: ### flags: STMT_END_F
+master-bin.000001 1285 Xid 3 1316 COMMIT /* xid=### */
+master-bin.000001 1316 Gtid 3 1358 BEGIN GTID 0-3-12
+master-bin.000001 1358 Annotate_rows 3 1451 UPDATE test1.t1, test2.t1 SET test1.t1.f2 = 'klm', test2.t1.f2 = 'xyz'
+master-bin.000001 1451 Table_map 3 1500 table_id: ### (test1.t1)
+master-bin.000001 1500 Update_rows_v1 3 1588 table_id: ### flags: STMT_END_F
+master-bin.000001 1588 Xid 3 1619 COMMIT /* xid=### */
+master-bin.000001 1619 Gtid 3 1661 BEGIN GTID 0-3-13
+master-bin.000001 1661 Annotate_rows 3 1795 DELETE test1.t1, test2.t1 FROM test1.t1 INNER JOIN test2.t1 WHERE test1.t1.f1 = test2.t1.f1 AND test1.t1.f1 = 3
+master-bin.000001 1795 Table_map 3 1844 table_id: ### (test1.t1)
+master-bin.000001 1844 Delete_rows_v1 3 1886 table_id: ### flags: STMT_END_F
+master-bin.000001 1886 Xid 3 1917 COMMIT /* xid=### */
+master-bin.000001 1917 Gtid 3 1959 BEGIN GTID 0-3-15
+master-bin.000001 1959 Annotate_rows 3 2020 INSERT INTO test1.t1 (f1) VALUES (111)
+master-bin.000001 2020 Table_map 3 2069 table_id: ### (test1.t1)
+master-bin.000001 2069 Write_rows_v1 3 2111 table_id: ### flags: STMT_END_F
+master-bin.000001 2111 Annotate_rows 3 2172 INSERT INTO test1.t1 (f1) VALUES (222)
+master-bin.000001 2172 Table_map 3 2221 table_id: ### (test1.t1)
+master-bin.000001 2221 Write_rows_v1 3 2263 table_id: ### flags: STMT_END_F
+master-bin.000001 2263 Xid 3 2294 COMMIT /* xid=### */
+master-bin.000001 2294 Gtid 3 2336 BEGIN GTID <effective_uuid>
+master-bin.000001 2336 Annotate_rows 3 2397 INSERT INTO test1.t1 (f1) VALUES (333)
+master-bin.000001 2397 Table_map 3 2446 table_id: ### (test1.t1)
+master-bin.000001 2446 Write_rows_v1 3 2488 table_id: ### flags: STMT_END_F
+master-bin.000001 2488 Xid 3 2519 COMMIT /* xid=### */
+connection node_1;
+gtid_executed_equal
+0
+SHOW BINLOG EVENTS IN 'master-bin.000001' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 256 Gtid_list 1 285 []
+master-bin.000001 285 Binlog_checkpoint 1 329 master-bin.000001
+master-bin.000001 329 Gtid 3 371 GTID 0-3-1
+master-bin.000001 371 Query 3 458 CREATE SCHEMA test1
+master-bin.000001 458 Gtid 3 500 GTID 0-3-2
+master-bin.000001 500 Query 3 647 use `test1`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB
+master-bin.000001 647 Gtid 3 689 BEGIN GTID 0-3-3
+master-bin.000001 689 Annotate_rows 3 748 INSERT INTO test1.t1 (f1) VALUES (1)
+master-bin.000001 748 Table_map 3 797 table_id: ### (test1.t1)
+master-bin.000001 797 Write_rows_v1 3 839 table_id: ### flags: STMT_END_F
+master-bin.000001 839 Xid 3 870 COMMIT /* xid=### */
+master-bin.000001 870 Gtid 3 912 BEGIN GTID 0-3-4
+master-bin.000001 912 Annotate_rows 3 971 INSERT INTO test1.t1 (f1) VALUES (2)
+master-bin.000001 971 Table_map 3 1020 table_id: ### (test1.t1)
+master-bin.000001 1020 Write_rows_v1 3 1062 table_id: ### flags: STMT_END_F
+master-bin.000001 1062 Xid 3 1093 COMMIT /* xid=### */
+master-bin.000001 1093 Gtid 3 1135 BEGIN GTID 0-3-5
+master-bin.000001 1135 Annotate_rows 3 1194 INSERT INTO test1.t1 (f1) VALUES (3)
+master-bin.000001 1194 Table_map 3 1243 table_id: ### (test1.t1)
+master-bin.000001 1243 Write_rows_v1 3 1285 table_id: ### flags: STMT_END_F
+master-bin.000001 1285 Xid 3 1316 COMMIT /* xid=### */
+master-bin.000001 1316 Gtid 3 1358 BEGIN GTID 0-3-6
+master-bin.000001 1358 Annotate_rows 3 1451 UPDATE test1.t1, test2.t1 SET test1.t1.f2 = 'klm', test2.t1.f2 = 'xyz'
+master-bin.000001 1451 Table_map 3 1500 table_id: ### (test1.t1)
+master-bin.000001 1500 Update_rows_v1 3 1588 table_id: ### flags: STMT_END_F
+master-bin.000001 1588 Xid 3 1619 COMMIT /* xid=### */
+master-bin.000001 1619 Gtid 3 1661 BEGIN GTID 0-3-7
+master-bin.000001 1661 Annotate_rows 3 1795 DELETE test1.t1, test2.t1 FROM test1.t1 INNER JOIN test2.t1 WHERE test1.t1.f1 = test2.t1.f1 AND test1.t1.f1 = 3
+master-bin.000001 1795 Table_map 3 1844 table_id: ### (test1.t1)
+master-bin.000001 1844 Delete_rows_v1 3 1886 table_id: ### flags: STMT_END_F
+master-bin.000001 1886 Xid 3 1917 COMMIT /* xid=### */
+master-bin.000001 1917 Gtid 3 1959 BEGIN GTID 0-3-8
+master-bin.000001 1959 Annotate_rows 3 2020 INSERT INTO test1.t1 (f1) VALUES (111)
+master-bin.000001 2020 Table_map 3 2069 table_id: ### (test1.t1)
+master-bin.000001 2069 Write_rows_v1 3 2111 table_id: ### flags: STMT_END_F
+master-bin.000001 2111 Annotate_rows 3 2172 INSERT INTO test1.t1 (f1) VALUES (222)
+master-bin.000001 2172 Table_map 3 2221 table_id: ### (test1.t1)
+master-bin.000001 2221 Write_rows_v1 3 2263 table_id: ### flags: STMT_END_F
+master-bin.000001 2263 Xid 3 2294 COMMIT /* xid=### */
+master-bin.000001 2294 Gtid 3 2336 BEGIN GTID 0-3-9
+master-bin.000001 2336 Annotate_rows 3 2397 INSERT INTO test1.t1 (f1) VALUES (333)
+master-bin.000001 2397 Table_map 3 2446 table_id: ### (test1.t1)
+master-bin.000001 2446 Write_rows_v1 3 2488 table_id: ### flags: STMT_END_F
+master-bin.000001 2488 Xid 3 2519 COMMIT /* xid=### */
+include/diff_servers.inc [servers=1 2]
+connection node_1;
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f1 IN (1,2);
+COUNT(*) = 2
+1
+SELECT COUNT(*) = 3 FROM test1.t1 WHERE f1 IN (111,222,333);
+COUNT(*) = 3
+1
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f2 = 'klm';
+COUNT(*) = 2
+1
+USE test2;
+ERROR 42000: Unknown database 'test2'
+connection node_3;
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+connection node_1;
+connection node_2;
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result b/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result
new file mode 100644
index 00000000000..fc10cc01a45
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result
@@ -0,0 +1,315 @@
+RESET MASTER;
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+START SLAVE USER='root';
+Warnings:
+Note 1759 Sending passwords in plain text without SSL/TLS is extremely insecure.
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+SET SESSION wsrep_on=OFF;
+include/wait_for_slave_sql_error.inc [errno=1047]
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+INSERT INTO test1.t1 (f1) VALUES (5);
+INSERT INTO test2.t1 (f1) VALUES (5);
+SET SESSION wsrep_on=ON;
+INSERT INTO test1.t1 (f1) VALUES (6);
+INSERT INTO test2.t1 (f1) VALUES (6);
+START SLAVE;
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 120 Previous_gtids 2 151
+mysqld-bin.000001 151 Gtid 1 199 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:1'
+mysqld-bin.000001 199 Query 1 294 CREATE SCHEMA test1
+mysqld-bin.000001 294 Gtid 1 342 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:2'
+mysqld-bin.000001 342 Query 1 415 BEGIN
+mysqld-bin.000001 415 Query 1 489 COMMIT
+mysqld-bin.000001 489 Gtid 1 537 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:3'
+mysqld-bin.000001 537 Query 1 655 use `test1`; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB
+mysqld-bin.000001 655 Gtid 1 703 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:4'
+mysqld-bin.000001 703 Query 1 776 BEGIN
+mysqld-bin.000001 776 Query 1 850 COMMIT
+mysqld-bin.000001 850 Gtid 1 898 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:5'
+mysqld-bin.000001 898 Query 1 961 BEGIN
+mysqld-bin.000001 961 Table_map 1 1007 table_id: ### (test1.t1)
+mysqld-bin.000001 1007 Write_rows 1 1047 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 1047 Xid 1 1078 COMMIT /* xid=### */
+mysqld-bin.000001 1078 Gtid 1 1126 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:6'
+mysqld-bin.000001 1126 Query 1 1189 BEGIN
+mysqld-bin.000001 1189 Query 1 1253 COMMIT
+mysqld-bin.000001 1253 Gtid 1 1301 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:7'
+mysqld-bin.000001 1301 Query 1 1364 BEGIN
+mysqld-bin.000001 1364 Table_map 1 1410 table_id: ### (test1.t1)
+mysqld-bin.000001 1410 Write_rows 1 1450 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 1450 Xid 1 1481 COMMIT /* xid=### */
+mysqld-bin.000001 1481 Gtid 1 1529 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:8'
+mysqld-bin.000001 1529 Query 1 1592 BEGIN
+mysqld-bin.000001 1592 Query 1 1656 COMMIT
+mysqld-bin.000001 1656 Gtid 2 1704 SET @@SESSION.GTID_NEXT= '<effective_uuid_2>:12'
+mysqld-bin.000001 1704 Query 2 1772 BEGIN
+mysqld-bin.000001 1772 Ignorable 2 1795 # Unrecognized ignorable event
+mysqld-bin.000001 1795 Query 2 1864 COMMIT
+mysqld-bin.000001 1864 Gtid 2 1912 SET @@SESSION.GTID_NEXT= '<effective_uuid_2>:13'
+mysqld-bin.000001 1912 Query 2 1980 BEGIN
+mysqld-bin.000001 1980 Ignorable 2 2003 # Unrecognized ignorable event
+mysqld-bin.000001 2003 Query 2 2072 COMMIT
+mysqld-bin.000001 2072 Gtid 1 2120 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:9'
+mysqld-bin.000001 2120 Query 1 2183 BEGIN
+mysqld-bin.000001 2183 Table_map 1 2229 table_id: ### (test1.t1)
+mysqld-bin.000001 2229 Write_rows 1 2269 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 2269 Xid 1 2300 COMMIT /* xid=### */
+mysqld-bin.000001 2300 Gtid 1 2348 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:10'
+mysqld-bin.000001 2348 Query 1 2411 BEGIN
+mysqld-bin.000001 2411 Query 1 2475 COMMIT
+mysqld-bin.000001 2475 Gtid 1 2523 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:11'
+mysqld-bin.000001 2523 Query 1 2586 BEGIN
+mysqld-bin.000001 2586 Table_map 1 2632 table_id: ### (test1.t1)
+mysqld-bin.000001 2632 Write_rows 1 2672 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 2672 Xid 1 2703 COMMIT /* xid=### */
+mysqld-bin.000001 2703 Gtid 1 2751 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:12'
+mysqld-bin.000001 2751 Query 1 2814 BEGIN
+mysqld-bin.000001 2814 Query 1 2878 COMMIT
+mysqld-bin.000001 2878 Gtid 1 2926 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:13'
+mysqld-bin.000001 2926 Query 1 2989 BEGIN
+mysqld-bin.000001 2989 Table_map 1 3035 table_id: ### (test1.t1)
+mysqld-bin.000001 3035 Write_rows 1 3075 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 3075 Xid 1 3106 COMMIT /* xid=### */
+mysqld-bin.000001 3106 Gtid 1 3154 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:14'
+mysqld-bin.000001 3154 Query 1 3217 BEGIN
+mysqld-bin.000001 3217 Query 1 3281 COMMIT
+mysqld-bin.000001 3281 Gtid 1 3329 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:15'
+mysqld-bin.000001 3329 Query 1 3392 BEGIN
+mysqld-bin.000001 3392 Table_map 1 3438 table_id: ### (test1.t1)
+mysqld-bin.000001 3438 Write_rows 1 3478 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 3478 Xid 1 3509 COMMIT /* xid=### */
+mysqld-bin.000001 3509 Gtid 1 3557 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:16'
+mysqld-bin.000001 3557 Query 1 3620 BEGIN
+mysqld-bin.000001 3620 Query 1 3684 COMMIT
+mysqld-bin.000001 3684 Gtid 1 3732 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:17'
+mysqld-bin.000001 3732 Query 1 3795 BEGIN
+mysqld-bin.000001 3795 Table_map 1 3841 table_id: ### (test1.t1)
+mysqld-bin.000001 3841 Write_rows 1 3881 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 3881 Xid 1 3912 COMMIT /* xid=### */
+mysqld-bin.000001 3912 Gtid 1 3960 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:18'
+mysqld-bin.000001 3960 Query 1 4023 BEGIN
+mysqld-bin.000001 4023 Query 1 4087 COMMIT
+mysqld-bin.000001 4087 Gtid 1 4135 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:19'
+mysqld-bin.000001 4135 Query 1 4198 BEGIN
+mysqld-bin.000001 4198 Table_map 1 4244 table_id: ### (test1.t1)
+mysqld-bin.000001 4244 Write_rows 1 4284 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 4284 Xid 1 4315 COMMIT /* xid=### */
+mysqld-bin.000001 4315 Gtid 1 4363 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:20'
+mysqld-bin.000001 4363 Query 1 4426 BEGIN
+mysqld-bin.000001 4426 Query 1 4490 COMMIT
+mysqld-bin.000001 4490 Gtid 1 4538 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:21'
+mysqld-bin.000001 4538 Query 1 4601 BEGIN
+mysqld-bin.000001 4601 Table_map 1 4647 table_id: ### (test1.t1)
+mysqld-bin.000001 4647 Write_rows 1 4687 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 4687 Xid 1 4718 COMMIT /* xid=### */
+mysqld-bin.000001 4718 Gtid 1 4766 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:22'
+mysqld-bin.000001 4766 Query 1 4829 BEGIN
+mysqld-bin.000001 4829 Query 1 4893 COMMIT
+mysqld-bin.000001 4893 Gtid 1 4941 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:23'
+mysqld-bin.000001 4941 Query 1 5004 BEGIN
+mysqld-bin.000001 5004 Table_map 1 5050 table_id: ### (test1.t1)
+mysqld-bin.000001 5050 Write_rows 1 5090 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 5090 Xid 1 5121 COMMIT /* xid=### */
+mysqld-bin.000001 5121 Gtid 1 5169 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:24'
+mysqld-bin.000001 5169 Query 1 5232 BEGIN
+mysqld-bin.000001 5232 Query 1 5296 COMMIT
+mysqld-bin.000001 5296 Gtid 1 5344 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:25'
+mysqld-bin.000001 5344 Query 1 5407 BEGIN
+mysqld-bin.000001 5407 Table_map 1 5453 table_id: ### (test1.t1)
+mysqld-bin.000001 5453 Write_rows 1 5493 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 5493 Xid 1 5524 COMMIT /* xid=### */
+mysqld-bin.000001 5524 Gtid 1 5572 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:26'
+mysqld-bin.000001 5572 Query 1 5635 BEGIN
+mysqld-bin.000001 5635 Query 1 5699 COMMIT
+mysqld-bin.000001 5699 Gtid 1 5747 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:27'
+mysqld-bin.000001 5747 Query 1 5810 BEGIN
+mysqld-bin.000001 5810 Table_map 1 5856 table_id: ### (test1.t1)
+mysqld-bin.000001 5856 Write_rows 1 5896 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 5896 Xid 1 5927 COMMIT /* xid=### */
+mysqld-bin.000001 5927 Gtid 1 5975 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:28'
+mysqld-bin.000001 5975 Query 1 6038 BEGIN
+mysqld-bin.000001 6038 Query 1 6102 COMMIT
+mysqld-bin.000001 6102 Gtid 1 6150 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:29'
+mysqld-bin.000001 6150 Query 1 6213 BEGIN
+mysqld-bin.000001 6213 Table_map 1 6259 table_id: ### (test1.t1)
+mysqld-bin.000001 6259 Write_rows 1 6299 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 6299 Xid 1 6330 COMMIT /* xid=### */
+mysqld-bin.000001 6330 Gtid 1 6378 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:30'
+mysqld-bin.000001 6378 Query 1 6441 BEGIN
+mysqld-bin.000001 6441 Query 1 6505 COMMIT
+USE test2;
+ERROR 42000: Unknown database 'test2'
+gtid_executed_equal
+1
+USE test2;
+ERROR 42000: Unknown database 'test2'
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 120 Previous_gtids 4 151
+mysqld-bin.000001 151 Gtid 1 199 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:1'
+mysqld-bin.000001 199 Query 1 294 CREATE SCHEMA test1
+mysqld-bin.000001 294 Gtid 1 342 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:2'
+mysqld-bin.000001 342 Query 1 415 BEGIN
+mysqld-bin.000001 415 Query 1 489 COMMIT
+mysqld-bin.000001 489 Gtid 1 537 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:3'
+mysqld-bin.000001 537 Query 1 655 use `test1`; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB
+mysqld-bin.000001 655 Gtid 1 703 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:4'
+mysqld-bin.000001 703 Query 1 776 BEGIN
+mysqld-bin.000001 776 Query 1 850 COMMIT
+mysqld-bin.000001 850 Gtid 1 898 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:5'
+mysqld-bin.000001 898 Query 1 961 BEGIN
+mysqld-bin.000001 961 Table_map 1 1007 table_id: ### (test1.t1)
+mysqld-bin.000001 1007 Write_rows 1 1047 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 1047 Xid 1 1078 COMMIT /* xid=### */
+mysqld-bin.000001 1078 Gtid 1 1126 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:6'
+mysqld-bin.000001 1126 Query 1 1189 BEGIN
+mysqld-bin.000001 1189 Query 1 1253 COMMIT
+mysqld-bin.000001 1253 Gtid 1 1301 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:7'
+mysqld-bin.000001 1301 Query 1 1364 BEGIN
+mysqld-bin.000001 1364 Table_map 1 1410 table_id: ### (test1.t1)
+mysqld-bin.000001 1410 Write_rows 1 1450 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 1450 Xid 1 1481 COMMIT /* xid=### */
+mysqld-bin.000001 1481 Gtid 1 1529 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:8'
+mysqld-bin.000001 1529 Query 1 1592 BEGIN
+mysqld-bin.000001 1592 Query 1 1656 COMMIT
+mysqld-bin.000001 1656 Gtid 4 1704 SET @@SESSION.GTID_NEXT= '<effective_uuid_2>:12'
+mysqld-bin.000001 1704 Query 4 1772 BEGIN
+mysqld-bin.000001 1772 Ignorable 4 1795 # Unrecognized ignorable event
+mysqld-bin.000001 1795 Query 4 1864 COMMIT
+mysqld-bin.000001 1864 Gtid 4 1912 SET @@SESSION.GTID_NEXT= '<effective_uuid_2>:13'
+mysqld-bin.000001 1912 Query 4 1980 BEGIN
+mysqld-bin.000001 1980 Ignorable 4 2003 # Unrecognized ignorable event
+mysqld-bin.000001 2003 Query 4 2072 COMMIT
+mysqld-bin.000001 2072 Gtid 1 2120 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:9'
+mysqld-bin.000001 2120 Query 1 2183 BEGIN
+mysqld-bin.000001 2183 Table_map 1 2229 table_id: ### (test1.t1)
+mysqld-bin.000001 2229 Write_rows 1 2269 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 2269 Xid 1 2300 COMMIT /* xid=### */
+mysqld-bin.000001 2300 Gtid 1 2348 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:10'
+mysqld-bin.000001 2348 Query 1 2411 BEGIN
+mysqld-bin.000001 2411 Query 1 2475 COMMIT
+mysqld-bin.000001 2475 Gtid 1 2523 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:11'
+mysqld-bin.000001 2523 Query 1 2586 BEGIN
+mysqld-bin.000001 2586 Table_map 1 2632 table_id: ### (test1.t1)
+mysqld-bin.000001 2632 Write_rows 1 2672 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 2672 Xid 1 2703 COMMIT /* xid=### */
+mysqld-bin.000001 2703 Gtid 1 2751 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:12'
+mysqld-bin.000001 2751 Query 1 2814 BEGIN
+mysqld-bin.000001 2814 Query 1 2878 COMMIT
+mysqld-bin.000001 2878 Gtid 1 2926 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:13'
+mysqld-bin.000001 2926 Query 1 2989 BEGIN
+mysqld-bin.000001 2989 Table_map 1 3035 table_id: ### (test1.t1)
+mysqld-bin.000001 3035 Write_rows 1 3075 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 3075 Xid 1 3106 COMMIT /* xid=### */
+mysqld-bin.000001 3106 Gtid 1 3154 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:14'
+mysqld-bin.000001 3154 Query 1 3217 BEGIN
+mysqld-bin.000001 3217 Query 1 3281 COMMIT
+mysqld-bin.000001 3281 Gtid 1 3329 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:15'
+mysqld-bin.000001 3329 Query 1 3392 BEGIN
+mysqld-bin.000001 3392 Table_map 1 3438 table_id: ### (test1.t1)
+mysqld-bin.000001 3438 Write_rows 1 3478 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 3478 Xid 1 3509 COMMIT /* xid=### */
+mysqld-bin.000001 3509 Gtid 1 3557 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:16'
+mysqld-bin.000001 3557 Query 1 3620 BEGIN
+mysqld-bin.000001 3620 Query 1 3684 COMMIT
+mysqld-bin.000001 3684 Gtid 1 3732 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:17'
+mysqld-bin.000001 3732 Query 1 3795 BEGIN
+mysqld-bin.000001 3795 Table_map 1 3841 table_id: ### (test1.t1)
+mysqld-bin.000001 3841 Write_rows 1 3881 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 3881 Xid 1 3912 COMMIT /* xid=### */
+mysqld-bin.000001 3912 Gtid 1 3960 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:18'
+mysqld-bin.000001 3960 Query 1 4023 BEGIN
+mysqld-bin.000001 4023 Query 1 4087 COMMIT
+mysqld-bin.000001 4087 Gtid 1 4135 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:19'
+mysqld-bin.000001 4135 Query 1 4198 BEGIN
+mysqld-bin.000001 4198 Table_map 1 4244 table_id: ### (test1.t1)
+mysqld-bin.000001 4244 Write_rows 1 4284 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 4284 Xid 1 4315 COMMIT /* xid=### */
+mysqld-bin.000001 4315 Gtid 1 4363 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:20'
+mysqld-bin.000001 4363 Query 1 4426 BEGIN
+mysqld-bin.000001 4426 Query 1 4490 COMMIT
+mysqld-bin.000001 4490 Gtid 1 4538 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:21'
+mysqld-bin.000001 4538 Query 1 4601 BEGIN
+mysqld-bin.000001 4601 Table_map 1 4647 table_id: ### (test1.t1)
+mysqld-bin.000001 4647 Write_rows 1 4687 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 4687 Xid 1 4718 COMMIT /* xid=### */
+mysqld-bin.000001 4718 Gtid 1 4766 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:22'
+mysqld-bin.000001 4766 Query 1 4829 BEGIN
+mysqld-bin.000001 4829 Query 1 4893 COMMIT
+mysqld-bin.000001 4893 Gtid 1 4941 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:23'
+mysqld-bin.000001 4941 Query 1 5004 BEGIN
+mysqld-bin.000001 5004 Table_map 1 5050 table_id: ### (test1.t1)
+mysqld-bin.000001 5050 Write_rows 1 5090 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 5090 Xid 1 5121 COMMIT /* xid=### */
+mysqld-bin.000001 5121 Gtid 1 5169 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:24'
+mysqld-bin.000001 5169 Query 1 5232 BEGIN
+mysqld-bin.000001 5232 Query 1 5296 COMMIT
+mysqld-bin.000001 5296 Gtid 1 5344 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:25'
+mysqld-bin.000001 5344 Query 1 5407 BEGIN
+mysqld-bin.000001 5407 Table_map 1 5453 table_id: ### (test1.t1)
+mysqld-bin.000001 5453 Write_rows 1 5493 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 5493 Xid 1 5524 COMMIT /* xid=### */
+mysqld-bin.000001 5524 Gtid 1 5572 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:26'
+mysqld-bin.000001 5572 Query 1 5635 BEGIN
+mysqld-bin.000001 5635 Query 1 5699 COMMIT
+mysqld-bin.000001 5699 Gtid 1 5747 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:27'
+mysqld-bin.000001 5747 Query 1 5810 BEGIN
+mysqld-bin.000001 5810 Table_map 1 5856 table_id: ### (test1.t1)
+mysqld-bin.000001 5856 Write_rows 1 5896 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 5896 Xid 1 5927 COMMIT /* xid=### */
+mysqld-bin.000001 5927 Gtid 1 5975 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:28'
+mysqld-bin.000001 5975 Query 1 6038 BEGIN
+mysqld-bin.000001 6038 Query 1 6102 COMMIT
+mysqld-bin.000001 6102 Gtid 1 6150 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:29'
+mysqld-bin.000001 6150 Query 1 6213 BEGIN
+mysqld-bin.000001 6213 Table_map 1 6259 table_id: ### (test1.t1)
+mysqld-bin.000001 6259 Write_rows 1 6299 table_id: ### flags: STMT_END_F
+mysqld-bin.000001 6299 Xid 1 6330 COMMIT /* xid=### */
+mysqld-bin.000001 6330 Gtid 1 6378 SET @@SESSION.GTID_NEXT= '<effective_uuid_1>:30'
+mysqld-bin.000001 6378 Query 1 6441 BEGIN
+mysqld-bin.000001 6441 Query 1 6505 COMMIT
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+STOP SLAVE;
+RESET SLAVE ALL;
+CALL mtr.add_suppression("GTID replication failed");
+CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed");
+CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+CALL mtr.add_suppression("TO isolation failed for");
+CALL mtr.add_suppression("Slave SQL: Error 'Deadlock found when trying to get lock; try restarting transaction' on query");
+CALL mtr.add_suppression("Slave SQL: Error 'WSREP has not yet prepared node for application use' on query");
+CALL mtr.add_suppression("Slave: WSREP has not yet prepared node for application use Error_code: 1047");
diff --git a/mysql-test/suite/galera/r/galera_as_slave_nonprim.result b/mysql-test/suite/galera/r/galera_as_slave_nonprim.result
index 365ea31f292..fefc988d9d4 100644
--- a/mysql-test/suite/galera/r/galera_as_slave_nonprim.result
+++ b/mysql-test/suite/galera/r/galera_as_slave_nonprim.result
@@ -1,13 +1,28 @@
+connection node_2;
+connection node_1;
+connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4;
+connection node_2;
START SLAVE;
SET SESSION wsrep_sync_wait = 0;
+connection node_4;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+connection node_2;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+connection node_1;
+connection node_4;
INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+connection node_2;
+connection node_1;
expected_error
1
+connection node_2;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+connection node_1;
+connection node_2;
START SLAVE;
+connection node_4;
DROP TABLE t1;
+connection node_2;
STOP SLAVE;
RESET SLAVE ALL;
CALL mtr.add_suppression("Slave SQL: Error 'Unknown command' on query");
@@ -15,4 +30,5 @@ CALL mtr.add_suppression("Slave: Unknown command Error_code: 1047");
CALL mtr.add_suppression("Transport endpoint is not connected");
CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed, 'Deadlock found when trying to get lock; try restarting transaction', Error_code: 1213");
CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+connection node_4;
RESET MASTER;
diff --git a/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result b/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result
index 91f45c93257..7c98b3e85ed 100644
--- a/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result
+++ b/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort.result b/mysql-test/suite/galera/r/galera_bf_abort.result
index c2e89965fce..cb4a27c82fd 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(6)) ENGINE=InnoDB;
connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2;
@@ -9,7 +11,7 @@ INSERT INTO t1 VALUES (1,'node_1');
connection node_2a;
connection node_2;
INSERT INTO t1 VALUES (2, 'node_2');
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
wsrep_local_aborts_increment
1
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result b/mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result
index 7b98c807efb..1150a9fff63 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort_flush_for_export.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET AUTOCOMMIT=OFF;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_for_update.result b/mysql-test/suite/galera/r/galera_bf_abort_for_update.result
index ec8bddb087a..7dd3053b7bb 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort_for_update.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort_for_update.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, 10);
connection node_1;
@@ -10,7 +12,7 @@ UPDATE t1 SET f1 = 2;
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
wsrep_local_bf_aborts_diff
1
connection node_1;
@@ -23,7 +25,7 @@ UPDATE t1 SET f2 = 20;
connection node_1a;
connection node_1;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
wsrep_local_bf_aborts_diff
1
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result b/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result
index ae1ca6d2157..43ca6089d78 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort_ftwrl.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET AUTOCOMMIT=OFF;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result
index 8c6c7b7d7a4..0ef2a1a72c6 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort_get_lock.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
connection node_2a;
SELECT GET_LOCK("foo", 1000);
@@ -10,7 +12,7 @@ SELECT GET_LOCK("foo", 1000);;
connection node_1;
INSERT INTO t1 VALUES (1);
connection node_2;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
wsrep_local_aborts_increment
1
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_group_commit.result b/mysql-test/suite/galera/r/galera_bf_abort_group_commit.result
new file mode 100644
index 00000000000..2a2ddd519f4
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_abort_group_commit.result
@@ -0,0 +1,685 @@
+SET SESSION wsrep_sync_wait = 0;
+galera_sr_bf_abort_at_commit = 0
+after_replicate_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync';
+INSERT INTO t1 VALUES (3);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+local_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+INSERT INTO t1 VALUES (3);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+apply_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_master_enter_sync';
+INSERT INTO t1 VALUES (3);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_master_enter_sync';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+commit_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+INSERT INTO t1 VALUES (3);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+galera_sr_bf_abort_at_commit = 1
+after_replicate_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+local_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+apply_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_master_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_master_enter_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+commit_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+galera_sr_bf_abort_at_commit = 1
+after_replicate_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 0;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+local_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 0;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+apply_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 0;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_master_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_master_enter_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+commit_monitor_master_enter_sync
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 0;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+COMMIT;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+ROLLBACK;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+CALL mtr.add_suppression("WSREP: fragment replication failed: 1");
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result b/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result
index 81b5816ddbe..e7882e43b6a 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort_lock_table.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET AUTOCOMMIT=OFF;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_shutdown.result b/mysql-test/suite/galera/r/galera_bf_abort_shutdown.result
new file mode 100644
index 00000000000..fa2a5c373f2
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_bf_abort_shutdown.result
@@ -0,0 +1,12 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INT PRIMARY KEY);
+connection node_2;
+SET DEBUG_SYNC = 'wsrep_before_certification WAIT_FOR continue';
+INSERT INTO t1 VALUES (1);
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_abort_sleep.result b/mysql-test/suite/galera/r/galera_bf_abort_sleep.result
index 9cd6abad5a1..00d6600d264 100644
--- a/mysql-test/suite/galera/r/galera_bf_abort_sleep.result
+++ b/mysql-test/suite/galera/r/galera_bf_abort_sleep.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET AUTOCOMMIT=OFF;
@@ -6,7 +8,7 @@ SELECT SLEEP(1000);;
connection node_1;
INSERT INTO t1 VALUES (1);
connection node_2;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
wsrep_local_aborts_increment
1
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_background_statistics.result b/mysql-test/suite/galera/r/galera_bf_background_statistics.result
index c2c3fce2b14..a8c8842b8e1 100644
--- a/mysql-test/suite/galera/r/galera_bf_background_statistics.result
+++ b/mysql-test/suite/galera/r/galera_bf_background_statistics.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT @@innodb_stats_persistent;
@@innodb_stats_persistent
1
@@ -27,7 +29,7 @@ SELECT SLEEP(1000);;
connection node_1;
ALTER TABLE t1 CHANGE f2 f2 INTEGER NOT NULL DEFAULT 1;
connection node_2;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
wsrep_local_aborts_increment
1
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_bf_lock_wait.result b/mysql-test/suite/galera/r/galera_bf_lock_wait.result
index 7ec524da888..f893848a72d 100644
--- a/mysql-test/suite/galera/r/galera_bf_lock_wait.result
+++ b/mysql-test/suite/galera/r/galera_bf_lock_wait.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2;
ALTER TABLE t1 add primary key(a);
CREATE PROCEDURE p1()
diff --git a/mysql-test/suite/galera/r/galera_binlog_cache_size.result b/mysql-test/suite/galera/r/galera_binlog_cache_size.result
index 6aac74ab5f0..c5a09074537 100644
--- a/mysql-test/suite/galera/r/galera_binlog_cache_size.result
+++ b/mysql-test/suite/galera/r/galera_binlog_cache_size.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 VARCHAR(767)) ENGINE=InnoDB;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
diff --git a/mysql-test/suite/galera/r/galera_binlog_checksum.result b/mysql-test/suite/galera/r/galera_binlog_checksum.result
index 7303aa61122..3ef7cf5c41e 100644
--- a/mysql-test/suite/galera/r/galera_binlog_checksum.result
+++ b/mysql-test/suite/galera/r/galera_binlog_checksum.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result b/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result
index 46582ff5c4b..b513c491bb0 100644
--- a/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result
+++ b/mysql-test/suite/galera/r/galera_binlog_event_max_size_max.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE t1 (f1 VARCHAR(1000));
diff --git a/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result b/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result
index 7b88af5d5af..6c2279bece0 100644
--- a/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result
+++ b/mysql-test/suite/galera/r/galera_binlog_event_max_size_min.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 VARCHAR(1000));
INSERT INTO t1 VALUES (REPEAT('x', 1000));
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_binlog_row_image.result b/mysql-test/suite/galera/r/galera_binlog_row_image.result
index d54db61105e..20e6bd9fab8 100644
--- a/mysql-test/suite/galera/r/galera_binlog_row_image.result
+++ b/mysql-test/suite/galera/r/galera_binlog_row_image.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET SESSION binlog_row_image=minimal;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_commit_empty.result b/mysql-test/suite/galera/r/galera_commit_empty.result
new file mode 100644
index 00000000000..75b94c54b1e
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_commit_empty.result
@@ -0,0 +1,15 @@
+connection node_2;
+connection node_1;
+START TRANSACTION;
+COMMIT;
+START TRANSACTION;
+COMMIT;
+START TRANSACTION READ ONLY;
+COMMIT;
+START TRANSACTION;
+COMMIT;
+START TRANSACTION;
+START TRANSACTION;
+COMMIT;
+wsrep_last_committed_diff
+1
diff --git a/mysql-test/suite/galera/r/galera_concurrent_ctas.result b/mysql-test/suite/galera/r/galera_concurrent_ctas.result
index 8a3ac1ae0d3..39c55277c52 100644
--- a/mysql-test/suite/galera/r/galera_concurrent_ctas.result
+++ b/mysql-test/suite/galera/r/galera_concurrent_ctas.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
disconnect node_2;
disconnect node_1;
# End of test
diff --git a/mysql-test/suite/galera/r/galera_create_function.result b/mysql-test/suite/galera/r/galera_create_function.result
index 9118c2864f3..85fa85d81f1 100644
--- a/mysql-test/suite/galera/r/galera_create_function.result
+++ b/mysql-test/suite/galera/r/galera_create_function.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE USER 'user1';
CREATE
diff --git a/mysql-test/suite/galera/r/galera_create_procedure.result b/mysql-test/suite/galera/r/galera_create_procedure.result
index 98dc4a856dc..24a0bd66b39 100644
--- a/mysql-test/suite/galera/r/galera_create_procedure.result
+++ b/mysql-test/suite/galera/r/galera_create_procedure.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE USER 'user1';
CREATE TABLE t1 (f1 INTEGER);
diff --git a/mysql-test/suite/galera/r/galera_create_table_as_select.result b/mysql-test/suite/galera/r/galera_create_table_as_select.result
new file mode 100644
index 00000000000..6f65ee99f0a
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_create_table_as_select.result
@@ -0,0 +1,103 @@
+connection node_2;
+connection node_1;
+connection node_1;
+SET SESSION default_storage_engine=InnoDB;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t1 AS SELECT * FROM t2;
+ERROR 42S01: Table 't1' already exists
+DROP TABLE t1,t2;
+CREATE TABLE t1 AS SELECT * FROM t2;
+ERROR 42S02: Table 'test.t2' doesn't exist
+CREATE TABLE t1 AS SELECT 1 FROM DUAL;
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+connection node_1;
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t1 AS SELECT * FROM t2;
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+DROP TABLE t1,t2;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+CREATE TABLE t1 AS SELECT * FROM t2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1;
+DROP TABLE t1,t2;
+connection node_1;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+CREATE TABLE t1 AS SELECT MAX(f1) AS f1 FROM t2;
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT f1 = 5 FROM t1;
+f1 = 5
+1
+connection node_1;
+DROP TABLE t1,t2;
+connection node_1;
+CREATE PROCEDURE sp1 ()
+BEGIN
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+CREATE TABLE t1 AS SELECT * FROM t2;
+END|
+CALL sp1();
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1;
+DROP TABLE t1, t2;
+DROP PROCEDURE sp1;
+connection node_1;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT * FROM t2';
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1, t2;
+connection node_1;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+LOCK TABLE t2 WRITE;
+connection node_1;
+CREATE TABLE t1 AS SELECT * FROM t2;;
+connection node_2;
+SELECT COUNT(*) = 5 FROM t2;
+COUNT(*) = 5
+1
+CREATE TABLE t1 AS SELECT * FROM t2;
+connection node_1a;
+UNLOCK TABLES;
+connection node_1;
+Got one of the listed errors
+DROP TABLE t1, t2;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+CREATE TEMPORARY TABLE t1 AS SELECT * FROM t2;
+connection node_2;
+SELECT * FROM t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test.t1'' on query");
+connection node_1;
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera/r/galera_create_table_like.result b/mysql-test/suite/galera/r/galera_create_table_like.result
index 131ac311bca..82543331ad5 100644
--- a/mysql-test/suite/galera/r/galera_create_table_like.result
+++ b/mysql-test/suite/galera/r/galera_create_table_like.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE SCHEMA schema1;
CREATE SCHEMA schema2;
USE schema1;
diff --git a/mysql-test/suite/galera/r/galera_create_trigger.result b/mysql-test/suite/galera/r/galera_create_trigger.result
index d07a007543e..56b35150d87 100644
--- a/mysql-test/suite/galera/r/galera_create_trigger.result
+++ b/mysql-test/suite/galera/r/galera_create_trigger.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE definer_root (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
CREATE TABLE definer_user (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
CREATE TABLE definer_current_user (f1 INTEGER, trigger_user VARCHAR(100)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_ddl_multiline.result b/mysql-test/suite/galera/r/galera_ddl_multiline.result
index 339a91125eb..9e70731a62b 100644
--- a/mysql-test/suite/galera/r/galera_ddl_multiline.result
+++ b/mysql-test/suite/galera/r/galera_ddl_multiline.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_defaults.result b/mysql-test/suite/galera/r/galera_defaults.result
index 6871ec6d56b..20ea590e2e5 100644
--- a/mysql-test/suite/galera/r/galera_defaults.result
+++ b/mysql-test/suite/galera/r/galera_defaults.result
@@ -1,6 +1,8 @@
-SELECT COUNT(*) = 43 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
-COUNT(*) = 43
-0
+connection node_2;
+connection node_1;
+SELECT COUNT(*) `expect 48` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
+expect 48
+48
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME LIKE 'wsrep_%'
@@ -31,6 +33,7 @@ WSREP_DRUPAL_282555_WORKAROUND OFF
WSREP_FORCED_BINLOG_FORMAT NONE
WSREP_GTID_DOMAIN_ID 0
WSREP_GTID_MODE OFF
+WSREP_IGNORE_APPLY_ERRORS 7
WSREP_LOAD_DATA_SPLITTING ON
WSREP_LOG_CONFLICTS OFF
WSREP_MAX_WS_ROWS 0
@@ -47,8 +50,11 @@ WSREP_RETRY_AUTOCOMMIT 1
WSREP_SLAVE_FK_CHECKS ON
WSREP_SLAVE_THREADS 1
WSREP_SLAVE_UK_CHECKS OFF
+WSREP_SR_STORE table
WSREP_SST_AUTH
WSREP_SST_DONOR
WSREP_SST_DONOR_REJECTS_QUERIES OFF
WSREP_SST_METHOD rsync
WSREP_SYNC_WAIT 15
+WSREP_TRX_FRAGMENT_SIZE 0
+WSREP_TRX_FRAGMENT_UNIT bytes
diff --git a/mysql-test/suite/galera/r/galera_delete_limit.result b/mysql-test/suite/galera/r/galera_delete_limit.result
index f6fb2e56346..9898bfcf169 100644
--- a/mysql-test/suite/galera/r/galera_delete_limit.result
+++ b/mysql-test/suite/galera/r/galera_delete_limit.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
diff --git a/mysql-test/suite/galera/r/galera_desync_overlapped.result b/mysql-test/suite/galera/r/galera_desync_overlapped.result
index f9920e7f7ad..e3f40d444ee 100644
--- a/mysql-test/suite/galera/r/galera_desync_overlapped.result
+++ b/mysql-test/suite/galera/r/galera_desync_overlapped.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
diff --git a/mysql-test/suite/galera/r/galera_drop_multi.result b/mysql-test/suite/galera/r/galera_drop_multi.result
index 7793ef93b90..1ff8afe3219 100644
--- a/mysql-test/suite/galera/r/galera_drop_multi.result
+++ b/mysql-test/suite/galera/r/galera_drop_multi.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result b/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result
index 38480d186ba..fdfca3316b1 100644
--- a/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result
+++ b/mysql-test/suite/galera/r/galera_encrypt_tmp_files.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
diff --git a/mysql-test/suite/galera/r/galera_enum.result b/mysql-test/suite/galera/r/galera_enum.result
index a2a6317e2a0..40fc6931f6a 100644
--- a/mysql-test/suite/galera/r/galera_enum.result
+++ b/mysql-test/suite/galera/r/galera_enum.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 ENUM('', 'one', 'two'), KEY (f1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES ('');
@@ -38,7 +40,7 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_1;
SELECT COUNT(*) FROM t1 WHERE f1 = 'three';
COUNT(*)
diff --git a/mysql-test/suite/galera/r/galera_events.result b/mysql-test/suite/galera/r/galera_events.result
index f01627aba70..791b0be729d 100644
--- a/mysql-test/suite/galera/r/galera_events.result
+++ b/mysql-test/suite/galera/r/galera_events.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE EVENT event1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO SELECT 1;
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_fk_cascade_delete.result b/mysql-test/suite/galera/r/galera_fk_cascade_delete.result
index 73375ae55c5..291d641db88 100644
--- a/mysql-test/suite/galera/r/galera_fk_cascade_delete.result
+++ b/mysql-test/suite/galera/r/galera_fk_cascade_delete.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE grandparent (
id INT NOT NULL PRIMARY KEY
) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_fk_cascade_update.result b/mysql-test/suite/galera/r/galera_fk_cascade_update.result
index 5fe8b532473..5294826a8f9 100644
--- a/mysql-test/suite/galera/r/galera_fk_cascade_update.result
+++ b/mysql-test/suite/galera/r/galera_fk_cascade_update.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE grandparent (
id INT NOT NULL PRIMARY KEY
) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_fk_conflict.result b/mysql-test/suite/galera/r/galera_fk_conflict.result
index a08aa30a82e..f9f151abce4 100644
--- a/mysql-test/suite/galera/r/galera_fk_conflict.result
+++ b/mysql-test/suite/galera/r/galera_fk_conflict.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE parent (
id INT PRIMARY KEY,
KEY (id)
@@ -22,6 +24,6 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE child;
DROP TABLE parent;
diff --git a/mysql-test/suite/galera/r/galera_fk_mismatch.result b/mysql-test/suite/galera/r/galera_fk_mismatch.result
index bdc60c9e099..a030b1214c5 100644
--- a/mysql-test/suite/galera/r/galera_fk_mismatch.result
+++ b/mysql-test/suite/galera/r/galera_fk_mismatch.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE parent (
id1 INT,
id2 INT,
diff --git a/mysql-test/suite/galera/r/galera_fk_multicolumn.result b/mysql-test/suite/galera/r/galera_fk_multicolumn.result
index f5b6aa23692..b626d963af8 100644
--- a/mysql-test/suite/galera/r/galera_fk_multicolumn.result
+++ b/mysql-test/suite/galera/r/galera_fk_multicolumn.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t0 (
f1 INT PRIMARY KEY,
f2 INT UNIQUE
diff --git a/mysql-test/suite/galera/r/galera_fk_multitable.result b/mysql-test/suite/galera/r/galera_fk_multitable.result
index 04ff7adc3e9..83e1491ab34 100644
--- a/mysql-test/suite/galera/r/galera_fk_multitable.result
+++ b/mysql-test/suite/galera/r/galera_fk_multitable.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t0 (
f0 INT PRIMARY KEY
);
diff --git a/mysql-test/suite/galera/r/galera_fk_no_pk.result b/mysql-test/suite/galera/r/galera_fk_no_pk.result
index e7b5f0b2b64..622e63dbb8f 100644
--- a/mysql-test/suite/galera/r/galera_fk_no_pk.result
+++ b/mysql-test/suite/galera/r/galera_fk_no_pk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE parent (
id INT,
KEY (id)
diff --git a/mysql-test/suite/galera/r/galera_fk_selfreferential.result b/mysql-test/suite/galera/r/galera_fk_selfreferential.result
index 3b4dbf2a8e9..9a64521e7b8 100644
--- a/mysql-test/suite/galera/r/galera_fk_selfreferential.result
+++ b/mysql-test/suite/galera/r/galera_fk_selfreferential.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (
f1 INT NOT NULL PRIMARY KEY,
f2 INT,
diff --git a/mysql-test/suite/galera/r/galera_fk_setnull.result b/mysql-test/suite/galera/r/galera_fk_setnull.result
index d4f20fe60a3..afb3fc3b9b8 100644
--- a/mysql-test/suite/galera/r/galera_fk_setnull.result
+++ b/mysql-test/suite/galera/r/galera_fk_setnull.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE parent (
id INT NOT NULL,
PRIMARY KEY (id)
diff --git a/mysql-test/suite/galera/r/galera_flush_local.result b/mysql-test/suite/galera/r/galera_flush_local.result
index a155a410a45..146833fc3c8 100644
--- a/mysql-test/suite/galera/r/galera_flush_local.result
+++ b/mysql-test/suite/galera/r/galera_flush_local.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
DROP TABLE IF EXISTS t1, t2, x1, x2;
connection node_1;
CREATE TABLE t1 (f1 INTEGER);
diff --git a/mysql-test/suite/galera/r/galera_forced_binlog_format.result b/mysql-test/suite/galera/r/galera_forced_binlog_format.result
index b94e6530886..a94ac0c112d 100644
--- a/mysql-test/suite/galera/r/galera_forced_binlog_format.result
+++ b/mysql-test/suite/galera/r/galera_forced_binlog_format.result
@@ -1,5 +1,10 @@
+connection node_2;
connection node_1;
+connection node_1;
+SEt GLOBAL wsrep_on=OFF;
RESET MASTER;
+SEt GLOBAL wsrep_on=ON;
+FLUSH BINARY LOGS;
SET SESSION binlog_format = 'STATEMENT';
Warnings:
Warning 1105 MariaDB Galera and flashback do not support binlog format: STATEMENT
@@ -13,18 +18,7 @@ SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256;
Log_name Pos Event_type Server_id End_log_pos Info
mysqld-bin.000001 <Pos> Gtid_list 1 <End_log_pos> []
mysqld-bin.000001 <Pos> Binlog_checkpoint 1 <End_log_pos> mysqld-bin.000001
-mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> GTID 0-1-1
-mysqld-bin.000001 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB
-mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
-mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1)
-mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
-mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
-mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
-mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-3
-mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (2)
-mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
-mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
-mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Rotate 1 <End_log_pos> mysqld-bin.000002;pos=4
DROP TABLE t1;
#
# MDEV-9401: wsrep_forced_binlog_format with binlog causes crash
@@ -43,6 +37,4 @@ 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;
-disconnect node_2;
-disconnect node_1;
# End of tests
diff --git a/mysql-test/suite/galera/r/galera_ftwrl.result b/mysql-test/suite/galera/r/galera_ftwrl.result
index 0565781c051..eae8028a7f4 100644
--- a/mysql-test/suite/galera/r/galera_ftwrl.result
+++ b/mysql-test/suite/galera/r/galera_ftwrl.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET GLOBAL wsrep_provider_options = "repl.causal_read_timeout=PT1S";
diff --git a/mysql-test/suite/galera/r/galera_ftwrl_drain.result b/mysql-test/suite/galera/r/galera_ftwrl_drain.result
index 751811b88fd..2342643e745 100644
--- a/mysql-test/suite/galera/r/galera_ftwrl_drain.result
+++ b/mysql-test/suite/galera/r/galera_ftwrl_drain.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
@@ -22,7 +24,7 @@ connection node_2;
SET SESSION lock_wait_timeout = 1;
SET SESSION innodb_lock_wait_timeout=1;
SET SESSION wait_timeout=1;
-INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (2);
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
connection node_2a;
UNLOCK TABLES;
diff --git a/mysql-test/suite/galera/r/galera_fulltext.result b/mysql-test/suite/galera/r/galera_fulltext.result
index 18e3bff40fc..a22296278fa 100644
--- a/mysql-test/suite/galera/r/galera_fulltext.result
+++ b/mysql-test/suite/galera/r/galera_fulltext.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_gcache_recover.result b/mysql-test/suite/galera/r/galera_gcache_recover.result
index d3ba06c1333..819c595ece3 100644
--- a/mysql-test/suite/galera/r/galera_gcache_recover.result
+++ b/mysql-test/suite/galera/r/galera_gcache_recover.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
SET SESSION wsrep_sync_wait = 0;
diff --git a/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result b/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result
index 588af5668bb..a0d128f5fa3 100644
--- a/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result
+++ b/mysql-test/suite/galera/r/galera_gcache_recover_full_gcache.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET SESSION wsrep_sync_wait = 0;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 LONGBLOB) ENGINE=InnoDB;
connection node_2;
@@ -21,6 +23,6 @@ include/diff_servers.inc [servers=1 2]
connection node_1;
DROP TABLE t1;
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
-include/assert_grep.inc [IST first seqno 2 not found from cache, falling back to SST]
+include/assert_grep.inc [IST first seqno [24] not found from cache, falling back to SST]
connection node_2;
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
diff --git a/mysql-test/suite/galera/r/galera_gcs_fc_limit.result b/mysql-test/suite/galera/r/galera_gcs_fc_limit.result
index 464a8b7ea97..83eaa0fb7aa 100644
--- a/mysql-test/suite/galera/r/galera_gcs_fc_limit.result
+++ b/mysql-test/suite/galera/r/galera_gcs_fc_limit.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_gcs_fragment.result b/mysql-test/suite/galera/r/galera_gcs_fragment.result
index 0c9c1819f60..bdd749047ee 100644
--- a/mysql-test/suite/galera/r/galera_gcs_fragment.result
+++ b/mysql-test/suite/galera/r/galera_gcs_fragment.result
@@ -1,24 +1,37 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 TEXT);
+connection node_2;
SET GLOBAL wsrep_cluster_address='';
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
SET SESSION wsrep_sync_wait=0;
SET GLOBAL wsrep_provider_options = 'dbug=d,gcs_core_after_frag_send';
+connection node_1;
SET SESSION wsrep_retry_autocommit=0;
INSERT INTO t1 VALUES (1, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_2;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
INSERT INTO t1 VALUES (2, "bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+connection node_1a;
SET GLOBAL wsrep_provider_options = 'signal=gcs_core_after_frag_send';
-ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_1;
+ERROR HY000: Got error 6 "No such device or address" during COMMIT
INSERT INTO t1 VALUES (3, "cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
SELECT * FROM t1;
f1 f2
2 bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
3 cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+connection node_2;
SELECT * FROM t1;
f1 f2
2 bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
3 cccccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+connection node_1;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result b/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result
index ce74f3db433..b97be5733ff 100644
--- a/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result
+++ b/mysql-test/suite/galera/r/galera_gcs_max_packet_size.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_gra_log.result b/mysql-test/suite/galera/r/galera_gra_log.result
index 777eda42046..33853188965 100644
--- a/mysql-test/suite/galera/r/galera_gra_log.result
+++ b/mysql-test/suite/galera/r/galera_gra_log.result
@@ -1,4 +1,6 @@
connection node_2;
+connection node_1;
+connection node_2;
SET SESSION wsrep_on=OFF;
CREATE TABLE t1 (f1 INTEGER);
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_gtid.result b/mysql-test/suite/galera/r/galera_gtid.result
index acc5eae9876..f27e2590898 100644
--- a/mysql-test/suite/galera/r/galera_gtid.result
+++ b/mysql-test/suite/galera/r/galera_gtid.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY);
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_gtid_slave.result b/mysql-test/suite/galera/r/galera_gtid_slave.result
index f8ca6322d22..7a3048231af 100644
--- a/mysql-test/suite/galera/r/galera_gtid_slave.result
+++ b/mysql-test/suite/galera/r/galera_gtid_slave.result
@@ -1,7 +1,9 @@
-connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2;
-START SLAVE;
connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_2;
+START SLAVE;
+connection node_3;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
@@ -11,27 +13,31 @@ insert into t2 values(22);
commit;
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4
+2-3-4
connection node_2;
INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(3);
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4,2-2-2
-connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+0-2-2,2-3-4
+connection node_1;
INSERT INTO t1 VALUES(4);
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4,2-2-2,2-3-3
-connection node_1;
+1-1-1,2-3-4,2-2-6
+connection node_3;
DROP TABLE t1,t2;
connection node_2;
-connection node_3;
+connection node_1;
connection node_2;
STOP SLAVE;
RESET SLAVE ALL;
+SET GLOBAL wsrep_on=OFF;
reset master;
-connection node_3;
-reset master;
+SET GLOBAL wsrep_on=ON;
connection node_1;
+SET GLOBAL wsrep_on=OFF;
+reset master;
+SET GLOBAL wsrep_on=ON;
+connection node_3;
reset master;
diff --git a/mysql-test/suite/galera/r/galera_gtid_slave_sst_rsync.result b/mysql-test/suite/galera/r/galera_gtid_slave_sst_rsync.result
index 380a0235ac2..7c5519af495 100644
--- a/mysql-test/suite/galera/r/galera_gtid_slave_sst_rsync.result
+++ b/mysql-test/suite/galera/r/galera_gtid_slave_sst_rsync.result
@@ -1,38 +1,40 @@
-connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
#Connection 2
connection node_2;
START SLAVE;
-#Connection 1
-connection node_1;
+#Connection 3
+connection node_3;
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 int unique) ENGINE=InnoDB;
INSERT INTO t2 VALUES(1,11);
INSERT INTO t2 VALUES(2,22);
INSERT INTO t2 VALUES(3,33);
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4
+2-3-4
include/save_master_gtid.inc
#Connection 2
connection node_2;
include/sync_with_master_gtid.inc
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4
+2-3-4
INSERT INTO t2 VALUES(4,44);
INSERT INTO t2 VALUES(5,55);
INSERT INTO t2 VALUES(6,66);
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4,2-2-3
-#Connection 3
-connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+0-2-3,2-3-4
+#Connection 1
+connection node_1;
INSERT INTO t2 VALUES(7,77);
INSERT INTO t2 VALUES(8,88);
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-4,2-2-3,2-3-5
-#Connection 1
-connection node_1;
+1-1-2,2-3-4,2-2-7
+#Connection 3
+connection node_3;
CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
@@ -48,76 +50,78 @@ START TRANSACTION;
INSERT INTO t1 VALUES ('node2_committed_before');
INSERT INTO t1 VALUES ('node2_committed_before');
COMMIT;
-#Connection 3
-connection node_3;
+#Connection 1
+connection node_1;
+connection node_1;
connection node_2;
-connection node_3;
-Shutting down server ...
#Connection 2
connection node_2;
+Shutting down server ...
+#Connection 1
+connection node_1;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
INSERT INTO t1 VALUES ('node1_committed_during');
INSERT INTO t1 VALUES ('node1_committed_during');
COMMIT;
-#Connection 3
-connection node_3;
+#Connection 2
+connection node_2;
Starting server ...
SET AUTOCOMMIT=OFF;
START TRANSACTION;
-INSERT INTO t1 VALUES ('node3_committed_after');
-INSERT INTO t1 VALUES ('node3_committed_after');
+INSERT INTO t1 VALUES ('node2_committed_after');
+INSERT INTO t1 VALUES ('node2_committed_after');
COMMIT;
-#Connection 2
-connection node_2;
+#Connection 1
+connection node_1;
Select * from t1 order by f1;
f1
node1_committed_before
node1_committed_before
node1_committed_during
node1_committed_during
+node2_committed_after
+node2_committed_after
node2_committed_before
node2_committed_before
-node3_committed_after
-node3_committed_after
-#Connection 3
-connection node_3;
+#Connection 2
+connection node_2;
Select * from t1 order by f1;
f1
node1_committed_before
node1_committed_before
node1_committed_during
node1_committed_during
+node2_committed_after
+node2_committed_after
node2_committed_before
node2_committed_before
-node3_committed_after
-node3_committed_after
+#Connection 1
+connection node_1;
+SELECT @@global.gtid_binlog_state;
+@@global.gtid_binlog_state
+1-1-3,2-3-6,2-2-9
#Connection 2
connection node_2;
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-6,2-2-7,2-3-8
+0-1-7,0-2-8,2-3-6
#Connection 3
connection node_3;
-SELECT @@global.gtid_binlog_state;
-@@global.gtid_binlog_state
-1-1-6,2-2-7,2-3-8
-#Connection 1
-connection node_1;
SET AUTOCOMMIT=ON;
#Connection 2
connection node_2;
SET AUTOCOMMIT=ON;
-#Connection 3
-connection node_3;
+#Connection 1
+connection node_1;
SET AUTOCOMMIT=ON;
#Connection 2
connection node_2;
STOP slave;
INSERT INTO t1 VALUES ('node2_slave_stoped');
-#Connection 1
-connection node_1;
-INSERT INTO t1 VALUES ('node1_normal_entry');
+#Connection 3
+connection node_3;
+INSERT INTO t1 VALUES ('node3_normal_entry');
include/save_master_gtid.inc
#Connection 2
connection node_2;
@@ -130,31 +134,35 @@ count(*)
12
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-7,2-3-8,2-2-11
-#Connection 3
-connection node_3;
+0-1-7,0-2-11,2-3-7
+#Connection 1
+connection node_1;
SELECT count(*) from t1;
count(*)
12
SELECT @@global.gtid_binlog_state;
@@global.gtid_binlog_state
-1-1-7,2-3-8,2-2-11
-#Connection 1
-connection node_1;
+1-1-3,2-3-7,2-2-12
+#Connection 3
+connection node_3;
DROP TABLE t2,t1;
#Connection 2
connection node_2;
-#Connection 3
-connection node_3;
+#Connection 1
+connection node_1;
#Connection 2
connection node_2;
STOP SLAVE;
RESET SLAVE ALL;
+set global wsrep_on=OFF;
+reset master;
+set global wsrep_on=ON;
set global gtid_slave_pos="";
+#Connection 1
+connection node_1;
+set global wsrep_on=OFF;
reset master;
+set global wsrep_on=ON;
#Connection 3
connection node_3;
reset master;
-#Connection 1
-connection node_1;
-reset master;
diff --git a/mysql-test/suite/galera/r/galera_insert_ignore.result b/mysql-test/suite/galera/r/galera_insert_ignore.result
index 7057affaa0e..417524240e7 100644
--- a/mysql-test/suite/galera/r/galera_insert_ignore.result
+++ b/mysql-test/suite/galera/r/galera_insert_ignore.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET GLOBAL wsrep_sync_wait = 15;
connection node_2;
SET GLOBAL wsrep_sync_wait = 15;
diff --git a/mysql-test/suite/galera/r/galera_insert_multi.result b/mysql-test/suite/galera/r/galera_insert_multi.result
index 913dd42403a..d7a4f01873e 100644
--- a/mysql-test/suite/galera/r/galera_insert_multi.result
+++ b/mysql-test/suite/galera/r/galera_insert_multi.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
@@ -51,7 +53,7 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
ROLLBACK;
INSERT INTO t1 VALUES (1), (2);
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
diff --git a/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result b/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result
index 481a85711be..cad00aaee48 100644
--- a/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result
+++ b/mysql-test/suite/galera/r/galera_ist_innodb_flush_logs.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
Performing State Transfer on a server that has been killed and restarted
connection node_1;
CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_ist_mariabackup,debug.rdiff b/mysql-test/suite/galera/r/galera_ist_mariabackup,debug.rdiff
index 9684e290778..fe54c515395 100644
--- a/mysql-test/suite/galera/r/galera_ist_mariabackup,debug.rdiff
+++ b/mysql-test/suite/galera/r/galera_ist_mariabackup,debug.rdiff
@@ -1,6 +1,6 @@
---- r/galera_ist_mariabackup.result 2018-11-21 22:30:21.968817468 +0200
-+++ r/galera_ist_mariabackup.reject 2018-11-22 09:16:27.832601754 +0200
-@@ -285,3 +285,111 @@
+--- galera_ist_mariabackup.result 2018-12-11 13:33:56.728535840 +0100
++++ galera_ist_mariabackup.reject 2018-12-11 13:37:40.572535840 +0100
+@@ -290,3 +290,111 @@
DROP TABLE t1;
COMMIT;
SET AUTOCOMMIT=ON;
diff --git a/mysql-test/suite/galera/r/galera_ist_mariabackup.result b/mysql-test/suite/galera/r/galera_ist_mariabackup.result
index 8a7c02ab1b6..13f7d898a59 100644
--- a/mysql-test/suite/galera/r/galera_ist_mariabackup.result
+++ b/mysql-test/suite/galera/r/galera_ist_mariabackup.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that has been temporarily disconnected
@@ -47,6 +49,9 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
connection node_2;
Loading wsrep provider ...
+disconnect node_2;
+connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
INSERT INTO t1 VALUES ('node2_committed_after');
diff --git a/mysql-test/suite/galera/r/galera_ist_mariabackup_innodb_flush_logs.result b/mysql-test/suite/galera/r/galera_ist_mariabackup_innodb_flush_logs.result
index 7813b5a58fc..99b9c8d6c1b 100644
--- a/mysql-test/suite/galera/r/galera_ist_mariabackup_innodb_flush_logs.result
+++ b/mysql-test/suite/galera/r/galera_ist_mariabackup_innodb_flush_logs.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
Performing State Transfer on a server that has been killed and restarted
connection node_1;
CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_ist_mysqldump.result b/mysql-test/suite/galera/r/galera_ist_mysqldump.result
index 296ecc2adc7..222eb7704e8 100644
--- a/mysql-test/suite/galera/r/galera_ist_mysqldump.result
+++ b/mysql-test/suite/galera/r/galera_ist_mysqldump.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
Setting SST method to mysqldump ...
call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to '127.0.0.1'");
call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
@@ -210,3 +212,4 @@ CALL mtr.add_suppression("Can't open and lock time zone table");
CALL mtr.add_suppression("Can't open and lock privilege tables");
CALL mtr.add_suppression("Info table is not ready to be used");
CALL mtr.add_suppression("Native table .* has the wrong structure");
+CALL mtr.add_suppression("Table \'mysql.gtid_slave_pos\' doesn\'t exist");
diff --git a/mysql-test/suite/galera/r/galera_ist_progress.result b/mysql-test/suite/galera/r/galera_ist_progress.result
index ed36a217624..9fc7febbea5 100644
--- a/mysql-test/suite/galera/r/galera_ist_progress.result
+++ b/mysql-test/suite/galera/r/galera_ist_progress.result
@@ -1,10 +1,6 @@
-connection node_2;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 1';
-connection node_1;
-connection node_2;
SET SESSION wsrep_on = OFF;
SET SESSION wsrep_on = ON;
-connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2);
@@ -16,13 +12,8 @@ INSERT INTO t1 VALUES (7);
INSERT INTO t1 VALUES (8);
INSERT INTO t1 VALUES (9);
INSERT INTO t1 VALUES (10);
-connection node_2;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0';
-connection node_1;
-connection node_2;
-connection node_1;
include/assert_grep.inc [Receiving IST: 11 writesets, seqnos]
include/assert_grep.inc [Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete]
include/assert_grep.inc [Receiving IST\.\.\.100\.0% \(11/11 events\) complete]
-connection node_1;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_ist_recv_bind.result b/mysql-test/suite/galera/r/galera_ist_recv_bind.result
index ffc751d8672..be72aa60ab0 100644
--- a/mysql-test/suite/galera/r/galera_ist_recv_bind.result
+++ b/mysql-test/suite/galera/r/galera_ist_recv_bind.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SELECT @@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%';
@@wsrep_provider_options LIKE '%ist.recv_bind = 127.0.0.1%'
diff --git a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
index c81cecfae1c..80d2c90642b 100644
--- a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
+++ b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
@@ -13,7 +15,6 @@ Loading wsrep_provider ...
SET SESSION wsrep_on=OFF;
SET SESSION wsrep_on=ON;
connection node_1;
-connection node_1;
UPDATE t1 SET f2 = 'd' WHERE f1 > 3;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_ist_rsync.result b/mysql-test/suite/galera/r/galera_ist_rsync.result
index 8a7c02ab1b6..13f7d898a59 100644
--- a/mysql-test/suite/galera/r/galera_ist_rsync.result
+++ b/mysql-test/suite/galera/r/galera_ist_rsync.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that has been temporarily disconnected
@@ -47,6 +49,9 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
connection node_2;
Loading wsrep provider ...
+disconnect node_2;
+connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
INSERT INTO t1 VALUES ('node2_committed_after');
diff --git a/mysql-test/suite/galera/r/galera_kill_ddl.result b/mysql-test/suite/galera/r/galera_kill_ddl.result
index b11353fcbcc..9d66140465c 100644
--- a/mysql-test/suite/galera/r/galera_kill_ddl.result
+++ b/mysql-test/suite/galera/r/galera_kill_ddl.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
call mtr.add_suppression("WSREP: Last Applied Action message in non-primary configuration from member .*");
connection node_1;
SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
diff --git a/mysql-test/suite/galera/r/galera_kill_largechanges.result b/mysql-test/suite/galera/r/galera_kill_largechanges.result
index f4de101fef8..a04729d2c87 100644
--- a/mysql-test/suite/galera/r/galera_kill_largechanges.result
+++ b/mysql-test/suite/galera/r/galera_kill_largechanges.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
call mtr.add_suppression("WSREP: Last Applied Action message in non-primary configuration from member .*");
connection node_1;
SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
diff --git a/mysql-test/suite/galera/r/galera_kill_smallchanges.result b/mysql-test/suite/galera/r/galera_kill_smallchanges.result
index 2ee291004b0..206591bbebe 100644
--- a/mysql-test/suite/galera/r/galera_kill_smallchanges.result
+++ b/mysql-test/suite/galera/r/galera_kill_smallchanges.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
call mtr.add_suppression("WSREP: Last Applied Action message in non-primary configuration from member .*");
connection node_1;
SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
diff --git a/mysql-test/suite/galera/r/galera_lock_table.result b/mysql-test/suite/galera/r/galera_lock_table.result
index ce529deb22c..c3df1749ada 100644
--- a/mysql-test/suite/galera/r/galera_lock_table.result
+++ b/mysql-test/suite/galera/r/galera_lock_table.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_log_bin.result b/mysql-test/suite/galera/r/galera_log_bin.result
index a6f0ef12be1..12e5e59a426 100644
--- a/mysql-test/suite/galera/r/galera_log_bin.result
+++ b/mysql-test/suite/galera/r/galera_log_bin.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 (id INT) ENGINE=InnoDB;
@@ -66,4 +68,6 @@ mysqld-bin.000003 # Query # # use `test`; ALTER TABLE t1 ADD COLUMN f2 INTEGER
DROP TABLE t1;
DROP TABLE t2;
connection node_1;
+SET GLOBAL wsrep_on=OFF;
RESET MASTER;
+SET GLOBAL wsrep_on=ON;
diff --git a/mysql-test/suite/galera/r/galera_log_output_csv.result b/mysql-test/suite/galera/r/galera_log_output_csv.result
index 5cb61b36332..efe8c73c986 100644
--- a/mysql-test/suite/galera/r/galera_log_output_csv.result
+++ b/mysql-test/suite/galera/r/galera_log_output_csv.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
SELECT COUNT(*) > 0 FROM mysql.general_log;
diff --git a/mysql-test/suite/galera/r/galera_many_columns.result b/mysql-test/suite/galera/r/galera_many_columns.result
index db8a8f5ec9d..64e97f11fa7 100644
--- a/mysql-test/suite/galera/r/galera_many_columns.result
+++ b/mysql-test/suite/galera/r/galera_many_columns.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
INSERT INTO t1 (f1) VALUES (DEFAULT);
connection node_2;
SELECT f1 = 'ABC', f1017 = 'ABC' FROM t1;
@@ -19,7 +21,7 @@ UPDATE t1 SET f2 = 'CDE' WHERE f1 = 'XYZ' AND f1017 = 'XYZ';
COMMIT;
connection node_1;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
ROLLBACK;
connection node_2;
ROLLBACK;
diff --git a/mysql-test/suite/galera/r/galera_many_indexes.result b/mysql-test/suite/galera/r/galera_many_indexes.result
index 0d8688e3709..963d3552252 100644
--- a/mysql-test/suite/galera/r/galera_many_indexes.result
+++ b/mysql-test/suite/galera/r/galera_many_indexes.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 VARCHAR(767) PRIMARY KEY) ENGINE=InnoDB;
CREATE UNIQUE INDEX i63 ON t1(f1);
CREATE UNIQUE INDEX i62 ON t1(f1);
@@ -131,5 +133,5 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_many_rows.result b/mysql-test/suite/galera/r/galera_many_rows.result
index b06925fea60..26771dc3c24 100644
--- a/mysql-test/suite/galera/r/galera_many_rows.result
+++ b/mysql-test/suite/galera/r/galera_many_rows.result
@@ -1,3 +1,7 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
connection node_1;
SET SESSION innodb_lock_wait_timeout=600;
SET SESSION lock_wait_timeout=600;
@@ -35,6 +39,6 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE t1;
DROP TABLE ten;
diff --git a/mysql-test/suite/galera/r/galera_many_tables_nopk.result b/mysql-test/suite/galera/r/galera_many_tables_nopk.result
index 573ce758a13..2a226defcc7 100644
--- a/mysql-test/suite/galera/r/galera_many_tables_nopk.result
+++ b/mysql-test/suite/galera/r/galera_many_tables_nopk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
@@ -18,6 +20,6 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP SCHEMA test;
CREATE SCHEMA test;
diff --git a/mysql-test/suite/galera/r/galera_many_tables_pk.result b/mysql-test/suite/galera/r/galera_many_tables_pk.result
index 67624d5edb0..2700df8ebe4 100644
--- a/mysql-test/suite/galera/r/galera_many_tables_pk.result
+++ b/mysql-test/suite/galera/r/galera_many_tables_pk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
SELECT COUNT(*) = 100 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME LIKE 't%';
@@ -23,7 +25,7 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
include/diff_servers.inc [servers=1 2]
DROP SCHEMA test;
CREATE SCHEMA test;
diff --git a/mysql-test/suite/galera/r/galera_mdev_10812.result b/mysql-test/suite/galera/r/galera_mdev_10812.result
index de0a08a3794..16eacc6beab 100644
--- a/mysql-test/suite/galera/r/galera_mdev_10812.result
+++ b/mysql-test/suite/galera/r/galera_mdev_10812.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-10812: On COM_STMT_CLOSE/COM_QUIT, when wsrep_conflict_state
# is ABORTED, it causes wrong response to be sent to the client
diff --git a/mysql-test/suite/galera/r/galera_mdev_13787.result b/mysql-test/suite/galera/r/galera_mdev_13787.result
index b1caec0283c..4d0770918c0 100644
--- a/mysql-test/suite/galera/r/galera_mdev_13787.result
+++ b/mysql-test/suite/galera/r/galera_mdev_13787.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
create table t(a int);
insert into t select 1;
diff --git a/mysql-test/suite/galera/r/galera_mdev_15611.result b/mysql-test/suite/galera/r/galera_mdev_15611.result
index 9ea1684494a..5461f8f03fb 100644
--- a/mysql-test/suite/galera/r/galera_mdev_15611.result
+++ b/mysql-test/suite/galera/r/galera_mdev_15611.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (
id int primary key
diff --git a/mysql-test/suite/galera/r/galera_mdl_race.result b/mysql-test/suite/galera/r/galera_mdl_race.result
index 048b2c46a67..e05c1493322 100644
--- a/mysql-test/suite/galera/r/galera_mdl_race.result
+++ b/mysql-test/suite/galera/r/galera_mdl_race.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
INSERT INTO t1 VALUES (1, 'a');
@@ -28,7 +30,7 @@ SET DEBUG_SYNC = "now SIGNAL signal.wsrep_before_mdl_wait";
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_after_BF_victim_lock";
UNLOCK TABLES;
connection node_1;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
COUNT(*) = 1
1
diff --git a/mysql-test/suite/galera/r/galera_multi_database.result b/mysql-test/suite/galera/r/galera_multi_database.result
index f6242de663b..a9d58d5d0e2 100644
--- a/mysql-test/suite/galera/r/galera_multi_database.result
+++ b/mysql-test/suite/galera/r/galera_multi_database.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE DATABASE d1;
CREATE TABLE d1.t1(f1 INTEGER) ENGINE=InnoDB;
CREATE DATABASE d2;
diff --git a/mysql-test/suite/galera/r/galera_myisam_autocommit.result b/mysql-test/suite/galera/r/galera_myisam_autocommit.result
index e9578a261e6..6213e8f6380 100644
--- a/mysql-test/suite/galera/r/galera_myisam_autocommit.result
+++ b/mysql-test/suite/galera/r/galera_myisam_autocommit.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1);
INSERT INTO t1 VALUES (2), (3);
diff --git a/mysql-test/suite/galera/r/galera_myisam_transactions.result b/mysql-test/suite/galera/r/galera_myisam_transactions.result
index 25796c309d1..091c5ffb6f6 100644
--- a/mysql-test/suite/galera/r/galera_myisam_transactions.result
+++ b/mysql-test/suite/galera/r/galera_myisam_transactions.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
CREATE TABLE t3 (f1 INTEGER) ENGINE=MyISAM;
diff --git a/mysql-test/suite/galera/r/galera_nopk_bit.result b/mysql-test/suite/galera/r/galera_nopk_bit.result
index 21da039df09..97ded793c08 100644
--- a/mysql-test/suite/galera/r/galera_nopk_bit.result
+++ b/mysql-test/suite/galera/r/galera_nopk_bit.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 BIT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL),(0),(b'1');
connection node_2;
@@ -28,6 +30,6 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera/r/galera_nopk_blob.result b/mysql-test/suite/galera/r/galera_nopk_blob.result
index 53e04f72d1e..6a3cee516c9 100644
--- a/mysql-test/suite/galera/r/galera_nopk_blob.result
+++ b/mysql-test/suite/galera/r/galera_nopk_blob.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 BLOB) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL),('abc');
connection node_2;
@@ -28,6 +30,6 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera/r/galera_nopk_large_varchar.result b/mysql-test/suite/galera/r/galera_nopk_large_varchar.result
index a83cf7f2d91..6d29306996b 100644
--- a/mysql-test/suite/galera/r/galera_nopk_large_varchar.result
+++ b/mysql-test/suite/galera/r/galera_nopk_large_varchar.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 VARCHAR(8000)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL),(CONCAT(REPEAT('x', 7999), 'a'));
connection node_2;
@@ -31,6 +33,6 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera/r/galera_nopk_unicode.result b/mysql-test/suite/galera/r/galera_nopk_unicode.result
index b2a8bb63df9..587ba9285da 100644
--- a/mysql-test/suite/galera/r/galera_nopk_unicode.result
+++ b/mysql-test/suite/galera/r/galera_nopk_unicode.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (
f1 VARCHAR(255),
KEY (f1)
@@ -19,7 +21,7 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SELECT f1 = 'текст2' FROM t1;
f1 = 'текст2'
1
diff --git a/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result b/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result
index ab56a8a2aa6..48625b3ba4a 100644
--- a/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result
+++ b/mysql-test/suite/galera/r/galera_parallel_apply_lock_table.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
@@ -8,10 +10,10 @@ INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
connection node_2a;
SET SESSION wsrep_sync_wait=0;
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%applied write set%';
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%committing%';
COUNT(*) = 1
1
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for table metadata lock';
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Waiting for table metadata lock%';
COUNT(*) = 1
1
SELECT COUNT(*) = 0 FROM t1;
@@ -30,7 +32,7 @@ COUNT(*) = 1
SELECT COUNT(*) = 1 FROM t2;
COUNT(*) = 1
1
-SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'committed%';
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%committed%';
COUNT(*) = 2
1
SET GLOBAL wsrep_slave_threads = 1;;
diff --git a/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result b/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result
index 827b2aa9dac..d2e09d7084f 100644
--- a/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result
+++ b/mysql-test/suite/galera/r/galera_parallel_autoinc_largetrx.result
@@ -1,5 +1,7 @@
+connection node_2;
+connection node_1;
connection node_1;
-CREATE TABLE ten (f1 INTEGER);
+CREATE TABLE ten (f1 INTEGER) engine=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
connection node_2;
@@ -11,18 +13,26 @@ INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
connection node_2;
INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
connection node_1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+30000
+SELECT COUNT(DISTINCT f1) FROM t1;
+COUNT(DISTINCT f1)
+30000
connection node_1a;
-connection node_2;
SELECT COUNT(*) FROM t1;
COUNT(*)
30000
SELECT COUNT(DISTINCT f1) FROM t1;
COUNT(DISTINCT f1)
30000
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE
-USER = 'system user' AND STATE NOT LIKE 'InnoDB%';
+connection node_2;
+SELECT COUNT(*) FROM t1;
COUNT(*)
-3
+30000
+SELECT COUNT(DISTINCT f1) FROM t1;
+COUNT(DISTINCT f1)
+30000
connection default;
DROP TABLE t1;
DROP TABLE ten;
diff --git a/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result b/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result
index c8c07221cb1..09a415d47eb 100644
--- a/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result
+++ b/mysql-test/suite/galera/r/galera_parallel_autoinc_manytrx.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
@@ -12,7 +14,7 @@ COUNT(*) = 20000
SELECT COUNT(DISTINCT f1) = 20000 FROM t1;
COUNT(DISTINCT f1) = 20000
1
-SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%';
+SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'wsrep applier committed%';
COUNT(*) = 4
1
connection default;
diff --git a/mysql-test/suite/galera/r/galera_parallel_simple.result b/mysql-test/suite/galera/r/galera_parallel_simple.result
index 3f657a0479e..d95abefdc24 100644
--- a/mysql-test/suite/galera/r/galera_parallel_simple.result
+++ b/mysql-test/suite/galera/r/galera_parallel_simple.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT) ENGINE=InnoDB;
CREATE TABLE t2 (id INT) ENGINE=InnoDB;
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_pc_recovery.result b/mysql-test/suite/galera/r/galera_pc_recovery.result
new file mode 100644
index 00000000000..17a43d17211
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_pc_recovery.result
@@ -0,0 +1,37 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+VARIABLE_VALUE = 'Primary'
+1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+VARIABLE_VALUE = 'Primary'
+1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+connection node_1;
+CALL mtr.add_suppression("points to own listening address, blacklisting");
+CALL mtr.add_suppression("non weight changing install in S_PRIM");
+CALL mtr.add_suppression("No re-merged primary component found");
+connection node_2;
+CALL mtr.add_suppression("points to own listening address, blacklisting");
+CALL mtr.add_suppression("non weight changing install in S_PRIM");
+CALL mtr.add_suppression("No re-merged primary component found");
diff --git a/mysql-test/suite/galera/r/galera_pk_bigint_signed.result b/mysql-test/suite/galera/r/galera_pk_bigint_signed.result
index 807ab62c548..0b538778204 100644
--- a/mysql-test/suite/galera/r/galera_pk_bigint_signed.result
+++ b/mysql-test/suite/galera/r/galera_pk_bigint_signed.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 BIGINT SIGNED PRIMARY KEY, f2 VARCHAR(5)) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(-9223372036854775808, 'min'),
@@ -27,6 +29,6 @@ COMMIT;
SET AUTOCOMMIT=ON;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SET AUTOCOMMIT=ON;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result b/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result
index c94b7e2314a..9442f79cd14 100644
--- a/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result
+++ b/mysql-test/suite/galera/r/galera_pk_bigint_unsigned.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 BIGINT UNSIGNED PRIMARY KEY, f2 VARCHAR(5)) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(18446744073709551615, 'max')
@@ -24,6 +26,6 @@ COMMIT;
SET AUTOCOMMIT=ON;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SET AUTOCOMMIT=ON;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_prepared_statement.result b/mysql-test/suite/galera/r/galera_prepared_statement.result
index 6f546b32819..b84f25e9929 100644
--- a/mysql-test/suite/galera/r/galera_prepared_statement.result
+++ b/mysql-test/suite/galera/r/galera_prepared_statement.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 CHAR(5)) ENGINE=InnoDB;
CREATE TABLE t2 (f1 CHAR(5)) ENGINE=InnoDB;
CREATE TABLE t3 (f1 CHAR(5)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_query_cache.result b/mysql-test/suite/galera/r/galera_query_cache.result
index e64c9438646..8f5bc4b6f37 100644
--- a/mysql-test/suite/galera/r/galera_query_cache.result
+++ b/mysql-test/suite/galera/r/galera_query_cache.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_query_cache_sync_wait.result b/mysql-test/suite/galera/r/galera_query_cache_sync_wait.result
index 8c9cece9097..4ee910f9169 100644
--- a/mysql-test/suite/galera/r/galera_query_cache_sync_wait.result
+++ b/mysql-test/suite/galera/r/galera_query_cache_sync_wait.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_read_only.result b/mysql-test/suite/galera/r/galera_read_only.result
index 4c2523f8691..fe8b45fa596 100644
--- a/mysql-test/suite/galera/r/galera_read_only.result
+++ b/mysql-test/suite/galera/r/galera_read_only.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET GLOBAL read_only=TRUE;
diff --git a/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result b/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result
index 2470f59c497..3d421216f93 100644
--- a/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result
+++ b/mysql-test/suite/galera/r/galera_repl_key_format_flat16.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET GLOBAL wsrep_provider_options = 'repl.key_format=FLAT16';
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_repl_max_ws_size.result b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result
index da24a741351..0528df7b9f6 100644
--- a/mysql-test/suite/galera/r/galera_repl_max_ws_size.result
+++ b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result
@@ -1,8 +1,10 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB;
SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512';
INSERT INTO t1 VALUES (REPEAT('a', 512));
-ERROR HY000: Got error 90 "Message too long" during COMMIT
+ERROR HY000: Got error 5 "Input/output error" during COMMIT
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
1
diff --git a/mysql-test/suite/galera/r/galera_restart_nochanges.result b/mysql-test/suite/galera/r/galera_restart_nochanges.result
index b35ae50e2fb..09f8d9a586b 100644
--- a/mysql-test/suite/galera/r/galera_restart_nochanges.result
+++ b/mysql-test/suite/galera/r/galera_restart_nochanges.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_restart_on_unknown_option.result b/mysql-test/suite/galera/r/galera_restart_on_unknown_option.result
index ba6f30fcf30..6e672c2d444 100644
--- a/mysql-test/suite/galera/r/galera_restart_on_unknown_option.result
+++ b/mysql-test/suite/galera/r/galera_restart_on_unknown_option.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CALL mtr.add_suppression("Aborting");
CALL mtr.add_suppression("unknown option '--galera-unknown-option'");
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_roles.result b/mysql-test/suite/galera/r/galera_roles.result
index bef89acfc92..b1124b597c5 100644
--- a/mysql-test/suite/galera/r/galera_roles.result
+++ b/mysql-test/suite/galera/r/galera_roles.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# Testing CREATE/GRANT role
#
diff --git a/mysql-test/suite/galera/r/galera_rsu_add_pk.result b/mysql-test/suite/galera/r/galera_rsu_add_pk.result
index 4c79da154e2..9b068ba30d1 100644
--- a/mysql-test/suite/galera/r/galera_rsu_add_pk.result
+++ b/mysql-test/suite/galera/r/galera_rsu_add_pk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
diff --git a/mysql-test/suite/galera/r/galera_rsu_drop_pk.result b/mysql-test/suite/galera/r/galera_rsu_drop_pk.result
index f64649ef4e2..7d731955691 100644
--- a/mysql-test/suite/galera/r/galera_rsu_drop_pk.result
+++ b/mysql-test/suite/galera/r/galera_rsu_drop_pk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
diff --git a/mysql-test/suite/galera/r/galera_rsu_error.result b/mysql-test/suite/galera/r/galera_rsu_error.result
index 5c16e34b492..f78e8fa544c 100644
--- a/mysql-test/suite/galera/r/galera_rsu_error.result
+++ b/mysql-test/suite/galera/r/galera_rsu_error.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
INSERT INTO t1 VALUES (1), (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_rsu_simple.result b/mysql-test/suite/galera/r/galera_rsu_simple.result
index d0ddcfb4d64..d75ef094065 100644
--- a/mysql-test/suite/galera/r/galera_rsu_simple.result
+++ b/mysql-test/suite/galera/r/galera_rsu_simple.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
connection node_2;
SET SESSION wsrep_OSU_method = "RSU";
diff --git a/mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result b/mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result
index a103e810588..310611a0e49 100644
--- a/mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result
+++ b/mysql-test/suite/galera/r/galera_rsu_wsrep_desync.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
SET GLOBAL wsrep_desync=1;
diff --git a/mysql-test/suite/galera/r/galera_sbr.result b/mysql-test/suite/galera/r/galera_sbr.result
index 0bdaeef5b8a..c5fdecece0e 100644
--- a/mysql-test/suite/galera/r/galera_sbr.result
+++ b/mysql-test/suite/galera/r/galera_sbr.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET SESSION binlog_format = 'STATEMENT';
Warnings:
diff --git a/mysql-test/suite/galera/r/galera_sbr_binlog.result b/mysql-test/suite/galera/r/galera_sbr_binlog.result
index 0bdaeef5b8a..c5fdecece0e 100644
--- a/mysql-test/suite/galera/r/galera_sbr_binlog.result
+++ b/mysql-test/suite/galera/r/galera_sbr_binlog.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET SESSION binlog_format = 'STATEMENT';
Warnings:
diff --git a/mysql-test/suite/galera/r/galera_schema_dirty_reads.result b/mysql-test/suite/galera/r/galera_schema_dirty_reads.result
index edf20da92c6..fbac9ff4eb7 100644
--- a/mysql-test/suite/galera/r/galera_schema_dirty_reads.result
+++ b/mysql-test/suite/galera/r/galera_schema_dirty_reads.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
USE information_schema;
SELECT * FROM SESSION_VARIABLES WHERE VARIABLE_NAME LIKE "wsrep_dirty_reads";
VARIABLE_NAME VARIABLE_VALUE
diff --git a/mysql-test/suite/galera/r/galera_serializable.result b/mysql-test/suite/galera/r/galera_serializable.result
index be3f93a081f..e3785663271 100644
--- a/mysql-test/suite/galera/r/galera_serializable.result
+++ b/mysql-test/suite/galera/r/galera_serializable.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
SET AUTOCOMMIT=OFF;
@@ -9,7 +11,7 @@ connection node_2;
INSERT INTO t1 VALUES (1,1);
connection node_1;
SELECT * FROM t1;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
ROLLBACK;
DELETE FROM t1;
connection node_1;
@@ -22,7 +24,7 @@ connection node_2;
UPDATE t1 SET f2 = 2;
connection node_1;
UPDATE t1 SET f2 = 3;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
ROLLBACK;
DELETE FROM t1;
connection node_1;
@@ -33,5 +35,5 @@ connection node_2;
INSERT INTO t1 VALUES (1,2);
connection node_1;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_server.result b/mysql-test/suite/galera/r/galera_server.result
index cc08b826e82..5130dee3459 100644
--- a/mysql-test/suite/galera/r/galera_server.result
+++ b/mysql-test/suite/galera/r/galera_server.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
# On node_1
CREATE SERVER s1
diff --git a/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result b/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result
index 14407c917a1..e9f81192386 100644
--- a/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result
+++ b/mysql-test/suite/galera/r/galera_sql_log_bin_zero.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
SET SESSION sql_log_bin = 0;
INSERT INTO t1 VALUES (1);
diff --git a/mysql-test/suite/galera/r/galera_ssl.result b/mysql-test/suite/galera/r/galera_ssl.result
index 022d06319b8..ec3b717e3f3 100644
--- a/mysql-test/suite/galera/r/galera_ssl.result
+++ b/mysql-test/suite/galera/r/galera_ssl.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
diff --git a/mysql-test/suite/galera/r/galera_ssl_compression.result b/mysql-test/suite/galera/r/galera_ssl_compression.result
index 333d646376c..0acc4b97eea 100644
--- a/mysql-test/suite/galera/r/galera_ssl_compression.result
+++ b/mysql-test/suite/galera/r/galera_ssl_compression.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup.result b/mysql-test/suite/galera/r/galera_sst_mariabackup.result
index fdb5883b590..4fdc283b286 100644
--- a/mysql-test/suite/galera/r/galera_sst_mariabackup.result
+++ b/mysql-test/suite/galera/r/galera_sst_mariabackup.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that has been shut down cleanly and restarted
diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_data_dir.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_data_dir.result
index fdb5883b590..4fdc283b286 100644
--- a/mysql-test/suite/galera/r/galera_sst_mariabackup_data_dir.result
+++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_data_dir.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that has been shut down cleanly and restarted
diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_encrypt_with_key.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_encrypt_with_key.result
index 990e0a29506..409da775d9a 100644
--- a/mysql-test/suite/galera/r/galera_sst_mariabackup_encrypt_with_key.result
+++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_encrypt_with_key.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT 1;
1
1
diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result
index 9180ed5e421..568c06de94c 100644
--- a/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result
+++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_table_options.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that starts from a clean var directory
diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff
index 3eadee615ed..2978411c8f7 100644
--- a/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff
+++ b/mysql-test/suite/galera/r/galera_sst_mysqldump,debug.rdiff
@@ -1,6 +1,22 @@
---- galera_sst_mysqldump.result
-+++ galera_sst_mysqldump,debug.reject
-@@ -388,6 +388,114 @@
+--- galera_sst_mysqldump.result 2018-11-29 23:54:03.663607613 +0100
++++ galera_sst_mysqldump,debug.reject 2018-11-29 23:55:42.377562815 +0100
+@@ -1,3 +1,5 @@
++connection node_2;
++connection node_1;
+ Setting SST method to mysqldump ...
+ call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to '127.0.0.1'");
+ call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
+@@ -56,6 +58,9 @@
+ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
+ connection node_2;
+ Loading wsrep provider ...
++disconnect node_2;
++connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2;
++connection node_2;
+ SET AUTOCOMMIT=OFF;
+ START TRANSACTION;
+ INSERT INTO t1 VALUES ('node2_committed_after');
+@@ -390,6 +395,114 @@
DROP TABLE t1;
COMMIT;
SET AUTOCOMMIT=ON;
diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump,release.rdiff b/mysql-test/suite/galera/r/galera_sst_mysqldump,release.rdiff
new file mode 100644
index 00000000000..3e8fee1b098
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_sst_mysqldump,release.rdiff
@@ -0,0 +1,18 @@
+--- suite/galera/r/galera_sst_mysqldump.result 2018-12-20 14:22:41.730134062 +0100
++++ suite/galera/r/galera_sst_mysqldump.reject 2019-01-16 22:18:44.139781857 +0100
+@@ -1,3 +1,5 @@
++connection node_2;
++connection node_1;
+ Setting SST method to mysqldump ...
+ call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to '127.0.0.1'");
+ call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
+@@ -56,6 +58,9 @@
+ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
+ connection node_2;
+ Loading wsrep provider ...
++disconnect node_2;
++connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2;
++connection node_2;
+ SET AUTOCOMMIT=OFF;
+ START TRANSACTION;
+ INSERT INTO t1 VALUES ('node2_committed_after');
diff --git a/mysql-test/suite/galera/r/galera_sst_mysqldump.result b/mysql-test/suite/galera/r/galera_sst_mysqldump.result
index 5c530c32ce6..4ed679ba477 100644
--- a/mysql-test/suite/galera/r/galera_sst_mysqldump.result
+++ b/mysql-test/suite/galera/r/galera_sst_mysqldump.result
@@ -400,3 +400,4 @@ CALL mtr.add_suppression("Can't open and lock time zone table");
CALL mtr.add_suppression("Can't open and lock privilege tables");
CALL mtr.add_suppression("Info table is not ready to be used");
CALL mtr.add_suppression("Native table .* has the wrong structure");
+CALL mtr.add_suppression("Table \'mysql.gtid_slave_pos\' doesn\'t exist");
diff --git a/mysql-test/suite/galera/r/galera_sst_rsync.result b/mysql-test/suite/galera/r/galera_sst_rsync.result
index ff85a7d6c0f..d41d0d34e75 100644
--- a/mysql-test/suite/galera/r/galera_sst_rsync.result
+++ b/mysql-test/suite/galera/r/galera_sst_rsync.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that has been shut down cleanly and restarted
diff --git a/mysql-test/suite/galera/r/galera_sst_rsync2,debug.rdiff b/mysql-test/suite/galera/r/galera_sst_rsync2,debug.rdiff
index 525156d88da..8ffe51c0cc3 100644
--- a/mysql-test/suite/galera/r/galera_sst_rsync2,debug.rdiff
+++ b/mysql-test/suite/galera/r/galera_sst_rsync2,debug.rdiff
@@ -1,6 +1,12 @@
---- suite/galera/r/galera_sst_rsync2.result 2018-09-12 13:09:35.352229478 +0200
-+++ suite/galera/r/galera_sst_rsync2,debug.reject 2018-09-12 17:00:51.601974979 +0200
-@@ -286,3 +286,111 @@
+--- galera_sst_rsync2.result 2018-11-29 17:57:53.288606346 +0100
++++ galera_sst_rsync2,debug.reject 2018-11-29 18:00:01.172512000 +0100
+@@ -1,3 +1,5 @@
++connection node_2;
++connection node_1;
+ connection node_1;
+ connection node_2;
+ Performing State Transfer on a server that has been shut down cleanly and restarted
+@@ -286,3 +288,111 @@
DROP TABLE t1;
COMMIT;
SET AUTOCOMMIT=ON;
diff --git a/mysql-test/suite/galera/r/galera_sst_rsync_data_dir.result b/mysql-test/suite/galera/r/galera_sst_rsync_data_dir.result
index ff85a7d6c0f..d41d0d34e75 100644
--- a/mysql-test/suite/galera/r/galera_sst_rsync_data_dir.result
+++ b/mysql-test/suite/galera/r/galera_sst_rsync_data_dir.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Performing State Transfer on a server that has been shut down cleanly and restarted
diff --git a/mysql-test/suite/galera/r/galera_status_cluster.result b/mysql-test/suite/galera/r/galera_status_cluster.result
index ad92a51b775..9db0b88adc9 100644
--- a/mysql-test/suite/galera/r/galera_status_cluster.result
+++ b/mysql-test/suite/galera/r/galera_status_cluster.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 2
diff --git a/mysql-test/suite/galera/r/galera_status_local_index.result b/mysql-test/suite/galera/r/galera_status_local_index.result
index 8c36b60cc5f..c67498fff9f 100644
--- a/mysql-test/suite/galera/r/galera_status_local_index.result
+++ b/mysql-test/suite/galera/r/galera_status_local_index.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE wsrep_local_indexes (wsrep_local_index INTEGER);
INSERT INTO wsrep_local_indexes VALUES ((SELECT variable_value FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_local_index'));
diff --git a/mysql-test/suite/galera/r/galera_status_local_state.result b/mysql-test/suite/galera/r/galera_status_local_state.result
index 65713f1975c..3fe988ee6ac 100644
--- a/mysql-test/suite/galera/r/galera_status_local_state.result
+++ b/mysql-test/suite/galera/r/galera_status_local_state.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state';
VARIABLE_VALUE = 4
1
diff --git a/mysql-test/suite/galera/r/galera_suspend_slave.result b/mysql-test/suite/galera/r/galera_suspend_slave.result
index 07433399081..ce49b491778 100644
--- a/mysql-test/suite/galera/r/galera_suspend_slave.result
+++ b/mysql-test/suite/galera/r/galera_suspend_slave.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_sync_wait_show.result b/mysql-test/suite/galera/r/galera_sync_wait_show.result
index def771ff88d..793da3246ff 100644
--- a/mysql-test/suite/galera/r/galera_sync_wait_show.result
+++ b/mysql-test/suite/galera/r/galera_sync_wait_show.result
@@ -1,4 +1,6 @@
connection node_2;
+connection node_1;
+connection node_2;
SET SESSION wsrep_sync_wait = 8;
connection node_1;
CREATE DATABASE db1;
diff --git a/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result b/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result
index 8a86dfd11e2..a23b0523140 100644
--- a/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result
+++ b/mysql-test/suite/galera/r/galera_toi_alter_auto_increment.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_error.result b/mysql-test/suite/galera/r/galera_toi_ddl_error.result
index dafad153867..386dc28bed3 100644
--- a/mysql-test/suite/galera/r/galera_toi_ddl_error.result
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_error.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
@@ -19,3 +21,6 @@ t1 CREATE TABLE `t1` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
DROP TABLE ten;
+CALL mtr.add_suppression("Ignoring error 'Duplicate entry '111110' for key 'PRIMARY'' on query.");
+connection node_2;
+CALL mtr.add_suppression("Ignoring error 'Duplicate entry '111110' for key 'PRIMARY'' on query.");
diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result b/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result
index 0dbc89978d4..0ecc4a4619f 100644
--- a/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_fk_insert.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE parent (
diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result b/mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result
index a5db90aa965..a7966e36133 100644
--- a/mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_fk_update.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE parent (
diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_locking.result b/mysql-test/suite/galera/r/galera_toi_ddl_locking.result
index 68743c024a0..bbe181ce6f5 100644
--- a/mysql-test/suite/galera/r/galera_toi_ddl_locking.result
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_locking.result
@@ -1,32 +1,46 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_sync_wait = 0;
connection node_1;
-SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
+SET DEBUG_SYNC= 'RESET';
+SET DEBUG_SYNC = 'alter_table_before_open_tables SIGNAL before_open_tables WAIT_FOR continue';
ALTER TABLE t1 ADD COLUMN f2 INTEGER;;
connection node_1a;
-SET SESSION wsrep_sync_wait = 0;
+SET DEBUG_SYNC= 'now WAIT_FOR before_open_tables';
+SET wsrep_retry_autocommit=0;
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
1
SELECT COUNT(*) = 0 FROM t2;
COUNT(*) = 0
1
-INSERT INTO t1 VALUES (1);
-Got one of the listed errors
+INSERT INTO t1 VALUES (1);;
+connection node_1c;
+SET SESSION wsrep_sync_wait = 0;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t2;
+COUNT(*) = 0
+1
INSERT INTO t2 VALUES (1);
COMMIT;;
connection node_1b;
SET SESSION wsrep_sync_wait = 0;
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'Commit';
-COUNT(*) = 1
-1
SELECT COUNT(*) = 0 FROM t2;
COUNT(*) = 0
1
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'Commit';
+COUNT(*) = 1
+1
SET DEBUG_SYNC= 'now SIGNAL continue';
connection node_1a;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_1c;
connection node_1;
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
@@ -34,6 +48,7 @@ COUNT(*) = 0
SELECT COUNT(*) = 1 FROM t2;
COUNT(*) = 1
1
+SET debug_sync='RESET';
connection node_2;
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
@@ -41,9 +56,5 @@ COUNT(*) = 0
SELECT COUNT(*) = 1 FROM t2;
COUNT(*) = 1
1
-connection node_1;
-SET DEBUG_SYNC= 'RESET';
-connection node_1b;
-SET DEBUG_SYNC= 'RESET';
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result b/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result
index 3844fa97d82..5412cd3faee 100644
--- a/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_nonconflicting.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 INTEGER);
connection node_2;
ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 (f1, f2) VALUES (DEFAULT, 123);;
diff --git a/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result b/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result
index 722bb9d9e12..db702b1a59e 100644
--- a/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result
+++ b/mysql-test/suite/galera/r/galera_toi_ddl_sequential.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_toi_drop_database.result b/mysql-test/suite/galera/r/galera_toi_drop_database.result
index 6d88c8ea230..48056c70126 100644
--- a/mysql-test/suite/galera/r/galera_toi_drop_database.result
+++ b/mysql-test/suite/galera/r/galera_toi_drop_database.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE DATABASE database1;
USE database1;
@@ -14,9 +16,9 @@ INSERT INTO t2 (f1) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, te
connection node_2;
DROP DATABASE database1;;
connection node_1;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_1a;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_2;
connection node_1;
SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'database1';
diff --git a/mysql-test/suite/galera/r/galera_toi_ftwrl.result b/mysql-test/suite/galera/r/galera_toi_ftwrl.result
index 0f13e95b689..fdc8b294c1c 100644
--- a/mysql-test/suite/galera/r/galera_toi_ftwrl.result
+++ b/mysql-test/suite/galera/r/galera_toi_ftwrl.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
FLUSH TABLES WITH READ LOCK;
diff --git a/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result b/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result
index f5cc14ed0f1..ee8c826fd18 100644
--- a/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result
+++ b/mysql-test/suite/galera/r/galera_toi_lock_exclusive.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
@@ -8,7 +10,7 @@ connection node_2a;
ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=EXCLUSIVE;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_1;
INSERT INTO t1 VALUES (2, 2);
SELECT COUNT(*) = 2 FROM t1;
diff --git a/mysql-test/suite/galera/r/galera_toi_lock_shared.result b/mysql-test/suite/galera/r/galera_toi_lock_shared.result
index 950c4d83c70..fe1c88075d5 100644
--- a/mysql-test/suite/galera/r/galera_toi_lock_shared.result
+++ b/mysql-test/suite/galera/r/galera_toi_lock_shared.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_toi_truncate.result b/mysql-test/suite/galera/r/galera_toi_truncate.result
index 73285d723c1..081a82e6e7d 100644
--- a/mysql-test/suite/galera/r/galera_toi_truncate.result
+++ b/mysql-test/suite/galera/r/galera_toi_truncate.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
@@ -11,7 +13,7 @@ connection node_1;
TRUNCATE TABLE t1;;
connection node_1;
connection node_2;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_2;
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
diff --git a/mysql-test/suite/galera/r/galera_transaction_read_only.result b/mysql-test/suite/galera/r/galera_transaction_read_only.result
index b388f195fb1..55923f58b65 100644
--- a/mysql-test/suite/galera/r/galera_transaction_read_only.result
+++ b/mysql-test/suite/galera/r/galera_transaction_read_only.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_transaction_replay.result b/mysql-test/suite/galera/r/galera_transaction_replay.result
index 7fd837433d2..272086c4eba 100644
--- a/mysql-test/suite/galera/r/galera_transaction_replay.result
+++ b/mysql-test/suite/galera/r/galera_transaction_replay.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
INSERT INTO t1 VALUES (1, 'a');
INSERT INTO t1 VALUES (2, 'a');
@@ -9,19 +11,73 @@ SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
f1 f2
2 a
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
-SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
connection node_1;
-COMMIT;;
+COMMIT;
connection node_1a;
-SET SESSION wsrep_sync_wait = 0;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+connection node_1;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+wsrep_local_replays
+1
connection node_2;
-UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+DROP TABLE t1;
+connection node_1;
+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;
+f1 f2
+2 a
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+connection node_2;
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
connection node_1;
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
COUNT(*) = 1
@@ -46,22 +102,34 @@ SELECT * FROM t1;
i j
1 0
3 0
+SET AUTOCOMMIT=ON;
PREPARE stmt1 FROM "UPDATE t1 SET j = 1 where i > 0";
connection node_1a;
-SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
-connection node_1;
-EXECUTE stmt1;;
-connection node_1a;
-SET SESSION wsrep_sync_wait = 0;
-SET SESSION wsrep_on = 0;
-SET SESSION wsrep_on = 1;
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
connection node_2;
INSERT INTO t1 VALUES(2,2);
connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+connection node_1;
+SET SESSION wsrep_sync_wait=0;
+EXECUTE stmt1;
connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
connection node_1;
+SET SESSION wsrep_sync_wait=7;
SELECT * FROM t1;
i j
1 1
@@ -74,5 +142,7 @@ i j
2 2
3 1
connection node_1;
+wsrep_local_replays
+1
DEALLOCATE PREPARE stmt1;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_truncate.result b/mysql-test/suite/galera/r/galera_truncate.result
index 4f3d72dbca7..c649d9bbaf9 100644
--- a/mysql-test/suite/galera/r/galera_truncate.result
+++ b/mysql-test/suite/galera/r/galera_truncate.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_truncate_temporary.result b/mysql-test/suite/galera/r/galera_truncate_temporary.result
index 183ebd9d24a..81373bda739 100644
--- a/mysql-test/suite/galera/r/galera_truncate_temporary.result
+++ b/mysql-test/suite/galera/r/galera_truncate_temporary.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TEMPORARY TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
INSERT INTO t1 VALUES (1);
TRUNCATE TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_unicode_identifiers.result b/mysql-test/suite/galera/r/galera_unicode_identifiers.result
index 77848bc751f..5db1be8c910 100644
--- a/mysql-test/suite/galera/r/galera_unicode_identifiers.result
+++ b/mysql-test/suite/galera/r/galera_unicode_identifiers.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET GLOBAL wsrep_sync_wait = 15;
connection node_2;
SET GLOBAL wsrep_sync_wait = 15;
diff --git a/mysql-test/suite/galera/r/galera_unicode_pk.result b/mysql-test/suite/galera/r/galera_unicode_pk.result
index 0e8965a76e3..bb36fd4f369 100644
--- a/mysql-test/suite/galera/r/galera_unicode_pk.result
+++ b/mysql-test/suite/galera/r/galera_unicode_pk.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (
f1 VARCHAR(255) PRIMARY KEY
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -18,7 +20,7 @@ connection node_1;
COMMIT;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SELECT f1 = 'текст2' FROM t1;
f1 = 'текст2'
1
@@ -35,6 +37,6 @@ connection node_2;
COMMIT;
connection node_1;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_update_limit.result b/mysql-test/suite/galera/r/galera_update_limit.result
index 20a94e6f504..30c89a38dff 100644
--- a/mysql-test/suite/galera/r/galera_update_limit.result
+++ b/mysql-test/suite/galera/r/galera_update_limit.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
diff --git a/mysql-test/suite/galera/r/galera_v1_row_events.result b/mysql-test/suite/galera/r/galera_v1_row_events.result
index b0ea2293119..80fe2fb6d8d 100644
--- a/mysql-test/suite/galera/r/galera_v1_row_events.result
+++ b/mysql-test/suite/galera/r/galera_v1_row_events.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_var_OSU_method.result b/mysql-test/suite/galera/r/galera_var_OSU_method.result
index 18e8bd2271a..2b0a713e86b 100644
--- a/mysql-test/suite/galera/r/galera_var_OSU_method.result
+++ b/mysql-test/suite/galera/r/galera_var_OSU_method.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
connection node_1;
SET SESSION wsrep_OSU_method = "RSU";
diff --git a/mysql-test/suite/galera/r/galera_var_OSU_method2.result b/mysql-test/suite/galera/r/galera_var_OSU_method2.result
index 0e3751645a8..ca4f617d903 100644
--- a/mysql-test/suite/galera/r/galera_var_OSU_method2.result
+++ b/mysql-test/suite/galera/r/galera_var_OSU_method2.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
connection node_1;
SET SESSION wsrep_OSU_method = "TOI";
diff --git a/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result b/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result
index ba117b4c2d5..86c30fa4b23 100644
--- a/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result
+++ b/mysql-test/suite/galera/r/galera_var_auto_inc_control_off.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET GLOBAL wsrep_auto_increment_control = OFF;
SET GLOBAL auto_increment_increment = 1;
@@ -59,7 +61,7 @@ connection node_1a;
COMMIT;
connection node_2a;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
connection node_1a;
SELECT * FROM t1;
f1 node
diff --git a/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result b/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result
index b71cf4c831d..48c649b66a8 100644
--- a/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result
+++ b/mysql-test/suite/galera/r/galera_var_auto_inc_control_on.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, node VARCHAR(10)) ENGINE=InnoDB;
SELECT @@auto_increment_increment = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size');
diff --git a/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result b/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result
index ca3844bf6bf..f5472aa931f 100644
--- a/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result
+++ b/mysql-test/suite/galera/r/galera_var_certify_nonPK_off.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET GLOBAL wsrep_certify_nonPK = OFF;
connection node_2;
SET GLOBAL wsrep_certify_nonPK = OFF;
diff --git a/mysql-test/suite/galera/r/galera_var_cluster_address.result b/mysql-test/suite/galera/r/galera_var_cluster_address.result
index 378d8ca84f5..8c1070e43ce 100644
--- a/mysql-test/suite/galera/r/galera_var_cluster_address.result
+++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result
@@ -1,7 +1,11 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_2;
SET GLOBAL wsrep_cluster_address = 'foo://';
+SHOW STATUS;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
SET SESSION wsrep_sync_wait=0;
SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
COUNT(*) > 0
@@ -11,7 +15,7 @@ Variable_name Value
wsrep_ready OFF
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
-wsrep_cluster_status non-Primary
+wsrep_cluster_status Disconnected
SHOW STATUS LIKE 'wsrep_local_state';
Variable_name Value
wsrep_local_state 0
@@ -39,7 +43,7 @@ CALL mtr.add_suppression("Failed to initialize backend using 'foo");
CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo");
CALL mtr.add_suppression("gcs connect failed: Socket type not supported");
CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7");
-CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)");
+CALL mtr.add_suppression("gcs_caused\\(\\) returned -[0-9]+ \\(Software caused connection abort\\)");
CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110");
CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)");
CALL mtr.add_suppression("gcs connect failed: Connection timed out");
diff --git a/mysql-test/suite/galera/r/galera_var_desync_on.result b/mysql-test/suite/galera/r/galera_var_desync_on.result
index 26798e51926..6a2e501eee2 100644
--- a/mysql-test/suite/galera/r/galera_var_desync_on.result
+++ b/mysql-test/suite/galera/r/galera_var_desync_on.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_var_dirty_reads.result b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
index 049aa5be3cc..33536d95186 100644
--- a/mysql-test/suite/galera/r/galera_var_dirty_reads.result
+++ b/mysql-test/suite/galera/r/galera_var_dirty_reads.result
@@ -1,6 +1,6 @@
-connection node_1;
connection node_2;
connection node_1;
+connection node_1;
connection node_2;
connection node_2;
CREATE TABLE t1(i INT) ENGINE=INNODB;
@@ -16,7 +16,7 @@ Variable_name Value
wsrep_ready OFF
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
-wsrep_cluster_status non-Primary
+wsrep_cluster_status Disconnected
SELECT * FROM t1;
ERROR 08S01: WSREP has not yet prepared node for application use
SELECT 1 FROM t1;
@@ -52,4 +52,3 @@ i
DROP TABLE t1;
disconnect node_2;
disconnect node_1;
-# End of test
diff --git a/mysql-test/suite/galera/r/galera_var_fkchecks.result b/mysql-test/suite/galera/r/galera_var_fkchecks.result
index 8b1b913a584..42f8085ee1a 100644
--- a/mysql-test/suite/galera/r/galera_var_fkchecks.result
+++ b/mysql-test/suite/galera/r/galera_var_fkchecks.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE parent (
id INT PRIMARY KEY,
KEY (id)
diff --git a/mysql-test/suite/galera/r/galera_var_gtid_domain_id.result b/mysql-test/suite/galera/r/galera_var_gtid_domain_id.result
index 1a8733e2e1a..d2faf5ff463 100644
--- a/mysql-test/suite/galera/r/galera_var_gtid_domain_id.result
+++ b/mysql-test/suite/galera/r/galera_var_gtid_domain_id.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
# On node_1
connection node_1;
list of GTID variables :
diff --git a/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result b/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result
new file mode 100644
index 00000000000..48c845a4c2b
--- /dev/null
+++ b/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result
@@ -0,0 +1,186 @@
+connection node_2;
+connection node_1;
+connection node_2;
+SET GLOBAL wsrep_ignore_apply_errors = 1;
+connection node_1;
+SET GLOBAL wsrep_on = OFF;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = ON;
+DROP TABLE t1;
+SET GLOBAL wsrep_on = OFF;
+CREATE SCHEMA s1;
+SET GLOBAL wsrep_on = ON;
+DROP SCHEMA s1;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+CREATE INDEX idx1 ON t1 (f1);
+SET GLOBAL wsrep_on = ON;
+DROP INDEX idx1 ON t1;
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+CREATE INDEX idx1 ON t1 (f1);
+SET GLOBAL wsrep_on = ON;
+ALTER TABLE t1 DROP INDEX idx1;
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+SET GLOBAL wsrep_on = ON;
+ALTER TABLE t1 DROP COLUMN f2;
+DROP TABLE t1;
+connection node_2;
+SET GLOBAL wsrep_ignore_apply_errors = 2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_on = ON;
+DELETE FROM t1 WHERE f1 = 1;
+connection node_1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (2);
+SET GLOBAL wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_on = ON;
+START TRANSACTION;
+INSERT INTO t1 VALUES (3);
+DELETE FROM t1 WHERE f1 = 1;
+DELETE FROM t1 WHERE f1 = 2;
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+connection node_2;
+SET SESSION wsrep_on = OFF;
+DELETE FROM t1 WHERE f1 = 3;
+SET SESSION wsrep_on = ON;
+connection node_1;
+DELETE FROM t1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+VARIABLE_VALUE = 'Primary'
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+connection node_2;
+SET SESSION wsrep_on = OFF;
+DELETE FROM t1 WHERE f1 = 3;
+SET SESSION wsrep_on = ON;
+connection node_1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+DELETE FROM t1 WHERE f1 = 1;
+DELETE FROM t1 WHERE f1 = 2;
+DELETE FROM t1 WHERE f1 = 3;
+DELETE FROM t1 WHERE f1 = 4;
+DELETE FROM t1 WHERE f1 = 5;
+COMMIT;
+SET AUTOCOMMIT=ON;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+VARIABLE_VALUE = 'Primary'
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+connection node_2;
+SET SESSION wsrep_on = OFF;
+DELETE FROM t2 WHERE f1 = 2;
+DELETE FROM t1 WHERE f1 = 3;
+SET SESSION wsrep_on = ON;
+connection node_1;
+DELETE t1, t2 FROM t1 JOIN t2 WHERE t1.f1 = t2.f1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+VARIABLE_VALUE = 'Primary'
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1,t2;
+connection node_1;
+CREATE TABLE parent (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
+INSERT INTO parent VALUES (1),(2),(3);
+CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE) ENGINE=INNODB;
+INSERT INTO child VALUES (1,1),(2,2),(3,3);
+connection node_2;
+SET SESSION wsrep_on = OFF;
+DELETE FROM child WHERE parent_id = 2;
+SET SESSION wsrep_on = ON;
+connection node_1;
+DELETE FROM parent;
+SELECT COUNT(*) = 0 FROM parent;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM child;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+VARIABLE_VALUE = 'Primary'
+1
+SELECT COUNT(*) = 0 FROM parent;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM child;
+COUNT(*) = 0
+1
+DROP TABLE child, parent;
+connection node_2;
+SET GLOBAL wsrep_ignore_apply_errors = 4;
+connection node_2;
+SET GLOBAL wsrep_on = OFF;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = ON;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER, f2 INTEGER);
+DROP TABLE t1;
+connection node_2;
+SET GLOBAL wsrep_ignore_apply_errors = 7;
+CALL mtr.add_suppression("Can't find record in 't.*'");
+CALL mtr.add_suppression("Slave SQL: Could not execute Delete_rows event");
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test.t1'' on query. Default database: 'test'. Query: 'DROP TABLE t1', Error_code: 1051");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't drop database 's1'; database doesn't exist' on query. Default database: 'test'. Query: 'DROP SCHEMA s1', Error_code: 1008");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't DROP 'idx1'; check that column/key exists' on query. Default database: 'test'. Query: 'DROP INDEX idx1 ON t1', Error_code: 1091");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't DROP 'idx1'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t1 DROP INDEX idx1', Error_code: 1091");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't DROP 'f2'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t1 DROP COLUMN f2', Error_code: 1091");
+CALL mtr.add_suppression("Slave SQL: Error 'Table 't1' already exists' on query.");
diff --git a/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result b/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result
index 4db4e539c50..f5ec473fea4 100644
--- a/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result
+++ b/mysql-test/suite/galera/r/galera_var_innodb_disallow_writes.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1a;
SET SESSION wsrep_sync_wait = 0;
connection node_1;
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
index 3e451abbed1..7c5fd44356e 100644
--- a/mysql-test/suite/galera/r/galera_var_load_data_splitting.result
+++ b/mysql-test/suite/galera/r/galera_var_load_data_splitting.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
SET GLOBAL wsrep_load_data_splitting = TRUE;
diff --git a/mysql-test/suite/galera/r/galera_var_log_bin.result b/mysql-test/suite/galera/r/galera_var_log_bin.result
index b0ea2293119..80fe2fb6d8d 100644
--- a/mysql-test/suite/galera/r/galera_var_log_bin.result
+++ b/mysql-test/suite/galera/r/galera_var_log_bin.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/galera_var_max_ws_rows.result b/mysql-test/suite/galera/r/galera_var_max_ws_rows.result
index 6bf67a3fb60..16e868f0485 100644
--- a/mysql-test/suite/galera/r/galera_var_max_ws_rows.result
+++ b/mysql-test/suite/galera/r/galera_var_max_ws_rows.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/galera_var_max_ws_size.result b/mysql-test/suite/galera/r/galera_var_max_ws_size.result
index 53bac04fa86..89c9698eed4 100644
--- a/mysql-test/suite/galera/r/galera_var_max_ws_size.result
+++ b/mysql-test/suite/galera/r/galera_var_max_ws_size.result
@@ -1,8 +1,10 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine=InnoDB;
SET GLOBAL wsrep_max_ws_size = 1024;
INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 1024));
-ERROR HY000: Got error 90 "Message too long" during COMMIT
+ERROR HY000: Got error 5 "Input/output error" during COMMIT
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
1
diff --git a/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result b/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result
index 202633a020e..d7a38d24722 100644
--- a/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result
+++ b/mysql-test/suite/galera/r/galera_var_mysql_replication_bundle.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
SET GLOBAL wsrep_mysql_replication_bundle = 2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_var_node_address.result b/mysql-test/suite/galera/r/galera_var_node_address.result
index 7696d1e3f4f..cf45861c8ad 100644
--- a/mysql-test/suite/galera/r/galera_var_node_address.result
+++ b/mysql-test/suite/galera/r/galera_var_node_address.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
call mtr.add_suppression("WSREP: Stray state UUID msg: .* current group state WAIT_STATE_UUID .*");
call mtr.add_suppression("WSREP: Protocol violation. JOIN message sender .* is not in state transfer (.*). Message ignored.");
call mtr.add_suppression("WSREP: Sending JOIN failed: -[0-9]+ (Transport endpoint is not connected). Will retry in new primary component.");
diff --git a/mysql-test/suite/galera/r/galera_var_reject_queries.result b/mysql-test/suite/galera/r/galera_var_reject_queries.result
index caf98566595..b95e5773830 100644
--- a/mysql-test/suite/galera/r/galera_var_reject_queries.result
+++ b/mysql-test/suite/galera/r/galera_var_reject_queries.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER);
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result
index 382466b1387..8968f89d11b 100644
--- a/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result
+++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_off.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SET GLOBAL wsrep_replicate_myisam = FALSE;
CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=MyISAM;
INSERT INTO t1 VALUES (1);
diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result
index 87f8862df7e..716af033e7a 100644
--- a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result
+++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_1;
SET GLOBAL wsrep_replicate_myisam = TRUE;
diff --git a/mysql-test/suite/galera/r/galera_var_retry_autocommit.result b/mysql-test/suite/galera/r/galera_var_retry_autocommit.result
index c0bf6035184..b8943464cb7 100644
--- a/mysql-test/suite/galera/r/galera_var_retry_autocommit.result
+++ b/mysql-test/suite/galera/r/galera_var_retry_autocommit.result
@@ -1,15 +1,17 @@
+connection node_2;
+connection node_1;
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 0;
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue';
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue';
INSERT INTO t1 (f1) VALUES (2);
connection node_1a;
-SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
connection node_2;
TRUNCATE TABLE t1;
connection node_1;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
1
@@ -18,10 +20,10 @@ DROP TABLE t1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 1;
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue';
-INSERT INTO t1 (f1) VALUES (2);
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue';
+INSERT INTO t1 (f1) VALUES (3);
connection node_1a;
-SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
connection node_2;
TRUNCATE TABLE t1;
connection node_1;
@@ -34,10 +36,10 @@ connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 1;
SET GLOBAL debug_dbug = '+d,sync.wsrep_retry_autocommit';
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue EXECUTE 2';
-INSERT INTO t1 VALUES (2);;
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue EXECUTE 2';
+INSERT INTO t1 VALUES (4);;
connection node_1a;
-SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
connection node_2;
TRUNCATE TABLE t1;
connection node_1a;
@@ -45,7 +47,7 @@ SET DEBUG_SYNC = 'now WAIT_FOR wsrep_retry_autocommit_reached';
SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
1
-SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue WAIT_FOR before_cert';
connection node_2;
TRUNCATE TABLE t1;
connection node_1a;
@@ -53,7 +55,7 @@ SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0
1
connection node_1;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
SET DEBUG_SYNC = 'RESET';
SET GLOBAL debug_dbug = NULL;
DROP TABLE t1;
@@ -61,8 +63,8 @@ connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 64;
SET GLOBAL debug_dbug = '+d,sync.wsrep_retry_autocommit';
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue EXECUTE 64';
-INSERT INTO t1 VALUES (2);
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue EXECUTE 64';
+INSERT INTO t1 VALUES (5);
connection node_1;
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
diff --git a/mysql-test/suite/galera/r/galera_var_slave_threads.result b/mysql-test/suite/galera/r/galera_var_slave_threads.result
index c28cc091ae9..168b45154b8 100644
--- a/mysql-test/suite/galera/r/galera_var_slave_threads.result
+++ b/mysql-test/suite/galera/r/galera_var_slave_threads.result
@@ -1,3 +1,7 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
connection node_1;
CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
CREATE TABLE t2 (f1 INT AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB;
@@ -13,6 +17,9 @@ SELECT @@wsrep_slave_threads = 1;
@@wsrep_slave_threads = 1
1
SET GLOBAL wsrep_slave_threads = 1;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND COMMAND != 'Daemon';
+COUNT(*)
+3
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
COUNT(*)
1
@@ -20,8 +27,11 @@ SET GLOBAL wsrep_slave_threads = 64;
connection node_1;
INSERT INTO t1 VALUES (1);
connection node_2;
-SELECT COUNT(*) = 1 FROM t1;
-COUNT(*) = 1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
+COUNT(*)
1
SET GLOBAL wsrep_slave_threads = 1;
connection node_1;
@@ -32,26 +42,42 @@ COUNT(*)
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
COUNT(*)
1
+SET GLOBAL wsrep_slave_threads = 5;
SET GLOBAL wsrep_slave_threads = 1;
-DROP TABLE t1;
-DROP TABLE t2;
-#
-# lp:1372840 - Changing wsrep_slave_threads causes future connections to hang
-#
+connection node_2;
+Shutting down server ...
+connection node_1;
+show status like 'wsrep_cluster_size';
+Variable_name Value
+wsrep_cluster_size 1
+SET GLOBAL wsrep_slave_threads = 6;
+SET GLOBAL wsrep_slave_threads = 1;
+SET GLOBAL wsrep_cluster_address='';
+SET GLOBAL wsrep_cluster_address='gcomm://';
+SET GLOBAL wsrep_slave_threads = 10;
+connection node_2;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND COMMAND != 'Daemon';
+COUNT(*)
+3
connection node_1;
-CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY) ENGINE=INNODB;
+SET GLOBAL wsrep_slave_threads = 1;
connection node_2;
-SET GLOBAL wsrep_slave_threads = 4;
SET GLOBAL wsrep_slave_threads = 1;
connection node_1;
-INSERT INTO t1 VALUES (DEFAULT);
-INSERT INTO t1 VALUES (DEFAULT);
-INSERT INTO t1 VALUES (DEFAULT);
-DROP TABLE t1;
connection node_2;
-SELECT NAME FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t%';
-NAME
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
-COUNT(*) = 1
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+192
+connection node_1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
1
+SELECT COUNT(*) FROM t2;
+COUNT(*)
+192
+DROP TABLE t1;
+DROP TABLE t2;
# End of tests
diff --git a/mysql-test/suite/galera/r/galera_var_sst_auth.result b/mysql-test/suite/galera/r/galera_var_sst_auth.result
index 1db83197870..6a5683e2633 100644
--- a/mysql-test/suite/galera/r/galera_var_sst_auth.result
+++ b/mysql-test/suite/galera/r/galera_var_sst_auth.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-10492: Assertion failure on shutdown when wsrep_sst_auth set in config
#
diff --git a/mysql-test/suite/galera/r/galera_var_sync_wait.result b/mysql-test/suite/galera/r/galera_var_sync_wait.result
index 3dfe902767c..80fbd3f3e05 100644
--- a/mysql-test/suite/galera/r/galera_var_sync_wait.result
+++ b/mysql-test/suite/galera/r/galera_var_sync_wait.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-10161: wsrep_sync_wait not enabled when set to 1 in config file
#
diff --git a/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result b/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result
index 36340f505ff..5323bc9bf60 100644
--- a/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result
+++ b/mysql-test/suite/galera/r/galera_var_wsrep_on_off.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
SET SESSION wsrep_on = FALSE;
diff --git a/mysql-test/suite/galera/r/galera_wan.result b/mysql-test/suite/galera/r/galera_wan.result
index 41b915fa5bf..bc4113ffb1c 100644
--- a/mysql-test/suite/galera/r/galera_wan.result
+++ b/mysql-test/suite/galera/r/galera_wan.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CALL mtr.add_suppression("WSREP: Stray state UUID msg:.*");
CALL mtr.add_suppression("WSREP: Sending JOIN failed:.*");
CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside");
diff --git a/mysql-test/suite/galera/r/galera_wan_restart_ist.result b/mysql-test/suite/galera/r/galera_wan_restart_ist.result
index 8a2a7d0818e..7b87d534d92 100644
--- a/mysql-test/suite/galera/r/galera_wan_restart_ist.result
+++ b/mysql-test/suite/galera/r/galera_wan_restart_ist.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_wan_restart_sst.result b/mysql-test/suite/galera/r/galera_wan_restart_sst.result
index 71786cdd023..1296744a9c1 100644
--- a/mysql-test/suite/galera/r/galera_wan_restart_sst.result
+++ b/mysql-test/suite/galera/r/galera_wan_restart_sst.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 4
1
diff --git a/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result b/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result
index 99c680c7b12..e01825fd944 100644
--- a/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result
+++ b/mysql-test/suite/galera/r/galera_wsrep_desync_wsrep_on.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
diff --git a/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result b/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result
index fa49d8c57c2..59883f1ca7e 100644
--- a/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result
+++ b/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (
f1 VARCHAR(255) PRIMARY KEY
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -20,6 +22,6 @@ connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2a;
connection node_2;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
include/assert_grep.inc [cluster conflict due to high priority abort for threads]
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result b/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result
index ca388496794..8edf1a02e9d 100644
--- a/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result
+++ b/mysql-test/suite/galera/r/galera_wsrep_new_cluster.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
VARIABLE_VALUE = 'Primary'
1
diff --git a/mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result b/mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result
index f19dc40205b..0f7cd134156 100644
--- a/mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result
+++ b/mysql-test/suite/galera/r/galera_wsrep_provider_options_syntax.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
call mtr.add_suppression("WSREP\: Unknown parameter 'gmcasts\.segment'");
call mtr.add_suppression("WSREP\: Set options returned 7");
SET GLOBAL wsrep_provider_options="gmcasts.segment=1";
diff --git a/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result b/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result
index d56d9340474..7a645407004 100644
--- a/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result
+++ b/mysql-test/suite/galera/r/galera_wsrep_provider_unset_set.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/galera_zero_length_column.result b/mysql-test/suite/galera/r/galera_zero_length_column.result
index 572d94d6756..fa29264704f 100644
--- a/mysql-test/suite/galera/r/galera_zero_length_column.result
+++ b/mysql-test/suite/galera/r/galera_zero_length_column.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY , f2 VARCHAR(0)) ENGINE=InnoDB;
CREATE TABLE t2 (f1 VARCHAR(0)) ENGINE=InnoDB;
diff --git a/mysql-test/suite/galera/r/grant.result b/mysql-test/suite/galera/r/grant.result
index bbcbb06a685..56f56d3b023 100644
--- a/mysql-test/suite/galera/r/grant.result
+++ b/mysql-test/suite/galera/r/grant.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV#6266: Changing password fails on galera cluster
#
diff --git a/mysql-test/suite/galera/r/lp1276424.result b/mysql-test/suite/galera/r/lp1276424.result
index 363758e0d66..be27ee5374f 100644
--- a/mysql-test/suite/galera/r/lp1276424.result
+++ b/mysql-test/suite/galera/r/lp1276424.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INT DEFAULT NULL, UNIQUE KEY i1 (f1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (NULL);
INSERT INTO t1 VALUES (NULL);
diff --git a/mysql-test/suite/galera/r/lp1347768.result b/mysql-test/suite/galera/r/lp1347768.result
index 7beb167d538..49c8894c081 100644
--- a/mysql-test/suite/galera/r/lp1347768.result
+++ b/mysql-test/suite/galera/r/lp1347768.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE `r8kmb_redirect_links` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`old_url` varchar(255) DEFAULT NULL,
diff --git a/mysql-test/suite/galera/r/lp1376747-2.result b/mysql-test/suite/galera/r/lp1376747-2.result
index b85e130f4f4..5e5b5be6c86 100644
--- a/mysql-test/suite/galera/r/lp1376747-2.result
+++ b/mysql-test/suite/galera/r/lp1376747-2.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/lp1376747-3.result b/mysql-test/suite/galera/r/lp1376747-3.result
index a2c55b5f1f6..62893b85bcf 100644
--- a/mysql-test/suite/galera/r/lp1376747-3.result
+++ b/mysql-test/suite/galera/r/lp1376747-3.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/lp1376747-4.result b/mysql-test/suite/galera/r/lp1376747-4.result
index f1d32aa8f69..d6884cc3746 100644
--- a/mysql-test/suite/galera/r/lp1376747-4.result
+++ b/mysql-test/suite/galera/r/lp1376747-4.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
diff --git a/mysql-test/suite/galera/r/lp1376747.result b/mysql-test/suite/galera/r/lp1376747.result
index 16d4fa3fc52..1b9dd545409 100644
--- a/mysql-test/suite/galera/r/lp1376747.result
+++ b/mysql-test/suite/galera/r/lp1376747.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_2;
diff --git a/mysql-test/suite/galera/r/lp1438990.result b/mysql-test/suite/galera/r/lp1438990.result
index d48d2435faa..a324121d7da 100644
--- a/mysql-test/suite/galera/r/lp1438990.result
+++ b/mysql-test/suite/galera/r/lp1438990.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
diff --git a/mysql-test/suite/galera/r/lp959512.result b/mysql-test/suite/galera/r/lp959512.result
index 55adfa360b0..589030002db 100644
--- a/mysql-test/suite/galera/r/lp959512.result
+++ b/mysql-test/suite/galera/r/lp959512.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
DROP TABLE IF EXISTS variable;
Warnings:
Note 1051 Unknown table 'test.variable'
diff --git a/mysql-test/suite/galera/r/mdev_10518.result b/mysql-test/suite/galera/r/mdev_10518.result
index 4ccd5fd1d23..252aa244f77 100644
--- a/mysql-test/suite/galera/r/mdev_10518.result
+++ b/mysql-test/suite/galera/r/mdev_10518.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
# On node_1
connection node_1;
list of GTID variables :
diff --git a/mysql-test/suite/galera/r/mdev_9290.result b/mysql-test/suite/galera/r/mdev_9290.result
index 276ab9e8ecb..d8fc35b02f4 100644
--- a/mysql-test/suite/galera/r/mdev_9290.result
+++ b/mysql-test/suite/galera/r/mdev_9290.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-9290 : InnoDB: Assertion failure in file trx0sys.cc line 353
# InnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#110.result b/mysql-test/suite/galera/r/mysql-wsrep#110.result
index 6d4031d71cd..344185f4f4e 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#110.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#110.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY);
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#198.result b/mysql-test/suite/galera/r/mysql-wsrep#198.result
index 33f36d407db..5b569ffae27 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#198.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#198.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
connection node_2;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#201.result b/mysql-test/suite/galera/r/mysql-wsrep#201.result
index fe5725cab27..e55c38ea7cc 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#201.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#201.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (id INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (DEFAULT);
connection node_2;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#216.result b/mysql-test/suite/galera/r/mysql-wsrep#216.result
new file mode 100644
index 00000000000..b07589d0c04
--- /dev/null
+++ b/mysql-test/suite/galera/r/mysql-wsrep#216.result
@@ -0,0 +1,11 @@
+SET GLOBAL wsrep_debug = ON;
+CREATE USER u1 IDENTIFIED BY 'plaintext_password';
+CREATE USER u1 IDENTIFIED BY 'plaintext_password';
+ERROR HY000: Operation CREATE USER failed for 'u1'@'%'
+0
+0
+2
+1
+DROP USER u1;
+CALL mtr.add_suppression('Operation CREATE USER failed');
+ \ No newline at end of file
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#237.result b/mysql-test/suite/galera/r/mysql-wsrep#237.result
index 19503dd5781..bc348613d25 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#237.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#237.result
@@ -1,6 +1,8 @@
+connection node_2;
+connection node_1;
CREATE TABLE t (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
connection node_1;
-SET DEBUG_SYNC = 'wsrep_before_replication WAIT_FOR continue';
+SET DEBUG_SYNC = 'wsrep_before_certification WAIT_FOR continue';
INSERT INTO t values (1);;
connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
connection node_1a;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#247.result b/mysql-test/suite/galera/r/mysql-wsrep#247.result
index e59c6d1a299..704f0ba923c 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#247.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#247.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
SET GLOBAL wsrep_desync=1;
SET wsrep_OSU_method=RSU;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#31.result b/mysql-test/suite/galera/r/mysql-wsrep#31.result
index 1092f4ddb0c..d1d2861ec3a 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#31.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#31.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#33.result b/mysql-test/suite/galera/r/mysql-wsrep#33.result
index 6a5251204b9..5589faad8b1 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#33.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#33.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
Setting SST method to mysqldump ...
@@ -56,6 +58,9 @@ INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
INSERT INTO t1 VALUES ('node1_to_be_rollbacked_after');
connection node_2;
Loading wsrep provider ...
+disconnect node_2;
+connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
INSERT INTO t1 VALUES ('node2_committed_after');
@@ -114,5 +119,6 @@ CALL mtr.add_suppression("Can't open and lock time zone table");
CALL mtr.add_suppression("Can't open and lock privilege tables");
CALL mtr.add_suppression("Info table is not ready to be used");
CALL mtr.add_suppression("Native table .* has the wrong structure");
+CALL mtr.add_suppression("Table \'mysql.gtid_slave_pos\' doesn\'t exist");
connection node_2;
Restarting server ...
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#332.result b/mysql-test/suite/galera/r/mysql-wsrep#332.result
index 8667f5e9c41..565979a93ae 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#332.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#332.result
@@ -1,26 +1,38 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1;
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER) ENGINE=INNODB;
INSERT INTO p VALUES (1, 0);
INSERT INTO p VALUES (2, 0);
INSERT INTO c VALUES (1, 1);
INSERT INTO c VALUES (2, 2);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
UPDATE p SET f1 = f1 + 100;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
ALTER TABLE c ADD FOREIGN KEY (p_id) REFERENCES p(f1);
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
SELECT * FROM p;
f1 f2
1 0
@@ -31,6 +43,7 @@ f1 p_id
2 2
DROP TABLE c;
DROP TABLE p;
+connection node_1;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id1 INTEGER, p_id2 INTEGER) ENGINE=INNODB;
@@ -38,23 +51,31 @@ INSERT INTO p1 VALUES (1, 0), (2, 0);
INSERT INTO p2 VALUES (1, 0), (2, 0);
INSERT INTO c VALUES (1, 1, 1);
INSERT INTO c VALUES (2, 2, 2);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
UPDATE p1 SET f1 = f1 + 100;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
ALTER TABLE c ADD FOREIGN KEY (p_id1) REFERENCES p1(f1), ADD FOREIGN KEY (p_id2) REFERENCES p2(f1);
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
SELECT * FROM p1;
f1 f2
1 0
@@ -70,6 +91,7 @@ f1 p_id1 p_id2
DROP TABLE c;
DROP TABLE p1;
DROP TABLE p2;
+connection node_1;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id1 INTEGER, p_id2 INTEGER) ENGINE=INNODB;
@@ -77,23 +99,31 @@ INSERT INTO p1 VALUES (1, 0), (2, 0);
INSERT INTO p2 VALUES (1, 0), (2, 0);
INSERT INTO c VALUES (1, 1, 1);
INSERT INTO c VALUES (2, 2, 2);
+connection node_1;
SET AUTOCOMMIT=ON;
START TRANSACTION;
UPDATE p2 SET f1 = f1 + 100;
+connection node_1a;
SET SESSION wsrep_sync_wait = 0;
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
ALTER TABLE c ADD FOREIGN KEY (p_id1) REFERENCES p1(f1), ADD FOREIGN KEY (p_id2) REFERENCES p2(f1);
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'dbug=';
-SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
COMMIT;
+connection node_1a;
SET SESSION wsrep_on = 0;
SET SESSION wsrep_on = 1;
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
-SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_2;
SELECT * FROM p1;
f1 f2
1 0
diff --git a/mysql-test/suite/galera/r/mysql-wsrep#90.result b/mysql-test/suite/galera/r/mysql-wsrep#90.result
index 0b8f55e6219..b0fa06ffaf8 100644
--- a/mysql-test/suite/galera/r/mysql-wsrep#90.result
+++ b/mysql-test/suite/galera/r/mysql-wsrep#90.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
connection node_1;
SET GLOBAL wsrep_OSU_method = "RSU";
diff --git a/mysql-test/suite/galera/r/partition.result b/mysql-test/suite/galera/r/partition.result
index bdf6df25589..e34028ab04f 100644
--- a/mysql-test/suite/galera/r/partition.result
+++ b/mysql-test/suite/galera/r/partition.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV#4953 Galera: DELETE from a partitioned table is not replicated
#
@@ -123,7 +125,7 @@ SELECT COUNT(*) FROM t1;
COUNT(*)
20002
wsrep_last_committed_diff
-1
+AS_EXPECTED_3_or_5
DROP TABLE t1;
# Case 2: wsrep_load_data_splitting = ON & LOAD DATA with 101 entries.
connection node_1;
@@ -148,7 +150,7 @@ SELECT COUNT(*) FROM t1;
COUNT(*)
20002
wsrep_last_committed_diff
-1
+AS_EXPECTED_1_or_2
DROP TABLE t1;
connection node_1;
SET GLOBAL wsrep_load_data_splitting = 1;;
diff --git a/mysql-test/suite/galera/r/pxc-421.result b/mysql-test/suite/galera/r/pxc-421.result
index a317b3e40e1..058af15c098 100644
--- a/mysql-test/suite/galera/r/pxc-421.result
+++ b/mysql-test/suite/galera/r/pxc-421.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_1;
diff --git a/mysql-test/suite/galera/r/query_cache.result b/mysql-test/suite/galera/r/query_cache.result
index 8592a68141c..5dabd38a982 100644
--- a/mysql-test/suite/galera/r/query_cache.result
+++ b/mysql-test/suite/galera/r/query_cache.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
# Execute FLUSH/RESET commands.
# On node-1
diff --git a/mysql-test/suite/galera/r/rename.result b/mysql-test/suite/galera/r/rename.result
index a7ec431657b..3ad715fa38c 100644
--- a/mysql-test/suite/galera/r/rename.result
+++ b/mysql-test/suite/galera/r/rename.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-8598 : Failed MySQL DDL commands and Galera replication
#
diff --git a/mysql-test/suite/galera/r/rpl_row_annotate.result b/mysql-test/suite/galera/r/rpl_row_annotate.result
index 23de06f015b..61fa2bc286c 100644
--- a/mysql-test/suite/galera/r/rpl_row_annotate.result
+++ b/mysql-test/suite/galera/r/rpl_row_annotate.result
@@ -1,9 +1,15 @@
+connection node_2;
+connection node_1;
# On node_2
connection node_2;
+SET GLOBAL wsrep_on=OFF;
RESET MASTER;
+SET GLOBAL wsrep_on=ON;
# On node_1
connection node_1;
+SET GLOBAL wsrep_on=OFF;
RESET MASTER;
+SET GLOBAL wsrep_on=ON;
CREATE TABLE t1(i INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(1);
DELETE FROM t1 WHERE i = 1;
@@ -68,6 +74,4 @@ mysqld-bin.000001 # Table_map 2 # table_id: # (test.t1)
mysqld-bin.000001 # Delete_rows_v1 2 # table_id: # flags: STMT_END_F
mysqld-bin.000001 # Xid 2 # COMMIT /* xid= */
DROP TABLE t1;
-disconnect node_2;
-disconnect node_1;
# End of test
diff --git a/mysql-test/suite/galera/r/sql_log_bin.result b/mysql-test/suite/galera/r/sql_log_bin.result
index c175a0a0e7a..6efd70ca8b8 100644
--- a/mysql-test/suite/galera/r/sql_log_bin.result
+++ b/mysql-test/suite/galera/r/sql_log_bin.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
# On node_1
connection node_1;
diff --git a/mysql-test/suite/galera/r/unique_key.result b/mysql-test/suite/galera/r/unique_key.result
index 9f1fc858389..bb7e22014d9 100644
--- a/mysql-test/suite/galera/r/unique_key.result
+++ b/mysql-test/suite/galera/r/unique_key.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV#5552 Deadlock when inserting NULL column value in column with
# UNIQUE index
diff --git a/mysql-test/suite/galera/r/versioning_trx_id.result b/mysql-test/suite/galera/r/versioning_trx_id.result
index f15916e51a5..232cca202c0 100644
--- a/mysql-test/suite/galera/r/versioning_trx_id.result
+++ b/mysql-test/suite/galera/r/versioning_trx_id.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
connection node_1;
create table t1 (a int, s bigint unsigned as row start, e bigint unsigned as row end, period for system_time(s,e)) engine=InnoDB with system versioning;
diff --git a/mysql-test/suite/galera/r/view.result b/mysql-test/suite/galera/r/view.result
index f8da811f9cc..45d5b422f3f 100644
--- a/mysql-test/suite/galera/r/view.result
+++ b/mysql-test/suite/galera/r/view.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
#
# MDEV-7222: Cluster Node Crash at CREATE DEFINER statement
#
diff --git a/mysql-test/suite/galera/r/wsrep_trx_fragment_size_sr.result b/mysql-test/suite/galera/r/wsrep_trx_fragment_size_sr.result
new file mode 100644
index 00000000000..4139ecd6472
--- /dev/null
+++ b/mysql-test/suite/galera/r/wsrep_trx_fragment_size_sr.result
@@ -0,0 +1,15 @@
+connection node_2;
+connection node_1;
+SELECT variable_value FROM information_schema.session_variables
+WHERE variable_name = 'wsrep_trx_fragment_size';
+variable_value
+0
+SET SESSION wsrep_trx_fragment_size = 0;
+SET SESSION wsrep_trx_fragment_size = 123;
+SELECT variable_value FROM information_schema.global_variables
+WHERE variable_name = 'wsrep_trx_fragment_size';
+variable_value
+0
+SET GLOBAL wsrep_trx_fragment_size = 0;
+SET GLOBAL wsrep_trx_fragment_size = 123;
+SET GLOBAL wsrep_trx_fragment_size = default;
diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm
index 1aabc697db1..a9fd1568f9c 100644
--- a/mysql-test/suite/galera/suite.pm
+++ b/mysql-test/suite/galera/suite.pm
@@ -9,9 +9,9 @@ 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/lib64/galera-3/libgalera_smm.so",
+ "/usr/lib64/galera-4/libgalera_smm.so",
"/usr/lib64/galera/libgalera_smm.so",
- "/usr/lib/galera-3/libgalera_smm.so",
+ "/usr/lib/galera-4/libgalera_smm.so",
"/usr/lib/galera/libgalera_smm.so";
return "No wsrep provider library" unless -f $provider;
@@ -81,6 +81,8 @@ push @::global_suppressions,
qr|WSREP: .*core_handle_uuid_msg.*|,
qr(WSREP: --wsrep-causal-reads=ON takes precedence over --wsrep-sync-wait=0. WSREP_SYNC_WAIT_BEFORE_READ is on),
qr|WSREP: JOIN message from member .* in non-primary configuration. Ignored.|,
+ qr|Query apply failed:*|,
+ qr(WSREP: Ignoring error*),
qr(WSREP: Failed to remove page file .*),
qr(WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to .*),
);
diff --git a/mysql-test/suite/galera/t/GAL-419.test b/mysql-test/suite/galera/t/GAL-419.test
index e50b948bf35..07abcbcc47b 100644
--- a/mysql-test/suite/galera/t/GAL-419.test
+++ b/mysql-test/suite/galera/t/GAL-419.test
@@ -5,11 +5,11 @@
--source include/galera_cluster.inc
--source include/big_test.inc
---connection node_2
+--connection node_1
SET SESSION wsrep_sync_wait = 0;
--source include/kill_galera.inc
---connection node_1
+--connection node_2
SET SESSION wsrep_sync_wait = 0;
--source include/kill_galera.inc
diff --git a/mysql-test/suite/galera/t/GCF-1081.test b/mysql-test/suite/galera/t/GCF-1081.test
new file mode 100644
index 00000000000..8296c55f1b6
--- /dev/null
+++ b/mysql-test/suite/galera/t/GCF-1081.test
@@ -0,0 +1,72 @@
+#
+# GCF-1081 - Assertion `!thd->sp_runtime_ctx`
+#
+# Test replaying of stored procedures
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
+
+--connection node_1
+
+--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 0), (3, 0);
+
+DELIMITER |;
+CREATE PROCEDURE proc_update ()
+BEGIN
+ UPDATE t1 SET f2 = 1 where f1 > 0;
+END|
+DELIMITER ;|
+
+# Block the SP
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--let $galera_sync_point = commit_monitor_master_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+--send CALL proc_update ();
+
+# Wait until SP is blocked
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--source include/galera_wait_sync_point.inc
+
+# Issue a conflicting insert on node #2
+--connection node_1a
+SET GLOBAL DEBUG = 'd,sync.wsrep_before_BF_victim_unlock';
+
+--connection node_2
+--send INSERT INTO t1 VALUES (2, 2);
+
+# Wait until it BF aborts the SP
+--connection node_1a
+SET SESSION DEBUG_SYNC = 'now WAIT_FOR sync.wsrep_before_BF_victim_unlock_reached';
+SET GLOBAL DEBUG = '';
+
+# Unblock the SP
+--connection node_1a
+--source include/galera_clear_sync_point.inc
+--source include/galera_signal_sync_point.inc
+
+--connection node_2
+--reap
+SELECT * FROM t1;
+
+# SP succeeds
+--connection node_1
+--reap
+SELECT * FROM t1;
+
+# 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 AS wsrep_local_replays;
+--enable_query_log
+
+DROP PROCEDURE proc_update;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/GCF-939.test b/mysql-test/suite/galera/t/GCF-939.test
new file mode 100644
index 00000000000..637d656996e
--- /dev/null
+++ b/mysql-test/suite/galera/t/GCF-939.test
@@ -0,0 +1,31 @@
+#
+# GCF-939 Avoid creation of GRA log files when applier is successfull
+#
+
+--source include/galera_cluster.inc
+
+--exec rm -rf $MYSQLTEST_VARDIR/mysqld.2/data/GRA_*.log
+
+--connection node_1
+--error ER_BAD_TABLE_ERROR
+DROP TABLE t1;
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+# Expect only one GRA_*.log file
+# TODO replace_regex is somehow broken, it will filter out
+# result totally if replacement string is already in result
+# fixed this temporarily by calling list_files twice
+# to get GRA_.log two times, this works for some reason
+#
+--replace_regex /GRA_.+\.log/GRA_.log/
+--list_files $MYSQLTEST_VARDIR/mysqld.2/data GRA_*.log
+--replace_regex /GRA_.+\.log/GRA_.log/
+--list_files $MYSQLTEST_VARDIR/mysqld.2/data GRA_*.log
+
+DROP TABLE t1;
+CALL mtr.add_suppression("Ignoring error 'Unknown table 'test.t1'' on query");
+--connection node_2
+CALL mtr.add_suppression("Error 'Unknown table 'test.t1'' on query");
+
diff --git a/mysql-test/suite/galera/t/MW-284.test b/mysql-test/suite/galera/t/MW-284.test
index 5e17baa1bdb..b52db4c68b0 100644
--- a/mysql-test/suite/galera/t/MW-284.test
+++ b/mysql-test/suite/galera/t/MW-284.test
@@ -63,7 +63,9 @@ CALL mtr.add_suppression('failed registering on master');
CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
--connection node_1
+set global wsrep_on=OFF;
RESET MASTER;
+set global wsrep_on=ON;
CALL mtr.add_suppression('WSREP: Last Applied Action message in non-primary configuration from member');
--connection node_2
diff --git a/mysql-test/suite/galera/t/MW-286.test b/mysql-test/suite/galera/t/MW-286.test
index 426b4493bb7..9c849861001 100644
--- a/mysql-test/suite/galera/t/MW-286.test
+++ b/mysql-test/suite/galera/t/MW-286.test
@@ -4,31 +4,55 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
---source include/big_test.inc
-
+--source include/have_debug_sync.inc
+
--connection node_1
-CREATE TABLE ten (f1 INTEGER) Engine=InnoDB;
-INSERT INTO ten VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
-
# Insert some values before the ALTER
-INSERT INTO t1 (f1) SELECT 000000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
-
-# Insert more values while the ALTER is running
---send INSERT INTO t1 (f1) SELECT 100000 + (10000 * a1.f1) + (1000 * a2.f1) + (100 * a3.f1) + (10 * a4.f1) + a5.f1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
+INSERT INTO t1 (f1) VALUES (1), (2), (3);
+#
+# run ALTER with no wsrep replication
+#
--connection node_2
SET GLOBAL wsrep_desync = TRUE;
SET wsrep_on = FALSE;
---error 0,ER_QUERY_INTERRUPTED
-ALTER TABLE t1 ADD PRIMARY KEY (f1);
+#
+# stop ALTER processing after it has acquired exclusive MDL lock
+#
+SET SESSION debug_sync = "alter_table_inplace_after_lock_upgrade SIGNAL mdl_locked WAIT_FOR mdl_continue";
+
+--send ALTER TABLE t1 ADD PRIMARY KEY (f1);
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+SET SESSION debug_sync = "now WAIT_FOR mdl_locked";
+
+#
+# replicate conflicting insert from node_1
+#
+--connection node_1
+INSERT INTO t1(f1) VALUES (11);
+
+#
+# let parked ALTER processing to continue after the conflict
+#
+--connection node_2a
+SET debug_sync = "now SIGNAL mdl_continue";
+SET debug_sync='RESET';
+
+#
+# ALTER should have been aborted with query interupted error code
+#
+--connection node_2
+--error ER_QUERY_INTERRUPTED
+--reap
SET wsrep_on = TRUE;
SET GLOBAL wsrep_desync = FALSE;
--connection node_1
-reap;
+
DROP TABLE t1;
-DROP TABLE ten;
diff --git a/mysql-test/suite/galera/t/MW-292.test b/mysql-test/suite/galera/t/MW-292.test
index ecb1273759e..9580d53d85c 100644
--- a/mysql-test/suite/galera/t/MW-292.test
+++ b/mysql-test/suite/galera/t/MW-292.test
@@ -9,7 +9,7 @@
--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
+--source 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'`
@@ -25,37 +25,51 @@ START TRANSACTION;
UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
-# Block the commit
+# Block the applier on node #1 and issue a conflicting update on node #2
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
---let $galera_sync_point = commit_monitor_enter_sync
+SET SESSION wsrep_sync_wait=0;
+--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc
---connection node_1
---send COMMIT;
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
-# Wait until commit is blocked
--connection node_1a
-SET SESSION wsrep_sync_wait = 0;
--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
-# Issue a conflicting update on node #2
---connection node_2
-UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+# Block the commit, send the COMMIT and wait until it gets blocked
-# 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 $galera_sync_point = commit_monitor_master_enter_sync
+--source include/galera_set_sync_point.inc
---let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'init' AND INFO = 'COMMIT';
---source include/wait_condition.inc
+--connection node_1
+--send COMMIT
-# Unblock the commit
--connection node_1a
+
+--let $galera_sync_point = apply_monitor_slave_enter_sync commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
--source include/galera_clear_sync_point.inc
+
+# Let the conflicting UPDATE proceed and wait until it hits abort_trx_end.
+# The victim transaction still sits in commit_monitor_master_sync_point.
+
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = abort_trx_end commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+
+# Let the transactions proceed
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = commit_monitor_master_enter_sync
--source include/galera_signal_sync_point.inc
-# Commit succeeds via replay
+# Commit succeeds
--connection node_1
--reap
diff --git a/mysql-test/suite/galera/t/MW-328A.test b/mysql-test/suite/galera/t/MW-328A.test
index 09aad1bcf60..097d4ac4ff6 100644
--- a/mysql-test/suite/galera/t/MW-328A.test
+++ b/mysql-test/suite/galera/t/MW-328A.test
@@ -3,8 +3,13 @@
#
#
-# Attempt to insert into t2 and check if insert actually inserted rows if
-# a success was reported.
+# test phase 1 is not deterministic
+#
+# Here we attempt to insert into t2 and check if insert actually
+# inserted rows if a success was reported.
+#
+# However, deadlocks may or may not happen in this test execution
+# it all depends on timing.
#
--source include/big_test.inc
@@ -25,7 +30,7 @@ while ($count)
{
TRUNCATE TABLE t2;
- --error 0,1213
+ --error 0,ER_LOCK_DEADLOCK
INSERT IGNORE INTO t2 SELECT f2 FROM t1;
if ($mysql_errno != 1213) {
--inc $successes
@@ -44,14 +49,31 @@ while ($count)
--enable_query_log
+
+--source suite/galera/t/MW-328-footer.inc
+
#
-# Check that the test produced both deadlocks and successes
+# Test phase 2 is deterministic
+# Here we generate a sure conflict in node 1 and verify that
+# insert failed in both nodes
#
+--connection node_1
+CREATE TABLE t1 (i int primary key, j int) engine=innodb;
+INSERT INTO t1 values (1,0);
---disable_query_log
---eval SELECT $successes > 0 AS have_successes
---eval SELECT $deadlocks > 0 AS have_deadlocks
---enable_query_log
+BEGIN;
+UPDATE t1 SET j=1 WHERE i=1;
+--connection node_2
+UPDATE t1 SET j=2 WHERE i=1;
---source suite/galera/t/MW-328-footer.inc
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+SELECT * FROM t1;
+--connection node_2
+SELECT * FROM t1;
+--connection node_1
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/MW-329.test b/mysql-test/suite/galera/t/MW-329.test
index 5baa4d14966..78755fc3b42 100644
--- a/mysql-test/suite/galera/t/MW-329.test
+++ b/mysql-test/suite/galera/t/MW-329.test
@@ -11,11 +11,6 @@ CREATE TABLE t1 (f1 INTEGER, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
# We start with a populated table
INSERT INTO t1 (f1) VALUES (1),(65535);
-# Clear the wsrep_local_replays counter
-
-FLUSH STATUS;
-SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
-
#
# Run concurrent INSERTs
#
@@ -42,8 +37,9 @@ DELIMITER ;|
#
--connection node_2
-CALL mtr.add_suppression("WSREP: Failed to report last committed .*");
---let $count = 200
+--let $count = 10
+--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+
while ($count)
{
--let $signature = `SELECT LEFT(MD5(RAND()), 10)`
@@ -57,14 +53,28 @@ while ($count)
--die ROW_COUNT() = 0
}
}
- --dec $count
+
+ #
+ # Ensure at least one replay happens
+ #
+
+ --let $wsrep_replays = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+ --disable_query_log
+ if (`SELECT $wsrep_replays - $wsrep_local_replays_old > 0`) {
+ --dec $count
+ }
+ --enable_query_log
}
#
# Confirm that some transaction replays occurred
#
-SELECT VARIABLE_VALUE > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+--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 > 0 AS wsrep_local_replays;
+--enable_query_log
+
#
# Terminate the stored procedure
diff --git a/mysql-test/suite/galera/t/MW-336.test b/mysql-test/suite/galera/t/MW-336.test
index 4bdbfb2ecff..67715c24992 100644
--- a/mysql-test/suite/galera/t/MW-336.test
+++ b/mysql-test/suite/galera/t/MW-336.test
@@ -11,9 +11,8 @@ CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
SET GLOBAL wsrep_slave_threads = 10;
SET GLOBAL wsrep_slave_threads = 1;
-
--let $wait_timeout=600
---let $wait_condition = SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
+--let $wait_condition = SELECT COUNT(*) = 12 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
--source include/wait_condition.inc
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
@@ -31,11 +30,11 @@ while ($count)
--connection node_1
SET GLOBAL wsrep_slave_threads = 10;
---let $wait_condition = SELECT COUNT(*) = 11 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
+--let $wait_condition = SELECT COUNT(*) = 12 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
--source include/wait_condition.inc
SET GLOBAL wsrep_slave_threads = 20;
---let $wait_condition = SELECT COUNT(*) = 21 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
+--let $wait_condition = SELECT COUNT(*) = 22 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
--source include/wait_condition.inc
SET GLOBAL wsrep_slave_threads = 1;
@@ -62,7 +61,7 @@ while ($count)
}
--connection node_1
---let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
+--let $wait_condition = SELECT COUNT(*) = 3 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
--source include/wait_condition.inc
SET GLOBAL wsrep_slave_threads = 1;
diff --git a/mysql-test/suite/galera/t/MW-360-master.opt b/mysql-test/suite/galera/t/MW-360-master.opt
new file mode 100644
index 00000000000..e51c49c3808
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-360-master.opt
@@ -0,0 +1,2 @@
+--gtid-domain-id=1 --log-bin --log-slave-updates
+
diff --git a/mysql-test/suite/galera/t/MW-360.test b/mysql-test/suite/galera/t/MW-360.test
new file mode 100644
index 00000000000..b776631cfff
--- /dev/null
+++ b/mysql-test/suite/galera/t/MW-360.test
@@ -0,0 +1,100 @@
+#
+# MW-360 DROP TABLE containing temporary tables results in binlog divergence
+#
+
+--source include/galera_cluster.inc
+--source include/have_binlog_format_row.inc
+
+--connection node_1
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+
+--connection node_2
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+
+--connection node_1
+
+#
+# Straightforward temporary table
+#
+
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+DROP TABLE t1;
+
+--let $local_uuid = `SELECT LEFT(@@global.gtid_executed, 36)`
+
+#
+# A mix of normal and temporary tables
+#
+
+# Temp table first, normal table second
+
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+
+DROP TABLE t1, t2;
+
+# Normal table first, temporary table second
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+
+DROP TABLE t1, t2;
+
+# Temporary table first, normal table second, temp table third
+
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+
+CREATE TEMPORARY TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (3);
+
+DROP TABLE t1, t2, t3;
+
+# Normal table first, temporary table second, normal table third
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+CREATE TEMPORARY TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (2);
+
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t3 VALUES (3);
+
+DROP TABLE t1, t2, t3;
+
+#
+# A temporary table masking a normal one
+#
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (2);
+
+DROP TABLE t1;
+DROP TABLE t1;
+
+--connection node_2
+--let $gtid_executed_node2 = `SELECT @@global.gtid_executed;`
+
+--connection node_1
+--disable_query_log
+# Node 1 has extra GTID set generated by the temporary table drop
+--eval SELECT GTID_SUBSET('$gtid_executed_node2', @@global.gtid_executed) AS gtid_executed_equal;
+--enable_query_log
diff --git a/mysql-test/suite/galera/t/MW-369.inc b/mysql-test/suite/galera/t/MW-369.inc
index 5fd9ef150ae..71df979d6ba 100644
--- a/mysql-test/suite/galera/t/MW-369.inc
+++ b/mysql-test/suite/galera/t/MW-369.inc
@@ -24,7 +24,6 @@
--connection node_1
SET AUTOCOMMIT=ON;
START TRANSACTION;
-
--eval $mw_369_parent_query
#
@@ -51,7 +50,7 @@ SET SESSION wsrep_sync_wait = 0;
--source include/galera_wait_sync_point.inc
--source include/galera_clear_sync_point.inc
---let $galera_sync_point = local_monitor_enter_sync
+--let $galera_sync_point = local_monitor_master_enter_sync
--source include/galera_set_sync_point.inc
--connection node_1
@@ -61,7 +60,7 @@ SET SESSION wsrep_sync_wait = 0;
# Wait until both sync points have been reached
#
--connection node_1a
---let $galera_sync_point = apply_monitor_slave_enter_sync local_monitor_enter_sync
+--let $galera_sync_point = apply_monitor_slave_enter_sync local_monitor_master_enter_sync
--source include/galera_wait_sync_point.inc
#
@@ -70,6 +69,6 @@ SET SESSION wsrep_sync_wait = 0;
--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_signal_sync_point.inc
---let $galera_sync_point = local_monitor_enter_sync
+--let $galera_sync_point = local_monitor_master_enter_sync
--source include/galera_signal_sync_point.inc
--source include/galera_clear_sync_point.inc
diff --git a/mysql-test/suite/galera/t/MW-369.test b/mysql-test/suite/galera/t/MW-369.test
index 720d6daf518..c8f8c974019 100644
--- a/mysql-test/suite/galera/t/MW-369.test
+++ b/mysql-test/suite/galera/t/MW-369.test
@@ -24,7 +24,7 @@
--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
+--source include/galera_have_debug_sync.inc
CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER,
@@ -244,3 +244,101 @@ SELECT * FROM c;
DROP TABLE c;
DROP TABLE p;
+--echo #
+--echo # Start of 10.4 tests
+--echo #
+#
+# Test F Outline:
+# ===============
+#
+# Test two concurrent INSERTs on the child table.
+#
+# The pf table will originally have row (1)
+# The cf table will originally be empty
+#
+# A new row (10, 1) pointing to parent row (1) is inserted from
+# connection node_2. A transaction which tries to INSERT another child
+# row (20, 1), pointing to the same parent, is run from connection node_1.
+#
+# Expected Outcome:
+# =================
+# Both INSERTs should succeed since they don't modify the common parent
+# key.
+#
+# At the end of the test:
+# parent table should have row (1)
+# child table should have rows (10, 1), (20, 1)
+
+--connection node_1
+
+CREATE TABLE pf (f1 INTEGER PRIMARY KEY) ENGINE=INNODB;
+CREATE TABLE cf (
+ f1 INTEGER PRIMARY KEY,
+ p_id INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES pf (f1)
+);
+
+INSERT INTO pf VALUES (1);
+
+# This is run on node1:
+--let $mw_369_parent_query = INSERT INTO cf (f1, p_id) VALUES (10, 1)
+# This is run on node2:
+--let $mw_369_child_query = INSERT INTO cf (f1, p_id) VALUES (20, 1)
+--source MW-369.inc
+
+--connection node_1
+--reap
+
+--connection node_2
+SELECT * FROM pf;
+SELECT * FROM cf;
+
+DROP TABLE cf;
+DROP TABLE pf;
+
+#
+# Test G Outline:
+# ===============
+#
+# This test is similar to test B where a existing
+# child table row is updated concurrently from another node
+# with a transaction which updates the parent table, except
+# that here the child table row is inserted, not updated.
+#
+# The pg table will originally have rows (1, 0), (2, 0).
+# The cg table will originally be empty
+#
+# Expected outcome:
+# ================
+#
+# Both UPDATE and INSERT should succeed since they are done to separate tables
+# and UPDATE to parent row does not touch the foreign key referenced by the
+# child row INSERT. The parent table shall contain rows (1, 1), (2, 0).
+# The child table shall contain row (1, 1, 0) which points to parent table
+# row (1, 0).
+#
+
+--connection node_1
+CREATE TABLE pg (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE cg (f1 INTEGER PRIMARY KEY, p_id INTEGER,
+ f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES pg (f1)) ;
+
+INSERT INTO pg VALUES (1, 0);
+INSERT INTO pg VALUES (2, 0);
+
+--let mw_369_parent_query = UPDATE pg SET f2 = 1 WHERE f1 = 1
+--let $mw_369_child_query = INSERT INTO cg VALUES (1, 1, 0)
+--source MW-369.inc
+
+# Commit succeeds
+--connection node_1
+--reap
+
+--connection node_2
+SELECT * FROM pg;
+SELECT * FROM cg;
+
+DROP TABLE cg;
+DROP TABLE pg;
+
diff --git a/mysql-test/suite/galera/t/MW-388.test b/mysql-test/suite/galera/t/MW-388.test
index de1ac52bf3e..9cf176434ba 100644
--- a/mysql-test/suite/galera/t/MW-388.test
+++ b/mysql-test/suite/galera/t/MW-388.test
@@ -2,7 +2,6 @@
--source include/have_innodb.inc
--source include/have_debug.inc
--source include/have_debug_sync.inc
-
--connection node_1
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB;
@@ -41,11 +40,11 @@ SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
--connection node_1
SET SESSION wsrep_sync_wait = 0;
-SET SESSION DEBUG_SYNC = 'wsrep_after_replication SIGNAL wsrep_after_replication_reached WAIT_FOR wsrep_after_replication_continue';
+SET SESSION DEBUG_SYNC = 'wsrep_after_certification SIGNAL wsrep_after_certification_reached WAIT_FOR wsrep_after_certification_continue';
--send CALL insert_proc ();
--connection node_1a
-SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_replication_reached";
+SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_certification_reached";
SET GLOBAL DEBUG_DBUG = "";
diff --git a/mysql-test/suite/galera/t/MW-402.test b/mysql-test/suite/galera/t/MW-402.test
index 36b691c6295..4b83e25dc50 100644
--- a/mysql-test/suite/galera/t/MW-402.test
+++ b/mysql-test/suite/galera/t/MW-402.test
@@ -1,6 +1,6 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
---source suite/galera/include/galera_have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
#
# we must open connection node_1a here, MW-369.inc will use it later
@@ -135,7 +135,6 @@ SELECT * FROM c;
DROP TABLE c;
DROP TABLE p;
-
#
# CASCADE DELETE tests with two parent tables
# Here we cause cascaded operation on child table through
@@ -151,10 +150,11 @@ DROP TABLE p;
CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
-CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER, f2 INTEGER,
- CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1) ON DELETE CASCADE,
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+ f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ ON DELETE CASCADE,
CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1));
-
INSERT INTO p1 VALUES (1, 0);
INSERT INTO p2 VALUES (1, 0);
@@ -171,7 +171,51 @@ INSERT INTO c VALUES (1, 1, 1, 0);
--connection node_1
--reap
-# same as previous, but statements in different order
+--connection node_2
+SELECT * FROM p1;
+SELECT * FROM p2;
+SELECT * FROM c;
+
+DROP TABLE c;
+DROP TABLE p1;
+DROP TABLE p2;
+
+#
+# CASCADE DELETE tests with two parent tables
+# Here we cause cascaded operation on child table through
+# one parent table and issue other delete operation through the
+# other parent table. The cascade progresses to same child table row where
+# we should see the conflict to happen
+#
+# As a result, the update on p2 should fail
+#
+--connection node_1
+
+CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB;
+CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER,
+ f2 INTEGER,
+ CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1)
+ ON DELETE CASCADE,
+ CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)
+ ON DELETE CASCADE);
+
+INSERT INTO p1 VALUES (1, 0);
+INSERT INTO p2 VALUES (1, 0);
+
+INSERT INTO c VALUES (1, 1, 1, 0);
+
+--let $mw_369_parent_query = DELETE FROM p2 WHERE f1=1
+--let $mw_369_child_query = DELETE FROM p1 WHERE f1=1
+
+--connection node_1a
+--source MW-369.inc
+
+# Commit succeeds
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
--connection node_2
SELECT * FROM p1;
SELECT * FROM p2;
diff --git a/mysql-test/suite/galera/t/MW-416.test b/mysql-test/suite/galera/t/MW-416.test
index df4fa35abc7..48eada95cb8 100644
--- a/mysql-test/suite/galera/t/MW-416.test
+++ b/mysql-test/suite/galera/t/MW-416.test
@@ -2,11 +2,10 @@
--source include/have_innodb.inc
--source include/wait_until_ready.inc
-
CREATE USER 'userMW416'@'localhost';
GRANT SELECT, INSERT, UPDATE ON test.* TO 'userMW416'@'localhost';
-SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
+--let $wsrep_replicated_before = `SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'wsrep_replicated'`
--connect userMW416, localhost, userMW416,, test, $NODE_MYPORT_1
--connection userMW416
@@ -131,4 +130,7 @@ UNINSTALL PLUGIN plg;
--connection node_1
DROP USER 'userMW416'@'localhost';
SHOW DATABASES;
-SHOW GLOBAL STATUS LIKE 'wsrep_replicated';
+--let $wsrep_replicated_after = `SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'wsrep_replicated'`
+--disable_query_log
+--eval SELECT $wsrep_replicated_after - $wsrep_replicated_before AS wsrep_replicated_after_diff
+--enable_query_log
diff --git a/mysql-test/suite/galera/t/MW-86-wait1.test b/mysql-test/suite/galera/t/MW-86-wait1.test
index 6c0982ad8b3..aee5a0b2486 100644
--- a/mysql-test/suite/galera/t/MW-86-wait1.test
+++ b/mysql-test/suite/galera/t/MW-86-wait1.test
@@ -6,13 +6,15 @@
--source include/galera_cluster.inc
--source include/have_binlog_format_row.inc
--source include/have_debug_sync.inc
+SET @orig_debug=@@debug;
--connection node_2
# Make sure no signals have been leftover from previous tests to surprise us.
SELECT @@debug_sync;
+set debug_sync='RESET';
SET SESSION wsrep_sync_wait = 1;
-SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
+SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb";
--connection node_1
CREATE TABLE t_wait1 (f1 INTEGER) ENGINE=InnoDB;
@@ -90,17 +92,16 @@ SHOW WARNINGS;
--enable_result_log
# Unblock the background INSERT and remove the sync point.
-SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
-SET SESSION debug_sync = "now SIGNAL signal.wsrep_apply_cb";
+#SET GLOBAL debug_dbug = "-d,sync.wsrep_apply_cb";
+SET GLOBAL debug_dbug = @orig_debug;
+SET SESSION debug_sync = "now SIGNAL signal.wsrep_apply_cb";
+SET debug_sync='RESET';
SET SESSION wsrep_sync_wait = default;
# This will wait for the background INSERT to complete before we quit
# from the test.
DROP TABLE t_wait1;
-SET GLOBAL debug = NULL;
-SET debug_sync='RESET';
-
# Make sure no pending signals are leftover to surprise subsequent tests.
SELECT @@debug_sync;
diff --git a/mysql-test/suite/galera/t/MW-86-wait8.test b/mysql-test/suite/galera/t/MW-86-wait8.test
index 65e612c5c8e..c40cd8b77c7 100644
--- a/mysql-test/suite/galera/t/MW-86-wait8.test
+++ b/mysql-test/suite/galera/t/MW-86-wait8.test
@@ -4,13 +4,14 @@
--source include/galera_cluster.inc
--source include/have_binlog_format_row.inc
--source include/have_debug_sync.inc
+SET @orig_debug=@@debug;
--connection node_2
# Make sure no signals have been leftover from previous tests to surprise us.
SELECT @@debug_sync;
SET SESSION wsrep_sync_wait = 8;
-SET GLOBAL debug = "+d,sync.wsrep_apply_cb";
+SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb";
--connection node_1
CREATE TABLE t_wait8 (f1 INTEGER) ENGINE=InnoDB;
@@ -112,8 +113,11 @@ SHOW WARNINGS;
--enable_query_log
# Unblock the background INSERT and remove the sync point.
-SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
+#SET GLOBAL debug = "-d,sync.wsrep_apply_cb";
+SET GLOBAL debug_dbug = @orig_debug;
+
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+SET debug_sync='RESET';
SET SESSION wsrep_sync_wait = default;
@@ -121,8 +125,5 @@ SET SESSION wsrep_sync_wait = default;
# from the test.
DROP TABLE t_wait8;
-SET GLOBAL debug = NULL;
-SET debug_sync='RESET';
-
# Make sure no pending signals are leftover to surprise subsequent tests.
SELECT @@debug_sync;
diff --git a/mysql-test/suite/galera/t/galera#500.test b/mysql-test/suite/galera/t/galera#500.test
index 3c8490b6907..60f303b7103 100644
--- a/mysql-test/suite/galera/t/galera#500.test
+++ b/mysql-test/suite/galera/t/galera#500.test
@@ -8,6 +8,10 @@
--source include/galera_cluster.inc
--source include/galera_have_debug_sync.inc
+--let $node_1=node_1
+--let $node_2=node_2
+--source suite/galera/include/auto_increment_offset_save.inc
+
# Force node_2 gcomm background thread to terminate via exception.
--connection node_2
--let $wsrep_cluster_address = `SELECT @@wsrep_cluster_address`
@@ -36,3 +40,5 @@ SET SESSION wsrep_on=0;
--connection node_2
CALL mtr.add_suppression("WSREP: exception from gcomm, backend must be restarted: Gcomm backend termination was requested by setting gmcast.isolate=2.");
+
+--source suite/galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt b/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt
index d8ecaacaa4c..6f688b39fd5 100644
--- a/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt
+++ b/mysql-test/suite/galera/t/galera_applier_ftwrl_table_alter-master.opt
@@ -1 +1 @@
---lock_wait_timeout=5 --innodb_lock_wait_timeout=5 --wait_timeout=5
+--lock_wait_timeout=5 --innodb_lock_wait_timeout=5 --wait_timeout=60
diff --git a/mysql-test/suite/galera/t/galera_as_master.test b/mysql-test/suite/galera/t/galera_as_master.test
index 49f3c993256..1c439ffff63 100644
--- a/mysql-test/suite/galera/t/galera_as_master.test
+++ b/mysql-test/suite/galera/t/galera_as_master.test
@@ -64,4 +64,6 @@ RESET SLAVE ALL;
CALL mtr.add_suppression('You need to use --log-bin to make --binlog-format work');
--connection node_1
+set global wsrep_on=OFF;
RESET MASTER;
+set global wsrep_on=ON;
diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid.cnf b/mysql-test/suite/galera/t/galera_as_master_gtid.cnf
index 19517556331..75caba5420a 100644
--- a/mysql-test/suite/galera/t/galera_as_master_gtid.cnf
+++ b/mysql-test/suite/galera/t/galera_as_master_gtid.cnf
@@ -1,8 +1,6 @@
!include ../galera_2nodes_as_master.cnf
[mysqld]
-gtid-mode=ON
log-bin=mysqld-bin
log-slave-updates
-enforce-gtid-consistency
binlog-format=ROW
diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid.test b/mysql-test/suite/galera/t/galera_as_master_gtid.test
index 9db104b7cab..9be065e448b 100644
--- a/mysql-test/suite/galera/t/galera_as_master_gtid.test
+++ b/mysql-test/suite/galera/t/galera_as_master_gtid.test
@@ -27,10 +27,6 @@ INSERT INTO t1 VALUES(1);
--eval SELECT '$effective_uuid' != @@global.server_uuid AS uuids_do_not_match;
--enable_query_log
---replace_result $effective_uuid <effective_uuid>
---replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
-SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 120;
-
--connection node_2
INSERT INTO t1 VALUES(2);
@@ -39,10 +35,6 @@ INSERT INTO t1 VALUES(2);
--eval SELECT '$effective_uuid' = LEFT(@@global.gtid_executed, 36) AS uuids_match;
--enable_query_log
---replace_result $effective_uuid <effective_uuid>
---replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
-SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 120;
-
--connection node_3
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
@@ -55,10 +47,6 @@ SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 120;
--eval SELECT '$effective_uuid' = LEFT(@@global.gtid_executed, 36) AS uuids_match;
--enable_query_log
---replace_result $effective_uuid <effective_uuid>
---replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
-SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
-
--connection node_1
DROP TABLE t1;
@@ -66,5 +54,17 @@ DROP TABLE t1;
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
+--connection node_1
+--let $gtid_executed_node1 = `SELECT @@global.gtid_executed;`
+
+--connection node_2
+--disable_query_log
+--eval SELECT '$gtid_executed_node1' = @@global.gtid_executed AS gtid_executed_equal
+--enable_query_log
+--connection node_3
+--disable_query_log
+--eval SELECT '$gtid_executed_node1' = @@global.gtid_executed AS gtid_executed_equal
+--enable_query_log
+
STOP SLAVE;
RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf
index 19517556331..75caba5420a 100644
--- a/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf
+++ b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.cnf
@@ -1,8 +1,6 @@
!include ../galera_2nodes_as_master.cnf
[mysqld]
-gtid-mode=ON
log-bin=mysqld-bin
log-slave-updates
-enforce-gtid-consistency
binlog-format=ROW
diff --git a/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test
index 23606d7ac4c..61c7eed6543 100644
--- a/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test
+++ b/mysql-test/suite/galera/t/galera_as_master_gtid_change_master.test
@@ -24,6 +24,8 @@ INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
--connection node_3
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
STOP SLAVE;
--disable_query_log
--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_2, MASTER_AUTO_POSITION=1;
diff --git a/mysql-test/suite/galera/t/galera_as_slave.test b/mysql-test/suite/galera/t/galera_as_slave.test
index 849b75eadd1..da92437b118 100644
--- a/mysql-test/suite/galera/t/galera_as_slave.test
+++ b/mysql-test/suite/galera/t/galera_as_slave.test
@@ -5,18 +5,19 @@
#
--source include/have_innodb.inc
-
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3;
--enable_query_log
START SLAVE;
---connection node_1
+--connection node_3
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
@@ -29,14 +30,14 @@ INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES (2);
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_1
SELECT COUNT(*) = 2 FROM t1;
INSERT INTO t1 VALUES (3);
--connection node_2
SELECT COUNT(*) = 3 FROM t1;
---connection node_1
+--connection node_3
DROP TABLE t1;
--connection node_2
@@ -46,5 +47,5 @@ DROP TABLE t1;
STOP SLAVE;
RESET SLAVE ALL;
---connection node_1
+--connection node_3
RESET MASTER;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_autoinc.test b/mysql-test/suite/galera/t/galera_as_slave_autoinc.test
index 59483d0591c..e0c8bf29682 100644
--- a/mysql-test/suite/galera/t/galera_as_slave_autoinc.test
+++ b/mysql-test/suite/galera/t/galera_as_slave_autoinc.test
@@ -5,18 +5,19 @@
#
--source include/have_innodb.inc
-
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3;
--enable_query_log
START SLAVE;
---connection node_1
+--connection node_3
##
## Verify the correct operation of the auto-increment when
@@ -62,14 +63,13 @@ select * from t1;
show variables like 'binlog_format';
show variables like 'auto_increment_increment';
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
-
+--connection node_1
select * from t1;
show variables like 'binlog_format';
show variables like 'auto_increment_increment';
---connection node_1
+--connection node_3
DROP TABLE t1;
--connection node_2
@@ -79,5 +79,5 @@ DROP TABLE t1;
STOP SLAVE;
RESET SLAVE ALL;
---connection node_1
+--connection node_3
RESET MASTER;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_gtid.test b/mysql-test/suite/galera/t/galera_as_slave_gtid.test
index c2331a2ae05..3b0f191ad83 100644
--- a/mysql-test/suite/galera/t/galera_as_slave_gtid.test
+++ b/mysql-test/suite/galera/t/galera_as_slave_gtid.test
@@ -8,18 +8,19 @@
#
--source include/have_innodb.inc
-
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3;
--enable_query_log
START SLAVE;
---connection node_1
+--connection node_3
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
@@ -34,17 +35,21 @@ SELECT LENGTH(@@global.gtid_binlog_state) > 1;
--source include/wait_condition.inc
--disable_query_log
+
--eval SELECT '$gtid_binlog_state_node1' = @@global.gtid_binlog_state AS gtid_binlog_state_equal;
+#--eval SELECT GTID_SUBSET('$gtid_executed_node1', @@global.gtid_executed) AS gtid_executed_equal;
+
--enable_query_log
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_1
SELECT COUNT(*) = 1 FROM t1;
--disable_query_log
--eval SELECT '$gtid_binlog_state_node1' = @@global.gtid_binlog_state AS gtid_binlog_state_equal;
+#--eval SELECT GTID_SUBSET('$gtid_executed_node1', @@global.gtid_executed) AS gtid_executed_equal;
--enable_query_log
---connection node_1
+--connection node_3
DROP TABLE t1;
#
@@ -55,7 +60,7 @@ DROP TABLE t1;
--sleep 1
---connection node_3
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
diff --git a/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf b/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf
new file mode 100644
index 00000000000..e0852c50c44
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf
@@ -0,0 +1,17 @@
+!include ../galera_2nodes_as_slave.cnf
+
+[mysqld]
+#gtid-mode=ON
+log-bin=master-bin
+log-bin-index=master-bin
+log-slave-updates
+#enforce-gtid-consistency
+binlog-format=ROW
+
+[mysqld.2]
+replicate-do-db=test1
+replicate-wild-do-table=test1.%
+
+[mysqld.3]
+replicate-do-db=test1
+replicate-wild-do-table=test1.%
diff --git a/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test b/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test
new file mode 100644
index 00000000000..81b6d446ba6
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test
@@ -0,0 +1,150 @@
+#
+# Test Galera as a slave to a MySQL master using GTIDs
+#
+
+--source include/have_innodb.inc
+--source include/galera_cluster.inc
+--source include/have_log_bin.inc
+
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
+--connection node_1
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+
+--connection node_3
+RESET MASTER;
+
+--connection node_2
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+--disable_query_log
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_3, MASTER_USER='root';
+--enable_query_log
+START SLAVE;
+
+--connection node_3
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+
+#
+# First , some autocommit stuff
+#
+
+# Simple inserts
+
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+
+# Update that only covers test2.t1
+
+UPDATE test2.t1 SET test2.t1.f2 = 'cde';
+
+# Multi-table UPDATE
+
+UPDATE test1.t1, test2.t1 SET test1.t1.f2 = 'klm', test2.t1.f2 = 'xyz';
+
+# Multi-table DELETE
+
+DELETE test1.t1, test2.t1 FROM test1.t1 INNER JOIN test2.t1 WHERE test1.t1.f1 = test2.t1.f1 AND test1.t1.f1 = 3;
+
+#
+# Multi-statement transactions
+#
+
+# Transaction which is not replicated at all
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO test2.t1 (f1) VALUES (999);
+INSERT INTO test2.t1 (f1) VALUES (9999);
+COMMIT;
+
+# Transaction that is completely replicated
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (111);
+INSERT INTO test1.t1 (f1) VALUES (222);
+COMMIT;
+
+# Transaction that is partially replicated
+
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (333);
+INSERT INTO test2.t1 (f1) VALUES (99999);
+COMMIT;
+
+#
+# Make sure binary logs and gtid_executed strings are equal
+#
+
+--sleep 2
+--connection node_2
+--let $effective_uuid = `SELECT LEFT(@@global.gtid_current_pos, 36)`
+--let $gtid_executed_node2 = `SELECT @@global.gtid_current_pos;`
+
+--replace_result $effective_uuid <effective_uuid>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'master-bin.000001' FROM 256;
+
+--connection node_1
+
+--disable_query_log
+--eval SELECT '$gtid_executed_node2' = @@global.gtid_current_pos AS gtid_executed_equal;
+--enable_query_log
+
+--replace_result $effective_uuid <effective_uuid>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'master-bin.000001' FROM 256;
+
+#
+# Final consistency checks
+#
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+--connection node_1
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f1 IN (1,2);
+SELECT COUNT(*) = 3 FROM test1.t1 WHERE f1 IN (111,222,333);
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f2 = 'klm';
+
+--error 1049
+USE test2;
+
+#
+# Cleanup
+#
+
+--connection node_3
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+
+--sleep 1
+
+--connection node_1
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test b/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test
new file mode 100644
index 00000000000..1604016f3c3
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test
@@ -0,0 +1,176 @@
+#
+# Test the case where a Galera slave to async replication goes non-prim while
+# a stream of replication events including filtered events is arriving
+#
+
+--source include/have_innodb.inc
+--source include/have_log_bin.inc
+--source include/big_test.inc
+
+# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--source include/galera_cluster.inc
+
+--connection node_1
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+
+--connection node_2
+SET global wsrep_on=OFF;
+RESET MASTER;
+SET global wsrep_on=ON;
+
+--connection node_2
+--disable_query_log
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE USER='root';
+
+--connection node_1
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 2 FROM test1.t1;
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+
+--connection node_2
+SET SESSION wsrep_on=OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+--let $slave_sql_errno = 1047
+--source include/wait_for_slave_sql_error.inc
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (5);
+INSERT INTO test2.t1 (f1) VALUES (5);
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+SET SESSION wsrep_on=ON;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_ready';
+--source include/wait_condition.inc
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (6);
+INSERT INTO test2.t1 (f1) VALUES (6);
+
+--connection node_2
+START SLAVE;
+
+#
+# Consistency checks
+#
+
+--sleep 2
+--connection node_2
+--let $wait_condition = SELECT COUNT(DISTINCT f1) = 6 FROM test1.t1;
+--source include/wait_condition.inc
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(DISTINCT f1) = 6 FROM test1.t1;
+--source include/wait_condition.inc
+
+--connection node_2
+--let $gtid_executed_node2 = `SELECT @@global.gtid_executed;`
+
+--let $effective_uuid_1 = `SELECT SUBSTRING_INDEX(@@global.gtid_executed, ':', 1)`
+--let $effective_uuid_2 = `SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(@@global.gtid_executed, '\n', -1), ':', 1)`
+
+--replace_result $effective_uuid_1 <effective_uuid_1> $effective_uuid_2 <effective_uuid_2>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+
+--error 1049
+USE test2;
+
+--connection node_3
+
+--disable_query_log
+--eval SELECT '$gtid_executed_node2' = @@global.gtid_executed AS gtid_executed_equal;
+--enable_query_log
+
+--error 1049
+USE test2;
+
+--replace_result $effective_uuid_1 <effective_uuid_1> $effective_uuid_2 <effective_uuid_2>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+
+#
+# Cleanup
+#
+
+--connection node_1
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+
+--sleep 1
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_2
+STOP SLAVE;
+RESET SLAVE ALL;
+CALL mtr.add_suppression("GTID replication failed");
+CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed");
+CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+CALL mtr.add_suppression("TO isolation failed for");
+CALL mtr.add_suppression("Slave SQL: Error 'Deadlock found when trying to get lock; try restarting transaction' on query");
+CALL mtr.add_suppression("Slave SQL: Error 'WSREP has not yet prepared node for application use' on query");
+CALL mtr.add_suppression("Slave: WSREP has not yet prepared node for application use Error_code: 1047");
diff --git a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
index 46a93458271..31c0b9ca162 100644
--- a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
+++ b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test
@@ -7,22 +7,23 @@
--source include/have_innodb.inc
--source include/big_test.inc
+--source include/galera_cluster.inc
# Step #1. Establish replication
#
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
-#
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
---source include/galera_cluster.inc
+# As node 4 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_4 connection here
+--connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1, MASTER_USER='root';
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_4, MASTER_USER='root';
--enable_query_log
START SLAVE;
SET SESSION wsrep_sync_wait = 0;
---connection node_1
+--connection node_4
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
--connection node_2
@@ -34,22 +35,21 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
---connection node_3
+--connection node_1
--source include/wait_until_connected_again.inc
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
# Step #3. Force async replication to fail by creating a replication event while the slave is non-prim
---connection node_1
+--connection node_4
INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
--connection node_2
--sleep 5
--let $value = query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1)
---connection node_3
+--connection node_1
--disable_query_log
--eval SELECT "$value" IN ("Error 'Unknown command' on query. Default database: 'test'. Query: 'BEGIN'", "Node has dropped from cluster") AS expected_error
--enable_query_log
@@ -58,7 +58,7 @@ INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
--connection node_2
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
---connection node_3
+--connection node_1
--source include/wait_until_connected_again.inc
--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
@@ -74,7 +74,7 @@ START SLAVE;
--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
--source include/wait_condition.inc
---connection node_1
+--connection node_4
DROP TABLE t1;
--sleep 2
@@ -92,5 +92,5 @@ CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be
CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
---connection node_1
+--connection node_4
RESET MASTER;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_preordered.test b/mysql-test/suite/galera/t/galera_as_slave_preordered.test
index 6f221f83b3a..5b3c78b2cb1 100644
--- a/mysql-test/suite/galera/t/galera_as_slave_preordered.test
+++ b/mysql-test/suite/galera/t/galera_as_slave_preordered.test
@@ -6,14 +6,15 @@
--source include/have_innodb.inc
--source include/have_log_bin.inc
-
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_3;
--enable_query_log
START SLAVE USER='root';
@@ -21,7 +22,7 @@ START SLAVE USER='root';
# Issue many large-ish transaction on the async master
#
---connection node_1
+--connection node_3
CREATE TABLE ten (f1 INTEGER);
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
@@ -63,8 +64,7 @@ while ($count)
SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
---connection node_3
+--connection node_1
SELECT COUNT(*) = 2 * 100 * 10 * 10 FROM t1;
SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
@@ -72,7 +72,7 @@ SELECT COUNT(DISTINCT f1) = 2 * 100 * 10 * 10 FROM t1;
# Cleanup
#
---connection node_1
+--connection node_3
DROP TABLE t1;
DROP TABLE ten;
@@ -80,5 +80,8 @@ DROP TABLE ten;
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'ten';
+--source include/wait_condition.inc
+
STOP SLAVE;
RESET SLAVE ALL;
diff --git a/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test b/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test
index 460e040c010..fa5f3f9c7c6 100644
--- a/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test
+++ b/mysql-test/suite/galera/t/galera_as_slave_replication_bundle.test
@@ -5,18 +5,19 @@
#
--source include/have_innodb.inc
-
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3;
--enable_query_log
START SLAVE;
---connection node_1
+--connection node_3
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
@@ -36,7 +37,7 @@ INSERT INTO t1 VALUES(5);
SELECT COUNT(*) = 4 FROM t1;
# Bundle is now complete, the last INSERT and the DROP are delivered
---connection node_1
+--connection node_3
DROP TABLE t1;
--connection node_2
diff --git a/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.cnf b/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.cnf
index bd6bf9d4f98..cddb8e0e174 100644
--- a/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.cnf
+++ b/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.cnf
@@ -5,7 +5,7 @@ wsrep_sst_method=mariabackup
wsrep_sst_auth="root:"
[mysqld.1]
-wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=10M;pc.ignore_sb=true'
[mysqld.2]
-wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=10M;pc.ignore_sb=true'
diff --git a/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test b/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test
index 9d5f821a170..ed3674ad0e0 100644
--- a/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test
+++ b/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test
@@ -45,6 +45,8 @@ DELIMITER ;|
--connection node_2a
--source include/kill_galera.inc
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+
--sleep 10
--source include/start_mysqld.inc
--sleep 25
@@ -59,7 +61,6 @@ INSERT INTO t1 VALUES (DEFAULT);
--disable_query_log
--eval KILL CONNECTION $connection_id
--enable_query_log
-
INSERT INTO t1 VALUES (DEFAULT);
--connection node_1
diff --git a/mysql-test/suite/galera/t/galera_bf_abort_group_commit.cnf b/mysql-test/suite/galera/t/galera_bf_abort_group_commit.cnf
new file mode 100644
index 00000000000..612418c17c0
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_group_commit.cnf
@@ -0,0 +1,15 @@
+!include ../galera_2nodes.cnf
+
+# We set repl.commit_order=1 in order to disable provider commit
+# ordering.
+
+[mysqld.1]
+log-bin
+log-slave-updates
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;repl.commit_order=1'
+
+[mysqld.2]
+
+log-bin
+log-slave-updates
+wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;repl.commit_order=1' \ No newline at end of file
diff --git a/mysql-test/suite/galera/t/galera_bf_abort_group_commit.test b/mysql-test/suite/galera/t/galera_bf_abort_group_commit.test
new file mode 100644
index 00000000000..a828701cd0e
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_group_commit.test
@@ -0,0 +1,77 @@
+#
+# This test uses galera_sr_bf_abort.inc to probe various BF abort points
+# for SR transactions with wsrep provider commit ordering disabled.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/galera_have_debug_sync.inc
+
+# Control connection for manipulating sync points on node 1
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_sync_wait = 0;
+
+# SR bf abort on fragment
+--let $wsrep_trx_fragment_size = 1
+--echo galera_sr_bf_abort_at_commit = 0
+--let $galera_sr_bf_abort_at_commit = 0
+
+--echo after_replicate_sync
+--let $galera_sr_bf_abort_sync_point = after_replicate_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo local_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = local_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo apply_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = apply_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo commit_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = commit_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+# SR bf abort on commit fragment
+--let $wsrep_trx_fragment_size = 1
+--echo galera_sr_bf_abort_at_commit = 1
+--let $galera_sr_bf_abort_at_commit = 1
+
+--echo after_replicate_sync
+--let $galera_sr_bf_abort_sync_point = after_replicate_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo local_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = local_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo apply_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = apply_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo commit_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = commit_monitor_master_enter_sync
+--source suite/galera/t/galera_sr_bf_abort.inc
+
+# Normal bf abort on commit
+--let $wsrep_trx_fragment_size = 0
+--echo galera_sr_bf_abort_at_commit = 1
+--let $galera_sr_bf_abort_at_commit = 1
+
+--echo after_replicate_sync
+--let $galera_sr_bf_abort_sync_point = after_replicate_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo local_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = local_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo apply_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = apply_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+--echo commit_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = commit_monitor_master_enter_sync
+--source ../../suite/galera_sr/t/galera_sr_bf_abort.inc
+
+CALL mtr.add_suppression("WSREP: fragment replication failed: 1");
diff --git a/mysql-test/suite/galera/t/galera_bf_abort_shutdown.test b/mysql-test/suite/galera/t/galera_bf_abort_shutdown.test
new file mode 100644
index 00000000000..c7af8375b3f
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_bf_abort_shutdown.test
@@ -0,0 +1,33 @@
+#
+# This test verifies that the server can be shut down even if
+# some of the wsrep transactions are in QUERY_COMMITTING state.
+# In this case the shutdown sequence may do a BF abort for the
+# connection.
+#
+
+--source include/have_innodb.inc
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INT PRIMARY KEY);
+
+--connection node_2
+SET DEBUG_SYNC = 'wsrep_before_certification WAIT_FOR continue';
+--send INSERT INTO t1 VALUES (1)
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--source include/restart_mysqld.inc
+
+# Restore original auto_increment_offset values.
+--let $node_2=node_2a
+--source include/auto_increment_offset_restore.inc
+
+--connection node_1
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_commit_empty.test b/mysql-test/suite/galera/t/galera_commit_empty.test
new file mode 100644
index 00000000000..4e1a1e4eb2c
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_commit_empty.test
@@ -0,0 +1,35 @@
+# Test empty transactions.
+#
+# Check that the empty transaction gets terminated by starting and new
+# transaction after it. If the empty transaction is not terminated
+# appropriately, the following START TRANSACTION will fail.
+#
+# Also check that empty transactions don't generate any write sets.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+START TRANSACTION;
+COMMIT;
+
+START TRANSACTION;
+COMMIT;
+
+START TRANSACTION READ ONLY;
+COMMIT;
+
+START TRANSACTION;
+COMMIT;
+
+START TRANSACTION;
+START TRANSACTION;
+COMMIT;
+
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--disable_query_log
+--eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before AS wsrep_last_committed_diff
+--enable_query_log
diff --git a/mysql-test/suite/galera/t/galera_create_table_as_select.test b/mysql-test/suite/galera/t/galera_create_table_as_select.test
new file mode 100644
index 00000000000..a6c1f657280
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_create_table_as_select.test
@@ -0,0 +1,145 @@
+#
+# CREATE TABLE AS SELECT tests
+#
+
+--source include/galera_cluster.inc
+
+--connection node_1
+SET SESSION default_storage_engine=InnoDB;
+
+# Left table already exists
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+--error ER_TABLE_EXISTS_ERROR
+CREATE TABLE t1 AS SELECT * FROM t2;
+DROP TABLE t1,t2;
+
+# Right table does not exist
+--error ER_NO_SUCH_TABLE
+CREATE TABLE t1 AS SELECT * FROM t2;
+
+# No right table at all
+CREATE TABLE t1 AS SELECT 1 FROM DUAL;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
+
+# Empty right table
+--connection node_1
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t1 AS SELECT * FROM t2;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+DROP TABLE t1,t2;
+
+# Right table is MyISAM
+
+CREATE TABLE t2 (f1 INTEGER) ENGINE=MyISAM;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+CREATE TABLE t1 AS SELECT * FROM t2;
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+DROP TABLE t1,t2;
+
+# Right side is a subquery
+
+--connection node_1
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+CREATE TABLE t1 AS SELECT MAX(f1) AS f1 FROM t2;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SELECT f1 = 5 FROM t1;
+
+--connection node_1
+DROP TABLE t1,t2;
+
+# Inside a stored procedure
+
+--connection node_1
+DELIMITER |;
+CREATE PROCEDURE sp1 ()
+BEGIN
+ CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+ INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+ CREATE TABLE t1 AS SELECT * FROM t2;
+END|
+DELIMITER ;|
+CALL sp1();
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+DROP TABLE t1, t2;
+DROP PROCEDURE sp1;
+
+# Inside a prepared statement
+
+--connection node_1
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+
+PREPARE stmt FROM 'CREATE TABLE t1 AS SELECT * FROM t2';
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+DROP TABLE t1, t2;
+
+#
+# Multi-master conflict
+#
+
+--connection node_1
+
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+LOCK TABLE t2 WRITE;
+
+--connection node_1
+--send CREATE TABLE t1 AS SELECT * FROM t2;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t2;
+CREATE TABLE t1 AS SELECT * FROM t2;
+
+--connection node_1a
+UNLOCK TABLES;
+
+--connection node_1
+--error ER_TABLE_EXISTS_ERROR,ER_LOCK_DEADLOCK
+--reap
+
+DROP TABLE t1, t2;
+
+#
+# Temporary table
+#
+
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3),(4),(5);
+
+CREATE TEMPORARY TABLE t1 AS SELECT * FROM t2;
+
+--connection node_2
+--error ER_NO_SUCH_TABLE
+SELECT * FROM t1;
+
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test.t1'' on query");
+
+--connection node_1
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera/t/galera_defaults.test b/mysql-test/suite/galera/t/galera_defaults.test
index 3d4a7da7b54..3f8be268135 100644
--- a/mysql-test/suite/galera/t/galera_defaults.test
+++ b/mysql-test/suite/galera/t/galera_defaults.test
@@ -19,7 +19,7 @@ source ../wsrep/include/check_galera_version.inc;
# Global Variables
-SELECT COUNT(*) = 43 FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
+SELECT COUNT(*) `expect 48` FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'wsrep_%';
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
diff --git a/mysql-test/suite/galera/t/galera_forced_binlog_format.test b/mysql-test/suite/galera/t/galera_forced_binlog_format.test
index 364f41529a4..e9d7fa1c3a3 100644
--- a/mysql-test/suite/galera/t/galera_forced_binlog_format.test
+++ b/mysql-test/suite/galera/t/galera_forced_binlog_format.test
@@ -7,7 +7,10 @@
--source include/galera_cluster.inc
--connection node_1
+SEt GLOBAL wsrep_on=OFF;
RESET MASTER;
+SEt GLOBAL wsrep_on=ON;
+FLUSH BINARY LOGS;
SET SESSION binlog_format = 'STATEMENT';
@@ -40,6 +43,6 @@ REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost;
DROP USER dummy@localhost;
DROP DATABASE testdb_9401;
---source include/galera_end.inc
+#--source include/galera_end.inc
--echo # End of tests
diff --git a/mysql-test/suite/galera/t/galera_ftwrl_drain.test b/mysql-test/suite/galera/t/galera_ftwrl_drain.test
index 690e890cdea..ee64e147f65 100644
--- a/mysql-test/suite/galera/t/galera_ftwrl_drain.test
+++ b/mysql-test/suite/galera/t/galera_ftwrl_drain.test
@@ -12,7 +12,7 @@
--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
+--source include/galera_have_debug_sync.inc
--connection node_1
CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
@@ -55,7 +55,7 @@ SET SESSION innodb_lock_wait_timeout=1;
SET SESSION wait_timeout=1;
--error ER_LOCK_WAIT_TIMEOUT
-INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (2);
--connection node_2a
UNLOCK TABLES;
diff --git a/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test
index b7fd9cf3aed..d728a094f10 100644
--- a/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test
+++ b/mysql-test/suite/galera/t/galera_gcache_recover_full_gcache.test
@@ -13,6 +13,14 @@ SET SESSION wsrep_sync_wait = 0;
--source include/kill_galera.inc
--connection node_1
+
+#
+# Wait until the configuration change is over in order to avoid
+# replication error due to configuration change.
+#
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
INSERT INTO t1 (f2) VALUES (REPEAT('x', 1024 * 1024 * 10));
@@ -48,8 +56,8 @@ DROP TABLE t1;
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
# Confirm that IST did not take place
---let $assert_text = IST first seqno 2 not found from cache, falling back to SST
---let $assert_select = IST first seqno 2 not found from cache, falling back to SST
+--let $assert_text = IST first seqno [24] not found from cache, falling back to SST
+--let $assert_select = IST first seqno [24] not found from cache, falling back to SST
--let $assert_count = 1
--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
--let $assert_only_after = starting as process
diff --git a/mysql-test/suite/galera/t/galera_gcs_fragment.test b/mysql-test/suite/galera/t/galera_gcs_fragment.test
index 80d3a5cb659..d2593fec8c8 100644
--- a/mysql-test/suite/galera/t/galera_gcs_fragment.test
+++ b/mysql-test/suite/galera/t/galera_gcs_fragment.test
@@ -1,7 +1,7 @@
# Test fragmentation over configuration changes
--source include/galera_cluster.inc
--source include/have_innodb.inc
---source suite/galera/include/galera_have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
# Save original auto_increment_offset values.
--let $node_1=node_1
@@ -54,7 +54,7 @@ INSERT INTO t1 VALUES (2, "bbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
# Deadlock error should be returned since write set send was
# interrupted by gcs
--connection node_1
---error ER_LOCK_DEADLOCK
+--error ER_ERROR_DURING_COMMIT
--reap
# Do additional insert to verify that node_1 remain operational
diff --git a/mysql-test/suite/galera/t/galera_gtid-master.opt b/mysql-test/suite/galera/t/galera_gtid-master.opt
index 8a755e98b00..30317469ae7 100644
--- a/mysql-test/suite/galera/t/galera_gtid-master.opt
+++ b/mysql-test/suite/galera/t/galera_gtid-master.opt
@@ -1 +1 @@
---log-bin --log-slave-updates
+--log-bin --log-slave-updates --loose-new-servers-for-galera_gtid-test
diff --git a/mysql-test/suite/galera/t/galera_gtid_slave.test b/mysql-test/suite/galera/t/galera_gtid_slave.test
index 19bfd8e17db..df55ea03cb0 100644
--- a/mysql-test/suite/galera/t/galera_gtid_slave.test
+++ b/mysql-test/suite/galera/t/galera_gtid_slave.test
@@ -8,18 +8,19 @@
#
--source include/have_innodb.inc
-
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3;
--enable_query_log
START SLAVE;
---connection node_1
+--connection node_3
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
@@ -49,31 +50,43 @@ INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(3);
SELECT @@global.gtid_binlog_state;
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 3 FROM t1;
--source include/wait_condition.inc
INSERT INTO t1 VALUES(4);
SELECT @@global.gtid_binlog_state;
---connection node_1
+--connection node_3
DROP TABLE t1,t2;
+#
+# Unfortunately without the sleep below the following statement fails with "query returned no rows", which
+# is difficult to understand given that it is an aggregate query. A "query execution was interrupted"
+# warning is also reported by MTR, which is also weird.
+#
+
+--sleep 1
+
--connection node_2
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
---connection node_3
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
--connection node_2
STOP SLAVE;
RESET SLAVE ALL;
+SET GLOBAL wsrep_on=OFF;
reset master;
+SET GLOBAL wsrep_on=ON;
---connection node_3
+--connection node_1
+SET GLOBAL wsrep_on=OFF;
reset master;
+SET GLOBAL wsrep_on=ON;
---connection node_1
+--connection node_3
reset master;
diff --git a/mysql-test/suite/galera/t/galera_gtid_slave_sst_rsync.test b/mysql-test/suite/galera/t/galera_gtid_slave_sst_rsync.test
index 3ed7ec1d09e..d03445d537a 100644
--- a/mysql-test/suite/galera/t/galera_gtid_slave_sst_rsync.test
+++ b/mysql-test/suite/galera/t/galera_gtid_slave_sst_rsync.test
@@ -8,21 +8,21 @@
--source include/big_test.inc
--source include/have_innodb.inc
-# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
---connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
--source include/galera_cluster.inc
+# As node #3 is not a Galera node, and galera_cluster.inc does not open connetion to it
+# we open the node_3 connection here
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
--echo #Connection 2
--connection node_2
--disable_query_log
---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1,master_use_gtid=slave_pos;
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3,master_use_gtid=slave_pos;
--enable_query_log
START SLAVE;
--sleep 1
-
---echo #Connection 1
---connection node_1
+--echo #Connection 3
+--connection node_3
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 int unique) ENGINE=InnoDB;
INSERT INTO t2 VALUES(1,11);
INSERT INTO t2 VALUES(2,22);
@@ -30,7 +30,6 @@ INSERT INTO t2 VALUES(3,33);
SELECT @@global.gtid_binlog_state;
--source include/save_master_gtid.inc
-
--echo #Connection 2
--connection node_2
--source include/sync_with_master_gtid.inc
@@ -40,9 +39,8 @@ INSERT INTO t2 VALUES(4,44);
INSERT INTO t2 VALUES(5,55);
INSERT INTO t2 VALUES(6,66);
SELECT @@global.gtid_binlog_state;
-
---echo #Connection 3
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--echo #Connection 1
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 't2';
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 6 FROM t2;
@@ -53,8 +51,8 @@ INSERT INTO t2 VALUES(8,88);
SELECT @@global.gtid_binlog_state;
#Perform SST
---echo #Connection 1
---connection node_1
+--echo #Connection 3
+--connection node_3
CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
@@ -62,7 +60,6 @@ INSERT INTO t1 VALUES ('node1_committed_before');
INSERT INTO t1 VALUES ('node1_committed_before');
COMMIT;
--source include/save_master_gtid.inc
-
--echo #Connection 2
--connection node_2
--source include/sync_with_master_gtid.inc
@@ -71,22 +68,21 @@ START TRANSACTION;
INSERT INTO t1 VALUES ('node2_committed_before');
INSERT INTO t1 VALUES ('node2_committed_before');
COMMIT;
-
---echo #Connection 3
---connection node_3
+--echo #Connection 1
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= 't1';
--source include/wait_condition.inc
--let $wait_condition = SELECT COUNT(*) = 4 FROM t1;
--source include/wait_condition.inc
---let $node_1= node_2
---let $node_2= node_3
+--let $node_1= node_1
+--let $node_2= node_2
--source include/auto_increment_offset_save.inc
---echo Shutting down server ...
---source include/shutdown_mysqld.inc
-
-
--echo #Connection 2
--connection node_2
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+--echo #Connection 1
+--connection node_1
--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
SET AUTOCOMMIT=OFF;
@@ -94,51 +90,46 @@ START TRANSACTION;
INSERT INTO t1 VALUES ('node1_committed_during');
INSERT INTO t1 VALUES ('node1_committed_during');
COMMIT;
-
---echo #Connection 3
---connection node_3
+--echo #Connection 2
+--connection node_2
--echo Starting server ...
--source include/start_mysqld.inc
+
--source include/wait_until_ready.inc
--source include/auto_increment_offset_restore.inc
SET AUTOCOMMIT=OFF;
START TRANSACTION;
-INSERT INTO t1 VALUES ('node3_committed_after');
-INSERT INTO t1 VALUES ('node3_committed_after');
+INSERT INTO t1 VALUES ('node2_committed_after');
+INSERT INTO t1 VALUES ('node2_committed_after');
COMMIT;
-
---echo #Connection 2
---connection node_2
+--echo #Connection 1
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 8 FROM t1;
--source include/wait_condition.inc
Select * from t1 order by f1;
-
---echo #Connection 3
---connection node_3
+--echo #Connection 2
+--connection node_2
Select * from t1 order by f1;
#SST Done
--sleep 1
+--echo #Connection 1
+--connection node_1
+SELECT @@global.gtid_binlog_state;
--echo #Connection 2
--connection node_2
SELECT @@global.gtid_binlog_state;
-
--echo #Connection 3
--connection node_3
-SELECT @@global.gtid_binlog_state;
-
---echo #Connection 1
---connection node_1
SET AUTOCOMMIT=ON;
#drop table t1;
#CREATE TABLE t1 (f1 CHAR(255)) ENGINE=InnoDB;
-
--echo #Connection 2
--connection node_2
SET AUTOCOMMIT=ON;
---echo #Connection 3
---connection node_3
+--echo #Connection 1
+--connection node_1
SET AUTOCOMMIT=ON;
#
@@ -148,10 +139,9 @@ SET AUTOCOMMIT=ON;
STOP slave;
--sleep 1
INSERT INTO t1 VALUES ('node2_slave_stoped');
-
---echo #Connection 1
---connection node_1
-INSERT INTO t1 VALUES ('node1_normal_entry');
+--echo #Connection 3
+--connection node_3
+INSERT INTO t1 VALUES ('node3_normal_entry');
--source include/save_master_gtid.inc
#start slave
@@ -163,16 +153,14 @@ start slave;
INSERT INTO t1 VALUES ('node2_slave_started');
SELECT count(*) from t1;
SELECT @@global.gtid_binlog_state;
-
---echo #Connection 3
---connection node_3
+--echo #Connection 1
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 12 FROM t1;
--source include/wait_condition.inc
SELECT count(*) from t1;
SELECT @@global.gtid_binlog_state;
-
---echo #Connection 1
---connection node_1
+--echo #Connection 3
+--connection node_3
DROP TABLE t2,t1;
# Unfortunately without the sleep below the following statement fails with "query returned no rows", which
@@ -181,30 +169,31 @@ DROP TABLE t2,t1;
#
--sleep 3
-
--echo #Connection 2
--connection node_2
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2';
--source include/wait_condition.inc
-
---echo #Connection 3
---connection node_3
+--echo #Connection 1
+--connection node_1
--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
--source include/wait_condition.inc
-
--echo #Connection 2
--connection node_2
STOP SLAVE;
RESET SLAVE ALL;
+set global wsrep_on=OFF;
+reset master;
+set global wsrep_on=ON;
+
--disable_warnings
set global gtid_slave_pos="";
--enable_warnings
-reset master;
-
---echo #Connection 3
---connection node_3
-reset master;
--echo #Connection 1
--connection node_1
+set global wsrep_on=OFF;
+reset master;
+set global wsrep_on=ON;
+--echo #Connection 3
+--connection node_3
reset master;
diff --git a/mysql-test/suite/galera/t/galera_ist_progress.test b/mysql-test/suite/galera/t/galera_ist_progress.test
index 3ba63415c28..dd93161eab8 100644
--- a/mysql-test/suite/galera/t/galera_ist_progress.test
+++ b/mysql-test/suite/galera/t/galera_ist_progress.test
@@ -58,8 +58,8 @@ SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0';
--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
--let $assert_only_after = Need state transfer
---let $assert_text = Receiving IST: 11 writesets, seqnos
---let $assert_select = Receiving IST: 11 writesets, seqnos
+--let $assert_text = Receiving IST: 1[13] writesets
+--let $assert_select = Receiving IST: 1[13] writesets
--source include/assert_grep.inc
--let $assert_text = Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete
diff --git a/mysql-test/suite/galera/t/galera_ist_restart_joiner.test b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
index 633318629a6..42f210170bc 100644
--- a/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
+++ b/mysql-test/suite/galera/t/galera_ist_restart_joiner.test
@@ -7,7 +7,7 @@
--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
+--source include/galera_have_debug_sync.inc
# This could cause out of storage if run /dev/shm
--source include/big_test.inc
@@ -43,8 +43,6 @@ UPDATE t1 SET f2 = 'c' WHERE f1 > 2;
# ... and restart provider to force IST
--echo Loading wsrep_provider ...
--disable_query_log
-# base_port setting is lost for some reason when unloading provider, so we need to restore it
---eval SET GLOBAL wsrep_provider_options= 'base_port=$NODE_GALERAPORT_2';
--eval SET GLOBAL wsrep_provider = '$wsrep_provider_orig';
# Make sure IST will block ...
--let $galera_sync_point = recv_IST_after_apply_trx
diff --git a/mysql-test/suite/galera/t/galera_kill_applier.test b/mysql-test/suite/galera/t/galera_kill_applier.test
index d04b72bce0a..b66e0bcbbd0 100644
--- a/mysql-test/suite/galera/t/galera_kill_applier.test
+++ b/mysql-test/suite/galera/t/galera_kill_applier.test
@@ -6,7 +6,6 @@
--source include/have_innodb.inc
--connection node_1
---sleep 2
--let $applier_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE IS NULL LIMIT 1`
--disable_query_log
diff --git a/mysql-test/suite/galera/t/galera_log_bin.test b/mysql-test/suite/galera/t/galera_log_bin.test
index 2f0faa761c5..57df53e29b1 100644
--- a/mysql-test/suite/galera/t/galera_log_bin.test
+++ b/mysql-test/suite/galera/t/galera_log_bin.test
@@ -36,4 +36,6 @@ DROP TABLE t1;
DROP TABLE t2;
--connection node_1
+SET GLOBAL wsrep_on=OFF;
RESET MASTER;
+SET GLOBAL wsrep_on=ON;
diff --git a/mysql-test/suite/galera/t/galera_many_rows.cnf b/mysql-test/suite/galera/t/galera_many_rows.cnf
new file mode 100644
index 00000000000..24c4cc1c60d
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_many_rows.cnf
@@ -0,0 +1,10 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+innodb-status-output=ON
+innodb-status-output-locks=ON
+
+[mysqld.2]
+innodb-status-output=ON
+innodb-status-output-locks=ON
+
diff --git a/mysql-test/suite/galera/t/galera_many_rows.test b/mysql-test/suite/galera/t/galera_many_rows.test
index 58ba85e1b9e..67e2eb6edbf 100644
--- a/mysql-test/suite/galera/t/galera_many_rows.test
+++ b/mysql-test/suite/galera/t/galera_many_rows.test
@@ -3,6 +3,11 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
--connection node_1
SET SESSION innodb_lock_wait_timeout=600;
SET SESSION lock_wait_timeout=600;
@@ -52,3 +57,5 @@ COMMIT;
DROP TABLE t1;
DROP TABLE ten;
+
+--source include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera/t/galera_migrate.cnf b/mysql-test/suite/galera/t/galera_migrate.cnf
index ed48f208e52..2e1e9f161a9 100644
--- a/mysql-test/suite/galera/t/galera_migrate.cnf
+++ b/mysql-test/suite/galera/t/galera_migrate.cnf
@@ -29,11 +29,13 @@ wsrep_sync_wait = 15
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+log-slave-updates
[mysqld.4]
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+log-slave-updates
[ENV]
NODE_MYPORT_1= @mysqld.1.port
diff --git a/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test b/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test
index 08ed3fac67e..5a33c16c86e 100644
--- a/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test
+++ b/mysql-test/suite/galera/t/galera_parallel_apply_lock_table.test
@@ -32,8 +32,8 @@ INSERT INTO t2 VALUES (1);
--connection node_2a
--sleep 1
SET SESSION wsrep_sync_wait=0;
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%applied write set%';
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for table metadata lock';
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%committing%';
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%Waiting for table metadata lock%';
SELECT COUNT(*) = 0 FROM t1;
SELECT COUNT(*) = 0 FROM t2;
@@ -44,7 +44,7 @@ UNLOCK TABLES;
--eval SET SESSION wsrep_sync_wait = $wsrep_sync_wait_orig;
SELECT COUNT(*) = 1 FROM t1;
SELECT COUNT(*) = 1 FROM t2;
-SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'committed%';
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE '%committed%';
--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test b/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test
index 644b4687cb3..203d18b85a6 100644
--- a/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test
+++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_largetrx.test
@@ -12,13 +12,16 @@
--source include/galera_connect.inc
--connection node_1
-CREATE TABLE ten (f1 INTEGER);
+CREATE TABLE ten (f1 INTEGER) engine=InnoDB;
INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
+
--connection node_2
--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
SET GLOBAL wsrep_slave_threads = 4;
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
+--source include/wait_condition.inc
--connection node_1
--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
@@ -31,16 +34,18 @@ SET GLOBAL wsrep_slave_threads = 4;
--connection node_1
--reap
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(DISTINCT f1) FROM t1;
--connection node_1a
--reap
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(DISTINCT f1) FROM t1;
--connection node_2
--reap
SELECT COUNT(*) FROM t1;
SELECT COUNT(DISTINCT f1) FROM t1;
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE
- USER = 'system user' AND STATE NOT LIKE 'InnoDB%';
--disable_query_log
--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
diff --git a/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test b/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test
index 8680d62a36d..d2156cb3577 100644
--- a/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test
+++ b/mysql-test/suite/galera/t/galera_parallel_autoinc_manytrx.test
@@ -42,7 +42,7 @@ while ($count)
SELECT COUNT(*) = 20000 FROM t1;
SELECT COUNT(DISTINCT f1) = 20000 FROM t1;
-SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%';
+SELECT COUNT(*) = 4 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'wsrep applier committed%';
--disable_query_log
--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
diff --git a/mysql-test/suite/galera/t/galera_parallel_simple.test b/mysql-test/suite/galera/t/galera_parallel_simple.test
index 2cd840123cf..51bb1355ba4 100644
--- a/mysql-test/suite/galera/t/galera_parallel_simple.test
+++ b/mysql-test/suite/galera/t/galera_parallel_simple.test
@@ -47,7 +47,7 @@ SET SESSION wsrep_sync_wait = 0;
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for table metadata lock%';
--source include/wait_condition.inc
---let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'applied write set%';
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'committing%';
--source include/wait_condition.inc
UNLOCK TABLES;
diff --git a/mysql-test/suite/galera/t/galera_pc_recovery.test b/mysql-test/suite/galera/t/galera_pc_recovery.test
new file mode 100644
index 00000000000..1621414aff5
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_pc_recovery.test
@@ -0,0 +1,102 @@
+#
+# Test the pc.recovery=1 option. Killing all nodes simultaneously and
+# restarting them should succeed and the cluster should re-form.
+#
+
+--source include/have_innodb.inc
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+# Save galera ports
+--connection node_1
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_1 = $_NODE_GALERAPORT
+
+--connection node_2
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_2 = $_NODE_GALERAPORT
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+
+# Instruct MTR to not restart the nodes automatically when they are killed
+
+--let $NODE_1_PIDFILE = `SELECT @@pid_file`
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+--let $NODE_2_PIDFILE = `SELECT @@pid_file`
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--exec kill -9 `cat $NODE_1_PIDFILE` `cat $NODE_2_PIDFILE`
+
+# Perform --wsrep-recover and preserve the positions into variables by placing them in $MYSQL_TMP_DIR/galera_wsrep_start_position.inc and then --source'ing it
+
+--exec $MYSQLD --defaults-group-suffix=.1 --defaults-file=$MYSQLTEST_VARDIR/my.cnf --wsrep-recover --log-error=$MYSQL_TMP_DIR/galera_wsrep_recover.1.log > $MYSQL_TMP_DIR/galera_wsrep_recover.1.log 2>&1
+--exec $MYSQLD --defaults-group-suffix=.2 --defaults-file=$MYSQLTEST_VARDIR/my.cnf --wsrep-recover --log-error=$MYSQL_TMP_DIR/galera_wsrep_recover.2.log > $MYSQL_TMP_DIR/galera_wsrep_recover.2.log 2>&1
+
+--perl
+ use strict;
+ my $wsrep_start_position1 = `grep 'WSREP: Recovered position:' $ENV{MYSQL_TMP_DIR}/galera_wsrep_recover.1.log | sed 's/.*WSREP\:\ Recovered\ position://' | sed 's/^[ \t]*//'`;
+ chomp($wsrep_start_position1);
+
+ my $wsrep_start_position2 = `grep 'WSREP: Recovered position:' $ENV{MYSQL_TMP_DIR}/galera_wsrep_recover.2.log | sed 's/.*WSREP\:\ Recovered\ position://' | sed 's/^[ \t]*//'`;
+ chomp($wsrep_start_position2);
+
+ die if $wsrep_start_position1 eq '' || $wsrep_start_position2 eq '';
+
+ open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/galera_wsrep_start_position.inc") or die;
+ print FILE "--let \$galera_wsrep_start_position1 = $wsrep_start_position1\n";
+ print FILE "--let \$galera_wsrep_start_position2 = $wsrep_start_position2\n";
+ close FILE;
+EOF
+
+--source $MYSQL_TMP_DIR/galera_wsrep_start_position.inc
+
+if ($galera_wsrep_start_position1 == '') {
+ --die "Could not obtain wsrep_start_position."
+}
+
+if ($galera_wsrep_start_position2 == '') {
+ --die "Could not obtain wsrep_start_position."
+}
+
+--remove_file $MYSQL_TMP_DIR/galera_wsrep_start_position.inc
+
+# Instruct MTR to perform the actual restart using --wsrep-start-position . Proper --wsrep_cluster_address is used as my.cnf only contains 'gcomm://' for node #1
+
+--exec echo "restart: --wsrep-start-position=$galera_wsrep_start_position1 --wsrep_cluster_address=gcomm://127.0.0.1:$NODE_GALERAPORT_1,127.0.0.1:$NODE_GALERAPORT_2" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--exec echo "restart: --wsrep-start-position=$galera_wsrep_start_position2 --wsrep_cluster_address=gcomm://127.0.0.1:$NODE_GALERAPORT_1,127.0.0.1:$NODE_GALERAPORT_2" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+
+--sleep 5
+--connection node_1
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# Confirm that the cluster has re-formed and data is present
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+SELECT COUNT(*) = 1 FROM t1;
+
+--connection node_2
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
+
+--connection node_1
+CALL mtr.add_suppression("points to own listening address, blacklisting");
+CALL mtr.add_suppression("non weight changing install in S_PRIM");
+CALL mtr.add_suppression("No re-merged primary component found");
+
+--connection node_2
+CALL mtr.add_suppression("points to own listening address, blacklisting");
+CALL mtr.add_suppression("non weight changing install in S_PRIM");
+CALL mtr.add_suppression("No re-merged primary component found");
diff --git a/mysql-test/suite/galera/t/galera_split_brain.test b/mysql-test/suite/galera/t/galera_split_brain.test
index a85a2ad9b8d..91a2cc326a2 100644
--- a/mysql-test/suite/galera/t/galera_split_brain.test
+++ b/mysql-test/suite/galera/t/galera_split_brain.test
@@ -1,6 +1,8 @@
#
-# Confirm that with two nodes, killing one causes the other to stop accepting connections
-# The pc.ignore_sb=true wsrep_provider option is tested in the galera_kill_* tests.
+# Confirm that with two nodes, killing one causes the other to stop accepting
+# connections.
+# The pc.ignore_sb=true wsrep_provider option is tested in the galera_kill_*
+# tests.
#
--source include/galera_cluster.inc
diff --git a/mysql-test/suite/galera/t/galera_ssl_upgrade.test b/mysql-test/suite/galera/t/galera_ssl_upgrade.test
index a424942da30..6dc3bf7a5a3 100644
--- a/mysql-test/suite/galera/t/galera_ssl_upgrade.test
+++ b/mysql-test/suite/galera/t/galera_ssl_upgrade.test
@@ -46,4 +46,8 @@ SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_N
--source include/wait_condition.inc
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+# 5. Make sure node_2 is ready as well
+--connection node_2
+--source include/galera_wait_ready.inc
+
# Upgrade complete. Both nodes now use the new key and certificate
diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf b/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf
index 574ae28b54a..0d05038f2fb 100644
--- a/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf
+++ b/mysql-test/suite/galera/t/galera_sst_mysqldump.cnf
@@ -5,7 +5,7 @@
[mysqld.1]
wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
-
+wsrep_sync_wait=0
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
-
+wsrep_sync_wait=0
diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump.test b/mysql-test/suite/galera/t/galera_sst_mysqldump.test
index 835fac94a68..cce4d374a6d 100644
--- a/mysql-test/suite/galera/t/galera_sst_mysqldump.test
+++ b/mysql-test/suite/galera/t/galera_sst_mysqldump.test
@@ -1,6 +1,5 @@
--source include/big_test.inc
--source include/galera_cluster.inc
-
--source suite/galera/include/galera_sst_set_mysqldump.inc
--let $node_1=node_1
@@ -14,7 +13,6 @@
--source suite/galera/include/galera_st_shutdown_slave.inc
--source suite/galera/include/galera_st_clean_slave.inc
-
--source suite/galera/include/galera_st_kill_slave.inc
--source suite/galera/include/galera_st_kill_slave_ddl.inc
diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf
index 44e5573b3e6..b7bca487fc5 100644
--- a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf
+++ b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf
@@ -5,9 +5,13 @@
[mysqld.1]
wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
+wsrep_causal_reads=0
+wsrep_sync_wait=0
[mysqld.2]
wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
+wsrep_causal_reads=0
+wsrep_sync_wait=0
[mysqld]
wsrep_debug=ON
diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_error.test b/mysql-test/suite/galera/t/galera_toi_ddl_error.test
index c586d97bdb5..6ee2a6e9b16 100644
--- a/mysql-test/suite/galera/t/galera_toi_ddl_error.test
+++ b/mysql-test/suite/galera/t/galera_toi_ddl_error.test
@@ -27,3 +27,8 @@ SHOW CREATE TABLE t1;
DROP TABLE t1;
DROP TABLE ten;
+
+CALL mtr.add_suppression("Ignoring error 'Duplicate entry '111110' for key 'PRIMARY'' on query.");
+
+--connection node_2
+CALL mtr.add_suppression("Ignoring error 'Duplicate entry '111110' for key 'PRIMARY'' on query."); \ No newline at end of file
diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_locking.test b/mysql-test/suite/galera/t/galera_toi_ddl_locking.test
index 12c83a1f87a..22a45316306 100644
--- a/mysql-test/suite/galera/t/galera_toi_ddl_locking.test
+++ b/mysql-test/suite/galera/t/galera_toi_ddl_locking.test
@@ -11,20 +11,31 @@
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
---connection node_1
-SET DEBUG_SYNC = 'alter_table_before_open_tables WAIT_FOR continue';
---send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
-
--let $galera_connection_name = node_1a
--let $galera_server_number = 1
--source include/galera_connect.inc
+SET SESSION wsrep_sync_wait = 0;
--let $galera_connection_name = node_1b
--let $galera_server_number = 1
--source include/galera_connect.inc
+# node_1c tests write to unrelated table trough a transaction
+--let $galera_connection_name = node_1c
+--let $galera_server_number = 1
+--source include/galera_connect.inc
+
+--connection node_1
+SET DEBUG_SYNC= 'RESET';
+SET DEBUG_SYNC = 'alter_table_before_open_tables SIGNAL before_open_tables WAIT_FOR continue';
+--send ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
--connection node_1a
-SET SESSION wsrep_sync_wait = 0;
+SET DEBUG_SYNC= 'now WAIT_FOR before_open_tables';
+
+# if we would retry the insert, it would fail for wrong column count
+# on second try
+SET wsrep_retry_autocommit=0;
# Allowed
SELECT COUNT(*) = 0 FROM t1;
@@ -32,45 +43,56 @@ SELECT COUNT(*) = 0 FROM t1;
# Allowed
SELECT COUNT(*) = 0 FROM t2;
-# Not allowed
---error ER_LOCK_DEADLOCK,ER_ERROR_DURING_COMMIT
-INSERT INTO t1 VALUES (1);
+# Not allowed, this will hang because of ALTER
+--send INSERT INTO t1 VALUES (1);
+
+--connection node_1c
+SET SESSION wsrep_sync_wait = 0;
SET AUTOCOMMIT=OFF;
START TRANSACTION;
# Allowed
+SELECT COUNT(*) = 0 FROM t1;
+
+# Allowed
+SELECT COUNT(*) = 0 FROM t2;
+
+# Allowed (until commit)
INSERT INTO t2 VALUES (1);
# Hangs
--send COMMIT;
---sleep 1
--connection node_1b
SET SESSION wsrep_sync_wait = 0;
# The Commit issued above is still not done
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'Commit';
+--sleep 1
SELECT COUNT(*) = 0 FROM t2;
+
+SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO = 'Commit';
+
SET DEBUG_SYNC= 'now SIGNAL continue';
--connection node_1a
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_1c
+# this will succeeed, becaus the query will be replayed
--reap
--connection node_1
--reap
+
SELECT COUNT(*) = 0 FROM t1;
SELECT COUNT(*) = 1 FROM t2;
+SET debug_sync='RESET';
--connection node_2
SELECT COUNT(*) = 0 FROM t1;
SELECT COUNT(*) = 1 FROM t2;
---connection node_1
-SET DEBUG_SYNC= 'RESET';
-
---connection node_1b
-SET DEBUG_SYNC= 'RESET';
-
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera/t/galera_transaction_replay.test b/mysql-test/suite/galera/t/galera_transaction_replay.test
index 29870829ba3..655714f26c9 100644
--- a/mysql-test/suite/galera/t/galera_transaction_replay.test
+++ b/mysql-test/suite/galera/t/galera_transaction_replay.test
@@ -1,12 +1,25 @@
#
-# This test tests the operation of transaction replay. If a potentially conflicting remote transaction arrives at
-# just the right time during the commit of a local transaction, the local transaction will be aborted and replayed.
+# This test tests the operation of transaction replay. If a potentially
+# conflicting remote transaction arrives at just the right time during
+# the commit of a local transaction, the local transaction will be aborted
+# and replayed.
+#
+# Because the write set with higher sequence number cannot BF abort
+# the victim with lower sequence number, the conflicting remote transaction
+# must be executed first and must be allowed to proceed up to the apply
+# monitor before sending the COMMIT for the transaction to be replayed.
#
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_debug_sync.inc
---source suite/galera/include/galera_have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
+
+######################################################################
+#
+# Scenario #1, the victim will have higher seqno and will be replayed
+#
+######################################################################
--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
@@ -21,34 +34,123 @@ START TRANSACTION;
UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
-# Block the commit
+# Block the applier on node #1 and issue a conflicting update on node #2
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
---let $galera_sync_point = commit_monitor_enter_sync
+SET SESSION wsrep_sync_wait=0;
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+
+--connection node_1a
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+# Block the commit, send the COMMIT and wait until it gets blocked
+
+--let $galera_sync_point = commit_monitor_master_enter_sync
--source include/galera_set_sync_point.inc
--connection node_1
---send COMMIT;
+--send COMMIT
-# Wait until commit is blocked
--connection node_1a
-SET SESSION wsrep_sync_wait = 0;
+
+--let $galera_sync_point = apply_monitor_slave_enter_sync commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+# Let the conflicting UPDATE proceed and wait until it hits abort_trx_end.
+# The victim transaction still sits in commit_monitor_master_sync_point.
+
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = abort_trx_end commit_monitor_master_enter_sync
--source include/galera_wait_sync_point.inc
-# Issue a conflicting update on node #2
+# Let the transactions proceed
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = commit_monitor_master_enter_sync
+--source include/galera_signal_sync_point.inc
+
+# Commit succeeds
+--connection node_1
+--reap
+
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+# wsrep_local_replays has increased by 1
+--let $wsrep_local_replays_new = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+--disable_query_log
+--eval SELECT $wsrep_local_replays_new - $wsrep_local_replays_old = 1 AS wsrep_local_replays;
+--enable_query_log
+
--connection node_2
-UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+DROP TABLE t1;
+
+#########################################################################
+#
+# Scenario #2, the victim will have lower seqno and will not be replayed
+#
+#########################################################################
+
+--connection node_1
+
+--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+
+--connection node_1
+SET AUTOCOMMIT=ON;
+START TRANSACTION;
+
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
+
+# Block the commit, send the COMMIT and wait until it gets blocked
+
+--let $galera_sync_point = commit_monitor_master_enter_sync
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+--send COMMIT
-# 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
+--let $galera_sync_point = commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+
+# Set sync point at the end of BF abort, issue a conflicting update
+# and wait for the conflicting update to hit the sync point.
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
-# Unblock the commit
--connection node_1a
+--let $galera_sync_point = abort_trx_end commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+# Let the transactions proceed
--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = commit_monitor_master_enter_sync
--source include/galera_signal_sync_point.inc
# Commit succeeds
@@ -58,10 +160,10 @@ UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
-# wsrep_local_replays has increased by 1
+# wsrep_local_replays should have not increased
--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;
+--eval SELECT $wsrep_local_replays_new - $wsrep_local_replays_old = 0 AS wsrep_local_replays;
--enable_query_log
--connection node_2
@@ -70,55 +172,84 @@ SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
DROP TABLE t1;
-#echo "# test for PS replaying"
+########################################
#
# test replaying of prepared statements
#
+########################################
+
--connection node_1
+
+--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+
CREATE TABLE t1 (i int primary key, j int) ENGINE=INNODB;
INSERT INTO t1 VALUES (1, 0), (3, 0);
SELECT * FROM t1;
-
+SET AUTOCOMMIT=ON;
PREPARE stmt1 FROM "UPDATE t1 SET j = 1 where i > 0";
-# block the commit of PS
+
+# Block the applier on node #1 and issue a conflicting update on node #2
--connection node_1a
---let $galera_sync_point = commit_monitor_enter_sync
+SET SESSION wsrep_sync_wait=0;
+--let $galera_sync_point = apply_monitor_slave_enter_sync
--source include/galera_set_sync_point.inc
---connection node_1
---send EXECUTE stmt1;
+--connection node_2
+INSERT INTO t1 VALUES(2,2);
-# Wait until commit is blocked
--connection node_1a
-SET SESSION wsrep_sync_wait = 0;
--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
-# Issue a conflicting update on node_2
---connection node_2
-#UPDATE t1 SET j=2;
-INSERT INTO t1 VALUES(2,2);
+# Block the commit, send the EXECUTE stmt1 and wait until it gets blocked
+--let $galera_sync_point = commit_monitor_master_enter_sync
+--source include/galera_set_sync_point.inc
-# Wait until applying begins in node_1
---connection node_1a
---let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Write_rows_log_event::write_row%';
---source include/wait_condition.inc
+--connection node_1
+SET SESSION wsrep_sync_wait=0;
+--send EXECUTE stmt1
-# Unblock the PS commit
--connection node_1a
+
+--let $galera_sync_point = apply_monitor_slave_enter_sync commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
--source include/galera_clear_sync_point.inc
+
+# Let the conflicting INSERT proceed and wait until it hits abort_trx_end.
+# The victim transaction still sits in commit_monitor_master_sync_point.
+
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = abort_trx_end commit_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+
+# Let the transactions proceed
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = commit_monitor_master_enter_sync
--source include/galera_signal_sync_point.inc
# Commit succeeds
--connection node_1
--reap
+SET SESSION wsrep_sync_wait=7;
SELECT * FROM t1;
--connection node_2
SELECT * FROM t1;
--connection node_1
+# 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
+
DEALLOCATE PREPARE stmt1;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_var_cluster_address.test b/mysql-test/suite/galera/t/galera_var_cluster_address.test
index 6d99d35cdac..85ae73ffda4 100644
--- a/mysql-test/suite/galera/t/galera_var_cluster_address.test
+++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test
@@ -19,8 +19,8 @@
SET GLOBAL wsrep_cluster_address = 'foo://';
# With wsrep_sync_wait, this returns an error
-#--error ER_LOCK_WAIT_TIMEOUT
-#SHOW STATUS;
+--error ER_LOCK_WAIT_TIMEOUT
+SHOW STATUS;
SET SESSION wsrep_sync_wait=0;
@@ -29,7 +29,7 @@ SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
# Must return 'OFF'
SHOW STATUS LIKE 'wsrep_ready';
-# Must return 'Non-primary'
+# Must return 'Disconnected'
SHOW STATUS LIKE 'wsrep_cluster_status';
# Must return 0 = 'Initialized'
@@ -49,10 +49,9 @@ SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VA
--connection node_2
--disable_query_log
--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node2';
+--source include/galera_wait_ready.inc
--enable_query_log
---source include/wait_until_connected_again.inc
-
--connection node_1
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
@@ -63,7 +62,7 @@ CALL mtr.add_suppression("Failed to initialize backend using 'foo");
CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo");
CALL mtr.add_suppression("gcs connect failed: Socket type not supported");
CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7");
-CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)");
+CALL mtr.add_suppression("gcs_caused\\(\\) returned -[0-9]+ \\(Software caused connection abort\\)");
CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110");
CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)");
CALL mtr.add_suppression("gcs connect failed: Connection timed out");
diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
index 1f01c4aac07..859642a6fdf 100644
--- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test
+++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test
@@ -11,11 +11,6 @@
--let $node_2=node_2
--source include/auto_increment_offset_save.inc
-# Save original auto_increment_offset values.
---let $node_1=node_1
---let $node_2=node_2
---source include/auto_increment_offset_save.inc
-
--connection node_2
--let $wsrep_cluster_address_saved = `SELECT @@global.wsrep_cluster_address`
@@ -32,7 +27,7 @@ SET SESSION wsrep_sync_wait=0;
# Must return 'OFF'
SHOW STATUS LIKE 'wsrep_ready';
-# Must return 'Non-primary'
+# Must return 'Disconnected'
SHOW STATUS LIKE 'wsrep_cluster_status';
--error ER_UNKNOWN_COM_ERROR
@@ -53,6 +48,7 @@ SET @@session.wsrep_dirty_reads=OFF;
--error ER_UNKNOWN_COM_ERROR
SELECT i, variable_name, variable_value FROM t1, information_schema.session_variables WHERE variable_name LIKE "wsrep_dirty_reads" AND i = 1;
+
SELECT 1;
USE information_schema;
@@ -65,6 +61,7 @@ SELECT COUNT(*) >= 10 FROM performance_schema.events_statements_history;
--eval SET @@global.wsrep_cluster_address = '$wsrep_cluster_address_saved'
--enable_query_log
--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
--connection node_1
USE test;
@@ -72,8 +69,7 @@ SELECT * FROM t1;
# Cleanup
DROP TABLE t1;
+# Restore original auto_increment_offset values.
--source include/auto_increment_offset_restore.inc
--source include/galera_end.inc
---echo # End of test
-
diff --git a/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test b/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test
new file mode 100644
index 00000000000..ddf561c8784
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test
@@ -0,0 +1,235 @@
+#
+# Test option wsrep_ignore_apply_errors
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+
+#
+# Ignore reconciling DDL errors on node_2
+#
+
+--connection node_2
+SET GLOBAL wsrep_ignore_apply_errors = 1;
+
+# Drop table that does not exist
+--connection node_1
+SET GLOBAL wsrep_on = OFF;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = ON;
+DROP TABLE t1;
+
+# Drop schema that does not exist
+SET GLOBAL wsrep_on = OFF;
+CREATE SCHEMA s1;
+SET GLOBAL wsrep_on = ON;
+DROP SCHEMA s1;
+
+# Drop index that does not exist using DROP INDEX
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+CREATE INDEX idx1 ON t1 (f1);
+SET GLOBAL wsrep_on = ON;
+DROP INDEX idx1 ON t1;
+DROP TABLE t1;
+
+# Drop index that does not exist using ALTER TABLE
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+CREATE INDEX idx1 ON t1 (f1);
+SET GLOBAL wsrep_on = ON;
+ALTER TABLE t1 DROP INDEX idx1;
+DROP TABLE t1;
+
+# Drop column that does not exist
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+SET GLOBAL wsrep_on = ON;
+ALTER TABLE t1 DROP COLUMN f2;
+DROP TABLE t1;
+
+
+#
+# Ignore reconciling DML errors on node_2
+#
+
+--connection node_2
+SET GLOBAL wsrep_ignore_apply_errors = 2;
+
+# Delete row that does not exist
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_on = ON;
+DELETE FROM t1 WHERE f1 = 1;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+DROP TABLE t1;
+
+# Delete row that does not exist in a multi statement transaction
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (2);
+SET GLOBAL wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_on = ON;
+START TRANSACTION;
+INSERT INTO t1 VALUES (3);
+DELETE FROM t1 WHERE f1 = 1;
+DELETE FROM t1 WHERE f1 = 2;
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 1 FROM t1;
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
+
+#
+# Multi-row delete where only one row does not exist
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
+--source include/wait_condition.inc
+
+SET SESSION wsrep_on = OFF;
+DELETE FROM t1 WHERE f1 = 3;
+SET SESSION wsrep_on = ON;
+--connection node_1
+DELETE FROM t1;
+
+SELECT COUNT(*) = 0 FROM t1;
+--connection node_2
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+SELECT COUNT(*) = 0 FROM t1;
+DROP TABLE t1;
+
+#
+# Multi-statement delete where only one row does not exist
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5);
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
+--source include/wait_condition.inc
+
+SET SESSION wsrep_on = OFF;
+DELETE FROM t1 WHERE f1 = 3;
+SET SESSION wsrep_on = ON;
+--connection node_1
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+DELETE FROM t1 WHERE f1 = 1;
+DELETE FROM t1 WHERE f1 = 2;
+DELETE FROM t1 WHERE f1 = 3;
+DELETE FROM t1 WHERE f1 = 4;
+DELETE FROM t1 WHERE f1 = 5;
+COMMIT;
+SET AUTOCOMMIT=ON;
+
+SELECT COUNT(*) = 0 FROM t1;
+--connection node_2
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+SELECT COUNT(*) = 0 FROM t1;
+DROP TABLE t1;
+
+#
+# Multi-table delete
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 3 FROM t2;
+--source include/wait_condition.inc
+
+SET SESSION wsrep_on = OFF;
+DELETE FROM t2 WHERE f1 = 2;
+DELETE FROM t1 WHERE f1 = 3;
+SET SESSION wsrep_on = ON;
+
+--connection node_1
+DELETE t1, t2 FROM t1 JOIN t2 WHERE t1.f1 = t2.f1;
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_2
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+SELECT COUNT(*) = 0 FROM t1;
+DROP TABLE t1,t2;
+
+#
+# Foreign keys
+#
+
+--connection node_1
+CREATE TABLE parent (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
+INSERT INTO parent VALUES (1),(2),(3);
+CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE) ENGINE=INNODB;
+INSERT INTO child VALUES (1,1),(2,2),(3,3);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 3 FROM child;
+--source include/wait_condition.inc
+
+SET SESSION wsrep_on = OFF;
+DELETE FROM child WHERE parent_id = 2;
+SET SESSION wsrep_on = ON;
+
+--connection node_1
+DELETE FROM parent;
+SELECT COUNT(*) = 0 FROM parent;
+SELECT COUNT(*) = 0 FROM child;
+
+--connection node_2
+SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+SELECT COUNT(*) = 0 FROM parent;
+SELECT COUNT(*) = 0 FROM child;
+DROP TABLE child, parent;
+
+#
+# Ignore all DDL errors on node_2
+#
+
+--connection node_2
+SET GLOBAL wsrep_ignore_apply_errors = 4;
+
+# Create a table that already exists
+--connection node_2
+SET GLOBAL wsrep_on = OFF;
+CREATE TABLE t1 (f1 INTEGER);
+SET GLOBAL wsrep_on = ON;
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER, f2 INTEGER);
+DROP TABLE t1;
+
+
+--connection node_2
+SET GLOBAL wsrep_ignore_apply_errors = 7;
+
+CALL mtr.add_suppression("Can't find record in 't.*'");
+CALL mtr.add_suppression("Slave SQL: Could not execute Delete_rows event");
+CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test.t1'' on query. Default database: 'test'. Query: 'DROP TABLE t1', Error_code: 1051");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't drop database 's1'; database doesn't exist' on query. Default database: 'test'. Query: 'DROP SCHEMA s1', Error_code: 1008");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't DROP 'idx1'; check that column/key exists' on query. Default database: 'test'. Query: 'DROP INDEX idx1 ON t1', Error_code: 1091");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't DROP 'idx1'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t1 DROP INDEX idx1', Error_code: 1091");
+CALL mtr.add_suppression("Slave SQL: Error 'Can't DROP 'f2'; check that column/key exists' on query. Default database: 'test'. Query: 'ALTER TABLE t1 DROP COLUMN f2', Error_code: 1091");
+CALL mtr.add_suppression("Slave SQL: Error 'Table 't1' already exists' on query.");
diff --git a/mysql-test/suite/galera/t/galera_var_log_bin.cnf b/mysql-test/suite/galera/t/galera_var_log_bin.cnf
index f7f17e3720a..30ccee2024e 100644
--- a/mysql-test/suite/galera/t/galera_var_log_bin.cnf
+++ b/mysql-test/suite/galera/t/galera_var_log_bin.cnf
@@ -3,3 +3,8 @@
[mysqld]
log-bin
+[mysqld.1]
+log-slave-updates
+
+[mysqld.2]
+log-slave-updates
diff --git a/mysql-test/suite/galera/t/galera_var_retry_autocommit.test b/mysql-test/suite/galera/t/galera_var_retry_autocommit.test
index 142f02546b4..df541b774a4 100644
--- a/mysql-test/suite/galera/t/galera_var_retry_autocommit.test
+++ b/mysql-test/suite/galera/t/galera_var_retry_autocommit.test
@@ -16,11 +16,11 @@
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 0;
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue';
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue';
--send INSERT INTO t1 (f1) VALUES (2)
--connection node_1a
-SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
--connection node_2
TRUNCATE TABLE t1;
@@ -42,11 +42,11 @@ DROP TABLE t1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 1;
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue';
---send INSERT INTO t1 (f1) VALUES (2)
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue';
+--send INSERT INTO t1 (f1) VALUES (3)
--connection node_1a
-SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
--connection node_2
TRUNCATE TABLE t1;
@@ -68,12 +68,12 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 1;
SET GLOBAL debug_dbug = '+d,sync.wsrep_retry_autocommit';
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue EXECUTE 2';
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue EXECUTE 2';
---send INSERT INTO t1 VALUES (2);
+--send INSERT INTO t1 VALUES (4);
--connection node_1a
-SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
--connection node_2
TRUNCATE TABLE t1;
@@ -81,7 +81,7 @@ TRUNCATE TABLE t1;
--connection node_1a
SET DEBUG_SYNC = 'now WAIT_FOR wsrep_retry_autocommit_reached';
SELECT COUNT(*) = 0 FROM t1;
-SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue WAIT_FOR before_rep';
+SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue WAIT_FOR before_cert';
--connection node_2
TRUNCATE TABLE t1;
@@ -107,9 +107,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
SET SESSION wsrep_retry_autocommit = 64;
SET GLOBAL debug_dbug = '+d,sync.wsrep_retry_autocommit';
-SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue EXECUTE 64';
+SET DEBUG_SYNC = 'wsrep_before_certification SIGNAL before_cert WAIT_FOR continue EXECUTE 64';
---send INSERT INTO t1 VALUES (2)
+--send INSERT INTO t1 VALUES (5)
--disable_query_log
--disable_result_log
@@ -117,7 +117,7 @@ SET DEBUG_SYNC = 'wsrep_before_replication SIGNAL before_rep WAIT_FOR continue E
while ($count)
{
--connection node_1a
- SET DEBUG_SYNC = 'now WAIT_FOR before_rep';
+ SET DEBUG_SYNC = 'now WAIT_FOR before_cert';
--connection node_2
TRUNCATE TABLE t1;
diff --git a/mysql-test/suite/galera/t/galera_var_slave_threads.cnf b/mysql-test/suite/galera/t/galera_var_slave_threads.cnf
new file mode 100644
index 00000000000..889c81b4a0a
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_var_slave_threads.cnf
@@ -0,0 +1,7 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+auto_increment_offset=1
+
+[mysqld.2]
+auto_increment_offset=2
diff --git a/mysql-test/suite/galera/t/galera_var_slave_threads.test b/mysql-test/suite/galera/t/galera_var_slave_threads.test
index 80edcb2aff9..12d8006db4b 100644
--- a/mysql-test/suite/galera/t/galera_var_slave_threads.test
+++ b/mysql-test/suite/galera/t/galera_var_slave_threads.test
@@ -8,6 +8,11 @@
--source include/have_innodb.inc
--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source include/auto_increment_offset_save.inc
+
--connection node_1
CREATE TABLE t1 (f1 INT PRIMARY KEY) Engine=InnoDB;
CREATE TABLE t2 (f1 INT AUTO_INCREMENT PRIMARY KEY) Engine=InnoDB;
@@ -21,6 +26,7 @@ SELECT @@wsrep_slave_threads = 1;
SET GLOBAL wsrep_slave_threads = 1;
# There is a separate wsrep_aborter thread at all times
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND COMMAND != 'Daemon';
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
#
@@ -33,13 +39,15 @@ SET GLOBAL wsrep_slave_threads = 64;
INSERT INTO t1 VALUES (1);
--connection node_2
---let $wait_timeout=600
---let $wait_condition = SELECT COUNT(*) = 1 FROM t1;
---source include/wait_condition.inc
+SELECT COUNT(*) FROM t1;
-SELECT COUNT(*) = 1 FROM t1;
+#
+# note, in wsrep API #26, we have 2 rollbacker threads, counted as system user's
+#
---let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%');
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
+
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
--source include/wait_condition.inc
#
@@ -65,49 +73,122 @@ while ($count)
--connection node_2
SELECT COUNT(*) FROM t2;
---let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%')
---source include/wait_condition.inc
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
+--source include/wait_condition.inc
---eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig
+--let $wsrep_cluster_address_node2 = `SELECT @@wsrep_cluster_address`
+--let $wsrep_provider_node2 = `SELECT @@wsrep_provider`
-DROP TABLE t1;
-DROP TABLE t2;
+SET GLOBAL wsrep_slave_threads = 5;
---echo #
---echo # lp:1372840 - Changing wsrep_slave_threads causes future connections to hang
---echo #
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
+--source include/wait_condition.inc
---connection node_1
-CREATE TABLE t1 (i INT AUTO_INCREMENT PRIMARY KEY) ENGINE=INNODB;
+SET GLOBAL wsrep_slave_threads = 1;
+#
+# test phase for bug https://github.com/codership/mysql-wsrep/issues/319
+#
+
+# shutdown node 2
--connection node_2
-SET GLOBAL wsrep_slave_threads = 4;
---let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%')
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+
+# wait until node_1 is ready as one node cluster
+--connection node_1
+
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
--source include/wait_condition.inc
+show status like 'wsrep_cluster_size';
+# step up slave threads to 6, and make sure all appliers and rollbacker thread are running
+SET GLOBAL wsrep_slave_threads = 6;
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
+--source include/wait_condition.inc
+
+# change to invalid cluster address
SET GLOBAL wsrep_slave_threads = 1;
+SET GLOBAL wsrep_cluster_address='';
---connection node_1
-INSERT INTO t1 VALUES (DEFAULT);
-INSERT INTO t1 VALUES (DEFAULT);
-INSERT INTO t1 VALUES (DEFAULT);
-DROP TABLE t1;
+# join back to single node cluster
+SET GLOBAL wsrep_cluster_address='gcomm://';
+--source include/wait_until_connected_again.inc
---connection node_2
+# we should have 1 applier thread now
+--let $wait_condition = SELECT COUNT(*) = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND COMMAND != 'Daemon'
+--source include/wait_condition.inc
-# Wait until above DDL is replicated
---let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t%';
+# test if we can increase applier count now (fails in bug #319)
+SET GLOBAL wsrep_slave_threads = 10;
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
--source include/wait_condition.inc
-SELECT NAME FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t%';
+# restart node 2
+--connection node_2
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND COMMAND != 'Daemon';
+#
#
-# make sure that we are left with exactly one applier thread before we leaving the test
+# cleanup to original state
#
---let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND (STATE IS NULL OR STATE NOT LIKE 'InnoDB%')
+--connection node_1
+--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig
+
+--connection node_2
+--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig
+
+
+--disable_result_log
+--disable_query_log
+# Generate 64 replication events, to help node 1 to purge excessive applier threads
+--let $count = 64
+while ($count)
+{
+ INSERT INTO t2 VALUES (DEFAULT);
+ --dec $count
+}
+--enable_query_log
+--enable_result_log
+
+--connection node_1
+--disable_result_log
+--disable_query_log
+# Generate 64 replication events, to help node 2 to purge excessive applier threads
+--let $count = 64
+while ($count)
+{
+ INSERT INTO t2 VALUES (DEFAULT);
+ --dec $count
+}
+--enable_query_log
+--enable_result_log
+
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
--source include/wait_condition.inc
-SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%wsrep aborter%';
+
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = @@wsrep_slave_threads + 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_thread_count';
+--source include/wait_condition.inc
+
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
+
+--connection node_1
+
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM t2;
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+# Restore original auto_increment_offset values.
+--source include/auto_increment_offset_restore.inc
--echo # End of tests
diff --git a/mysql-test/suite/galera/t/galera_vote_drop_temporary-master.opt b/mysql-test/suite/galera/t/galera_vote_drop_temporary-master.opt
new file mode 100644
index 00000000000..beae84b3862
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_vote_drop_temporary-master.opt
@@ -0,0 +1 @@
+--log-bin
diff --git a/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test b/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test
index 6ba8ce786c8..28025363019 100644
--- a/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test
+++ b/mysql-test/suite/galera/t/galera_wsrep_new_cluster.test
@@ -5,7 +5,6 @@
#
--source include/galera_cluster.inc
---source include/have_innodb.inc
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_connected';
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#198-master.opt b/mysql-test/suite/galera/t/mysql-wsrep#198-master.opt
new file mode 100644
index 00000000000..beae84b3862
--- /dev/null
+++ b/mysql-test/suite/galera/t/mysql-wsrep#198-master.opt
@@ -0,0 +1 @@
+--log-bin
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#237.test b/mysql-test/suite/galera/t/mysql-wsrep#237.test
index cba8dfeb275..174266bdbc5 100644
--- a/mysql-test/suite/galera/t/mysql-wsrep#237.test
+++ b/mysql-test/suite/galera/t/mysql-wsrep#237.test
@@ -7,13 +7,13 @@
CREATE TABLE t (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
--connection node_1
-SET DEBUG_SYNC = 'wsrep_before_replication WAIT_FOR continue';
+SET DEBUG_SYNC = 'wsrep_before_certification WAIT_FOR continue';
--send INSERT INTO t values (1);
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
--connection node_1a
SET SESSION wsrep_sync_wait = 0;
---let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: wsrep_before_replication'
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: wsrep_before_certification'
--source include/wait_condition.inc
--connection node_2
diff --git a/mysql-test/suite/galera/t/mysql-wsrep#332.test b/mysql-test/suite/galera/t/mysql-wsrep#332.test
index 2da01ba900e..674a5c3de52 100644
--- a/mysql-test/suite/galera/t/mysql-wsrep#332.test
+++ b/mysql-test/suite/galera/t/mysql-wsrep#332.test
@@ -1,7 +1,7 @@
--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
+--source include/galera_have_debug_sync.inc
# Open connection node_1a here, MW-369.inc will use it later
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
diff --git a/mysql-test/suite/galera/t/partition.test b/mysql-test/suite/galera/t/partition.test
index 0159ef8f607..13e09a4e3e6 100644
--- a/mysql-test/suite/galera/t/partition.test
+++ b/mysql-test/suite/galera/t/partition.test
@@ -134,9 +134,12 @@ CREATE TABLE t1 (pk INT PRIMARY KEY)
SELECT COUNT(*) FROM t1;
-# LOAD-ing 20002 rows causes 3 commits to be registered
+# LOAD-ing 20002 rows causes
+# 3 commits to be registered when the Galera library does not support streaming replication and
+# 5 commits to be registered when the Galera library supports streaming replication
--disable_query_log
---eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 3 AS wsrep_last_committed_diff;
+--replace_result 3 AS_EXPECTED_3_or_5 5 AS_EXPECTED_3_or_5
+--eval SELECT $wsrep_last_committed_after - $wsrep_last_committed_before AS wsrep_last_committed_diff;
--enable_query_log
DROP TABLE t1;
@@ -167,7 +170,7 @@ SELECT COUNT(*) 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;
+--eval SELECT $wsrep_last_committed_after - $wsrep_last_committed_before AS wsrep_last_committed_diff;
--enable_query_log
DROP TABLE t1;
@@ -196,9 +199,12 @@ CREATE TABLE t1 (pk INT PRIMARY KEY)
--source include/wait_condition.inc
SELECT COUNT(*) FROM t1;
-# LOAD-ing 20002 rows causes 1 commit to be registered
+# LOAD-ing 20002 rows causes
+# 1 commit to be registered when the Galera library does not support streaming replication and
+# 2 commits to be registered when the Galera library supports streaming replication
--disable_query_log
---eval SELECT $wsrep_last_committed_after = $wsrep_last_committed_before + 1 AS wsrep_last_committed_diff;
+--replace_result 1 AS_EXPECTED_1_or_2 2 AS_EXPECTED_1_or_2
+--eval SELECT $wsrep_last_committed_after - $wsrep_last_committed_before AS wsrep_last_committed_diff;
--enable_query_log
DROP TABLE t1;
diff --git a/mysql-test/suite/galera/t/rpl_row_annotate.test b/mysql-test/suite/galera/t/rpl_row_annotate.test
index b1cfdb36639..0ec30829982 100644
--- a/mysql-test/suite/galera/t/rpl_row_annotate.test
+++ b/mysql-test/suite/galera/t/rpl_row_annotate.test
@@ -3,11 +3,15 @@
--echo # On node_2
--connection node_2
+SET GLOBAL wsrep_on=OFF;
RESET MASTER;
+SET GLOBAL wsrep_on=ON;
--echo # On node_1
--connection node_1
+SET GLOBAL wsrep_on=OFF;
RESET MASTER;
+SET GLOBAL wsrep_on=ON;
CREATE TABLE t1(i INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(1);
DELETE FROM t1 WHERE i = 1;
@@ -38,5 +42,4 @@ let $start_pos= `select @binlog_start_pos`;
# Cleanup
DROP TABLE t1;
---source include/galera_end.inc
--echo # End of test
diff --git a/mysql-test/suite/galera/t/wsrep_trx_fragment_size_sr.test b/mysql-test/suite/galera/t/wsrep_trx_fragment_size_sr.test
new file mode 100644
index 00000000000..a970cc09afc
--- /dev/null
+++ b/mysql-test/suite/galera/t/wsrep_trx_fragment_size_sr.test
@@ -0,0 +1,22 @@
+-- source include/galera_cluster.inc
+
+-- let $sr = `SELECT variable_value LIKE '%:STREAMING:%' FROM information_schema.session_status WHERE variable_name = 'wsrep_provider_capabilities'`
+
+if (!$sr)
+{
+ -- skip The test requires a wsrep provider that supports streaming replication.
+}
+
+SELECT variable_value FROM information_schema.session_variables
+WHERE variable_name = 'wsrep_trx_fragment_size';
+
+SET SESSION wsrep_trx_fragment_size = 0;
+SET SESSION wsrep_trx_fragment_size = 123;
+
+SELECT variable_value FROM information_schema.global_variables
+WHERE variable_name = 'wsrep_trx_fragment_size';
+
+SET GLOBAL wsrep_trx_fragment_size = 0;
+SET GLOBAL wsrep_trx_fragment_size = 123;
+
+SET GLOBAL wsrep_trx_fragment_size = default;
diff --git a/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf b/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf
index 3f39b82f7b7..39a68d2be41 100644
--- a/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf
+++ b/mysql-test/suite/galera_3nodes/galera_2x3nodes.cnf
@@ -10,7 +10,6 @@ default-storage-engine=innodb
wsrep_gtid_mode=1
gtid_ignore_duplicates
-wsrep-on=1
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
# enforce read-committed characteristics across the cluster
@@ -21,6 +20,7 @@ wsrep_node_address=127.0.0.1
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep-cluster-address='gcomm://'
wsrep_provider_options='base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT300S;evs.inactive_timeout=PT1000M;evs.install_timeout=PT155S;evs.keepalive_period = PT100S'
@@ -32,6 +32,7 @@ wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT300S;evs.inactive_timeout=PT1000M;evs.install_timeout=PT155S;evs.keepalive_period = PT100S'
@@ -43,6 +44,7 @@ wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.suspect_timeout=PT300S;evs.inactive_timeout=PT1000M;evs.install_timeout=PT155S;evs.keepalive_period = PT100S'
@@ -56,7 +58,7 @@ wsrep_cluster_name=cluster2
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
-
+wsrep-on=1
wsrep-cluster-address='gcomm://'
wsrep_provider_options='base_port=@mysqld.4.#galera_port;evs.suspect_timeout=PT300S;evs.inactive_timeout=PT1000M;evs.install_timeout=PT155S;evs.keepalive_period = PT100S'
@@ -69,6 +71,7 @@ wsrep_cluster_name=cluster2
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.4.#galera_port'
wsrep_provider_options='base_port=@mysqld.5.#galera_port;evs.suspect_timeout=PT300S;evs.inactive_timeout=PT1000M;evs.install_timeout=PT155S;evs.keepalive_period = PT100S'
@@ -81,6 +84,7 @@ wsrep_cluster_name=cluster2
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.4.#galera_port'
wsrep_provider_options='base_port=@mysqld.6.#galera_port;evs.suspect_timeout=PT300S;evs.inactive_timeout=PT1000M;evs.install_timeout=PT155S;evs.keepalive_period = PT100S'
@@ -106,17 +110,3 @@ NODE_MYSOCK_5= @mysqld.5.socket
NODE_MYPORT_6= @mysqld.6.port
NODE_MYSOCK_6= @mysqld.6.socket
-
-NODE_GALERAPORT_1= @mysqld.1.#galera_port
-NODE_GALERAPORT_2= @mysqld.2.#galera_port
-NODE_GALERAPORT_3= @mysqld.3.#galera_port
-NODE_GALERAPORT_4= @mysqld.4.#galera_port
-NODE_GALERAPORT_5= @mysqld.5.#galera_port
-NODE_GALERAPORT_6= @mysqld.6.#galera_port
-
-NODE_SSTPORT_1= @mysqld.1.#sst_port
-NODE_SSTPORT_2= @mysqld.2.#sst_port
-NODE_SSTPORT_3= @mysqld.3.#sst_port
-NODE_SSTPORT_4= @mysqld.4.#sst_port
-NODE_SSTPORT_5= @mysqld.5.#sst_port
-NODE_SSTPORT_6= @mysqld.6.#sst_port
diff --git a/mysql-test/suite/galera_3nodes/galera_3nodes.cnf b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
index 91aa53ad7b1..708902fd7e7 100644
--- a/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
+++ b/mysql-test/suite/galera_3nodes/galera_3nodes.cnf
@@ -6,7 +6,6 @@ binlog-format=row
innodb-autoinc-lock-mode=2
default-storage-engine=innodb
-wsrep-on=1
wsrep-provider=@ENV.WSREP_PROVIDER
wsrep_node_address=127.0.0.1
# enforce read-committed characteristics across the cluster
@@ -17,6 +16,8 @@ wsrep-sync-wait=15
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+#wsrep-new-cluster
+wsrep-on=1
wsrep-cluster-address='gcomm://'
wsrep_provider_options='base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
@@ -28,6 +29,7 @@ wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
@@ -39,6 +41,7 @@ wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S'
@@ -55,12 +58,3 @@ NODE_MYSOCK_2= @mysqld.2.socket
NODE_MYPORT_3= @mysqld.3.port
NODE_MYSOCK_3= @mysqld.3.socket
-
-NODE_GALERAPORT_1= @mysqld.1.#galera_port
-NODE_GALERAPORT_2= @mysqld.2.#galera_port
-NODE_GALERAPORT_3= @mysqld.3.#galera_port
-
-NODE_SSTPORT_1= @mysqld.1.#sst_port
-NODE_SSTPORT_2= @mysqld.2.#sst_port
-NODE_SSTPORT_3= @mysqld.3.#sst_port
-
diff --git a/mysql-test/suite/galera/include/galera_resume.inc b/mysql-test/suite/galera_3nodes/include/galera_resume.inc
index 232cb46479e..af8f2b956fd 100644
--- a/mysql-test/suite/galera/include/galera_resume.inc
+++ b/mysql-test/suite/galera_3nodes/include/galera_resume.inc
@@ -3,7 +3,7 @@
my $pid_filename = $ENV{'_SUSPEND_NODE_PIDFILE'};
my $mysqld_pid = `cat $pid_filename`;
chomp($mysqld_pid);
- system("kill -18 $mysqld_pid");
+ system("kill -SIGCONT $mysqld_pid");
exit(0);
EOF
diff --git a/mysql-test/suite/galera_3nodes/include/galera_suspend.inc b/mysql-test/suite/galera_3nodes/include/galera_suspend.inc
index 3495ad2342b..d4037d8958c 100644
--- a/mysql-test/suite/galera_3nodes/include/galera_suspend.inc
+++ b/mysql-test/suite/galera_3nodes/include/galera_suspend.inc
@@ -9,6 +9,6 @@
my $pid_filename = $ENV{'_SUSPEND_NODE_PIDFILE'};
my $mysqld_pid = `cat $pid_filename`;
chomp($mysqld_pid);
- system("kill -19 $mysqld_pid");
+ system("kill -SIGSTOP $mysqld_pid");
exit(0);
EOF
diff --git a/mysql-test/suite/galera_3nodes/include/have_ipv6.inc b/mysql-test/suite/galera_3nodes/include/have_ipv6.inc
deleted file mode 100644
index 560cad03350..00000000000
--- a/mysql-test/suite/galera_3nodes/include/have_ipv6.inc
+++ /dev/null
@@ -1,15 +0,0 @@
-# Check if ipv6 is available.
-#
---disable_query_log
---disable_result_log
-connect (checkcon123456789,::1,root,,test);
-if($mysql_errno)
-{
- skip No IPv6 support;
-}
-connection default;
-disconnect checkcon123456789;
---enable_result_log
---enable_query_log
-# end check
-
diff --git a/mysql-test/suite/galera_3nodes/r/GAL-501.result b/mysql-test/suite/galera_3nodes/r/GAL-501.result
index a2bf5f4d98c..063e88ec21a 100644
--- a/mysql-test/suite/galera_3nodes/r/GAL-501.result
+++ b/mysql-test/suite/galera_3nodes/r/GAL-501.result
@@ -1,12 +1,18 @@
+connection node_2;
+connection node_1;
+connection node_3;
SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
VARIABLE_VALUE LIKE '%[::1]%'
1
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 3
1
+connection node_2;
SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
+connection node_2;
SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
diff --git a/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result b/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result
index b1bbb1406a1..6393a30da6f 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_certification_ccc.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_3;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result b/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result
index e1528c6f74f..d43b42bec45 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_certification_double_failure.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
@@ -11,6 +13,7 @@ connection node_3;
INSERT INTO t2 VALUES (1);
connection node_1;
COMMIT;
-ERROR 40001: Deadlock: wsrep aborted transaction
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_3;
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result b/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result
index 7e0d282ec7f..3543feff78c 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_evs_suspect_timeout.result
@@ -1,12 +1,19 @@
+connection node_2;
+connection node_1;
+connection node_1;
SET GLOBAL wsrep_provider_options = 'evs.inactive_timeout=PT100M; evs.suspect_timeout=PT1S';
+connection node_2;
SET GLOBAL wsrep_provider_options = 'evs.inactive_timeout=PT100M; evs.suspect_timeout=PT1S';
+connection node_3;
Suspending node ...
+connection node_1;
SET SESSION wsrep_sync_wait = 0;
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 2
1
CREATE TABLE t1 (f1 INTEGER);
INSERT INTO t1 VALUES (1);
+connection node_2;
SET SESSION wsrep_sync_wait = 0;
SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 2
@@ -16,5 +23,6 @@ SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
1
DROP TABLE t1;
+connection node_3;
Resuming node ...
CALL mtr.add_suppression("WSREP: gcs_caused() returned -1 \\(Operation not permitted\\)");
diff --git a/mysql-test/suite/galera_3nodes/r/galera_garbd.result b/mysql-test/suite/galera_3nodes/r/galera_garbd.result
index 180aade029c..88bb3ca2ff9 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_garbd.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_garbd.result
@@ -1,17 +1,31 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_3;
Killing node #3 to free ports for garbd ...
+connection node_1;
Starting garbd ...
CREATE TABLE t1 (f1 INTEGER);
INSERT INTO t1 VALUES (1);
+connection node_2;
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
1
Killing garbd ...
+connection node_1;
INSERT INTO t1 VALUES (2);
+connection node_2;
SELECT COUNT(*) = 2 FROM t1;
COUNT(*) = 2
1
DROP TABLE t1;
Restarting node #3 to satisfy MTR's end-of-test checks
+connection node_3;
+connection node_1;
CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+connection node_2;
CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
+connection node_3;
CALL mtr.add_suppression("WSREP: Protocol violation\. JOIN message sender 1\.0 \(.*\) is not in state transfer \(SYNCED\)");
diff --git a/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result b/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result
deleted file mode 100644
index 85000db8e77..00000000000
--- a/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result
+++ /dev/null
@@ -1,11 +0,0 @@
-CREATE TABLE t1 (f1 INTEGER);
-INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
-SELECT COUNT(*) = 10 FROM t1;
-COUNT(*) = 10
-1
-Killing server ...
-INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
-SELECT COUNT(*) = 20 FROM t1;
-COUNT(*) = 20
-1
-DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result
index f519654952b..a977f784e54 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result
@@ -1,10 +1,22 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+CREATE USER 'sst';
GRANT ALL PRIVILEGES ON *.* TO 'sst';
SET GLOBAL wsrep_sst_auth = 'sst:';
+connection node_2;
SET GLOBAL wsrep_sst_method = 'mysqldump';
+connection node_2;
Unloading wsrep provider ...
SET GLOBAL wsrep_provider = 'none';
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
+connection node_2;
Loading wsrep provider ...
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
@@ -13,14 +25,16 @@ DROP TABLE t1;
SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
VARIABLE_VALUE LIKE '%[::1]%'
1
+connection node_1;
CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
DROP USER sst;
+connection node_2;
CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
-CALL mtr.add_suppression("InnoDB: New log files created");
-CALL mtr.add_suppression("InnoDB: Creating foreign key constraint system tables");
CALL mtr.add_suppression("Can't open and lock time zone table");
CALL mtr.add_suppression("Can't open and lock privilege tables");
CALL mtr.add_suppression("Info table is not ready to be used");
CALL mtr.add_suppression("Native table .* has the wrong structure");
+CALL mtr.add_suppression("Table \'mysql.gtid_slave_pos\' doesn\'t exist");
+connection node_2;
CALL mtr.add_suppression("Unsupported protocol downgrade: incremental data collection disabled. Expect abort");
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result
index a2bf5f4d98c..3f810d3eb97 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result
@@ -1,12 +1,17 @@
+connection node_2;
+connection node_1;
SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
VARIABLE_VALUE LIKE '%[::1]%'
1
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 3
1
+connection node_2;
SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
+connection node_2;
SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
SELECT COUNT(*) = 1 FROM t1;
COUNT(*) = 1
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result
deleted file mode 100644
index 53e35939a79..00000000000
--- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_xtrabackup-v2.result
+++ /dev/null
@@ -1,18 +0,0 @@
-SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
-VARIABLE_VALUE LIKE '%[::1]%'
-1
-SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
-VARIABLE_VALUE = 3
-1
-SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
-CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (1);
-SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
-SELECT COUNT(*) = 1 FROM t1;
-COUNT(*) = 1
-1
-DROP TABLE t1;
-include/assert_grep.inc [Streaming the backup to joiner at \[::1\]]
-include/assert_grep.inc [async IST sender starting to serve tcp://\[::1\]:]
-include/assert_grep.inc [IST receiver addr using tcp://\[::1\]]
-include/assert_grep.inc [Prepared IST receiver, listening at: tcp://\[::1\]]
diff --git a/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result b/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result
index 3d4dbcc00b0..7780c3f73b8 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
connection node_1;
connection node_2;
connection node_3;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result b/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result
index 4f9951c382f..8211fb8501e 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_parallel_apply_3nodes.result
@@ -1,3 +1,5 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
connection node_3;
@@ -12,7 +14,7 @@ connection node_3;
SELECT f1 = 111 FROM t1;
f1 = 111
1
-SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%';
+SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
COUNT(*) IN (1, 2)
1
SET GLOBAL wsrep_slave_threads = 1;;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result b/mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result
index 69995acb982..ee49330e892 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_pc_bootstrap.result
@@ -1,8 +1,15 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER);
+connection node_1;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+connection node_2;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_3;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
SET SESSION wsrep_sync_wait = 0;
+connection node_2;
SET GLOBAL wsrep_provider_options = 'pc.bootstrap=1';
SHOW STATUS LIKE 'wsrep_cluster_size';
Variable_name Value
@@ -11,15 +18,21 @@ SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
wsrep_cluster_status Primary
INSERT INTO t1 VALUES (1);
+connection node_2;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+connection node_1;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+connection node_3;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+connection node_1;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
+connection node_2;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
+connection node_3;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
diff --git a/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result b/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result
index 9f845ffe776..3ae983f9550 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_pc_weight.result
@@ -1,9 +1,15 @@
+connection node_2;
+connection node_1;
+connection node_1;
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 3
+1
SET GLOBAL wsrep_provider_options = 'pc.weight=3';
SELECT VARIABLE_VALUE = 5 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 5
+1
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+connection node_2;
SET SESSION wsrep_sync_wait=0;
SET SESSION wsrep_on=OFF;
SET SESSION wsrep_on=ON;
@@ -12,6 +18,7 @@ Variable_name Value
wsrep_cluster_size 2
SHOW STATUS LIKE 'wsrep_cluster_weight';
Variable_name Value
+wsrep_cluster_weight 0
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
wsrep_cluster_status non-Primary
@@ -27,6 +34,7 @@ wsrep_local_state 0
SHOW STATUS LIKE 'wsrep_local_state_comment';
Variable_name Value
wsrep_local_state_comment Initialized
+connection node_3;
SET SESSION wsrep_sync_wait=0;
SET SESSION wsrep_on=OFF;
SET SESSION wsrep_on=ON;
@@ -35,6 +43,7 @@ Variable_name Value
wsrep_cluster_size 2
SHOW STATUS LIKE 'wsrep_cluster_weight';
Variable_name Value
+wsrep_cluster_weight 0
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
wsrep_cluster_status non-Primary
@@ -50,8 +59,10 @@ wsrep_local_state 0
SHOW STATUS LIKE 'wsrep_local_state_comment';
Variable_name Value
wsrep_local_state_comment Initialized
+connection node_1;
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 3
+1
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
VARIABLE_VALUE = 'Primary'
1
@@ -70,12 +81,18 @@ VARIABLE_VALUE = 'Synced'
SET GLOBAL wsrep_provider_options = 'pc.weight=1';
SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 1
+1
+connection node_1;
SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+connection node_2;
+connection node_3;
+connection node_1;
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 3
1
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 3
+1
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
VARIABLE_VALUE = 'Primary'
1
@@ -91,11 +108,13 @@ VARIABLE_VALUE = 4
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
+connection node_2;
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 3
1
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 3
+1
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
VARIABLE_VALUE = 'Primary'
1
@@ -111,11 +130,13 @@ VARIABLE_VALUE = 4
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
+connection node_3;
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
VARIABLE_VALUE = 3
1
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
VARIABLE_VALUE = 3
+1
SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
VARIABLE_VALUE = 'Primary'
1
@@ -131,12 +152,15 @@ VARIABLE_VALUE = 4
SELECT VARIABLE_VALUE = 'Synced' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_state_comment';
VARIABLE_VALUE = 'Synced'
1
+connection node_1;
SET GLOBAL wsrep_provider_options = 'pc.weight=1';
CALL mtr.add_suppression('WSREP: gcs_caused\\(\\) returned -1');
+connection node_2;
CALL mtr.add_suppression('overriding reported weight for');
CALL mtr.add_suppression('SYNC message from member');
CALL mtr.add_suppression('user message in state LEAVING');
CALL mtr.add_suppression('sending install message failed: (Transport endpoint is not connected|Socket is not connected)');
+connection node_3;
CALL mtr.add_suppression('WSREP: user message in state LEAVING');
CALL mtr.add_suppression('sending install message failed: (Transport endpoint is not connected|Socket is not connected)');
CALL mtr.add_suppression('overriding reported weight for');
diff --git a/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result b/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result
index 21f747d280b..b87c8743406 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result
@@ -1,23 +1,46 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+connection node_2;
+connection node_1;
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+connection node_3;
+connection node_1;
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 1']
+connection node_2;
+connection node_1;
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0']
+connection node_2;
+connection node_1;
SET SESSION wsrep_on = OFF;
Killing server ...
safe_to_bootstrap: 1
safe_to_bootstrap: 0
safe_to_bootstrap: 0
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_2;
CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+CALL mtr.add_suppression("It may not be safe to bootstrap the cluster from this node");
+CALL mtr.add_suppression("Aborting");
+connection node_3;
CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+CALL mtr.add_suppression("It may not be safe to bootstrap the cluster from this node");
+CALL mtr.add_suppression("Aborting");
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
diff --git a/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result b/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result
index 88780a2c87f..8e6d27823f6 100644
--- a/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result
+++ b/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result
@@ -1,6 +1,11 @@
+connection node_2;
+connection node_1;
CREATE TABLE t1 (f1 INTEGER);
INSERT INTO t1 VALUES (1);
+connection node_2;
SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+connection node_1;
+connection node_2;
SET SESSION wsrep_sync_wait = 0;
SET SESSION wsrep_dirty_reads = 1;
SELECT f1 FROM t1;
@@ -45,4 +50,6 @@ SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST;
COUNT(*) > 0
1
SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+connection node_1;
+connection node_2;
DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result b/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result
new file mode 100644
index 00000000000..23ced3ba734
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result
@@ -0,0 +1,82 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_3;
+SHOW CREATE TABLE mysql.wsrep_cluster;
+Table Create Table
+wsrep_cluster CREATE TABLE `wsrep_cluster` (
+ `cluster_uuid` char(36) NOT NULL,
+ `view_id` bigint(20) NOT NULL,
+ `view_seqno` bigint(20) NOT NULL,
+ `protocol_version` int(11) NOT NULL,
+ `capabilities` int(11) NOT NULL,
+ PRIMARY KEY (`cluster_uuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW CREATE TABLE mysql.wsrep_cluster_members;
+Table Create Table
+wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` (
+ `node_uuid` char(36) NOT NULL,
+ `cluster_uuid` char(36) NOT NULL,
+ `node_name` char(32) NOT NULL,
+ `node_incoming_address` varchar(256) NOT NULL,
+ PRIMARY KEY (`node_uuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SELECT COUNT(*) = 1 FROM mysql.wsrep_cluster;
+COUNT(*) = 1
+1
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid')
+1
+SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_members;
+COUNT(*) = 3
+1
+SELECT COUNT(*) = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size') FROM mysql.wsrep_cluster_members;
+COUNT(*) = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size')
+1
+SELECT COUNT(*) = 1 FROM mysql.wsrep_cluster_members WHERE node_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_gcomm_uuid');
+COUNT(*) = 1
+1
+SELECT node_incoming_address LIKE '127.0.0.1:%' from mysql.wsrep_cluster_members;
+node_incoming_address LIKE '127.0.0.1:%'
+1
+1
+1
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster_members;
+cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid')
+1
+1
+1
+SELECT COUNT(*) = 1 FROM mysql.wsrep_cluster_members WHERE node_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_gcomm_uuid');
+COUNT(*) = 1
+1
+connection node_2;
+connection node_1;
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid')
+1
+SELECT COUNT(*) = 2 FROM mysql.wsrep_cluster_members;
+COUNT(*) = 2
+1
+connection node_2;
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid')
+1
+SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_members;
+COUNT(*) = 3
+1
+connection node_1;
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid')
+1
+SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_members;
+COUNT(*) = 3
+1
+connection node_1;
+CALL mtr.add_suppression("SYNC message from member");
+connection node_2;
+CALL mtr.add_suppression("SYNC message from member");
+connection node_3;
+CALL mtr.add_suppression("SYNC message from member");
diff --git a/mysql-test/suite/galera_3nodes/suite.pm b/mysql-test/suite/galera_3nodes/suite.pm
index 3a1237ecf75..03eeeeaf057 100644
--- a/mysql-test/suite/galera_3nodes/suite.pm
+++ b/mysql-test/suite/galera_3nodes/suite.pm
@@ -9,9 +9,9 @@ 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/lib64/galera-3/libgalera_smm.so",
+ "/usr/lib64/galera-4/libgalera_smm.so",
"/usr/lib64/galera/libgalera_smm.so",
- "/usr/lib/galera-3/libgalera_smm.so",
+ "/usr/lib/galera-4/libgalera_smm.so",
"/usr/lib/galera/libgalera_smm.so";
return "No wsrep provider library" unless -f $provider;
diff --git a/mysql-test/suite/galera_3nodes/t/GAL-501.test b/mysql-test/suite/galera_3nodes/t/GAL-501.test
index 60ed5989227..c4b17cdb21e 100644
--- a/mysql-test/suite/galera_3nodes/t/GAL-501.test
+++ b/mysql-test/suite/galera_3nodes/t/GAL-501.test
@@ -5,7 +5,13 @@
# ist.recv_addr=[::1]
--source include/galera_cluster.inc
---source include/have_ipv6.inc
+--source include/check_ipv6.inc
+
+--let $galera_connection_name = node_3
+--let $galera_server_number = 3
+--source include/galera_connect.inc
+--connection node_3
+--source include/galera_wait_ready.inc
# Confirm that initial handshake happened over ipv6
diff --git a/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test b/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test
index a2ad0765028..5366d2a4a6e 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_certification_double_failure.test
@@ -29,5 +29,7 @@ INSERT INTO t2 VALUES (1);
--error ER_LOCK_DEADLOCK
COMMIT;
+--connection node_3
+--source include/galera_wait_ready.inc
DROP TABLE t1;
DROP TABLE t2;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test b/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test
index 03236a3cb93..a4767928681 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_evs_suspect_timeout.test
@@ -60,9 +60,9 @@ DROP TABLE t1;
--source include/galera_resume.inc
--source include/wait_until_connected_again.inc
-CALL mtr.add_suppression("WSREP: gcs_caused() returned -1 \\(Operation not permitted\\)");
-
--disable_query_log
--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node3';
--enable_query_log
---source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+
+CALL mtr.add_suppression("WSREP: gcs_caused() returned -1 \\(Operation not permitted\\)");
diff --git a/mysql-test/suite/galera_3nodes/t/galera_garbd.test b/mysql-test/suite/galera_3nodes/t/galera_garbd.test
index a68ba8ce15b..81d927894c7 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_garbd.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_garbd.test
@@ -7,10 +7,21 @@
--source include/have_innodb.inc
--source include/big_test.inc
+# Save galera ports
+--connection node_1
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_1 = $_NODE_GALERAPORT
+
+--connection node_2
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_2 = $_NODE_GALERAPORT
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--source suite/galera/include/galera_base_port.inc
+--let $NODE_GALERAPORT_3 = $_NODE_GALERAPORT
+
+--connection node_3
--echo Killing node #3 to free ports for garbd ...
---let $galera_connection_name = node_3
---let $galera_server_number = 3
---source include/galera_connect.inc
--source include/shutdown_mysqld.inc
--connection node_1
@@ -32,7 +43,10 @@ INSERT INTO t1 VALUES (1);
SELECT COUNT(*) = 1 FROM t1;
--echo Killing garbd ...
---exec pkill --oldest --full garbd.*$NODE_GALERAPORT_3
+# FreeBSD's /bin/pkill only supports short versions of the options:
+# -o Select only the oldest (least recently started)
+# -f Match against full argument lists
+--exec pkill -o -f garbd.*$NODE_GALERAPORT_3
--sleep 5
diff --git a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test b/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test
deleted file mode 100644
index cc3f42c7290..00000000000
--- a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# This test uses innobackupex to take a backup on node #2 and then restores that node from backup
-#
-
---source include/galera_cluster.inc
---source include/have_innodb.inc
-
---connection node_1
-CREATE TABLE t1 (f1 INTEGER);
-INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
-
---connection node_2
-SELECT COUNT(*) = 10 FROM t1;
-
---exec rm -rf $MYSQL_TMP_DIR/innobackupex_backup
---exec innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 $MYSQL_TMP_DIR/innobackupex_backup --galera-info --port=$NODE_MYPORT_2 --host=127.0.0.1 --no-timestamp > $MYSQL_TMP_DIR/innobackupex-backup.log
---exec innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 $MYSQL_TMP_DIR/innobackupex_backup --apply-log --galera-info --port=$NODE_MYPORT_2 --host=127.0.0.1 --no-timestamp > $MYSQL_TMP_DIR/innobackupex-apply.log
-
---source ../galera/include/kill_galera.inc
---sleep 1
-
---connection node_1
-INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
-
---exec rm -rf $MYSQLTEST_VARDIR/mysqld.2/data/*
---exec innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 --copy-back $MYSQL_TMP_DIR/innobackupex_backup --port=$NODE_MYPORT_2 --host=127.0.0.1 > $MYSQL_TMP_DIR/innobackupex-restore.log
-
-#
-# Convert the xtrabackup_galera_info into a grastate.dat file
-#
-
---perl
- use strict;
- my $xtrabackup_galera_info_file = $ENV{'MYSQL_TMP_DIR'}.'/innobackupex_backup/xtrabackup_galera_info';
- open(XTRABACKUP_GALERA_INFO, $xtrabackup_galera_info_file) or die "Can not open $xtrabackup_galera_info_file: $!";
- my $xtrabackup_galera_info = <XTRABACKUP_GALERA_INFO>;
- my ($uuid, $seqno) = split(':', $xtrabackup_galera_info);
-
- my $grastate_dat_file = $ENV{'MYSQLTEST_VARDIR'}.'/mysqld.2/data/grastate.dat';
- die "grastate.dat already exists" if -e $grastate_dat_file;
-
- open(GRASTATE_DAT, ">$grastate_dat_file") or die "Can not write to $grastate_dat_file: $!";
- print GRASTATE_DAT "version: 2.1\n";
- print GRASTATE_DAT "uuid: $uuid\n";
- print GRASTATE_DAT "seqno: $seqno\n";
- print GRASTATE_DAT "cert_index:\n";
- exit(0);
-EOF
-
---source include/start_mysqld.inc
---sleep 5
-
---source include/wait_until_connected_again.inc
-SELECT COUNT(*) = 20 FROM t1;
-
-DROP TABLE t1;
-
---sleep 10
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt
new file mode 100644
index 00000000000..215293eccec
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt
@@ -0,0 +1 @@
+--bind-address=*
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test
index 5b06e617eef..93050b54f5d 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test
@@ -1,7 +1,15 @@
--source include/galera_cluster.inc
---source include/have_ipv6.inc
+--source include/check_ipv6.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+ # Save original auto_increment_offset values.
+ --let $node_1=node_1
+ --let $node_2=node_2
+ --let $node_3=node_3
+ --source ../galera/include/auto_increment_offset_save.inc
--connection node_1
+CREATE USER 'sst';
GRANT ALL PRIVILEGES ON *.* TO 'sst';
--let $wsrep_sst_auth_orig = `SELECT @@wsrep_sst_auth`
@@ -51,6 +59,11 @@ DROP TABLE t1;
SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
+# restart node so we don't fail on WSREP_START_POSITION internal check
+--source include/restart_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+--source ../galera/include/auto_increment_offset_restore.inc
--source suite/galera/include/galera_sst_restore.inc
--connection node_2
CALL mtr.add_suppression("Unsupported protocol downgrade: incremental data collection disabled. Expect abort");
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test
index 7ee209d8e72..1937eb43e13 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test
@@ -1,5 +1,5 @@
--source include/galera_cluster.inc
---source include/have_ipv6.inc
+--source include/check_ipv6.inc
# Confirm that initial handshake happened over ipv6
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf
deleted file mode 100644
index 8a80be0d2a9..00000000000
--- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.cnf
+++ /dev/null
@@ -1,26 +0,0 @@
-!include ../galera_3nodes.cnf
-
-[mysqld]
-wsrep_sst_method=xtrabackup-v2
-wsrep_sst_auth="root:"
-
-[mysqld.1]
-wsrep-cluster-address=gcomm://
-wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port'
-wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port'
-wsrep_node_incoming_address='[::1]:@mysqld.1.port'
-
-[mysqld.2]
-wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
-wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port'
-wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port'
-wsrep_node_incoming_address='[::1]:@mysqld.2.port'
-
-[mysqld.3]
-wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port'
-wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port'
-wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port'
-wsrep_node_incoming_address='[::1]:@mysqld.3.port'
-
-[SST]
-sockopt=",pf=ip6"
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test
deleted file mode 100644
index 84eee017700..00000000000
--- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_xtrabackup-v2.test
+++ /dev/null
@@ -1,62 +0,0 @@
---source include/galera_cluster.inc
---source include/have_ipv6.inc
-
-# Confirm that initial handshake happened over ipv6
-
-SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses';
-SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
-
-# Force IST
-
---connection node_2
-SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
-
---connection node_1
---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
---source include/wait_condition.inc
-
-CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
-INSERT INTO t1 VALUES (1);
-
---connection node_2
-SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
-
---let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
---source include/wait_condition.inc
-
---let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
---source include/wait_condition.inc
-
-SELECT COUNT(*) = 1 FROM t1;
-
-DROP TABLE t1;
-
-# Confirm that key messages around SST and IST reference IPv6
-
---connection node_1
---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
---let $assert_only_after = CURRENT_TEST
-
---let $assert_count = 2
---let $assert_text = Streaming the backup to joiner at \[::1\]
---let $assert_select = Streaming the backup to joiner at \[::1\]
---source include/assert_grep.inc
-
---let $assert_count = 1
---let $assert_text = async IST sender starting to serve tcp://\[::1\]:
---let $assert_select = async IST sender starting to serve tcp://\[::1\]:
---source include/assert_grep.inc
-
---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
-
---let $assert_text = IST receiver addr using tcp://\[::1\]
---let $assert_select = IST receiver addr using tcp://\[::1\]
---source include/assert_grep.inc
-
---let $assert_text = Prepared IST receiver, listening at: tcp://\[::1\]
---let $assert_select = Prepared IST receiver, listening at: tcp://\[::1\]
---source include/assert_grep.inc
-
-
-
-
diff --git a/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test
index a67b30e3fa1..9e43c90bfc1 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test
@@ -11,7 +11,7 @@
--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
+--source include/galera_have_debug_sync.inc
--let $galera_connection_name = node_3
--let $galera_server_number = 3
diff --git a/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test b/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test
index 7d80d8036a1..659df2b3c93 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_parallel_apply_3nodes.test
@@ -31,7 +31,7 @@ SET GLOBAL wsrep_slave_threads = 2;
--connection node_3
SELECT f1 = 111 FROM t1;
-SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE 'committed%';
+SELECT COUNT(*) IN (1, 2) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE LIKE '%committed%';
--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf
index 57026ce6928..1a61471d581 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf
+++ b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.cnf
@@ -1,5 +1,7 @@
-# We need a dedicated .cnf file, even if empty, in order to force this test to run
-# alone on a freshly started cluster. Otherwise there are adverse interactions with
-# following tests such as galera_3nodes.galera_var_dirty_reads2
+# We need a dedicated .cnf file, even if empty, in order to force this test
+# to run alone on a freshly started cluster. Otherwise there are adverse
+# interactions with following tests such as
+# galera_3nodes.galera_var_dirty_reads2
+!include ../galera_3nodes.cnf
!include ../galera_3nodes.cnf
diff --git a/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test
index 0a94e7cd85d..729f14a731f 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_pc_weight.test
@@ -1,11 +1,11 @@
#
-# Test the pc.weight wsrep provider option. We set Node #1 to have a high weight and then
-# suspend it. This will cause Nodes #2 and #3 to transition to non-primary component.
+# Test the pc.weight wsrep provider option. We set Node #1 to have a high
+# weight and then suspend it. This will cause Nodes #2 and #3 to transition
+# to non-primary component.
#
--source include/big_test.inc
--source include/galera_cluster.inc
---source include/have_innodb.inc
--connection node_1
SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_weight';
@@ -55,6 +55,9 @@ SHOW STATUS LIKE 'wsrep_local_state_comment';
--connection node_1
# For Node #1, we expect a primary component of size 1
+# (NOTE: this is a bit racy as nodes 2 and 3 will try to reconnect ASAP.
+# to avoid the raice they should be suspended first as well, but that's
+# not currently possible)
--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
diff --git a/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test
index 88d0cfba4f4..722242b22c8 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test
@@ -3,6 +3,22 @@
#
--source include/galera_cluster.inc
+
+#
+# Create connection node_3 and save auto increment variables.
+#
+--let $galera_connection_name = node_3
+--let $galera_server_number = 3
+--source include/galera_connect.inc
+
+--let $node_1 = node_1
+--let $node_2 = node_2
+--let $node_3 = node_3
+
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_1
+
CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
#
@@ -48,7 +64,6 @@ CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
# Shut down one more node
#
---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
--connection node_3
--source include/shutdown_mysqld.inc
@@ -155,9 +170,18 @@ SET SESSION wsrep_on = OFF;
--connection node_2
CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+CALL mtr.add_suppression("It may not be safe to bootstrap the cluster from this node");
+CALL mtr.add_suppression("Aborting");
--connection node_3
CALL mtr.add_suppression("Failed to prepare for incremental state transfer");
+CALL mtr.add_suppression("It may not be safe to bootstrap the cluster from this node");
+CALL mtr.add_suppression("Aborting");
SHOW CREATE TABLE t1;
DROP TABLE t1;
+
+#
+# Restore auto increment variables.
+#
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test b/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test
index 3e8b1557e7b..8e73dee70ae 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_slave_options_ignore.test
@@ -25,6 +25,7 @@ SELECT COUNT(*) = 1 FROM db2.t2B;
--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
--connection node_3
+--source include/galera_wait_ready.inc
SELECT COUNT(*) = 0 FROM db1.t1;
SELECT COUNT(*) = 1 FROM db2.t2A;
SELECT COUNT(*) = 1 FROM db2.t2B;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test b/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test
index 129ba2e1f38..2ceda1ed352 100644
--- a/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test
+++ b/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test
@@ -106,7 +106,8 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
--source include/wait_condition.inc
--connection node_2
---let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
--source include/wait_condition.inc
+--source include/galera_wait_ready.inc
DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes/t/galera_wsrep_schema.test b/mysql-test/suite/galera_3nodes/t/galera_wsrep_schema.test
new file mode 100644
index 00000000000..5c2cae75bd0
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes/t/galera_wsrep_schema.test
@@ -0,0 +1,83 @@
+#
+# This test performs basic checks on the contents of the wsrep_schema
+#
+# wsrep_members_history checks are temporarily disabled until it
+# can be made configurable.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_1
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+# Make the test fail if table structure has changed
+
+SHOW CREATE TABLE mysql.wsrep_cluster;
+SHOW CREATE TABLE mysql.wsrep_cluster_members;
+#disabled SHOW CREATE TABLE mysql.wsrep_member_history;
+
+# Checks for the wsrep_cluster table
+
+SELECT COUNT(*) = 1 FROM mysql.wsrep_cluster;
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+
+# Checks for the wsrep_cluster_members table
+
+SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_members;
+SELECT COUNT(*) = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size') FROM mysql.wsrep_cluster_members;
+SELECT COUNT(*) = 1 FROM mysql.wsrep_cluster_members WHERE node_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_gcomm_uuid');
+
+SELECT node_incoming_address LIKE '127.0.0.1:%' from mysql.wsrep_cluster_members;
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster_members;
+
+# Checks for the wsrep_cluster_member_history table
+
+#disabled SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_member_history;
+#disabled SELECT COUNT(*) = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size') FROM mysql.wsrep_cluster_member_history;
+SELECT COUNT(*) = 1 FROM mysql.wsrep_cluster_members WHERE node_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_gcomm_uuid');
+
+#disabled SELECT last_view_id = (SELECT view_id FROM mysql.wsrep_cluster) FROM mysql.wsrep_cluster_member_history;
+#disabled SELECT last_view_seqno = (SELECT view_seqno FROM mysql.wsrep_cluster) FROM mysql.wsrep_cluster_member_history;
+#disabled SELECT node_incoming_address LIKE '127.0.0.1:%' from mysql.wsrep_cluster_member_history;
+#disabled SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster_member_history;
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+SELECT COUNT(*) = 2 FROM mysql.wsrep_cluster_members;
+#disabled SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_member_history;
+#disabled SELECT COUNT(*) = 2 FROM mysql.wsrep_cluster_member_history WHERE last_view_id = (SELECT MAX(last_view_id) FROM mysql.wsrep_cluster_member_history);
+
+--connection node_2
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_members;
+#disabled SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_member_history WHERE last_view_id = (SELECT MAX(last_view_id) FROM mysql.wsrep_cluster_member_history);
+
+--connection node_1
+SELECT cluster_uuid = (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_state_uuid') FROM mysql.wsrep_cluster;
+SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_members;
+#disabled SELECT COUNT(*) = 3 FROM mysql.wsrep_cluster_member_history WHERE last_view_id = (SELECT MAX(last_view_id) FROM mysql.wsrep_cluster_member_history);
+
+--source ../galera/include/auto_increment_offset_restore.inc
+
+--connection node_1
+CALL mtr.add_suppression("SYNC message from member");
+
+--connection node_2
+CALL mtr.add_suppression("SYNC message from member");
+
+--connection node_3
+CALL mtr.add_suppression("SYNC message from member");
diff --git a/mysql-test/suite/galera_3nodes_sr/galera_3nodes.cnf b/mysql-test/suite/galera_3nodes_sr/galera_3nodes.cnf
new file mode 100644
index 00000000000..62c8214b8f2
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/galera_3nodes.cnf
@@ -0,0 +1 @@
+!include ../galera_3nodes/galera_3nodes.cnf
diff --git a/mysql-test/suite/galera_3nodes_sr/my.cnf b/mysql-test/suite/galera_3nodes_sr/my.cnf
new file mode 100644
index 00000000000..bb25b95ceea
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/my.cnf
@@ -0,0 +1 @@
+!include galera_3nodes.cnf
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-336.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-336.result
new file mode 100644
index 00000000000..bb6c11edf36
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-336.result
@@ -0,0 +1,26 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM t1;
+COUNT(*) > 0
+1
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+SET SESSION wsrep_sync_wait=0;
+INSERT INTO t1 VALUES (2);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+COMMIT;
+ERROR 08S01: WSREP has not yet prepared node for application use
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+DROP TABLE t1;
+CALL mtr.add_suppression("replication aborted");
+CALL mtr.add_suppression("WSREP: fragment replication failed: 3");
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-582.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-582.result
new file mode 100644
index 00000000000..9e2a4823973
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-582.result
@@ -0,0 +1,23 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+5
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+5
+COMMIT;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-606.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-606.result
new file mode 100644
index 00000000000..775f7ee0412
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-606.result
@@ -0,0 +1,38 @@
+connection node_2;
+connection node_1;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+connection node_2;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (21);
+INSERT INTO t1 VALUES (22);
+INSERT INTO t1 VALUES (23);
+INSERT INTO t1 VALUES (24);
+connection node_1;
+connection node_2a;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+SET WSREP_ON=ON;
+connection node_1;
+connection node_2a;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+connection node_1;
+connection node_1;
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+0
+connection node_2;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1
+COMMIT;
+connection node_1;
+SELECT * FROM t1;
+f1
+DROP TABLE t1;
+connection node_2;
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-609.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-609.result
new file mode 100644
index 00000000000..8fe13c7e2bf
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-609.result
@@ -0,0 +1,20 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+INSERT INTO t1 VALUES (31),(32),(33);
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+0
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+0
+COMMIT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-810A.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-810A.result
new file mode 100644
index 00000000000..9a83ff3c041
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-810A.result
@@ -0,0 +1,256 @@
+SET GLOBAL debug="d,crash_last_fragment_commit_before_fragment_removal";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+crash_last_fragment_commit_before_fragment_removal
+COMMIT;
+Got one of the listed errors
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+SET GLOBAL debug="d,crash_last_fragment_commit_after_fragment_removal";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+crash_last_fragment_commit_after_fragment_removal
+COMMIT;
+Got one of the listed errors
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+SET GLOBAL debug="d,crash_replicate_fragment_success";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+crash_replicate_fragment_success
+COMMIT;
+Got one of the listed errors
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+SET GLOBAL debug="d,crash_replicate_fragment_after_certify";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+crash_replicate_fragment_after_certify
+COMMIT;
+Got one of the listed errors
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+SET GLOBAL debug="d,crash_replicate_fragment_before_certify";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+crash_replicate_fragment_before_certify
+COMMIT;
+Got one of the listed errors
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-810B.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-810B.result
new file mode 100644
index 00000000000..bbec3531a49
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-810B.result
@@ -0,0 +1,100 @@
+SET GLOBAL debug="d,crash_apply_cb_before_append_frag";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+SET GLOBAL debug="d,crash_apply_cb_after_append_frag";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+COMMIT;
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+COMMIT;
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug = '';
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member");
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-810C.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-810C.result
new file mode 100644
index 00000000000..1a6dcbfd392
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-810C.result
@@ -0,0 +1,177 @@
+SET GLOBAL debug="d,crash_commit_cb_last_fragment_commit_success";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+SET SESSION wsrep_trx_fragment_size=1;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary');
+SELECT 1 FROM t1;
+Got one of the listed errors
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug="d,crash_commit_cb_before_last_fragment_commit";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+SET SESSION wsrep_trx_fragment_size=1;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary');
+SELECT 1 FROM t1;
+Got one of the listed errors
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug="d,crash_apply_cb_after_fragment_removal";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+SET SESSION wsrep_trx_fragment_size=1;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary');
+SELECT 1 FROM t1;
+Got one of the listed errors
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET GLOBAL debug="d,crash_apply_cb_before_fragment_removal";
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('secondary'),('secondary'),('secondary'),('secondary'),('secondary');
+SET SESSION wsrep_trx_fragment_size=1;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary'),('primary');
+SELECT 1 FROM t1;
+Got one of the listed errors
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) > 0 FROM t1 WHERE f1 = 'primary';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f1 = 'secondary';
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-817.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-817.result
new file mode 100644
index 00000000000..4eb0ebca4f4
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-817.result
@@ -0,0 +1,54 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+SET SESSION wsrep_on = OFF;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+connection node_3;
+connection node_1a;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+connection node_3;
+connection node_1a;
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_1a;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/GCF-832.result b/mysql-test/suite/galera_3nodes_sr/r/GCF-832.result
new file mode 100644
index 00000000000..d670b8c24a0
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/GCF-832.result
@@ -0,0 +1,26 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_2;
+SET GLOBAL debug="d,crash_last_fragment_commit_after_fragment_removal";
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+CREATE TABLE t1 (f1 VARCHAR(30)) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+COMMIT;
+ERROR HY000: Lost connection to MySQL server during query
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_isolate_master.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_isolate_master.result
new file mode 100644
index 00000000000..bb4eb829abc
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_isolate_master.result
@@ -0,0 +1,80 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM t1;
+COUNT(*) > 0
+1
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+connection node_2;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_2;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_3;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+connection node_2;
+connection node_3;
+connection node_1a;
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_3;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+CALL mtr.add_suppression("failed to send SR rollback for");
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_join_slave.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_join_slave.result
new file mode 100644
index 00000000000..0260ebec86a
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_join_slave.result
@@ -0,0 +1,39 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_3;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+connection node_1;
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+COMMIT;
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+connection node_2;
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+connection node_3;
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_master.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_master.result
new file mode 100644
index 00000000000..1a179565666
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_master.result
@@ -0,0 +1,33 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_3;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_2;
+Killing server ...
+connection node_3;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (1);
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply.result
new file mode 100644
index 00000000000..595bd30d675
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply.result
@@ -0,0 +1,53 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+Killing server ...
+connection node_1;
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+connection node_2;
+connection node_1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 15 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 15
+1
+connection node_1;
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 15 FROM t1;
+COUNT(*) = 15
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+connection node_3;
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member");
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback.result
new file mode 100644
index 00000000000..239eb748385
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback.result
@@ -0,0 +1,58 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+Killing server ...
+connection node_1;
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+connection node_2;
+connection node_1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 15 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 15
+1
+connection node_1;
+ROLLBACK;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback2.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback2.result
new file mode 100644
index 00000000000..21e301ed353
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_after_apply_rollback2.result
@@ -0,0 +1,31 @@
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+Killing server ...
+INSERT INTO t1 VALUES (6);
+ROLLBACK;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_before_apply.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_before_apply.result
new file mode 100644
index 00000000000..4a135cd9274
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_kill_slave_before_apply.result
@@ -0,0 +1,44 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+CREATE TABLE t2 (f1 INTEGER);
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+LOCK TABLE t2 WRITE;
+connection node_1;
+INSERT INTO t2 VALUES (1);
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+Killing server ...
+connection node_1;
+COMMIT;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_3nodes_sr/r/galera_sr_threeway_split.result b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_threeway_split.result
new file mode 100644
index 00000000000..1a50bace279
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/r/galera_sr_threeway_split.result
@@ -0,0 +1,117 @@
+connection node_2;
+connection node_1;
+connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1;
+connection node_2;
+connection node_3;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (200);
+INSERT INTO t1 VALUES (201);
+INSERT INTO t1 VALUES (202);
+INSERT INTO t1 VALUES (203);
+INSERT INTO t1 VALUES (204);
+connection node_3;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (300);
+INSERT INTO t1 VALUES (301);
+INSERT INTO t1 VALUES (302);
+INSERT INTO t1 VALUES (303);
+INSERT INTO t1 VALUES (304);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connect node_3a, 127.0.0.1, root, , test, $NODE_MYPORT_3;
+connection node_1a;
+connection node_2a;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+connection node_3a;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+connection node_1a;
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (21);
+INSERT INTO t1 VALUES (22);
+INSERT INTO t1 VALUES (23);
+INSERT INTO t1 VALUES (24);
+connection node_2a;
+SET SESSION wsrep_on = ON;
+SET SESSION wsrep_sync_wait = 15;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+connection node_3a;
+SET SESSION wsrep_on = ON;
+SET SESSION wsrep_sync_wait = 15;
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+connection node_1a;
+connection node_2a;
+connection node_3a;
+connection node_2;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+wsrep_gcomm_uuid_match
+1
+connection node_3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+COUNT(DISTINCT node_uuid) = 1
+1
+wsrep_gcomm_uuid_match
+1
+connection node_1;
+INSERT INTO t1 VALUES (30);
+INSERT INTO t1 VALUES (31);
+INSERT INTO t1 VALUES (32);
+INSERT INTO t1 VALUES (33);
+INSERT INTO t1 VALUES (34);
+COMMIT;
+SELECT COUNT(*) = 15, MIN(f1) = 10, MAX(f1) = 34 FROM t1;
+COUNT(*) = 15 MIN(f1) = 10 MAX(f1) = 34
+1 1 1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+connection node_2;
+COMMIT;
+SELECT COUNT(*) = 15, MIN(f1) = 10, MAX(f1) = 34 FROM t1;
+COUNT(*) = 15 MIN(f1) = 10 MAX(f1) = 34
+1 1 1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+connection node_3;
+COMMIT;
+SELECT COUNT(*) = 15, MIN(f1) = 10, MAX(f1) = 34 FROM t1;
+COUNT(*) = 15 MIN(f1) = 10 MAX(f1) = 34
+1 1 1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=ON;
+DROP TABLE t1;
+connection node_1;
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
+connection node_2;
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
+connection node_3;
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-336.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-336.test
new file mode 100644
index 00000000000..b8d46db74f1
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-336.test
@@ -0,0 +1,47 @@
+--source include/galera_cluster.inc
+
+--connection node_2
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM t1;
+
+--connection node_2a
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+SET SESSION wsrep_sync_wait=0;
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (2);
+--error ER_UNKNOWN_COM_ERROR
+COMMIT;
+
+--connection node_2a
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
+--source include/wait_condition.inc
+DROP TABLE t1;
+
+CALL mtr.add_suppression("replication aborted");
+CALL mtr.add_suppression("WSREP: fragment replication failed: 3");
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+--source include/galera_wait_ready.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-582.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-582.test
new file mode 100644
index 00000000000..bf19ea84c87
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-582.test
@@ -0,0 +1,39 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--source include/start_mysqld.inc
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COMMIT;
+SELECT COUNT(*) FROM t1;
+
+--connection node_2
+SELECT COUNT(*) FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-606.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-606.test
new file mode 100644
index 00000000000..6d49247ab5e
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-606.test
@@ -0,0 +1,80 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the case where the cluster splits 3 ways.
+# The master transitions to a non-prim view and back to prim. Its ongoing
+# should fail to commit.
+#
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+--connection node_2
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (21);
+INSERT INTO t1 VALUES (22);
+INSERT INTO t1 VALUES (23);
+INSERT INTO t1 VALUES (24);
+
+--connection node_1
+--let $wait_condition = SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+#
+# Isolate node_2 into a separate non-primary component
+#
+
+--connection node_2a
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+--disable_query_log
+SET WSREP_ON=OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+SET WSREP_ON=ON;
+--enable_query_log
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+#
+# Confirm that node_1 has no transactions in SR table
+#
+
+--let $wait_condition = SELECT COUNT(DISTINCT node_uuid) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+#
+# Restore cluster
+#
+
+--connection node_2a
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+--source include/galera_wait_ready.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_1
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+SELECT * FROM t1;
+COMMIT;
+
+--connection node_1
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--connection node_2
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-609.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-609.test
new file mode 100644
index 00000000000..fd346cf365b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-609.test
@@ -0,0 +1,30 @@
+#
+# GCF-609 SR: Assertion wsrep_apply_cb on slave after master causes a duplicate key error
+#
+
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+--connection node_2
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+INSERT INTO t1 VALUES (31),(32),(33);
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COMMIT;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-810A.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-810A.test
new file mode 100644
index 00000000000..38d95556e48
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-810A.test
@@ -0,0 +1,137 @@
+#
+# Exercise the crash points which crash the server at various points important to SR
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+--connect node_2_check, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connect node_3_check, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
+#
+# crash_last_fragment_commit_before_fragment_removal
+#
+
+--connection node_2
+--enable_reconnect
+SET GLOBAL debug="d,crash_last_fragment_commit_before_fragment_removal";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes.inc
+
+--echo crash_last_fragment_commit_before_fragment_removal
+
+--connection node_2
+--error 2006,2013
+COMMIT;
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_2
+--source include/start_mysqld.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check.inc
+
+#
+# crash_last_fragment_commit_after_fragment_removal
+#
+
+--connection node_2
+SET GLOBAL debug="d,crash_last_fragment_commit_after_fragment_removal";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes.inc
+
+--echo crash_last_fragment_commit_after_fragment_removal
+
+--connection node_2
+--error 2006,2013
+COMMIT;
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_2
+--source include/start_mysqld.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check.inc
+
+#
+# crash_last_fragment_commit_success
+#
+# Case crash_last_fragment_commit_success is commented out,
+# the changes will be visible on slave due to succesful commit,
+# so the galera_sr_crash_post_check will fail.
+#
+
+# --connection node_2
+# SET GLOBAL debug="d,crash_last_fragment_commit_success";
+# --source suite/galera_3nodes/include/galera_expect_node_crash.inc
+# --source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes.inc
+
+# --echo crash_last_fragment_commit_success
+
+# --connection node_2
+# --error 2006,2013
+# COMMIT;
+
+# --source include/start_mysqld.inc
+# --source suite/galera_3nodes/include/galera_sr_crash_post_check.inc
+
+#
+# crash_replicate_fragment_success
+#
+
+--connection node_2
+SET GLOBAL debug="d,crash_replicate_fragment_success";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes.inc
+
+--echo crash_replicate_fragment_success
+
+--connection node_2
+--error 2006,2013
+COMMIT;
+
+--source include/start_mysqld.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check.inc
+
+#
+# crash_replicate_fragment_after_certify
+#
+
+--connection node_2
+SET GLOBAL debug="d,crash_replicate_fragment_after_certify";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes.inc
+
+--echo crash_replicate_fragment_after_certify
+
+--connection node_2
+--error 2006,2013
+COMMIT;
+
+--source include/start_mysqld.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check.inc
+
+#
+# crash_replicate_fragment_before_certify
+#
+
+--connection node_2
+SET GLOBAL debug="d,crash_replicate_fragment_before_certify";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes.inc
+
+--echo crash_replicate_fragment_before_certify
+
+--connection node_2
+--error 2006,2013
+COMMIT;
+
+--source include/start_mysqld.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check.inc
+
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-810B.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-810B.test
new file mode 100644
index 00000000000..24a518af9f7
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-810B.test
@@ -0,0 +1,49 @@
+#
+# Exercise the crash points which crash the server at various points important to SR
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+--connect node_2_check, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connect node_3_check, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
+#
+# crash_apply_cb_before_append_frag
+#
+
+--connection node_3
+SET GLOBAL debug="d,crash_apply_cb_before_append_frag";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes2.inc
+
+--connection node_3
+--error 0,2006,2013
+COMMIT;
+
+--source include/start_mysqld.inc
+--sleep 5
+--source suite/galera_3nodes/include/galera_sr_crash_post_check2.inc
+
+#
+# crash_apply_cb_after_append_frag
+#
+
+--connection node_3
+SET GLOBAL debug="d,crash_apply_cb_after_append_frag";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes2.inc
+
+--connection node_3
+--error 0,2006,2013
+COMMIT;
+
+--source include/start_mysqld.inc
+--sleep 5
+--source suite/galera_3nodes/include/galera_sr_crash_post_check2.inc
+
+--connection node_1
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member");
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-810C.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-810C.test
new file mode 100644
index 00000000000..79948e5a46d
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-810C.test
@@ -0,0 +1,70 @@
+#
+# Exercise the crash points which crash the server at various points important to SR
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+--connect node_2_check, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--enable_reconnect
+--connect node_3_check, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
+#
+# crash_commit_cb_last_fragment_commit_success
+#
+
+--connection node_3
+SET GLOBAL debug="d,crash_commit_cb_last_fragment_commit_success";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes3.inc
+
+--source include/start_mysqld.inc
+--sleep 5
+--source include/galera_wait_ready.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check3.inc
+
+#
+# crash_commit_cb_before_last_fragment_commit
+#
+
+--connection node_3
+SET GLOBAL debug="d,crash_commit_cb_before_last_fragment_commit";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes3.inc
+
+--source include/start_mysqld.inc
+--sleep 5
+--source include/galera_wait_ready.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check3.inc
+
+#
+# crash_apply_cb_after_fragment_removal
+#
+
+--connection node_3
+SET GLOBAL debug="d,crash_apply_cb_after_fragment_removal";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes3.inc
+
+--source include/start_mysqld.inc
+--sleep 5
+--source include/galera_wait_ready.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check3.inc
+
+#
+# crash_apply_cb_before_fragment_removal
+#
+
+--connection node_3
+SET GLOBAL debug="d,crash_apply_cb_before_fragment_removal";
+--source suite/galera_3nodes/include/galera_expect_node_crash.inc
+--source suite/galera_3nodes/include/galera_sr_crash_prepare_nodes3.inc
+
+--source include/start_mysqld.inc
+--sleep 5
+--source include/galera_wait_ready.inc
+--source suite/galera_3nodes/include/galera_sr_crash_post_check3.inc
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-817.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-817.test
new file mode 100644
index 00000000000..a32da959429
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-817.test
@@ -0,0 +1,109 @@
+#
+# GCF-817 SR: master removes SR trx in non-primary view
+#
+
+--source include/galera_cluster.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--connection node_1a
+# Force node #1 to go non-primary
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1';
+
+SET SESSION wsrep_on = OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+# SR table on master should still contain entries after going non-Prim
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+# SR table on slave should eventually clean up entries when master goes non-Prim
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+--connection node_3
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+# Restore node #1 to primary
+
+--connection node_1a
+#
+# The following sleep is a workaround for issue GCF-861.
+# Normally it's sufficient to make sure that the CC happened
+# by checking that wsrep_cluster_size has shrinked, as above.
+# However that is not always enough, so we sleep a few seconds.
+# See GCF-861 on how to reproduce.
+#
+
+--connection node_1a
+--sleep 6
+SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0';
+
+--connection node_3
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_1a
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+--source include/wait_condition.inc
+
+--source include/galera_wait_ready.inc
+
+# SR table on master should contain no entries after going back to Prim state
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+--connection node_2
+# And none on slave
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+# SR table is now empty everywhere
+--connection node_1a
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+DROP TABLE t1;
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/GCF-832.test b/mysql-test/suite/galera_3nodes_sr/t/GCF-832.test
new file mode 100644
index 00000000000..c5a6346d6a1
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/GCF-832.test
@@ -0,0 +1,43 @@
+#
+# GCF-832 SR: mysql.wsrep_streaming_log table remains populated on all nodes after crash
+# followed by immediate recovery
+#
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_2
+SET GLOBAL debug="d,crash_last_fragment_commit_after_fragment_removal";
+
+--let $_server_id= `SELECT @@server_id`
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
+--exec echo "wait" > $_expect_file_name
+
+CREATE TABLE t1 (f1 VARCHAR(30)) ENGINE=InnoDB;
+
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES ('primary'),('primary'),('primary'),('primary'),('primary');
+--error 2013
+COMMIT;
+
+--source include/start_mysqld.inc
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--enable_reconnect
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/disabled.def b/mysql-test/suite/galera_3nodes_sr/t/disabled.def
new file mode 100644
index 00000000000..0944abd0ad5
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/disabled.def
@@ -0,0 +1,7 @@
+GCF-336 :
+GCF-582 :
+GCF-609 :
+GCF-810A :
+GCF-810B :
+GCF-810C :
+galera_sr_kill_slave_after_apply_rollback2 : \ No newline at end of file
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_isolate_master.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_isolate_master.test
new file mode 100644
index 00000000000..30fd0192f26
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_isolate_master.test
@@ -0,0 +1,127 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of gmcast.isolate on master during an SR transaction
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM t1;
+
+#
+# Trigger gmcast.isolate=1 .
+# The transaction is aborted and we expect the SR tables to be cleaned up
+#
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+--source include/galera_wait_ready.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+--source include/galera_wait_ready.inc
+
+#
+# Expect that the transaction is cleaned up entirely across the cluster and in all mysql.wsrep_streaming_log tables
+#
+
+--connection node_2
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_3
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+#
+# Restore cluster
+#
+
+--connection node_1a
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_3
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_1a
+--source include/galera_wait_ready.inc
+
+#
+# Confirm that the previous transaction is gone on Node #1 as well
+#
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+#
+# Confirm that the transaction can be retried
+#
+
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+CALL mtr.add_suppression("failed to send SR rollback for");
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_join_slave.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_join_slave.test
new file mode 100644
index 00000000000..95aa1a37a78
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_join_slave.test
@@ -0,0 +1,59 @@
+#
+# This test kills the slave before a Streaming Replication transaction has started
+# and restarts it when the transaction is already in progress. IST should
+# bring the slave up to date so that it can receive the complete transaction.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_1
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--source include/start_mysqld.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+COMMIT;
+SELECT COUNT(*) = 10 FROM t1;
+
+--connection node_2
+SELECT COUNT(*) = 10 FROM t1;
+
+--connection node_3
+SELECT COUNT(*) = 10 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_master.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_master.test
new file mode 100644
index 00000000000..c7e7528679b
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_master.test
@@ -0,0 +1,58 @@
+#
+# This test kills the master while a Streaming Replication transaction is in progress
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_2
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_3
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_2
+--source include/kill_galera.inc
+
+--connection node_3
+# We expect that uncommitted values are no longer present
+
+--let $wait_condition = SELECT COUNT(*) = 0 FROM t1;
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# and we can insert them again
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+--source include/start_mysqld.inc
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply.test
new file mode 100644
index 00000000000..270af538085
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply.test
@@ -0,0 +1,81 @@
+#
+# This test kills the slave while a Streaming Replication transaction is in progress
+# and after a fragment has already been applied on the slave. It is expected that
+# after the slave restarts, the cluster will continue to be consistent
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_1
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+
+--connection node_2
+--source include/start_mysqld.inc
+
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+
+--connection node_2
+
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) = 15 FROM t1;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 15 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+COMMIT;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 15 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+
+--connection node_3
+CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member");
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback.test
new file mode 100644
index 00000000000..c0df6b2777a
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback.test
@@ -0,0 +1,80 @@
+#
+# This test kills the slave while a Streaming Replication transaction is in progress
+# and after a fragment has already been applied on the slave. It is expected that
+# after the slave restarts, the cluster will continue to be consistent even if ROLLBACK
+# is issued on the SR transaction after restart.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_1
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+
+--connection node_2
+--source include/start_mysqld.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+
+--connection node_2
+
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) = 15 FROM t1;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 15 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+ROLLBACK;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback2.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback2.test
new file mode 100644
index 00000000000..83964769ef5
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_after_apply_rollback2.test
@@ -0,0 +1,56 @@
+#
+# This test kills the slave while a Streaming Replication transaction is in progress
+# and after a fragment has already been applied on the slave. It is expected that
+# after the slave restarts, the cluster will continue to be consistent
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+--sleep 1
+
+--connection node_1
+INSERT INTO t1 VALUES (6);
+ROLLBACK;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--source include/start_mysqld.inc
+--sleep 1
+
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+
+--connection node_2
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_before_apply.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_before_apply.test
new file mode 100644
index 00000000000..92566fa6323
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_kill_slave_before_apply.test
@@ -0,0 +1,73 @@
+#
+# This test kills the slave while a Streaming Replication transaction is in progress
+# but before a fragment has already been applied on the slave. It is expected that
+# after the slave restarts, the cluster will continue to be consistent.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+
+# Block node #2's applier before table t1's inserts have come into play
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+CREATE TABLE t2 (f1 INTEGER);
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+LOCK TABLE t2 WRITE;
+
+--connection node_1
+INSERT INTO t2 VALUES (1);
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--source include/kill_galera.inc
+--source include/start_mysqld.inc
+
+# Expect that the SR table will get some entries after the restart
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE t2;
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.cnf b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.cnf
new file mode 100644
index 00000000000..910d945949a
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.cnf
@@ -0,0 +1,5 @@
+!include ../galera_3nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.weight=3'
+
diff --git a/mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.test b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.test
new file mode 100644
index 00000000000..62122fe4292
--- /dev/null
+++ b/mysql-test/suite/galera_3nodes_sr/t/galera_sr_threeway_split.test
@@ -0,0 +1,177 @@
+#
+# Test the case where the cluster splits 3 ways . The master remains in the
+# primary component and is able to commit its transaction.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--let $node_3=node_3
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+#
+# Begin a separate SR transaction on every node and confirm that each node
+# has SR table entries for every transaction
+#
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (10);
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (200);
+INSERT INTO t1 VALUES (201);
+INSERT INTO t1 VALUES (202);
+INSERT INTO t1 VALUES (203);
+INSERT INTO t1 VALUES (204);
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(DISTINCT node_uuid) = 2 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (300);
+INSERT INTO t1 VALUES (301);
+INSERT INTO t1 VALUES (302);
+INSERT INTO t1 VALUES (303);
+INSERT INTO t1 VALUES (304);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connect node_3a, 127.0.0.1, root, , test, $NODE_MYPORT_3
+
+--connection node_1a
+--let $wait_condition = SELECT COUNT(DISTINCT node_uuid) = 3 FROM mysql.wsrep_streaming_log
+--source include/wait_condition.inc
+
+#
+# Isolate nodes #2 and #3 into separate non-primary components
+#
+
+--connection node_2a
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--connection node_3a
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--connection node_1a
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+INSERT INTO t1 VALUES (20);
+INSERT INTO t1 VALUES (21);
+INSERT INTO t1 VALUES (22);
+INSERT INTO t1 VALUES (23);
+INSERT INTO t1 VALUES (24);
+
+#
+# Restore cluster
+#
+
+--connection node_2a
+--source include/wsrep_wait_disconnect.inc
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+--source include/galera_wait_ready.inc
+
+--connection node_3a
+--source include/wsrep_wait_disconnect.inc
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+--source include/galera_wait_ready.inc
+
+--connection node_1a
+--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+--let $node_1_gcomm_uuid = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_gcomm_uuid'`
+
+--connection node_2a
+--source include/wait_condition.inc
+
+--connection node_3a
+--source include/wait_condition.inc
+
+
+#
+# Confirm that the rejoined nodes only have node #1's transaction in their SR tables
+#
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+--disable_query_log
+--eval SELECT DISTINCT node_uuid = '$node_1_gcomm_uuid' AS wsrep_gcomm_uuid_match FROM mysql.wsrep_streaming_log;
+--enable_query_log
+
+--connection node_3
+--error ER_LOCK_DEADLOCK
+COMMIT;
+SELECT COUNT(DISTINCT node_uuid) = 1 FROM mysql.wsrep_streaming_log;
+--disable_query_log
+--eval SELECT DISTINCT node_uuid = '$node_1_gcomm_uuid' AS wsrep_gcomm_uuid_match FROM mysql.wsrep_streaming_log;
+--enable_query_log
+
+#
+# Finalize transaction on node #1
+#
+
+--connection node_1
+INSERT INTO t1 VALUES (30);
+INSERT INTO t1 VALUES (31);
+INSERT INTO t1 VALUES (32);
+INSERT INTO t1 VALUES (33);
+INSERT INTO t1 VALUES (34);
+COMMIT;
+
+#
+# Confirm that transaction is replicated correctly and SR tables are empty at the end of the test
+#
+
+SELECT COUNT(*) = 15, MIN(f1) = 10, MAX(f1) = 34 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SET AUTOCOMMIT=ON;
+
+--connection node_2
+COMMIT;
+SELECT COUNT(*) = 15, MIN(f1) = 10, MAX(f1) = 34 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SET AUTOCOMMIT=ON;
+
+--connection node_3
+COMMIT;
+SELECT COUNT(*) = 15, MIN(f1) = 10, MAX(f1) = 34 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SET AUTOCOMMIT=ON;
+
+DROP TABLE t1;
+
+--connection node_1
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
+--connection node_2
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
+--connection node_3
+CALL mtr.add_suppression("WSREP: failed to send SR rollback for ");
+
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_sr/galera_2nodes.cnf b/mysql-test/suite/galera_sr/galera_2nodes.cnf
new file mode 100644
index 00000000000..0412b5654dd
--- /dev/null
+++ b/mysql-test/suite/galera_sr/galera_2nodes.cnf
@@ -0,0 +1 @@
+!include ../galera/galera_2nodes.cnf
diff --git a/mysql-test/suite/galera_sr/my.cnf b/mysql-test/suite/galera_sr/my.cnf
new file mode 100644
index 00000000000..ca163a540d9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/my.cnf
@@ -0,0 +1 @@
+!include galera_2nodes.cnf
diff --git a/mysql-test/suite/galera_sr/r/GCF-1008.result b/mysql-test/suite/galera_sr/r/GCF-1008.result
new file mode 100644
index 00000000000..541ac3cddfb
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1008.result
@@ -0,0 +1,70 @@
+connection node_2;
+connection node_1;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) ENGINE=InnoDB;
+connection node_2;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'x');
+connection node_2a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,before_local_commit_monitor_enter';
+connection node_2;
+COMMIT;
+connection node_2b;
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+REPLACE INTO t1 VALUES (1,'y');
+connection node_2b;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2a;
+SET GLOBAL wsrep_provider_options = 'signal=before_local_commit_monitor_enter';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) ENGINE=InnoDB;
+connection node_2;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'x');
+connection node_2a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,before_certify_apply_monitor_enter';
+connection node_2;
+COMMIT;
+connection node_2b;
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+REPLACE INTO t1 VALUES (1,'y');
+connection node_2b;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2a;
+SET GLOBAL wsrep_provider_options = 'signal=before_certify_apply_monitor_enter';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-1018.result b/mysql-test/suite/galera_sr/r/GCF-1018.result
new file mode 100644
index 00000000000..ec5bdca214c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1018.result
@@ -0,0 +1,24 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+INSERT INTO t1 (f2) VALUES ('a');
+INSERT INTO t1 (f2) VALUES ('b');
+INSERT INTO t1 (f2) VALUES ('c');
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2a;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'dbug=d,after_certify_apply_monitor_enter';
+connection node_2;
+SET SESSION wsrep_trx_fragment_size = 64;
+DELETE FROM t1 ORDER BY f1 DESC LIMIT 2;;
+connection node_2a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+connection node_1;
+INSERT INTO t1 (f2) VALUES ('d'),('e');
+connection node_2a;
+SET GLOBAL wsrep_provider_options = 'signal=after_certify_apply_monitor_enter';
+SET GLOBAL wsrep_provider_options = 'dbug=';
+connection node_2;
+Got one of the listed errors
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-1018B.result b/mysql-test/suite/galera_sr/r/GCF-1018B.result
new file mode 100644
index 00000000000..4752c072cc1
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1018B.result
@@ -0,0 +1,12 @@
+connection node_2;
+connection node_1;
+connection node_1;
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 64;
+SET SESSION innodb_lock_wait_timeout = 1000;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 64;
+SET SESSION innodb_lock_wait_timeout = 1000;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-1043A.result b/mysql-test/suite/galera_sr/r/GCF-1043A.result
new file mode 100644
index 00000000000..cc90461291d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1043A.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+Running a concurrent test with the following queries:
+DELETE FROM t1
+REPLACE INTO t1 VALUES (1,'y'),(2,'x')
+REPLACE INTO t1 VALUES (1,'y'),(2,'y'),(3,'y')
+connection node_1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1;
+Concurrent test end
diff --git a/mysql-test/suite/galera_sr/r/GCF-1043B.result b/mysql-test/suite/galera_sr/r/GCF-1043B.result
new file mode 100644
index 00000000000..a10295c00b9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1043B.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+Running a concurrent test with the following queries:
+DELETE FROM t1
+INSERT INTO t1 VALUES (1,'y'),(2,'x')
+UPDATE t1 SET f2 = 'y' WHERE f1 = 1 OR f1 = 2;
+connection node_1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1;
+Concurrent test end
diff --git a/mysql-test/suite/galera_sr/r/GCF-1051.result b/mysql-test/suite/galera_sr/r/GCF-1051.result
new file mode 100644
index 00000000000..82fa389bb1d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1051.result
@@ -0,0 +1,46 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size=1;
+connection node_1;
+START TRANSACTION;
+SAVEPOINT A;
+INSERT INTO t1 VALUES (1);
+ROLLBACK TO SAVEPOINT A;
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=OFF;
+SAVEPOINT A;
+INSERT INTO t1 VALUES (2);
+ROLLBACK TO SAVEPOINT A;
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-1060.result b/mysql-test/suite/galera_sr/r/GCF-1060.result
new file mode 100644
index 00000000000..58af97d064b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-1060.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+Running a concurrent test with the following queries:
+TRUNCATE TABLE t1
+INSERT INTO t1 VALUE (1,'x'),(2,'x'),(3,'x')
+INSERT INTO t1 VALUE (4, 'z');
+connection node_1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;;;
+include/diff_servers.inc [servers=1 2]
+DROP TABLE t1;
+Concurrent test end
diff --git a/mysql-test/suite/galera_sr/r/GCF-437.result b/mysql-test/suite/galera_sr/r/GCF-437.result
new file mode 100644
index 00000000000..1aa0c9c0768
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-437.result
@@ -0,0 +1,12 @@
+CREATE TABLE ten (f1 INTEGER) ENGINE=MyISAM;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(512)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 2 * 1024 * 1024;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 512) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
+ERROR HY000: Writing one row to the row-based binary log failed
+CALL mtr.add_suppression("InnoDB: The total blob data length*");
+CALL mtr.add_suppression("WSREP: Error writing into mysql.wsrep_streaming_log: 139");
+CALL mtr.add_suppression("WSREP: Failed to write to frag table: 1");
+CALL mtr.add_suppression("WSREP: Failed to append frag to persistent storage");
+DROP TABLE t1;
+DROP table ten;
diff --git a/mysql-test/suite/galera_sr/r/GCF-561.result b/mysql-test/suite/galera_sr/r/GCF-561.result
new file mode 100644
index 00000000000..58663caf134
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-561.result
@@ -0,0 +1,50 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+ALTER TABLE t1 DROP COLUMN f2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+INSERT INTO t1 VALUES (6, 6);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (6, 6);
+ERROR 21S01: Column count doesn't match value count at row 1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-571.result b/mysql-test/suite/galera_sr/r/GCF-571.result
new file mode 100644
index 00000000000..4b4f749d910
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-571.result
@@ -0,0 +1,67 @@
+connection node_2;
+connection node_1;
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('%abcdef%');
+INSERT INTO t1 VALUES ('%abcdef%');
+INSERT INTO t1 VALUES ('%abcdef%');
+INSERT INTO t1 VALUES ('%abcdef%');
+SAVEPOINT A;
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%abcdef%';
+COUNT(*) > 0
+1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%xyz%';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%SAVEPOINT `A`%';
+COUNT(*) = 1
+0
+connection node_1;
+ROLLBACK TO SAVEPOINT A;
+connection node_1a;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%abcdef%';
+COUNT(*) > 0
+1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%xyz%';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%SAVEPOINT `A`%';
+COUNT(*) = 1
+0
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%ROLLBACK TO `A`%';
+COUNT(*) = 1
+0
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%abcdef%';
+COUNT(*) > 0
+1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%xyz%';
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%SAVEPOINT `A`%';
+COUNT(*) = 1
+0
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%ROLLBACK TO `A`%';
+COUNT(*) = 1
+0
+connection node_1;
+ROLLBACK;
+connection node_1a;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-572.result b/mysql-test/suite/galera_sr/r/GCF-572.result
new file mode 100644
index 00000000000..cb4d48b3600
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-572.result
@@ -0,0 +1,37 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(10)) ENGINE=InnoDB;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'node1');
+connection node_1a;
+INSERT INTO t1 VALUES (5, 'node2');
+connection node_1;
+INSERT INTO t1 VALUES (5, 'node1');
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+5 node2
+SET SESSION wsrep_trx_fragment_size = 10000;
+START TRANSACTION;
+INSERT INTO t1 VALUE (10, 'node1');
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+connection node_1a;
+INSERT INTO t1 VALUES(15, 'node2');
+connection node_1;
+SELECT * FROM t1;
+f1 f2
+5 node2
+10 node1
+INSERT INTO t1 VALUES(15, 'node1');
+ERROR 23000: Duplicate entry '15' for key 'PRIMARY'
+COMMIT;
+SELECT * FROM t1;
+f1 f2
+5 node2
+10 node1
+15 node2
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-574.result b/mysql-test/suite/galera_sr/r/GCF-574.result
new file mode 100644
index 00000000000..bbf817c8c6c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-574.result
@@ -0,0 +1,11 @@
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+wsrep_last_committed_delta
+1
+SELECT COUNT(*) = 10000 FROM t1;
+COUNT(*) = 10000
+1
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/GCF-580.result b/mysql-test/suite/galera_sr/r/GCF-580.result
new file mode 100644
index 00000000000..3ee69c6c4b3
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-580.result
@@ -0,0 +1,13 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+last_committed_matches_fragment_count
+1
+COMMIT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-585.result b/mysql-test/suite/galera_sr/r/GCF-585.result
new file mode 100644
index 00000000000..ab5fed59081
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-585.result
@@ -0,0 +1,28 @@
+connection node_2;
+connection node_1;
+create table t1 (f1 integer primary key) engine=innodb;
+set autocommit=off;
+set session wsrep_trx_fragment_size=1;
+start transaction;
+insert into t1 values (1);
+insert into t1 values (2),(1);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+alter table t1 drop primary key;
+drop table t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+update t1 set f1 = 100 where f1 = 10;
+connection node_2;
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+SET SESSION wsrep_trx_fragment_size=1;
+SET SESSION innodb_lock_wait_timeout=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+delete from t1 where f1 > 10;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+delete from t1 where f1 > 10 and f1 < 100;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-597.result b/mysql-test/suite/galera_sr/r/GCF-597.result
new file mode 100644
index 00000000000..7afca229251
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-597.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+connection node_1;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+ROLLBACK;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-620.result b/mysql-test/suite/galera_sr/r/GCF-620.result
new file mode 100644
index 00000000000..33789f82add
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-620.result
@@ -0,0 +1,18 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 200;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (1);
+SAVEPOINT A;
+INSERT INTO t1 VALUES (1);
+ROLLBACK TO SAVEPOINT A;
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 2 FROM t1;
+COUNT(*) = 2
+0
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-623.result b/mysql-test/suite/galera_sr/r/GCF-623.result
new file mode 100644
index 00000000000..f3500b7ac2b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-623.result
@@ -0,0 +1,29 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-627.result b/mysql-test/suite/galera_sr/r/GCF-627.result
new file mode 100644
index 00000000000..891cf4af5a9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-627.result
@@ -0,0 +1,26 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER);
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+connection node_2;
+DROP TABLE t1;
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+INSERT INTO t1 VALUES (2);
+ERROR 42S02: Table 'test.t1' doesn't exist
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/r/GCF-845.result b/mysql-test/suite/galera_sr/r/GCF-845.result
new file mode 100644
index 00000000000..df842049332
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-845.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+CREATE TABLE IF NOT EXISTS t1 (f1 INTEGER) ENGINE = InnoDB;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET SESSION AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (161);
+COMMIT;
+DELETE FROM t1 WHERE f1 > 13;
+disconnect node_1a;
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+include/assert_grep.inc [No BF-BF log line found]
diff --git a/mysql-test/suite/galera_sr/r/GCF-851.result b/mysql-test/suite/galera_sr/r/GCF-851.result
new file mode 100644
index 00000000000..52aa4c78745
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-851.result
@@ -0,0 +1,30 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION WSREP_TRX_FRAGMENT_SIZE=1;
+SET SESSION AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (10);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_1;
+START TRANSACTION;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) > 0 FROM t1;
+COUNT(*) > 0
+1
+connection node_1;
+SELECT COUNT(*) > 0 FROM t1;
+COUNT(*) > 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-867.result b/mysql-test/suite/galera_sr/r/GCF-867.result
new file mode 100644
index 00000000000..9521a86d621
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-867.result
@@ -0,0 +1,4 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-889.result b/mysql-test/suite/galera_sr/r/GCF-889.result
new file mode 100644
index 00000000000..617377de15a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-889.result
@@ -0,0 +1,25 @@
+connection node_2;
+connection node_1;
+connection node_2;
+SET GLOBAL wsrep_ignore_apply_errors = 2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_on = ON;
+SET SESSION wsrep_trx_fragment_size = 1;
+DELETE FROM t1 WHERE f1 = 1;
+SET SESSION wsrep_trx_fragment_size = 0;
+INSERT INTO t1 VALUES (1);
+SELECT COUNT(*) = 1;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT COUNT(*) = 1;
+COUNT(*) = 1
+1
+CALL mtr.add_suppression("Could not execute Delete_rows event on table");
+CALL mtr.add_suppression("Can't find record in 't1'");
+SET GLOBAL wsrep_ignore_apply_errors = 7;
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/GCF-900.result b/mysql-test/suite/galera_sr/r/GCF-900.result
new file mode 100644
index 00000000000..caa2d2c4138
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/GCF-900.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT) ENGINE=InnoDB;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 128;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 0);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (2, 0);
+connection node_2;
+ALTER TABLE t1 DROP COLUMN f2;
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_1a;
+INSERT INTO t1 VALUES (3, 0);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera-features#56.result b/mysql-test/suite/galera_sr/r/galera-features#56.result
new file mode 100644
index 00000000000..1d04b6f9cee
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera-features#56.result
@@ -0,0 +1,32 @@
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+connection node_1;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+connection node_2;
+SET GLOBAL wsrep_slave_threads = 4;
+SET SESSION wsrep_trx_fragment_size = 1;
+connection node_1;
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
+connection node_1a;
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
+connection node_2;
+INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;;
+connection node_1;
+connection node_1a;
+connection node_2;
+SELECT COUNT(*) = 30000 FROM t1;
+COUNT(*) = 30000
+1
+SELECT COUNT(DISTINCT f1) = 30000 FROM t1;
+COUNT(DISTINCT f1) = 30000
+1
+SELECT COUNT(*) = 6 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+COUNT(*) = 6
+0
+connection default;
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_bf_abort.result b/mysql-test/suite/galera_sr/r/galera_sr_bf_abort.result
new file mode 100644
index 00000000000..bf92a48b242
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_bf_abort.result
@@ -0,0 +1,555 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET SESSION wsrep_sync_wait = 0;
+galera_sr_bf_abort_at_commit = 0
+after_replicate_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync';
+connection node_1;
+INSERT INTO t1 VALUES (3);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+local_monitor_master_enter_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+INSERT INTO t1 VALUES (3);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+apply_monitor_master_enter_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_master_enter_sync';
+connection node_1;
+INSERT INTO t1 VALUES (3);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_master_enter_sync';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+commit_monitor_master_enter_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+connection node_1;
+INSERT INTO t1 VALUES (3);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+galera_sr_bf_abort_at_commit = 1
+after_replicate_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync';
+connection node_1;
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+local_monitor_master_enter_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+connection node_1;
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+apply_monitor_master_enter_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_master_enter_sync';
+connection node_1;
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+commit_monitor_master_enter_sync
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+f1
+1
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
+connection node_1;
+ROLLBACK;
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+connection node_1;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+1
+2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+DROP TABLE t1;
+CALL mtr.add_suppression("WSREP: fragment replication failed: 1");
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_blob.result b/mysql-test/suite/galera_sr/r/galera_sr_blob.result
new file mode 100644
index 00000000000..db25f54a611
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_blob.result
@@ -0,0 +1,23 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 TEXT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_2;
+connection node_1;
+INSERT INTO t1 VALUES (REPEAT('x', 65535));
+connection node_2;
+wsrep_last_committed_delta
+1
+connection node_1;
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT LENGTH(f1) = 65535 FROM t1;
+LENGTH(f1) = 65535
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_cc_master.result b/mysql-test/suite/galera_sr/r/galera_sr_cc_master.result
new file mode 100644
index 00000000000..79bc29200f9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_cc_master.result
@@ -0,0 +1,65 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_2;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_1;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2a;
+SET SESSION wsrep_sync_wait=0;
+SET GLOBAL wsrep_cluster_address = '';
+SET SESSION wsrep_sync_wait = DEFAULT;
+connection node_2;
+INSERT INTO t1 VALUES (6);
+ERROR HY000: Lost connection to MySQL server during query
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2a;
+connection node_1;
+connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2b;
+SELECT * FROM mysql.wsrep_streaming_log;
+node_uuid trx_id seqno flags frag
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+connection node_2b;
+CALL mtr.add_suppression("WSREP: Failed to replicate rollback fragment for");
+disconnect node_2;
+connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result
new file mode 100644
index 00000000000..671745c8686
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_cc_slave.result
@@ -0,0 +1,59 @@
+connection node_2;
+connection node_1;
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+SET GLOBAL wsrep_cluster_address = '';
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_sync_wait = default;
+connection node_1;
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (16);
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+CALL mtr.add_suppression("points to own listening address, blacklisting");
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_concurrent.result b/mysql-test/suite/galera_sr/r/galera_sr_concurrent.result
new file mode 100644
index 00000000000..75acba366c2
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_concurrent.result
@@ -0,0 +1,36 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t2 VALUES (3);
+INSERT INTO t2 VALUES (4);
+INSERT INTO t2 VALUES (5);
+connection node_1;
+COMMIT;
+connection node_1a;
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 5 FROM t2;
+COUNT(*) = 5
+1
+connection node_1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_conflict.result b/mysql-test/suite/galera_sr/r/galera_sr_conflict.result
new file mode 100644
index 00000000000..a45bffeaa81
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_conflict.result
@@ -0,0 +1,21 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+INSERT INTO t1 VALUES(1);;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_1;
+COMMIT;
+connection node_2;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit.result b/mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit.result
new file mode 100644
index 00000000000..5de1ac2422c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit.result
@@ -0,0 +1,31 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+connection node_1;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_1;
+COMMIT;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit2.result b/mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit2.result
new file mode 100644
index 00000000000..2ee3d4c714c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_conflict_on_commit2.result
@@ -0,0 +1,28 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_1;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+INSERT INTO t1 VALUES (5);;
+connection node_1;
+COMMIT;
+connection node_2;
+ERROR 23000: Duplicate entry '5' for key 'PRIMARY'
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_conflict_with_rollback_master.result b/mysql-test/suite/galera_sr/r/galera_sr_conflict_with_rollback_master.result
new file mode 100644
index 00000000000..92bf007e21b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_conflict_with_rollback_master.result
@@ -0,0 +1,29 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+connection node_1;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+ROLLBACK;
+connection node_2;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_ddl_master.result b/mysql-test/suite/galera_sr/r/galera_sr_ddl_master.result
new file mode 100644
index 00000000000..cf9c7771bed
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_ddl_master.result
@@ -0,0 +1,48 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+connection node_1;
+INSERT INTO t1 VALUES (6);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+ROLLBACK;
+START TRANSACTION;
+INSERT INTO t1 (f1) VALUES (1);
+INSERT INTO t1 (f1) VALUES (2);
+INSERT INTO t1 (f1) VALUES (3);
+INSERT INTO t1 (f1) VALUES (4);
+INSERT INTO t1 (f1) VALUES (5);
+INSERT INTO t1 (f1) VALUES (6);
+COMMIT;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_ddl_schema.result b/mysql-test/suite/galera_sr/r/galera_sr_ddl_schema.result
new file mode 100644
index 00000000000..fcd6cfa4a6e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_ddl_schema.result
@@ -0,0 +1,23 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+DROP SCHEMA test;
+SELECT COUNT(*) = 0 FROM test.t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+connection node_1;
+INSERT INTO test.t1 VALUES (6, 6);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+INSERT INTO test.t1 VALUES (6, 6);
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE SCHEMA test;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_ddl_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_ddl_slave.result
new file mode 100644
index 00000000000..58663caf134
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_ddl_slave.result
@@ -0,0 +1,50 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+ALTER TABLE t1 DROP COLUMN f2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+INSERT INTO t1 VALUES (6, 6);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (6, 6);
+ERROR 21S01: Column count doesn't match value count at row 1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_ddl_unrelated.result b/mysql-test/suite/galera_sr/r/galera_sr_ddl_unrelated.result
new file mode 100644
index 00000000000..0f23ade58c1
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_ddl_unrelated.result
@@ -0,0 +1,42 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+ALTER TABLE t2 DROP COLUMN f2;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+connection node_1;
+INSERT INTO t1 VALUES (6, 6);
+connection node_2;
+connection node_1;
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_dupkey_error.result b/mysql-test/suite/galera_sr/r/galera_sr_dupkey_error.result
new file mode 100644
index 00000000000..b23b934da33
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_dupkey_error.result
@@ -0,0 +1,46 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 BLOB) ENGINE=InnoDB;
+CREATE UNIQUE INDEX i1 ON t1 (f1(512));
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1024;
+INSERT INTO t1 VALUES (REPEAT('a', 512));
+INSERT INTO t1 VALUES (REPEAT('b', 512));
+INSERT INTO t1 VALUES (REPEAT('c', 512));
+INSERT INTO t1 VALUES (REPEAT('d', 512));
+INSERT INTO t1 VALUES (REPEAT('e', 512));
+INSERT INTO t1 VALUES (REPEAT('f', 512));
+connection node_2;
+connection node_1;
+INSERT INTO t1 VALUES (REPEAT('c', 512));
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+INSERT INTO t1 VALUES (REPEAT('d', 512));
+INSERT INTO t1 VALUES (REPEAT('e', 512));
+INSERT INTO t1 VALUES (REPEAT('f', 512));
+COMMIT;
+connection node_2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (REPEAT('a', 512));
+INSERT INTO t1 VALUES (REPEAT('b', 512));
+INSERT INTO t1 VALUES (REPEAT('c', 512));
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+1
+connection node_2;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_fk_conflict.result b/mysql-test/suite/galera_sr/r/galera_sr_fk_conflict.result
new file mode 100644
index 00000000000..1d12533cc1d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_fk_conflict.result
@@ -0,0 +1,39 @@
+connection node_2;
+connection node_1;
+CREATE TABLE grandparent (
+id INT NOT NULL PRIMARY KEY
+) ENGINE=InnoDB;
+CREATE TABLE parent (
+id INT NOT NULL PRIMARY KEY,
+grandparent_id INT,
+FOREIGN KEY (grandparent_id)
+REFERENCES grandparent(id)
+ON UPDATE CASCADE
+) ENGINE=InnoDB;
+CREATE TABLE child (
+id INT NOT NULL PRIMARY KEY,
+grandparent_id INT,
+FOREIGN KEY (grandparent_id)
+REFERENCES parent(grandparent_id)
+ON UPDATE CASCADE
+) ENGINE=InnoDB;
+INSERT INTO grandparent VALUES (1),(2),(3),(4);
+INSERT INTO parent VALUES (1,1), (2,2);
+INSERT INTO child VALUES (1,1), (2,2);
+connection node_1;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+UPDATE grandparent SET id = 5 WHERE id = 1;
+connection node_2;
+SET SESSION innodb_lock_wait_timeout = 1;
+UPDATE grandparent SET id = 10 WHERE id = 5;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+DELETE FROM child;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+connection node_1;
+COMMIT;
+include/diff_servers.inc [servers=1 2]
+DROP TABLE child;
+DROP TABLE parent;
+DROP TABLE grandparent;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_gtid.result b/mysql-test/suite/galera_sr/r/galera_sr_gtid.result
new file mode 100644
index 00000000000..be631d1d916
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_gtid.result
@@ -0,0 +1,57 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INT PRIMARY KEY);
+SET SESSION wsrep_trx_fragment_size=1;
+INSERT INTO t1 VALUES (1);
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SET SESSION wsrep_trx_fragment_size=1;
+UPDATE t1 SET f1 = 2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size=0;
+connection node_2;
+SET SESSION wsrep_trx_fragment_size=0;
+connection node_1;
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000002 <Pos> Gtid_list 1 <End_log_pos> []
+mysqld-bin.000002 <Pos> Binlog_checkpoint 1 <End_log_pos> mysqld-bin.000001
+mysqld-bin.000002 <Pos> Binlog_checkpoint 1 <End_log_pos> mysqld-bin.000002
+mysqld-bin.000002 <Pos> Gtid 1 <End_log_pos> GTID 0-1-1
+mysqld-bin.000002 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INT PRIMARY KEY)
+mysqld-bin.000002 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000002 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1)
+mysqld-bin.000002 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000002 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000002 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000002 <Pos> Gtid 2 <End_log_pos> BEGIN GTID 0-2-3
+mysqld-bin.000002 <Pos> Annotate_rows 2 <End_log_pos> UPDATE t1 SET f1 = 2
+mysqld-bin.000002 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000002 <Pos> Update_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000002 <Pos> Xid 2 <End_log_pos> COMMIT /* xid=### */
+connection node_2;
+SELECT 1 FROM DUAL;
+1
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000003 <Pos> Gtid_list 2 <End_log_pos> []
+mysqld-bin.000003 <Pos> Binlog_checkpoint 2 <End_log_pos> mysqld-bin.000003
+mysqld-bin.000003 <Pos> Gtid 1 <End_log_pos> GTID 0-1-1
+mysqld-bin.000003 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INT PRIMARY KEY)
+mysqld-bin.000003 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000003 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1)
+mysqld-bin.000003 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000003 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000003 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000003 <Pos> Gtid 2 <End_log_pos> BEGIN GTID 0-2-3
+mysqld-bin.000003 <Pos> Annotate_rows 2 <End_log_pos> UPDATE t1 SET f1 = 2
+mysqld-bin.000003 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000003 <Pos> Update_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000003 <Pos> Xid 2 <End_log_pos> COMMIT /* xid=### */
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_insert_select.result b/mysql-test/suite/galera_sr/r/galera_sr_insert_select.result
new file mode 100644
index 00000000000..0302290123d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_insert_select.result
@@ -0,0 +1,18 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('a', 255) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+COMMIT;
+connection node_2;
+connection node_1;
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_all_nobootstrap.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_nobootstrap.result
new file mode 100644
index 00000000000..a78926a9794
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_nobootstrap.result
@@ -0,0 +1,29 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+Killing server ...
+connection node_1;
+Killing server ...
+connection node_1;
+connection node_2;
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result
new file mode 100644
index 00000000000..7525cd6d4b7
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_norecovery.result
@@ -0,0 +1,30 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+Killing server ...
+connection node_1;
+Killing server ...
+connection node_1;
+connection node_2;
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_all_pcrecovery.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_pcrecovery.result
new file mode 100644
index 00000000000..7525cd6d4b7
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_all_pcrecovery.result
@@ -0,0 +1,30 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+Killing server ...
+connection node_1;
+Killing server ...
+connection node_1;
+connection node_2;
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_connection.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_connection.result
new file mode 100644
index 00000000000..96a85bc038b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_connection.result
@@ -0,0 +1,32 @@
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1a;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result
new file mode 100644
index 00000000000..59942e717e7
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result
@@ -0,0 +1,31 @@
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;;
+connection node_2;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+Killing query ...
+connection node_1;
+ERROR 70100: Query execution was interrupted
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+INSERT INTO t1 SELECT 1 FROM ten AS t1, ten AS t2, ten AS t3;
+SELECT COUNT(*) = 1000 FROM t1;
+COUNT(*) = 1000
+1
+connection node_1a;
+SELECT COUNT(*) = 1000 FROM t1;
+COUNT(*) = 1000
+1
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result
new file mode 100644
index 00000000000..b4e84b1b72a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result
@@ -0,0 +1,53 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+connection node_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+CREATE TABLE t2 (f1 INTEGER);
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+LOCK TABLE t2 WRITE;
+connection node_1;
+INSERT INTO t2 VALUES (1);
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+Killing server ...
+connection node_1;
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+connection node_2;
+connection node_1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 15 FROM t1;
+COUNT(*) = 15
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_large_fragment.result b/mysql-test/suite/galera_sr/r/galera_sr_large_fragment.result
new file mode 100644
index 00000000000..bf111f5cee4
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_large_fragment.result
@@ -0,0 +1,33 @@
+connection node_2;
+connection node_1;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(512)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1024 * 1024 * 10;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 512) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 50000 FROM t1;
+COUNT(*) > 50000
+1
+connection node_1;
+ROLLBACK;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT10M';
+SET SESSION wsrep_sync_wait = 7;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+COUNT(*) = 0
+1
+COUNT(*) = 0
+1
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_load_data.result b/mysql-test/suite/galera_sr/r/galera_sr_load_data.result
new file mode 100644
index 00000000000..a474a7e3ae8
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_load_data.result
@@ -0,0 +1,13 @@
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 512;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+connection node_2;
+connection node_1;
+connection node_2;
+SELECT COUNT(*) = 20000 FROM t1;
+COUNT(*) = 20000
+1
+wsrep_last_committed_diff
+0
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result b/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result
new file mode 100644
index 00000000000..b25a8877005
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_load_data_splitting.result
@@ -0,0 +1,9 @@
+SET SESSION wsrep_trx_fragment_size = 512;
+SET GLOBAL wsrep_load_data_splitting = TRUE;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SELECT COUNT(*) = 95000 FROM t1;
+COUNT(*) = 95000
+1
+wsrep_last_committed_diff
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_log_bin.result b/mysql-test/suite/galera_sr/r/galera_sr_log_bin.result
new file mode 100644
index 00000000000..cb8e84383bc
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_log_bin.result
@@ -0,0 +1,124 @@
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t4 (f1 INTEGER) ENGINE=InnoDB;
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t2 VALUES (1);
+connection node_2;
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t3 VALUES (1);
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+connection node_2a;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t4 VALUES (1);
+connection node_1;
+INSERT INTO t1 VALUES (2);
+COMMIT;
+connection node_1a;
+INSERT INTO t2 VALUES (2);
+COMMIT;
+connection node_2;
+INSERT INTO t3 VALUES (2);
+COMMIT;
+connection node_2a;
+INSERT INTO t4 VALUES (2);
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 2 FROM t4;
+COUNT(*) = 2
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 <Pos> Gtid_list 1 <End_log_pos> []
+mysqld-bin.000001 <Pos> Binlog_checkpoint 1 <End_log_pos> mysqld-bin.000001
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-1
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t2 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t2)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t2 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t2)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 2 <End_log_pos> BEGIN GTID 0-2-3
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t3 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t3)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t3 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t3)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 2 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 2 <End_log_pos> BEGIN GTID 0-2-4
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t4 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t4)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t4 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t4)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 2 <End_log_pos> COMMIT /* xid=### */
+connection node_2;
+SELECT COUNT(*) = 2 FROM t4;
+COUNT(*) = 2
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 <Pos> Gtid_list 2 <End_log_pos> []
+mysqld-bin.000001 <Pos> Binlog_checkpoint 2 <End_log_pos> mysqld-bin.000001
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-1
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t2 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t2)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t2 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t2)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 2 <End_log_pos> BEGIN GTID 0-2-3
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t3 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t3)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t3 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t3)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 2 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 2 <End_log_pos> BEGIN GTID 0-2-4
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t4 VALUES (1)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t4)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 2 <End_log_pos> INSERT INTO t4 VALUES (2)
+mysqld-bin.000001 <Pos> Table_map 2 <End_log_pos> table_id: ### (test.t4)
+mysqld-bin.000001 <Pos> Write_rows_v1 2 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 2 <End_log_pos> COMMIT /* xid=### */
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_many_fragments.result b/mysql-test/suite/galera_sr/r/galera_sr_many_fragments.result
new file mode 100644
index 00000000000..8c89d100260
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_many_fragments.result
@@ -0,0 +1,33 @@
+connection node_2;
+connection node_1;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(512)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 512) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 10000 FROM t1;
+COUNT(*) = 10000
+1
+connection node_1;
+ROLLBACK;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT10M';
+SET SESSION wsrep_sync_wait = 7;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+COUNT(*) = 0
+1
+COUNT(*) = 0
+1
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_myisam.result b/mysql-test/suite/galera_sr/r/galera_sr_myisam.result
new file mode 100644
index 00000000000..97818f072e1
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_myisam.result
@@ -0,0 +1,16 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 TEXT) ENGINE=MyISAM;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET GLOBAL wsrep_replicate_myisam = TRUE;
+INSERT INTO t1 VALUES (REPEAT('x', 65535));
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT LENGTH(f1) = 65535 FROM t1;
+LENGTH(f1) = 65535
+1
+DROP TABLE t1;
+connection node_1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_mysqldump_sst.result b/mysql-test/suite/galera_sr/r/galera_sr_mysqldump_sst.result
new file mode 100644
index 00000000000..f1b60c7f76a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_mysqldump_sst.result
@@ -0,0 +1,58 @@
+connection node_2;
+connection node_1;
+Setting SST method to mysqldump ...
+call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to '127.0.0.1'");
+call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos");
+connection node_1;
+CREATE USER 'sst';
+GRANT ALL PRIVILEGES ON *.* TO 'sst';
+SET GLOBAL wsrep_sst_auth = 'sst:';
+connection node_2;
+SET GLOBAL wsrep_sst_method = 'mysqldump';
+connection node_1;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1000;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 255) FROM ten AS a1, ten AS a2, ten AS a3;
+UPDATE t1 SET f2 = REPEAT('y', 255);
+connection node_2;
+connection node_2;
+Shutting down server ...
+connection node_1;
+connection node_2;
+Starting server ...
+connection node_1;
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+UPDATE t1 SET f2 = REPEAT('z', 255);
+COMMIT;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 1000 FROM t1;
+COUNT(*) = 1000
+1
+SELECT COUNT(*) = 1000 FROM t1 WHERE f2 = REPEAT('z', 255);
+COUNT(*) = 1000
+1
+DROP TABLE t1;
+DROP TABLE ten;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size=0;
+connection node_1;
+CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
+DROP USER sst;
+connection node_2;
+CALL mtr.add_suppression("Slave SQL: Error 'The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement' on query");
+CALL mtr.add_suppression("InnoDB: Error: Table \"mysql\"\\.\"innodb_index_stats\" not found");
+CALL mtr.add_suppression("Can't open and lock time zone table");
+CALL mtr.add_suppression("Can't open and lock privilege tables");
+CALL mtr.add_suppression("Info table is not ready to be used");
+CALL mtr.add_suppression("Native table .* has the wrong structure");
+CALL mtr.add_suppression("Table \'mysql.gtid_slave_pos\' doesn\'t exist");
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_parallel_apply.result b/mysql-test/suite/galera_sr/r/galera_sr_parallel_apply.result
new file mode 100644
index 00000000000..e2194e08cb8
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_parallel_apply.result
@@ -0,0 +1,37 @@
+connection node_2;
+connection node_1;
+connection node_2;
+SET GLOBAL wsrep_slave_threads = 5;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+COMMIT;
+connection node_1a;
+ROLLBACK;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1;
+DROP TABLE t1;
+connection node_2;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_rollback.result b/mysql-test/suite/galera_sr/r/galera_sr_rollback.result
new file mode 100644
index 00000000000..4b275c6e0b6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_rollback.result
@@ -0,0 +1,42 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+connection node_2;
+connection node_1;
+ROLLBACK;
+connection node_2;
+connection node_1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+connection node_2;
+connection node_1;
+COMMIT;
+connection node_2;
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result b/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result
new file mode 100644
index 00000000000..054f7cf2eae
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result
@@ -0,0 +1,33 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+ROLLBACK;
+connection node_2;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+connection node_1;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_rollback_savepoint.result b/mysql-test/suite/galera_sr/r/galera_sr_rollback_savepoint.result
new file mode 100644
index 00000000000..f2efa20f0d3
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_rollback_savepoint.result
@@ -0,0 +1,42 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+SAVEPOINT s1;
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+connection node_2;
+connection node_1;
+ROLLBACK TO SAVEPOINT s1;
+INSERT INTO t1 VALUES (21, 'c');
+INSERT INTO t1 VALUES (22, 'c');
+INSERT INTO t1 VALUES (23, 'c');
+INSERT INTO t1 VALUES (24, 'c');
+INSERT INTO t1 VALUES (25, 'c');
+connection node_2;
+SELECT COUNT(*) = 5 FROM t1 WHERE f2 = 'a';
+COUNT(*) = 5
+1
+SELECT COUNT(*) = 0 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 0
+0
+SELECT COUNT(*) = 5 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 5
+1
+connection node_1;
+COMMIT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_rollback_statement.result b/mysql-test/suite/galera_sr/r/galera_sr_rollback_statement.result
new file mode 100644
index 00000000000..21e6ef4b057
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_rollback_statement.result
@@ -0,0 +1,22 @@
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) ENGINE=InnoDB;
+INSERT INTO t1 (f2) SELECT REPEAT('a', 255) FROM ten AS a1, ten AS a2, ten AS a3;
+ALTER TABLE t1 CHANGE f1 f1 INTEGER;
+ALTER TABLE t1 DROP PRIMARY KEY;
+INSERT INTO t1 VALUES (1, 'abc');
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t2 SELECT * FROM t1;
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+INSERT INTO t2 VALUES (1, 'abc');
+INSERT INTO t2 VALUES (2, 'abc');
+SELECT COUNT(*) = 2 FROM t2;
+COUNT(*) = 2
+1
+SELECT COUNT(*) = 2 FROM t2;
+COUNT(*) = 2
+1
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_sbr.result b/mysql-test/suite/galera_sr/r/galera_sr_sbr.result
new file mode 100644
index 00000000000..c83db3d5ea6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_sbr.result
@@ -0,0 +1,16 @@
+CREATE TABLE t1 (id INT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET SESSION BINLOG_FORMAT='STATEMENT';
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+COMMIT;
+SELECT COUNT(*) = 5 FROM t1;
+COUNT(*) = 5
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_shutdown_master.result b/mysql-test/suite/galera_sr/r/galera_sr_shutdown_master.result
new file mode 100644
index 00000000000..eb493f66ed6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_shutdown_master.result
@@ -0,0 +1,31 @@
+connection node_2;
+connection node_1;
+connection node_1;
+connection node_2;
+connection node_2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1),(2),(3);
+connection node_1;
+connection node_2;
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (1),(2),(3);
+connection node_1;
+SELECT COUNT(*) = 3 FROM t1;
+COUNT(*) = 3
+1
+DROP TABLE t1;
+connection node_2;
+CALL mtr.add_suppression("WSREP: Failed to replicate rollback fragment for ");
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_shutdown_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_shutdown_slave.result
new file mode 100644
index 00000000000..568452b10b0
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_shutdown_slave.result
@@ -0,0 +1,43 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE = InnoDB;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (11),(12),(13);
+connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1b;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (21),(22),(23);
+connection node_2;
+connection node_1;
+connection node_1a;
+INSERT INTO t1 VALUES (14),(15),(16);
+COMMIT;
+connection node_2;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) > 0
+1
+SELECT COUNT(*) = 6 FROM t1 WHERE f1 IN (11,12,13,14,15,16);
+COUNT(*) = 6
+1
+connection node_1b;
+INSERT INTO t1 VALUES (24),(25),(26);
+COMMIT;
+connection node_2;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 12 FROM t1;
+COUNT(*) = 12
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_small_gcache.result b/mysql-test/suite/galera_sr/r/galera_sr_small_gcache.result
new file mode 100644
index 00000000000..875f2df5214
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_small_gcache.result
@@ -0,0 +1,15 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+connection node_2;
+SELECT COUNT(*) = 10000 FROM t1;
+COUNT(*) = 10000
+1
+connection node_1;
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_table_contents.result b/mysql-test/suite/galera_sr/r/galera_sr_table_contents.result
new file mode 100644
index 00000000000..29bb71704e2
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_table_contents.result
@@ -0,0 +1,198 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3);
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+Start of Simple Insert
+INSERT INTO t1 VALUES (4);
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 73 Query thread_id=<QUERY_THREAD_ID> exec_time=<EXEC_TIME> error_code=0
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+/*!\C latin1 *//*!*/;
+BEGIN
+/*!*/;
+# at 193
+<ISO TIMESTAMP> server id 1 end_log_pos 114 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 234
+<ISO TIMESTAMP> server id 1 end_log_pos 150 Write_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+End of Simple Insert
+
+ROLLBACK;
+Start of Multi-row Update
+UPDATE t1 SET f1 = f1 + 10;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 73 Query thread_id=<QUERY_THREAD_ID> exec_time=<EXEC_TIME> error_code=0
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+/*!\C latin1 *//*!*/;
+BEGIN
+/*!*/;
+# at 193
+<ISO TIMESTAMP> server id 1 end_log_pos 114 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 234
+<ISO TIMESTAMP> server id 1 end_log_pos 156 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 197 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 239 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 280 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 322 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+End of Multi-row Update
+
+ROLLBACK;
+Start of Multi-table Update
+UPDATE t1, t2 SET t1.f1 = t1.f1 + 100, t2.f1 = t2.f1 + 100;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 82 Query thread_id=<QUERY_THREAD_ID> exec_time=<EXEC_TIME> error_code=0
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+/*!\C latin1 *//*!*/;
+BEGIN
+/*!*/;
+# at 202
+<ISO TIMESTAMP> server id 1 end_log_pos 123 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 243
+<ISO TIMESTAMP> server id 1 end_log_pos 164 Table_map: `test`.`t2` mapped to number <TABLE_ID>
+# at 284
+<ISO TIMESTAMP> server id 1 end_log_pos 206 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 247 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 288 Table_map: `test`.`t2` mapped to number <TABLE_ID>
+# at 202
+<ISO TIMESTAMP> server id 1 end_log_pos 330 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 371 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 412 Table_map: `test`.`t2` mapped to number <TABLE_ID>
+# at 202
+<ISO TIMESTAMP> server id 1 end_log_pos 454 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 495 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 536 Table_map: `test`.`t2` mapped to number <TABLE_ID>
+# at 202
+<ISO TIMESTAMP> server id 1 end_log_pos 578 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 619 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 660 Table_map: `test`.`t2` mapped to number <TABLE_ID>
+# at 202
+<ISO TIMESTAMP> server id 1 end_log_pos 702 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 743 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 784 Table_map: `test`.`t2` mapped to number <TABLE_ID>
+# at 202
+<ISO TIMESTAMP> server id 1 end_log_pos 826 Update_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+End of Multi-table Update
+
+ROLLBACK;
+Start of Savepoint
+INSERT INTO t1 VALUES (1000);
+SAVEPOINT X;
+INSERT INTO t1 VALUES (2000);
+ROLLBACK TO SAVEPOINT X;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 73 Query thread_id=<QUERY_THREAD_ID> exec_time=<EXEC_TIME> error_code=0
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+/*!\C latin1 *//*!*/;
+BEGIN
+/*!*/;
+# at 193
+<ISO TIMESTAMP> server id 1 end_log_pos 114 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 234
+<ISO TIMESTAMP> server id 1 end_log_pos 150 Write_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 231 Query thread_id=<QUERY_THREAD_ID> exec_time=<EXEC_TIME> error_code=0
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+/*!\C latin1 *//*!*/;
+SAVEPOINT `X`
+/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 272 Table_map: `test`.`t1` mapped to number <TABLE_ID>
+# at 161
+<ISO TIMESTAMP> server id 1 end_log_pos 308 Write_rows: table id <TABLE_ID> flags: STMT_END_F
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+DELIMITER /*!*/;
+# at 120
+<ISO TIMESTAMP> server id 1 end_log_pos 391 Query thread_id=<QUERY_THREAD_ID> exec_time=<EXEC_TIME> error_code=0
+SET TIMESTAMP=<TIMESTAMP>/*!*/;
+/*!\C latin1 *//*!*/;
+ROLLBACK TO `X`
+/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+End of Savepoint
+
+ROLLBACK;
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_transaction_replay.result b/mysql-test/suite/galera_sr/r/galera_sr_transaction_replay.result
new file mode 100644
index 00000000000..5806ab5558d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_transaction_replay.result
@@ -0,0 +1,121 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+SET SESSION wsrep_sync_wait = 0;
+connection node_1;
+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;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
+f1 f2
+2 a
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+connection node_1;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+wsrep_local_replays
+1
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DELETE FROM t1;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+connection node_1;
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+UPDATE t1 SET f2 = 'x' WHERE f1 = 1;
+SET SESSION wsrep_trx_fragment_size = 0;
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
+f1 f2
+2 a
+connection node_1a;
+SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
+connection node_2;
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+connection node_1a;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_master_enter_sync';
+connection node_1;
+COMMIT;
+connection node_1a;
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'dbug=d,abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
+SET SESSION wsrep_on = 0;
+SET SESSION wsrep_on = 1;
+SET GLOBAL wsrep_provider_options = 'dbug=';
+SET GLOBAL wsrep_provider_options = 'signal=abort_trx_end';
+SET GLOBAL wsrep_provider_options = 'signal=local_monitor_master_enter_sync';
+connection node_1;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+wsrep_local_replays
+1
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DELETE FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_unit_statements.result b/mysql-test/suite/galera_sr/r/galera_sr_unit_statements.result
new file mode 100644
index 00000000000..4e3bd52483e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_unit_statements.result
@@ -0,0 +1,54 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 3;
+SET SESSION wsrep_trx_fragment_unit = 'statements';
+connection node_1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+0
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+0
+connection node_1;
+INSERT INTO t1 VALUES (2);
+connection node_2;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+2
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+1
+connection node_1;
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+2
+connection node_1;
+COMMIT;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+0
+connection node_2;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+5
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+COUNT(*)
+0
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_v1_row_events.result b/mysql-test/suite/galera_sr/r/galera_sr_v1_row_events.result
new file mode 100644
index 00000000000..ab090e5c2a7
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_v1_row_events.result
@@ -0,0 +1,20 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+connection node_1;
+COMMIT;
+SET AUTOCOMMIT=ON;
+UPDATE t1 SET f1 = 2 WHERE f1 = 1;
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+COUNT(*) = 1
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_ws_size.result b/mysql-test/suite/galera_sr/r/galera_sr_ws_size.result
new file mode 100644
index 00000000000..b7bdd94dd68
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_ws_size.result
@@ -0,0 +1,36 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(254)) ENGINE=InnoDB;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+SET SESSION wsrep_trx_fragment_size = 512;
+SET GLOBAL wsrep_provider_options='repl.max_ws_size=4096';
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+COMMIT;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+SELECT COUNT(*) = 100 FROM t1;
+COUNT(*) = 100
+1
+DROP TABLE t1;
+DROP TABLE ten;
+connection node_1;
+call mtr.add_suppression('WSREP: transaction size limit.*');
+call mtr.add_suppression('WSREP: rbr write fail.*');
+call mtr.add_suppression('WSREP: Maximum writeset size exceeded by.*');
+call mtr.add_suppression('WSREP: transaction size exceeded.*');
diff --git a/mysql-test/suite/galera_sr/r/galera_sr_ws_size2.result b/mysql-test/suite/galera_sr/r/galera_sr_ws_size2.result
new file mode 100644
index 00000000000..6bd8b6b8212
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_sr_ws_size2.result
@@ -0,0 +1,34 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(254)) ENGINE=InnoDB;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+SET SESSION wsrep_trx_fragment_size = 256;
+SET GLOBAL wsrep_provider_options='repl.max_ws_size=128';
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1, ten AS a2;
+Got one of the listed errors
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+DROP TABLE t1;
+DROP TABLE ten;
+call mtr.add_suppression('WSREP: SR rollback replication failure.*');
+call mtr.add_suppression('WSREP: transaction size limit.*');
+call mtr.add_suppression('WSREP: SR rbr write fail.*');
+call mtr.add_suppression('WSREP: Maximum writeset size exceeded by.*');
+call mtr.add_suppression('WSREP: transaction size exceeded.*');
+call mtr.add_suppression('WSREP: fragment replication failed:');
+call mtr.add_suppression('WSREP: post commit failed for SR rollback');
+call mtr.add_suppression('WSREP: pre_commit for SR rollback returned 2, thd:*');
+call mtr.add_suppression('WSREP: wsrep_rollback failed to send SR ROLLBACK for *');
diff --git a/mysql-test/suite/galera_sr/r/galera_var_ignore_apply_errors_sr.result b/mysql-test/suite/galera_sr/r/galera_var_ignore_apply_errors_sr.result
new file mode 100644
index 00000000000..852208437e5
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/galera_var_ignore_apply_errors_sr.result
@@ -0,0 +1,29 @@
+connection node_2;
+connection node_1;
+connection node_2;
+SET GLOBAL wsrep_ignore_apply_errors = 2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (2);
+SET GLOBAL wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_on = ON;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (3);
+DELETE FROM t1 WHERE f1 = 1;
+DELETE FROM t1 WHERE f1 = 2;
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SET SESSION wsrep_trx_fragment_size = 0;
+DROP TABLE t1;
+SET GLOBAL wsrep_ignore_apply_errors = 7;
+CALL mtr.add_suppression("Slave SQL: Could not execute Delete_rows event");
+CALL mtr.add_suppression("Can't find record in 't1'");
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep#215.result b/mysql-test/suite/galera_sr/r/mysql-wsrep#215.result
new file mode 100644
index 00000000000..623bef4c3c4
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep#215.result
@@ -0,0 +1,137 @@
+connection node_2;
+connection node_1;
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 2;
+SET SESSION wsrep_trx_fragment_unit = 'statements';
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_1a;
+SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_apply_cb';
+SET SESSION wsrep_sync_wait = 0;
+connection node_2;
+INSERT INTO t1 VALUES (1);
+connection node_1a;
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (1);;
+connection node_1a;
+connection node_1a;
+SET GLOBAL DEBUG_DBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+COMMIT;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1a;
+SET DEBUG_SYNC = 'RESET';
+connection node_1;
+TRUNCATE TABLE t1;
+SET SESSION wsrep_trx_fragment_size = 10;
+SET SESSION wsrep_trx_fragment_unit = 'bytes';
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_1a;
+SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_apply_cb';
+SET SESSION wsrep_sync_wait = 0;
+connection node_2;
+INSERT INTO t1 VALUES (1);
+connection node_1a;
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (1);
+connection node_1a;
+SET GLOBAL DEBUG_DBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+ROLLBACK;
+SELECT * FROM t1;
+f1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT * FROM t1;
+f1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1a;
+SET DEBUG_SYNC = 'RESET';
+connection node_1;
+TRUNCATE TABLE t1;
+SET SESSION wsrep_trx_fragment_size = 200;
+SET SESSION wsrep_trx_fragment_unit = 'bytes';
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+connection node_1a;
+SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_apply_cb';
+SET SESSION wsrep_sync_wait = 0;
+connection node_2;
+INSERT INTO t1 VALUES (1);
+connection node_1a;
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+connection node_1a;
+SET GLOBAL DEBUG_DBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+connection node_1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 1 FROM t1;
+COUNT(*) = 1
+1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_1a;
+DROP TABLE t1;
+SET DEBUG_SYNC = 'RESET';
+connection node_2;
+CALL mtr.add_suppression("WSREP: Could not find applier context for");
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#136.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#136.result
new file mode 100644
index 00000000000..25bc2e11a3e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#136.result
@@ -0,0 +1,65 @@
+connection node_2;
+connection node_1;
+connection node_1;
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+connection node_2;
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+COMMIT;
+SET SESSION wsrep_trx_fragment_size = 0;
+INSERT INTO t1 VALUES (3),(4);
+COMMIT;
+connection node_1;
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 <Pos> Gtid_list 1 <End_log_pos> []
+mysqld-bin.000001 <Pos> Binlog_checkpoint 1 <End_log_pos> mysqld-bin.000001
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> GTID 0-1-1
+mysqld-bin.000001 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1),(2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1),(2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-3
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (3),(4)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+connection node_2;
+SELECT COUNT(*) = 4 FROM t1;
+COUNT(*) = 4
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256;
+Log_name Pos Event_type Server_id End_log_pos Info
+mysqld-bin.000001 <Pos> Gtid_list 2 <End_log_pos> []
+mysqld-bin.000001 <Pos> Binlog_checkpoint 2 <End_log_pos> mysqld-bin.000001
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> GTID 0-1-1
+mysqld-bin.000001 <Pos> Query 1 <End_log_pos> use `test`; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-2
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1),(2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (1),(2)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+mysqld-bin.000001 <Pos> Gtid 1 <End_log_pos> BEGIN GTID 0-1-3
+mysqld-bin.000001 <Pos> Annotate_rows 1 <End_log_pos> INSERT INTO t1 VALUES (3),(4)
+mysqld-bin.000001 <Pos> Table_map 1 <End_log_pos> table_id: ### (test.t1)
+mysqld-bin.000001 <Pos> Write_rows_v1 1 <End_log_pos> table_id: ### flags: STMT_END_F
+mysqld-bin.000001 <Pos> Xid 1 <End_log_pos> COMMIT /* xid=### */
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#138.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#138.result
new file mode 100644
index 00000000000..fc9afd6e1e0
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#138.result
@@ -0,0 +1,24 @@
+connection node_2;
+connection node_1;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+connection node_2;
+SELECT flags FROM mysql.wsrep_streaming_log;
+flags
+1
+0
+connection node_1;
+ROLLBACK;
+INSERT INTO t1 VALUES (3),(4);
+connection node_2;
+SELECT flags FROM mysql.wsrep_streaming_log;
+flags
+1
+0
+connection node_1;
+ROLLBACK;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#14.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#14.result
new file mode 100644
index 00000000000..b09c7d4047a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#14.result
@@ -0,0 +1,12 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+COMMIT;
+DROP TABLE t1;
+connection node_2;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result
new file mode 100644
index 00000000000..a85c0f302d0
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#148.result
@@ -0,0 +1,42 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (6),(7),(8),(9),(10),(1);
+connection node_2;
+SET GLOBAL wsrep_slave_threads = 2;
+SET GLOBAL DEBUG = 'd,sync.wsrep_apply_cb';
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+connection node_1a;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);;
+connection node_1;
+INSERT INTO t1 SELECT * FROM t2;;
+connection node_1a;
+INSERT INTO t1 VALUES (6), (7), (8), (9), (10);
+COMMIT;
+connection node_1;
+Got one of the listed errors
+connection node_2;
+SET GLOBAL wsrep_slave_threads = 1;
+SET GLOBAL DEBUG = '';
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SELECT COUNT(*) = 10 FROM t1;
+COUNT(*) = 10
+1
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#15.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#15.result
new file mode 100644
index 00000000000..610019e2b48
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#15.result
@@ -0,0 +1,11 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (id INT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+COMMIT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#165.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#165.result
new file mode 100644
index 00000000000..fe0761d186d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#165.result
@@ -0,0 +1,752 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+START TRANSACTION;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (3, 'c');
+SELECT * FROM t1;
+f1 f2
+1 x
+2 x
+4 x
+5 x
+UPDATE t1 SET f2 = 'a' WHERE f1 = 2;
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+SET DEBUG_SYNC = 'now SIGNAL continue';
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+SELECT * FROM t1;
+f1 f2
+1 a
+2 a
+3 x
+4 a
+5 a
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#22.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#22.result
new file mode 100644
index 00000000000..0053619187c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#22.result
@@ -0,0 +1,35 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+connection node_1;
+SAVEPOINT s1;
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+connection node_2;
+connection node_1;
+ROLLBACK TO SAVEPOINT s1;
+INSERT INTO t1 VALUES (21, 'c');
+COMMIT;
+connection node_1;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+1
+connection node_2;
+SELECT COUNT(*) = 6 FROM t1;
+COUNT(*) = 6
+0
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#27.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#27.result
new file mode 100644
index 00000000000..4cbcd49dd24
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#27.result
@@ -0,0 +1,23 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+connection node_1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result
new file mode 100644
index 00000000000..29b17ea07d6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#29.result
@@ -0,0 +1,14 @@
+SET SESSION wsrep_trx_fragment_size = 1;
+SET SESSION binlog_format = STATEMENT;
+create table t1 (id int not null, f_id int not null, f int not null,
+primary key(f_id, id)) engine=innodb;
+create table t2 (id int not null,s_id int not null,s varchar(200),
+primary key(id)) engine=innodb;
+INSERT INTO t1 VALUES (8, 1, 3);
+INSERT INTO t1 VALUES (1, 2, 1);
+INSERT INTO t2 VALUES (1, 0, '');
+INSERT INTO t2 VALUES (8, 1, '');
+DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
+WHERE mm.id IS NULL;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#32.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#32.result
new file mode 100644
index 00000000000..ca749a45e9a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#32.result
@@ -0,0 +1,27 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SET AUTOCOMMIT=OFF;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+START TRANSACTION;
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (5);
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+ROLLBACK;
+connection node_1;
+COMMIT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#35.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#35.result
new file mode 100644
index 00000000000..41657d7340a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#35.result
@@ -0,0 +1,41 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL debug = '+d,sync.wsrep_apply_cb';
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+connection node_2a;
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+connection node_2;
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+INSERT INTO t1 VALUES (1);;
+connection node_1;
+COMMIT;
+connection node_2a;
+SET GLOBAL debug = '';
+Warnings:
+Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+connection node_2;
+Got one of the listed errors
+ROLLBACK;
+DROP TABLE t1;
+connection node_2a;
+SET DEBUG_SYNC = "RESET";
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#8.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#8.result
new file mode 100644
index 00000000000..56905c03e10
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#8.result
@@ -0,0 +1,39 @@
+connection node_2;
+connection node_1;
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+connection node_1;
+CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(100), FULLTEXT (f2)) ENGINE=InnoDB;
+connection node_2;
+SELECT COUNT(*) = 13 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE name LIKE 'test/%';
+COUNT(*) = 13
+1
+connection node_1;
+INSERT INTO t1 (f2) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+connection node_2;
+SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('foobarbaz');
+COUNT(f2) = 10000
+1
+UPDATE t1 SET f2 = 'abcdefjhk';
+connection node_1;
+SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('abcdefjhk');
+COUNT(f2) = 10000
+1
+connection node_2;
+DROP TABLE t1;
+connection node_1;
+CREATE TABLE t1 (f1 VARCHAR(100), FULLTEXT (f1)) ENGINE=InnoDB;
+connection node_2;
+INSERT INTO t1 (f1) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3;
+connection node_1;
+SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('foobarbaz');
+COUNT(f1) = 1000
+1
+UPDATE t1 SET f1 = 'abcdefjhk';
+connection node_2;
+SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('abcdefjhk');
+COUNT(f1) = 1000
+1
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#9.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#9.result
new file mode 100644
index 00000000000..990ea47f8bc
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#9.result
@@ -0,0 +1,20 @@
+connection node_2;
+connection node_1;
+connection node_1;
+SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+connection node_2;
+Killing server ...
+connection node_1;
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+connection node_2;
+connection node_2a;
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1';
+COUNT(*) = 2
+1
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+VARIABLE_VALUE = 2
+1
+connection node_1;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#93.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#93.result
new file mode 100644
index 00000000000..17f71213767
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#93.result
@@ -0,0 +1,18 @@
+connection node_2;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER);
+SET SESSION WSREP_TRX_FRAGMENT_SIZE=1;
+START TRANSACTION;
+SAVEPOINT a;
+INSERT INTO t1 VALUES (1);
+ROLLBACK TO SAVEPOINT a;
+INSERT INTO t1 values (2);
+COMMIT;
+SELECT COUNT(*) = 0 from mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+connection node_2;
+SELECT COUNT(*) = 0 from mysql.wsrep_streaming_log;
+COUNT(*) = 0
+1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/r/mysql-wsrep-features#96.result b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#96.result
new file mode 100644
index 00000000000..dbe91aad9fd
--- /dev/null
+++ b/mysql-test/suite/galera_sr/r/mysql-wsrep-features#96.result
@@ -0,0 +1,33 @@
+connection node_2;
+connection node_1;
+connection node_1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f2 VARCHAR(32));
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2),(1);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+INSERT INTO t2 VALUES ('abc');
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 1 FROM t2;
+COUNT(*) = 1
+1
+connection node_1;
+ROLLBACK;
+connection node_2;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM t2;
+COUNT(*) = 0
+1
+connection node_1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/GCF-1008.inc b/mysql-test/suite/galera_sr/t/GCF-1008.inc
new file mode 100644
index 00000000000..69245b3a91f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1008.inc
@@ -0,0 +1,36 @@
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) ENGINE=InnoDB;
+
+--connection node_2
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'x');
+
+--connection node_2a
+--source include/galera_set_sync_point.inc
+
+--connection node_2
+--send COMMIT
+
+--connection node_2b
+--sleep 1
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 1;
+SELECT COUNT(*) = 1 FROM t1;
+REPLACE INTO t1 VALUES (1,'y');
+
+--connection node_2b
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_2a
+--source include/galera_signal_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+--connection node_2
+--reap
+SELECT COUNT(*) = 1 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-1008.test b/mysql-test/suite/galera_sr/t/GCF-1008.test
new file mode 100644
index 00000000000..c6926840bd1
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1008.test
@@ -0,0 +1,18 @@
+#
+# GCF-1008 SR trx fails to apply because previous trx is not committed yet on applier
+#
+
+--source include/have_debug_sync.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/galera_have_debug_sync.inc
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2
+
+--let $galera_sync_point = before_local_commit_monitor_enter
+--source GCF-1008.inc
+
+--let $galera_sync_point = before_certify_apply_monitor_enter
+--source GCF-1008.inc
+
diff --git a/mysql-test/suite/galera_sr/t/GCF-1018.test b/mysql-test/suite/galera_sr/t/GCF-1018.test
new file mode 100644
index 00000000000..1ff8f81e824
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1018.test
@@ -0,0 +1,38 @@
+#
+# SR: Node hang with one thread waiting in InnoDB
+#
+--source include/have_debug_sync.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/galera_have_debug_sync.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+INSERT INTO t1 (f2) VALUES ('a');
+INSERT INTO t1 (f2) VALUES ('b');
+INSERT INTO t1 (f2) VALUES ('c');
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+SET SESSION wsrep_sync_wait = 0;
+--let $galera_sync_point = after_certify_apply_monitor_enter
+--source include/galera_set_sync_point.inc
+
+--connection node_2
+SET SESSION wsrep_trx_fragment_size = 64;
+--send DELETE FROM t1 ORDER BY f1 DESC LIMIT 2;
+
+--connection node_2a
+--source include/galera_wait_sync_point.inc
+
+--connection node_1
+INSERT INTO t1 (f2) VALUES ('d'),('e');
+
+--connection node_2a
+--source include/galera_signal_sync_point.inc
+--source include/galera_clear_sync_point.inc
+
+--connection node_2
+--error ER_LOCK_DEADLOCK, ER_QUERY_INTERRUPTED
+--reap
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-1018B.test b/mysql-test/suite/galera_sr/t/GCF-1018B.test
new file mode 100644
index 00000000000..f11309080c0
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1018B.test
@@ -0,0 +1,40 @@
+#
+# SR: Node hang with one thread waiting in InnoDB
+#
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 64;
+SET SESSION innodb_lock_wait_timeout = 1000;
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+SET SESSION wsrep_trx_fragment_size = 64;
+SET SESSION innodb_lock_wait_timeout = 1000;
+
+--let $count = 500
+--disable_query_log
+while ($count)
+{
+ --connection node_1
+ --send INSERT INTO t1 (f2) VALUES ('abc'),('abc');
+
+ --connection node_2
+ --send DELETE FROM t1 ORDER BY f1 DESC LIMIT 2;
+
+ --connection node_1
+ --error 0,ER_LOCK_DEADLOCK,ER_DUP_ENTRY,ER_LOCK_WAIT_TIMEOUT,ER_QUERY_INTERRUPTED
+ --reap
+
+ --connection node_2
+ --error 0,ER_LOCK_DEADLOCK,ER_DUP_ENTRY,ER_LOCK_WAIT_TIMEOUT,ER_QUERY_INTERRUPTED
+ --reap
+
+ --dec $count
+}
+--enable_query_log
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-1043A.test b/mysql-test/suite/galera_sr/t/GCF-1043A.test
new file mode 100644
index 00000000000..c76623742d7
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1043A.test
@@ -0,0 +1,13 @@
+#
+# Assertion `retval == WSREP_OK || retval == WSREP_TRX_FAIL || retval == WSREP_BF_ABORT || retval == WSREP_CONN_FAIL' failed with SR
+#
+
+--source include/galera_cluster.inc
+
+--let $count = 1000;
+--let $wsrep_trx_fragment_size = 1;
+--let $query_node_1 = DELETE FROM t1
+--let $query_node_1a = REPLACE INTO t1 VALUES (1,'y'),(2,'x')
+--let $query_node_2 = REPLACE INTO t1 VALUES (1,'y'),(2,'y'),(3,'y')
+
+--source suite/galera/include/galera_concurrent_test.inc
diff --git a/mysql-test/suite/galera_sr/t/GCF-1043B.test b/mysql-test/suite/galera_sr/t/GCF-1043B.test
new file mode 100644
index 00000000000..e3b6b7439ca
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1043B.test
@@ -0,0 +1,13 @@
+#
+# Assertion `retval == WSREP_OK || retval == WSREP_TRX_FAIL || retval == WSREP_BF_ABORT || retval == WSREP_CONN_FAIL' failed with SR
+#
+
+--source include/galera_cluster.inc
+
+--let $count = 1000;
+--let $wsrep_trx_fragment_size = 1;
+--let $query_node_1 = DELETE FROM t1
+--let $query_node_1a = INSERT INTO t1 VALUES (1,'y'),(2,'x')
+--let $query_node_2 = UPDATE t1 SET f2 = 'y' WHERE f1 = 1 OR f1 = 2;
+
+--source suite/galera/include/galera_concurrent_test.inc
diff --git a/mysql-test/suite/galera_sr/t/GCF-1051.test b/mysql-test/suite/galera_sr/t/GCF-1051.test
new file mode 100644
index 00000000000..1db4ed15c41
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1051.test
@@ -0,0 +1,51 @@
+#
+# Test the case where SR is rolled back to savepoint that points to the
+# very beginning of the transaction. This results in regular rollback
+# rather than rollback to savepoint.
+#
+
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size=1;
+
+#
+# Test 1: regular transaction
+#
+--connection node_1
+START TRANSACTION;
+SAVEPOINT A;
+INSERT INTO t1 VALUES (1);
+ROLLBACK TO SAVEPOINT A;
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+#
+# Test 2: AUTOCOMMIT OFF
+#
+--connection node_1
+SET AUTOCOMMIT=OFF;
+SAVEPOINT A;
+INSERT INTO t1 VALUES (2);
+ROLLBACK TO SAVEPOINT A;
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-1060.test b/mysql-test/suite/galera_sr/t/GCF-1060.test
new file mode 100644
index 00000000000..714a5ef9f90
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-1060.test
@@ -0,0 +1,9 @@
+--source include/galera_cluster.inc
+
+--let $count = 100;
+--let $wsrep_trx_fragment_size = 1;
+--let $query_node_1 = TRUNCATE TABLE t1
+--let $query_node_1a = INSERT INTO t1 VALUE (1,'x'),(2,'x'),(3,'x')
+--let $query_node_2 = INSERT INTO t1 VALUE (4, 'z');
+
+--source suite/galera/include/galera_concurrent_test.inc
diff --git a/mysql-test/suite/galera_sr/t/GCF-437.test b/mysql-test/suite/galera_sr/t/GCF-437.test
new file mode 100644
index 00000000000..f71be65708e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-437.test
@@ -0,0 +1,21 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+CREATE TABLE ten (f1 INTEGER) ENGINE=MyISAM;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(512)) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 2 * 1024 * 1024;
+
+--error ER_BINLOG_ROW_LOGGING_FAILED
+INSERT INTO t1 (f2) SELECT REPEAT('x', 512) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
+
+CALL mtr.add_suppression("InnoDB: The total blob data length*");
+CALL mtr.add_suppression("WSREP: Error writing into mysql.wsrep_streaming_log: 139");
+CALL mtr.add_suppression("WSREP: Failed to write to frag table: 1");
+CALL mtr.add_suppression("WSREP: Failed to append frag to persistent storage");
+
+DROP TABLE t1;
+DROP table ten;
diff --git a/mysql-test/suite/galera_sr/t/GCF-561.test b/mysql-test/suite/galera_sr/t/GCF-561.test
new file mode 100644
index 00000000000..4a652284e59
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-561.test
@@ -0,0 +1,65 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of DDL on a concurrent SR transaction
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+ALTER TABLE t1 DROP COLUMN f2;
+
+# SR applied before the DDL is no longer visible
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+# Transaction can not continue due to DDL, implicit ROLLBACK
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (6, 6);
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# DDL is now in effect
+--error ER_WRONG_VALUE_COUNT_ON_ROW
+INSERT INTO t1 VALUES (6, 6);
+
+# But it should be possible to reissue the transaction
+
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-571.test b/mysql-test/suite/galera_sr/t/GCF-571.test
new file mode 100644
index 00000000000..aca0b9f7907
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-571.test
@@ -0,0 +1,54 @@
+#
+# GCF-571 ROLLBACK TO SAVEPOINT causes all SR records to be deleted
+#
+
+--source include/galera_cluster.inc
+
+SET AUTOCOMMIT=OFF;
+CREATE TABLE t1 (f1 VARCHAR(10)) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES ('%abcdef%');
+INSERT INTO t1 VALUES ('%abcdef%');
+INSERT INTO t1 VALUES ('%abcdef%');
+INSERT INTO t1 VALUES ('%abcdef%');
+SAVEPOINT A;
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+INSERT INTO t1 VALUES ('xyzxyz');
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%abcdef%';
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%xyz%';
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%SAVEPOINT `A`%';
+
+--connection node_1
+ROLLBACK TO SAVEPOINT A;
+
+--connection node_1a
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%abcdef%';
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%xyz%';
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%SAVEPOINT `A`%';
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%ROLLBACK TO `A`%';
+
+--connection node_2
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%abcdef%';
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%xyz%';
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%SAVEPOINT `A`%';
+SELECT COUNT(*) = 1 FROM mysql.wsrep_streaming_log WHERE frag LIKE '%ROLLBACK TO `A`%';
+
+--connection node_1
+ROLLBACK;
+
+--connection node_1a
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-572.test b/mysql-test/suite/galera_sr/t/GCF-572.test
new file mode 100644
index 00000000000..abefb9b08f6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-572.test
@@ -0,0 +1,54 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(10)) ENGINE=InnoDB;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+#
+# Test 1: statement rollback is not safe
+# (some fragments were already replicated)
+#
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'node1');
+
+--connection node_1a
+INSERT INTO t1 VALUES (5, 'node2');
+
+--connection node_1
+# If we try to INSERT a duplicate key, ER_LOCK_DEADLOCK is the only possible
+# outcome at this point. Notice that ER_DUP_ENTRY is NOT an option here
+# because we were forced to rollback the whole transaction (not just the
+# statement)
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (5, 'node1');
+
+SELECT * FROM t1;
+
+#
+# Test 2: statement rollback is safe
+# (no fragments have been replicated)
+#
+
+SET SESSION wsrep_trx_fragment_size = 10000;
+
+START TRANSACTION;
+INSERT INTO t1 VALUE (10, 'node1');
+SELECT * FROM mysql.wsrep_streaming_log;
+
+--connection node_1a
+INSERT INTO t1 VALUES(15, 'node2');
+
+--connection node_1
+SELECT * FROM t1;
+# This time, only the statement is rolled back and we expect ER_DUP_ENTRY.
+--error ER_DUP_ENTRY
+INSERT INTO t1 VALUES(15, 'node1');
+
+COMMIT;
+SELECT * FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-574.test b/mysql-test/suite/galera_sr/t/GCF-574.test
new file mode 100644
index 00000000000..c9d7c405d14
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-574.test
@@ -0,0 +1,27 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test CREATE TABLE ... SELECT with Streaming Replication
+#
+
+--connection node_1
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+--disable_query_log
+--eval SELECT ($wsrep_last_committed_after - $wsrep_last_committed_before) > 1 AS wsrep_last_committed_delta;
+--enable_query_log
+
+--connection node_2
+SELECT COUNT(*) = 10000 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/GCF-580.test b/mysql-test/suite/galera_sr/t/GCF-580.test
new file mode 100644
index 00000000000..39a237fda57
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-580.test
@@ -0,0 +1,27 @@
+#
+# GCF-580 wsrep_last_committed_counter increases twice for every SR fragment
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+
+--let $fragments_count = `SELECT COUNT(*) FROM mysql.wsrep_streaming_log`
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+--disable_query_log
+--eval SELECT ($wsrep_last_committed_after - $wsrep_last_committed_before) = $fragments_count AS last_committed_matches_fragment_count
+--enable_query_log
+
+COMMIT;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-585.test b/mysql-test/suite/galera_sr/t/GCF-585.test
new file mode 100644
index 00000000000..ceb7da60df6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-585.test
@@ -0,0 +1,44 @@
+#
+# GCF-585 SR: Assertion `total_length + wsrep_get_fragment_base(thd) == saved_pos' failed in wsrep_write_cache_once after SQL error
+#
+
+--source include/galera_cluster.inc
+
+# Test case #1
+
+create table t1 (f1 integer primary key) engine=innodb;
+set autocommit=off;
+set session wsrep_trx_fragment_size=1;
+start transaction;
+insert into t1 values (1);
+# If we try to INSERT a duplicate key, ER_LOCK_DEADLOCK is the only possible
+# outcome at this point. Notice that ER_DUP_ENTRY is NOT an option here
+# because we were forced to rollback the whole transaction (not just the
+# statement)
+--error ER_LOCK_DEADLOCK
+insert into t1 values (2),(1);
+alter table t1 drop primary key;
+drop table t1;
+
+# Test case #2
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+update t1 set f1 = 100 where f1 = 10;
+
+--connection node_2
+INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+SET SESSION wsrep_trx_fragment_size=1;
+SET SESSION innodb_lock_wait_timeout=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+--error ER_LOCK_DEADLOCK
+delete from t1 where f1 > 10;
+--error ER_LOCK_DEADLOCK
+delete from t1 where f1 > 10 and f1 < 100;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-597.test b/mysql-test/suite/galera_sr/t/GCF-597.test
new file mode 100644
index 00000000000..d3d80ffc4f8
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-597.test
@@ -0,0 +1,29 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+
+SET wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_2
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+ROLLBACK;
+
+DROP TABLE t1; \ No newline at end of file
diff --git a/mysql-test/suite/galera_sr/t/GCF-620.test b/mysql-test/suite/galera_sr/t/GCF-620.test
new file mode 100644
index 00000000000..abfba47ee5a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-620.test
@@ -0,0 +1,22 @@
+#
+# GCF-620 SR: ROLLBACK TO SAVEPOINT causes slave crash if wsrep_trx_fragment_size does not fall on boundary
+#
+
+--source include/galera_cluster.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 200;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (1);
+SAVEPOINT A;
+INSERT INTO t1 VALUES (1);
+ROLLBACK TO SAVEPOINT A;
+COMMIT;
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-623.test b/mysql-test/suite/galera_sr/t/GCF-623.test
new file mode 100644
index 00000000000..6784989bde9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-623.test
@@ -0,0 +1,31 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1; \ No newline at end of file
diff --git a/mysql-test/suite/galera_sr/t/GCF-627.test b/mysql-test/suite/galera_sr/t/GCF-627.test
new file mode 100644
index 00000000000..86637ad8e7f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-627.test
@@ -0,0 +1,30 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER);
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+
+--connection node_2
+DROP TABLE t1;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--error ER_NO_SUCH_TABLE
+INSERT INTO t1 VALUES (2);
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/GCF-845.test b/mysql-test/suite/galera_sr/t/GCF-845.test
new file mode 100644
index 00000000000..316317c6a10
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-845.test
@@ -0,0 +1,30 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE IF NOT EXISTS t1 (f1 INTEGER) ENGINE = InnoDB;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (161);
+COMMIT;
+DELETE FROM t1 WHERE f1 > 13;
+--disconnect node_1a
+--sleep 2
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let $assert_count = 0
+--let $assert_select = BF-BF X
+--let $assert_text = No BF-BF log line found
+--let $assert_only_after = CURRENT_TEST
+--source include/assert_grep.inc
+
diff --git a/mysql-test/suite/galera_sr/t/GCF-851.test b/mysql-test/suite/galera_sr/t/GCF-851.test
new file mode 100644
index 00000000000..28d5302a422
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-851.test
@@ -0,0 +1,24 @@
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION WSREP_TRX_FRAGMENT_SIZE=1;
+SET SESSION AUTOCOMMIT=OFF;
+
+INSERT INTO t1 VALUES (10);
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--connection node_2
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+START TRANSACTION;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) > 0 FROM t1;
+
+--connection node_1
+SELECT COUNT(*) > 0 FROM t1;
+DROP TABLE t1;
+
diff --git a/mysql-test/suite/galera_sr/t/GCF-867.test b/mysql-test/suite/galera_sr/t/GCF-867.test
new file mode 100644
index 00000000000..54476a860b7
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-867.test
@@ -0,0 +1,42 @@
+#
+# Test many ongoing SR transactions
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
+--disable_query_log
+
+--let $connections = 62
+
+--let $count = $connections
+while ($count)
+{
+--connect $count, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET SESSION wsrep_sync_wait = 0;
+--dec $count
+}
+
+
+--let $count = $connections
+while ($count)
+{
+--connection $count
+START TRANSACTION;
+--send_eval INSERT INTO t1 VALUES ($count)
+--dec $count
+}
+
+--let $count = $connections
+while ($count)
+{
+--connection $count
+--reap
+COMMIT;
+--dec $count
+}
+
+--enable_query_log
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/GCF-889.test b/mysql-test/suite/galera_sr/t/GCF-889.test
new file mode 100644
index 00000000000..e785b282019
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-889.test
@@ -0,0 +1,29 @@
+--source include/galera_cluster.inc
+
+--connection node_2
+SET GLOBAL wsrep_ignore_apply_errors = 2;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET SESSION wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET SESSION wsrep_on = ON;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+DELETE FROM t1 WHERE f1 = 1;
+SET SESSION wsrep_trx_fragment_size = 0;
+
+INSERT INTO t1 VALUES (1);
+
+SELECT COUNT(*) = 1;
+
+--connection node_2
+SELECT COUNT(*) = 1;
+CALL mtr.add_suppression("Could not execute Delete_rows event on table");
+CALL mtr.add_suppression("Can't find record in 't1'");
+SET GLOBAL wsrep_ignore_apply_errors = 7;
+
+--connection node_1
+DROP TABLE t1;
+
diff --git a/mysql-test/suite/galera_sr/t/GCF-900.test b/mysql-test/suite/galera_sr/t/GCF-900.test
new file mode 100644
index 00000000000..3f1b53630b6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/GCF-900.test
@@ -0,0 +1,28 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT) ENGINE=InnoDB;
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 128;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 0);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (2, 0);
+
+--connection node_2
+ALTER TABLE t1 DROP COLUMN f2;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+--connection node_1a
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (3, 0);
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/disabled.def b/mysql-test/suite/galera_sr/t/disabled.def
new file mode 100644
index 00000000000..94f328bf31b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/disabled.def
@@ -0,0 +1,3 @@
+mysql-wsrep-features#29 : binlog_format=STATEMENT not supported with SR
+GCF-574 : CTAS is not supported together with SR
+galera_sr_sbr : binlog_format=STATEMENT not supported with SR
diff --git a/mysql-test/suite/galera_sr/t/galera-features#56.test b/mysql-test/suite/galera_sr/t/galera-features#56.test
new file mode 100644
index 00000000000..0497952e355
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera-features#56.test
@@ -0,0 +1,55 @@
+##
+## This test tests parallel application of multiple auto-increment insert transactions
+##
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+# Create a second connection to node1 so that we can run transactions concurrently
+--let $galera_connection_name = node_1a
+--let $galera_server_number = 1
+--source include/galera_connect.inc
+SET SESSION wsrep_trx_fragment_size = 1;
+
+--connection node_1
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 INTEGER) Engine=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+
+--connection node_2
+--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
+SET GLOBAL wsrep_slave_threads = 4;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+--connection node_1
+--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_1a
+--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_2
+--send INSERT INTO t1 (f2) SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_1
+--reap
+
+--connection node_1a
+--reap
+
+--connection node_2
+--reap
+
+SELECT COUNT(*) = 30000 FROM t1;
+SELECT COUNT(DISTINCT f1) = 30000 FROM t1;
+SELECT COUNT(*) = 6 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user';
+
+--disable_query_log
+--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
+--enable_query_log
+
+--connection default
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_bf_abort.inc b/mysql-test/suite/galera_sr/t/galera_sr_bf_abort.inc
new file mode 100644
index 00000000000..cd9884cee81
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_bf_abort.inc
@@ -0,0 +1,145 @@
+#
+# Test SR BF abort for all sync points in master side code path
+#
+# The procedure in all test cases is the following:
+# 1) Start SR transaction on node 1, do INSERT + SELECT .. FOR UPDATE
+# 2) Set up sync point on node 1 to block slave thread processing
+# in apply monitor
+# 3) Do write on node 2 which will conflict with SELECT .. FOR UPDATE
+# 4) Set up desired sync point on master side and commit
+# 5) Wait until commit reaches master side sync point, clear sync points
+# and release all sync point waiters
+# 6) COMMIT on node 1 should return deadlock error
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+--eval SET SESSION wsrep_trx_fragment_size = $wsrep_trx_fragment_size
+SET AUTOCOMMIT=OFF;
+
+INSERT INTO t1 VALUES (1);
+SELECT * FROM t1 FOR UPDATE;
+
+# Set up sync point
+--connection node_1a
+--let galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_set_sync_point.inc
+
+# Conflicting insert
+--connection node_2
+
+SET AUTOCOMMIT=ON;
+INSERT INTO t1 VALUES (2);
+
+--connection node_1a
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = $galera_sr_bf_abort_sync_point
+--source include/galera_set_sync_point.inc
+
+--connection node_1
+if ($galera_sr_bf_abort_at_commit)
+{
+ --send COMMIT
+}
+if (!$galera_sr_bf_abort_at_commit)
+{
+ --send INSERT INTO t1 VALUES (3)
+}
+
+--connection node_1a
+
+--let $cmp = `SELECT STRCMP('apply_monitor_slave_enter_sync', '$galera_sr_bf_abort_sync_point') = -1`
+
+if ($cmp)
+{
+ --let $galera_sync_point = apply_monitor_slave_enter_sync $galera_sr_bf_abort_sync_point
+}
+if (!$cmp)
+{
+ --let $galera_sync_point = $galera_sr_bf_abort_sync_point apply_monitor_slave_enter_sync
+}
+--source include/galera_wait_sync_point.inc
+
+# Let conflicting insert proceed, make sure it hits abort_trx_end and
+# let both threads continue.
+
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = abort_trx_end $galera_sr_bf_abort_sync_point
+
+--source include/galera_wait_sync_point.inc
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+--let $galera_sync_point = $galera_sr_bf_abort_sync_point
+--source include/galera_signal_sync_point.inc
+
+# Deadlock should now be retured by node_1
+--connection node_1
+if (!$galera_sr_bf_abort_at_commit)
+{
+ --error ER_LOCK_DEADLOCK
+ --reap
+}
+if ($galera_sr_bf_abort_at_commit)
+{
+ --reap
+}
+
+ROLLBACK;
+
+# Release slave insert
+--connection node_1a
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+
+# Verify that nodes are consistent
+
+# End result:
+# If the statement which was BF aborted was commit,
+# node_1 must replay the transaction so that the table
+# will have rows 1, 2. If it in turn was INSERT,
+# node_1 must abort the transaction so that only
+# INSERT ... VALUES (2) survives.
+
+--connection node_1
+SELECT * FROM t1;
+if ($galera_sr_bf_abort_at_commit)
+{
+ SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+ SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+}
+if (!$galera_sr_bf_abort_at_commit)
+{
+ SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+}
+--connection node_2
+SELECT * FROM t1;
+if ($galera_sr_bf_abort_at_commit)
+{
+ SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 1;
+ SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+}
+if (!$galera_sr_bf_abort_at_commit)
+{
+ SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+}
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Delete entery to verify that node is unblocked
+--connection node_1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 0;
+DELETE FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_bf_abort.test b/mysql-test/suite/galera_sr/t/galera_sr_bf_abort.test
new file mode 100644
index 00000000000..a2db6a8bad2
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_bf_abort.test
@@ -0,0 +1,50 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
+
+--let $wsrep_trx_fragment_size = 1
+
+# Control connection for manipulating sync points on node 1
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_sync_wait = 0;
+
+--echo galera_sr_bf_abort_at_commit = 0
+--let $galera_sr_bf_abort_at_commit = 0
+
+--echo after_replicate_sync
+--let $galera_sr_bf_abort_sync_point = after_replicate_sync
+--source galera_sr_bf_abort.inc
+
+--echo local_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = local_monitor_master_enter_sync
+--source galera_sr_bf_abort.inc
+
+--echo apply_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = apply_monitor_master_enter_sync
+--source galera_sr_bf_abort.inc
+
+--echo commit_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = commit_monitor_master_enter_sync
+--source galera_sr_bf_abort.inc
+
+--echo galera_sr_bf_abort_at_commit = 1
+--let $galera_sr_bf_abort_at_commit = 1
+
+--echo after_replicate_sync
+--let $galera_sr_bf_abort_sync_point = after_replicate_sync
+--source galera_sr_bf_abort.inc
+
+--echo local_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = local_monitor_master_enter_sync
+--source galera_sr_bf_abort.inc
+
+--echo apply_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = apply_monitor_master_enter_sync
+--source galera_sr_bf_abort.inc
+
+--echo commit_monitor_master_enter_sync
+--let $galera_sr_bf_abort_sync_point = commit_monitor_master_enter_sync
+--source galera_sr_bf_abort.inc
+
+CALL mtr.add_suppression("WSREP: fragment replication failed: 1");
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_blob.test b/mysql-test/suite/galera_sr/t/galera_sr_blob.test
new file mode 100644
index 00000000000..ed314d09f5a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_blob.test
@@ -0,0 +1,38 @@
+#
+# Test that a single-blob will be replicated using SR if it is sufficiently
+# large.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 TEXT) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_2
+--let $wsrep_last_committed_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+--connection node_1
+INSERT INTO t1 VALUES (REPEAT('x', 65535));
+
+--connection node_2
+--let $wsrep_last_committed_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed'`
+
+# Confirm that exactly one fragment was replicated
+
+--disable_query_log
+--eval SELECT ($wsrep_last_committed_after - $wsrep_last_committed_before) = 1 AS wsrep_last_committed_delta;
+--enable_query_log
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SELECT LENGTH(f1) = 65535 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_cc_master.test b/mysql-test/suite/galera_sr/t/galera_sr_cc_master.test
new file mode 100644
index 00000000000..8ae8c204f60
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_cc_master.test
@@ -0,0 +1,98 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of Cluster Configuration Change on a concurrently-running SR transaction
+# We use SET GLOBAL wsrep_cluster_address = '' to cause the master (node_2) to temporarily
+# leave the cluster.
+#
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_2
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+#
+# Trigger CC . The transaction is aborted and we expect the SR tables to be cleaned up
+#
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+SET SESSION wsrep_sync_wait=0;
+--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
+SET GLOBAL wsrep_cluster_address = '';
+
+--let $wait_condition = SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+SET SESSION wsrep_sync_wait = DEFAULT;
+
+--connection node_2
+--error 2013 # CR_SERVER_LOST
+INSERT INTO t1 VALUES (6);
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Restore cluster
+
+--connection node_2a
+--disable_query_log
+--eval SET GLOBAL wsrep_cluster_address='$wsrep_cluster_address_orig'
+--enable_query_log
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+
+--connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2b
+--source include/galera_wait_ready.inc
+SELECT * FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Repeat transaction to confirm no locks are left from previous transaction
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+
+--connection node_2b
+CALL mtr.add_suppression("WSREP: Failed to replicate rollback fragment for");
+
+--disconnect node_2
+--connect node_2, 127.0.0.1, root, , test, $NODE_MYPORT_2
+# Restore original auto_increment_offset values.
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test
new file mode 100644
index 00000000000..8c790ac7cd2
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_cc_slave.test
@@ -0,0 +1,97 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of Cluster Configuration Change on a concurrently-running SR transaction
+# We use SET GLOBAL wsrep_cluster_address = '' to cause the slave (node_2) to temporarily
+# leave the cluster.
+#
+
+# Start with a clean slate
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+#
+# Trigger CC . The transaction should be able to continue
+#
+
+--connection node_2
+--let $wsrep_cluster_address_orig = `SELECT @@wsrep_cluster_address`
+SET GLOBAL wsrep_cluster_address = '';
+
+# Wait until the node_2 disconnects from the cluster
+SET SESSION wsrep_sync_wait = 0;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Disconnected' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'
+--source include/wait_condition.inc
+SET SESSION wsrep_sync_wait = default;
+
+--connection node_1
+
+# Wait until the node_1 sees the cluster configuration change
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+# Continue generating events in the transaction
+
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+# Restore cluster
+
+--connection node_2
+--disable_query_log
+--eval SET GLOBAL wsrep_cluster_address='$wsrep_cluster_address_orig';
+--enable_query_log
+--source include/galera_wait_ready.inc
+
+# Confirm that the SR table still contains entries from ongoing transaction
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+# Continue and finalize transaction
+--connection node_1
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (16);
+COMMIT;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Confirm that transaction was replicated properly
+# and SR table is cleaned up afterwards.
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 15 FROM t1;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+
+CALL mtr.add_suppression("points to own listening address, blacklisting");
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_concurrent.test b/mysql-test/suite/galera_sr/t/galera_sr_concurrent.test
new file mode 100644
index 00000000000..9ec7143d25c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_concurrent.test
@@ -0,0 +1,45 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test two concurrent SR-replicated transactions
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t2 VALUES (3);
+INSERT INTO t2 VALUES (4);
+INSERT INTO t2 VALUES (5);
+
+--connection node_1
+COMMIT;
+
+--connection node_1a
+COMMIT;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 5 FROM t2;
+
+--connection node_1
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_conflict.test b/mysql-test/suite/galera_sr/t/galera_sr_conflict.test
new file mode 100644
index 00000000000..dd133c2d12e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_conflict.test
@@ -0,0 +1,45 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# A conflict between a streaming replication fragment and a local transaction
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+# Wait until a streaming replication fragment has arrived
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+# Attempt a conflicting INSERT. This will block
+--send INSERT INTO t1 VALUES(1);
+
+# Observe the block from a separate connection
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'wsrep applier committed%';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'update';
+--source include/wait_condition.inc
+
+# Commit the remote transaction, causing the local transaction to return an error
+--connection node_1
+COMMIT;
+
+--connection node_2
+--error ER_DUP_ENTRY
+--reap
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit.test b/mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit.test
new file mode 100644
index 00000000000..6675321641f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit.test
@@ -0,0 +1,45 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the following sequence of events:
+#
+# 1. Node #2 begins a transaction
+# 2. Node #1 begins conflicting transaction that is SR replicated
+# 3. Node #2 attempts to commit, gets a deadlock error, even before #1 has committed
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_2
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+--connection node_1
+COMMIT;
+
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit2.test b/mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit2.test
new file mode 100644
index 00000000000..0ea52290bb6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_conflict_on_commit2.test
@@ -0,0 +1,46 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the following sequence of events:
+#
+# 1. Node #1 begins a transaction that is SR replicated
+# 2. Node #2 begins a conflicting transaction, hangs
+# 3. Node #1 comits
+# 4. Node #2 gets a dup key error
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--send INSERT INTO t1 VALUES (5);
+
+--sleep 1
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+--error ER_DUP_ENTRY
+--reap
+
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_conflict_with_rollback_master.test b/mysql-test/suite/galera_sr/t/galera_sr_conflict_with_rollback_master.test
new file mode 100644
index 00000000000..cb96fae0122
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_conflict_with_rollback_master.test
@@ -0,0 +1,44 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the following sequence of events:
+#
+# 1. Node #2 begins a transaction
+# 2. Node #1 begins conflicting transaction that is SR replicated
+# 3. Node #1 rolls back
+# 4. Node #2 can not commit because it was BF-aborted even though the SR transaction was rolled back
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_2
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+ROLLBACK;
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_ddl_master.test b/mysql-test/suite/galera_sr/t/galera_sr_ddl_master.test
new file mode 100644
index 00000000000..7da7f55ba15
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_ddl_master.test
@@ -0,0 +1,63 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the following sequence of events on the master:
+#
+# 1. Connection #1 begins a SR transaction
+# 2. Connection #2 issues DDL
+# 3. Connection #1 attempts to continue the transaction, gets deadlock
+# 4. Connection #1 retries the transaction and succeeds
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+# SR replication is triggered and rows have been delivered to the slave
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (6);
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Check that the transaction thus aborted could be reissued
+
+ROLLBACK;
+START TRANSACTION;
+INSERT INTO t1 (f1) VALUES (1);
+INSERT INTO t1 (f1) VALUES (2);
+INSERT INTO t1 (f1) VALUES (3);
+INSERT INTO t1 (f1) VALUES (4);
+INSERT INTO t1 (f1) VALUES (5);
+INSERT INTO t1 (f1) VALUES (6);
+COMMIT;
+
+SELECT COUNT(*) = 6 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 6 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_ddl_schema.test b/mysql-test/suite/galera_sr/t/galera_sr_ddl_schema.test
new file mode 100644
index 00000000000..a3045773387
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_ddl_schema.test
@@ -0,0 +1,43 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of DROP SCHEMA DDL on a concurrent SR transaction
+# Most other DDL tests work on a table level, so this test exercises a
+# different granularity.
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+DROP SCHEMA test;
+
+--error ER_NO_SUCH_TABLE
+SELECT COUNT(*) = 0 FROM test.t1;
+
+--connection node_1
+
+# Transaction can not continue due to DDL
+--error ER_LOCK_DEADLOCK
+INSERT INTO test.t1 VALUES (6, 6);
+
+# DDL is now in effect
+--error ER_NO_SUCH_TABLE
+INSERT INTO test.t1 VALUES (6, 6);
+
+CREATE SCHEMA test;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_ddl_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_ddl_slave.test
new file mode 100644
index 00000000000..4a652284e59
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_ddl_slave.test
@@ -0,0 +1,65 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of DDL on a concurrent SR transaction
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+ALTER TABLE t1 DROP COLUMN f2;
+
+# SR applied before the DDL is no longer visible
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+# Transaction can not continue due to DDL, implicit ROLLBACK
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (6, 6);
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# DDL is now in effect
+--error ER_WRONG_VALUE_COUNT_ON_ROW
+INSERT INTO t1 VALUES (6, 6);
+
+# But it should be possible to reissue the transaction
+
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_ddl_unrelated.test b/mysql-test/suite/galera_sr/t/galera_sr_ddl_unrelated.test
new file mode 100644
index 00000000000..77b6e64641d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_ddl_unrelated.test
@@ -0,0 +1,53 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the effect of unrelated DDL on a concurrent SR transaction
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (3, 3);
+INSERT INTO t1 VALUES (4, 4);
+INSERT INTO t1 VALUES (5, 5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+ALTER TABLE t2 DROP COLUMN f2;
+
+# SR applied before the DDL is still visible
+SELECT COUNT(*) = 5 FROM t1;
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+
+# Transaction can continue, even after the DDL
+--error 0
+INSERT INTO t1 VALUES (6, 6);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 6 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_dupkey_error.test b/mysql-test/suite/galera_sr/t/galera_sr_dupkey_error.test
new file mode 100644
index 00000000000..a7aca042829
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_dupkey_error.test
@@ -0,0 +1,59 @@
+#
+# Test the case where a duplicate key error happens in the middle of an SR transaction
+#
+
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (f1 BLOB) ENGINE=InnoDB;
+CREATE UNIQUE INDEX i1 ON t1 (f1(512));
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1024;
+
+INSERT INTO t1 VALUES (REPEAT('a', 512));
+INSERT INTO t1 VALUES (REPEAT('b', 512));
+INSERT INTO t1 VALUES (REPEAT('c', 512));
+INSERT INTO t1 VALUES (REPEAT('d', 512));
+INSERT INTO t1 VALUES (REPEAT('e', 512));
+INSERT INTO t1 VALUES (REPEAT('f', 512));
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+# Deadlock error instead of dupkey since the transaction is SR and
+# statement rollback is not safe.
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (REPEAT('c', 512));
+
+# Confirm that the wsrep_streaming_log table is now empty, as it was a full transaction rollback
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Confirm that the transaction can be restarted on either node
+
+--connection node_1
+INSERT INTO t1 VALUES (REPEAT('d', 512));
+INSERT INTO t1 VALUES (REPEAT('e', 512));
+INSERT INTO t1 VALUES (REPEAT('f', 512));
+COMMIT;
+
+--connection node_2
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (REPEAT('a', 512));
+INSERT INTO t1 VALUES (REPEAT('b', 512));
+INSERT INTO t1 VALUES (REPEAT('c', 512));
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 6 FROM t1;
+
+--connection node_2
+SELECT COUNT(*) = 6 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_fk_conflict.test b/mysql-test/suite/galera_sr/t/galera_sr_fk_conflict.test
new file mode 100644
index 00000000000..b83deaee244
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_fk_conflict.test
@@ -0,0 +1,62 @@
+#
+# Test Foreign Key with SR
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE grandparent (
+ id INT NOT NULL PRIMARY KEY
+) ENGINE=InnoDB;
+
+CREATE TABLE parent (
+ id INT NOT NULL PRIMARY KEY,
+ grandparent_id INT,
+ FOREIGN KEY (grandparent_id)
+ REFERENCES grandparent(id)
+ ON UPDATE CASCADE
+) ENGINE=InnoDB;
+
+CREATE TABLE child (
+ id INT NOT NULL PRIMARY KEY,
+ grandparent_id INT,
+ FOREIGN KEY (grandparent_id)
+ REFERENCES parent(grandparent_id)
+ ON UPDATE CASCADE
+) ENGINE=InnoDB;
+
+INSERT INTO grandparent VALUES (1),(2),(3),(4);
+INSERT INTO parent VALUES (1,1), (2,2);
+INSERT INTO child VALUES (1,1), (2,2);
+
+# Start and SR transaction
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+
+UPDATE grandparent SET id = 5 WHERE id = 1;
+
+# No conflicting transactions are allowed to proceed on slave
+
+--connection node_2
+SET SESSION innodb_lock_wait_timeout = 1;
+
+--error ER_LOCK_WAIT_TIMEOUT
+UPDATE grandparent SET id = 10 WHERE id = 5;
+
+--error ER_LOCK_WAIT_TIMEOUT
+DELETE FROM child;
+
+# SR transaction succesffull
+
+--connection node_1
+COMMIT;
+
+--let $diff_servers = 1 2
+--source include/diff_servers.inc
+
+DROP TABLE child;
+DROP TABLE parent;
+DROP TABLE grandparent;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_gtid-master.opt b/mysql-test/suite/galera_sr/t/galera_sr_gtid-master.opt
new file mode 100644
index 00000000000..6623c33c484
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_gtid-master.opt
@@ -0,0 +1 @@
+ --log-bin --log-slave-updates --loose-galera-sr-gtid-unique
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_gtid.test b/mysql-test/suite/galera_sr/t/galera_sr_gtid.test
new file mode 100644
index 00000000000..56464ba6f63
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_gtid.test
@@ -0,0 +1,46 @@
+#
+# Test basic Galera operation
+#
+
+--source include/have_log_bin.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INT PRIMARY KEY);
+
+SET SESSION wsrep_trx_fragment_size=1;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+
+SET SESSION wsrep_trx_fragment_size=1;
+UPDATE t1 SET f1 = 2;
+
+#--let $gtid_executed_node2 = `SELECT @@global.gtid_executed;`
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size=0;
+
+--connection node_2
+SET SESSION wsrep_trx_fragment_size=0;
+
+--connection node_1
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+
+--disable_query_log
+#--eval SELECT '$gtid_executed_node2' = @@global.gtid_executed AS gtid_executed_equal;
+--enable_query_log
+
+--replace_regex /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/<GTID>/ /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+--replace_column 2 <Pos> 5 <End_log_pos>
+SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 256;
+
+--connection node_2
+# Perform causal wait
+SELECT 1 FROM DUAL;
+--replace_regex /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/<GTID>/ /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+--replace_column 2 <Pos> 5 <End_log_pos>
+SHOW BINLOG EVENTS IN 'mysqld-bin.000003' FROM 256;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_insert_select.test b/mysql-test/suite/galera_sr/t/galera_sr_insert_select.test
new file mode 100644
index 00000000000..01481db5a8b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_insert_select.test
@@ -0,0 +1,33 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test large INSERT ... SELECT with SR
+#
+
+--connection node_1
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+# Insert 10K rows.
+INSERT INTO t1 (f2) SELECT REPEAT('a', 255) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 99 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 10000 FROM t1;
+
+--connection node_1
+
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_nobootstrap.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_nobootstrap.test
new file mode 100644
index 00000000000..8fba27f9a73
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_nobootstrap.test
@@ -0,0 +1,52 @@
+#
+# Kill entire cluster during SR while pc.bootstrap is in effect
+# after restart, confirm that the mysql.wsrep_streaming_log table is empty
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+--connection node_1
+--source include/kill_galera.inc
+
+--sleep 1
+
+# Bootstrap the cluster from scratch
+
+--connection node_1
+--remove_file $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+
+--connection node_2
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf
new file mode 100644
index 00000000000..6422d7541ba
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.cnf
@@ -0,0 +1,4 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.recovery=false'
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test
new file mode 100644
index 00000000000..042e3d3ef57
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_norecovery.test
@@ -0,0 +1,53 @@
+#
+# Kill entire cluster during SR while pc.recovery is NOT in effect
+# after restart, confirm that the mysql.wsrep_streaming_log table is empty
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+--connection node_1
+--source include/kill_galera.inc
+
+--sleep 1
+
+--connection node_1
+--remove_file $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--let $start_mysqld_params = "--wsrep-new-cluster"
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+
+--connection node_2
+--let $start_mysqld_params = ""
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_all_pcrecovery.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_pcrecovery.test
new file mode 100644
index 00000000000..0ba7cedbd8f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_all_pcrecovery.test
@@ -0,0 +1,54 @@
+#
+# Kill entire cluster during SR while pc.recovery is in effect
+# after restart, confirm that the mysql.wsrep_streaming_log table is empty
+#
+
+--source include/galera_cluster.inc
+--source include/big_test.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--source include/kill_galera.inc
+--connection node_1
+--source include/kill_galera.inc
+
+--sleep 1
+
+# Bootstrap the cluster from scratch
+
+--connection node_1
+--remove_file $MYSQLTEST_VARDIR/mysqld.1/data/grastate.dat
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--source include/start_mysqld.inc
+
+--connection node_2
+--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
+--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
+--source include/start_mysqld.inc
+
+--connection node_1
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_connection.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_connection.test
new file mode 100644
index 00000000000..03d09f33fab
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_connection.test
@@ -0,0 +1,59 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test KILL CONNECTION on a transaction that has already replicated some data via SR
+#
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+# Confirm that the transaction is SR-replicated
+--connection node_2
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+# Kill the transaction by killing the entire connection
+
+--connection node_1
+--let $connection_id = `SELECT CONNECTION_ID()`
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--disable_query_log
+--eval KILL CONNECTION $connection_id
+--enable_query_log
+
+# Confirm that the disconnection caused the updates made so far to be removed
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM t1;
+--source include/wait_condition.inc
+
+# Confirm that the transaction can be reissued in its entirety on the slave without a conflict
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+COMMIT;
+
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1a
+SELECT COUNT(*) = 5 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test
new file mode 100644
index 00000000000..4c9f2b4d7bc
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test
@@ -0,0 +1,48 @@
+--source include/galera_cluster.inc
+
+#
+# Test KILL QUERY on a statement that has already replicated some data via SR
+#
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+--let $connection_id = `SELECT CONNECTION_ID()`
+--send INSERT INTO t1 SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5, ten AS a6;
+
+# Wait for some SR to arrive on the slave.
+--connection node_2
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT TABLE_ROWS > 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_1
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--echo Killing query ...
+--disable_query_log
+--eval KILL QUERY $connection_id
+--enable_query_log
+
+--connection node_1
+--error ER_QUERY_INTERRUPTED
+--reap
+
+# Confirm that the kill caused the updates made so far to be removed
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Confirm that the transaction can be reissued in its entirety on the slave without a conflict
+
+INSERT INTO t1 SELECT 1 FROM ten AS t1, ten AS t2, ten AS t3;
+SELECT COUNT(*) = 1000 FROM t1;
+
+--connection node_1a
+SELECT COUNT(*) = 1000 FROM t1;
+
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.cnf b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.cnf
new file mode 100644
index 00000000000..290d8fe196e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.cnf
@@ -0,0 +1,4 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.weight=2'
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test
new file mode 100644
index 00000000000..a76a03e49b9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test
@@ -0,0 +1,80 @@
+#
+# This test kills the slave while a Streaming Replication transaction is in
+# progress but before a fragment has already been applied on the slave. It
+# is expected that after the slave restarts, the cluster will continue to
+# be consistent.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+# Block node #2's applier before table t1's inserts have come into play
+
+--connection node_2
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+CREATE TABLE t2 (f1 INTEGER);
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+LOCK TABLE t2 WRITE;
+
+--connection node_1
+INSERT INTO t2 VALUES (1);
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_1
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--sleep 2
+
+--connection node_2
+--source include/kill_galera.inc
+--sleep 1
+
+--connection node_1
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+
+--connection node_2
+--source include/start_mysqld.inc
+--sleep 1
+
+--source include/wait_until_connected_again.inc
+--source include/galera_wait_ready.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (11);
+INSERT INTO t1 VALUES (12);
+INSERT INTO t1 VALUES (13);
+INSERT INTO t1 VALUES (14);
+INSERT INTO t1 VALUES (15);
+COMMIT;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+--sleep 5
+SELECT COUNT(*) = 15 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_large_fragment-master.opt b/mysql-test/suite/galera_sr/t/galera_sr_large_fragment-master.opt
new file mode 100644
index 00000000000..132c6aed246
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_large_fragment-master.opt
@@ -0,0 +1 @@
+--innodb_log_file_size=1G --binlog-row-event-max-size=100M
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_large_fragment.test b/mysql-test/suite/galera_sr/t/galera_sr_large_fragment.test
new file mode 100644
index 00000000000..63278555723
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_large_fragment.test
@@ -0,0 +1,58 @@
+#
+# Test the replication and subsequent cleanup of a few, very large fragments
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(512)) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1024 * 1024 * 10;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 (f2) SELECT REPEAT('x', 512) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4, ten AS a5;
+
+--connection node_2
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) > 50000 FROM t1;
+
+--connection node_1
+ROLLBACK;
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--let $wsrep_provider_options_node_2 = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_provider_options'`
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT10M';
+SET SESSION wsrep_sync_wait = 7;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node_2';
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+--let $wsrep_provider_options_node_1 = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_provider_options'`
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT10M';
+SET SESSION wsrep_sync_wait = 7;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node_1';
+
+DROP TABLE ten;
+DROP TABLE t1;
+
+CALL mtr.add_suppression('InnoDB: Resizing redo log from');
+CALL mtr.add_suppression('InnoDB: Starting to delete and rewrite log files');
+CALL mtr.add_suppression('InnoDB: New log files created, LSN=');
+
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_load_data.test b/mysql-test/suite/galera_sr/t/galera_sr_load_data.test
new file mode 100644
index 00000000000..b430ace5d69
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_load_data.test
@@ -0,0 +1,39 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test Streaming Replication + LOAD DATA
+#
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 512;
+
+# Create a file for LOAD DATA with 20K entries
+--perl
+open(FILE, ">", "$ENV{'MYSQLTEST_VARDIR'}/tmp/galera_sr_load_data.csv") or die;
+foreach my $i (1..20000) {
+ 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'`
+
+--connection node_1
+--disable_query_log
+--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/galera_sr_load_data.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(*) = 20000 FROM t1;
+# LOAD-ing 20K 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;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_load_data_splitting.test b/mysql-test/suite/galera_sr/t/galera_sr_load_data_splitting.test
new file mode 100644
index 00000000000..40e63e7c67f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_load_data_splitting.test
@@ -0,0 +1,50 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+#
+# Test Streaming Replication and LOAD DATA splitting operating at the same time
+#
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+--let $wsrep_load_data_splitting_orig = `SELECT @@wsrep_load_data_splitting`
+
+SET SESSION wsrep_trx_fragment_size = 512;
+SET GLOBAL wsrep_load_data_splitting = TRUE;
+
+
+# Create a file for LOAD DATA with 95K entries
+--perl
+open(FILE, ">", "$ENV{'MYSQLTEST_VARDIR'}/tmp/galera_sr_load_data.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'`
+
+--connection node_1
+--disable_query_log
+--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/galera_sr_load_data.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
+--disable_query_log
+--eval SET GLOBAL wsrep_load_data_splitting = $wsrep_load_data_splitting_orig;
+--enable_query_log
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_log_bin-master.opt b/mysql-test/suite/galera_sr/t/galera_sr_log_bin-master.opt
new file mode 100644
index 00000000000..03fcb5d040d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_log_bin-master.opt
@@ -0,0 +1 @@
+--log-slave-updates --log-bin
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_log_bin.test b/mysql-test/suite/galera_sr/t/galera_sr_log_bin.test
new file mode 100644
index 00000000000..7dfa7850c15
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_log_bin.test
@@ -0,0 +1,70 @@
+#
+# Interleave SR and non-SR transactions and confirm that the binlog is in correct order
+#
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t3 (f1 INTEGER) ENGINE=InnoDB;
+CREATE TABLE t4 (f1 INTEGER) ENGINE=InnoDB;
+
+--source include/galera_cluster.inc
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t2 VALUES (1);
+
+--connection node_2
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t3 VALUES (1);
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t4 VALUES (1);
+
+--connection node_1
+INSERT INTO t1 VALUES (2);
+COMMIT;
+
+--connection node_1a
+INSERT INTO t2 VALUES (2);
+COMMIT;
+
+--connection node_2
+INSERT INTO t3 VALUES (2);
+COMMIT;
+--connection node_2a
+INSERT INTO t4 VALUES (2);
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 2 FROM t4;
+
+--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 256;
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM t4;
+
+--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 256;
+
+DROP TABLE t1,t2,t3,t4;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_many_fragments.test b/mysql-test/suite/galera_sr/t/galera_sr_many_fragments.test
new file mode 100644
index 00000000000..9b8dae9d8e3
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_many_fragments.test
@@ -0,0 +1,53 @@
+#
+# Test the replication and subsequent cleanup of a large number of small transaction fragments
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(512)) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 (f2) SELECT REPEAT('x', 512) FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_2
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 10000 FROM t1;
+
+--connection node_1
+ROLLBACK;
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+--let $wsrep_provider_options_node_2 = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_provider_options'`
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT10M';
+SET SESSION wsrep_sync_wait = 7;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node_2';
+
+--connection node_1
+SET SESSION wsrep_sync_wait = 0;
+--let $wsrep_provider_options_node_1 = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME = 'wsrep_provider_options'`
+SET GLOBAL wsrep_provider_options = 'repl.causal_read_timeout=PT10M';
+SET SESSION wsrep_sync_wait = 7;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_node_1';
+
+DROP TABLE ten;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_myisam.test b/mysql-test/suite/galera_sr/t/galera_sr_myisam.test
new file mode 100644
index 00000000000..b037f817610
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_myisam.test
@@ -0,0 +1,29 @@
+#
+# Test that the basic MyISAM replication works even with SR enabled
+# We basically check that the data arrived on the slave and that there
+# were no assertions.
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 TEXT) ENGINE=MyISAM;
+
+--let $wsrep_replicate_myisam_orig = `SELECT @@wsrep_replicate_myisam`
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET GLOBAL wsrep_replicate_myisam = TRUE;
+
+INSERT INTO t1 VALUES (REPEAT('x', 65535));
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SELECT LENGTH(f1) = 65535 FROM t1;
+
+DROP TABLE t1;
+
+--connection node_1
+--disable_query_log
+--eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig;
+--enable_query_log
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.cnf b/mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.cnf
new file mode 100644
index 00000000000..574ae28b54a
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.cnf
@@ -0,0 +1,11 @@
+!include ../galera_2nodes.cnf
+
+# We do not set mysqldump-related SST options here because doing so on startup
+# causes the first MTR connection to be forefully dropped by Galera, which in turn confuses MTR
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=1;pc.ignore_sb=true'
+
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.test b/mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.test
new file mode 100644
index 00000000000..25ded94e100
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_mysqldump_sst.test
@@ -0,0 +1,79 @@
+#
+# Test mysqldump SST on slave if SR transaction is in progress
+#
+
+--source include/big_test.inc
+--source include/galera_cluster.inc
+
+--source suite/galera/include/galera_sst_set_mysqldump.inc
+
+--connection node_1
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size = 1000;
+START TRANSACTION;
+# Insert 1000 rows
+INSERT INTO t1 (f2) SELECT REPEAT('x', 255) FROM ten AS a1, ten AS a2, ten AS a3;
+
+# Update 1000 rows
+UPDATE t1 SET f2 = REPEAT('y', 255);
+
+# Wait for SR replication to kick in
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+# Restart node #2
+
+--connection node_2
+--let $MYSQLD2_DATADIR = `SELECT @@datadir`
+
+--echo Shutting down server ...
+--source include/shutdown_mysqld.inc
+
+# Force SST
+--remove_file $MYSQLD2_DATADIR/grastate.dat
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+--connection node_2
+--echo Starting server ...
+--let $start_mysqld_params = --wsrep_sst_auth=sst:sst --wsrep_sst_method=mysqldump --wsrep-sst-receive-address=127.0.0.1:$NODE_MYPORT_2
+--source include/start_mysqld.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
+--source include/wait_condition.inc
+
+# Check that node #2 is caught up with the SR transaction that is still in progress
+--connection node_2
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+# Finalize transaction
+--connection node_1
+UPDATE t1 SET f2 = REPEAT('z', 255);
+COMMIT;
+
+# Confirm proper replication of entire transaction to node #2
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 1000 FROM t1;
+SELECT COUNT(*) = 1000 FROM t1 WHERE f2 = REPEAT('z', 255);
+
+DROP TABLE t1;
+DROP TABLE ten;
+
+--connection node_1
+# galera_sst_restore.inc uses DROP USER internally which is incompatible
+# with SR, need to disable SR before that.
+SET SESSION wsrep_trx_fragment_size=0;
+--source suite/galera/include/galera_sst_restore.inc
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_parallel_apply.test b/mysql-test/suite/galera_sr/t/galera_sr_parallel_apply.test
new file mode 100644
index 00000000000..83a7acbe3e0
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_parallel_apply.test
@@ -0,0 +1,59 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test SR with parallel apply
+#
+
+--connection node_2
+--let $wsrep_slave_threads_orig = `SELECT @@wsrep_slave_threads`
+SET GLOBAL wsrep_slave_threads = 5;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 INTEGER) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);
+INSERT INTO t1 (f2) VALUES (1);
+--send INSERT INTO t1 (f2) VALUES (1);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);
+INSERT INTO t1 (f2) VALUES (2);
+--send INSERT INTO t1 (f2) VALUES (2);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1 WHERE f2 = 1;
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1 WHERE f2 = 2;
+--source include/wait_condition.inc
+
+--connection node_1
+--reap
+COMMIT;
+
+--connection node_1a
+--reap
+ROLLBACK;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
+
+--connection node_2
+--disable_query_log
+--eval SET GLOBAL wsrep_slave_threads = $wsrep_slave_threads_orig;
+--enable_query_log
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_rollback.test b/mysql-test/suite/galera_sr/t/galera_sr_rollback.test
new file mode 100644
index 00000000000..33a318f8ae3
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_rollback.test
@@ -0,0 +1,76 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that ROLLBACK works correctly with streaming replication
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) >= 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+ROLLBACK;
+
+#
+# After ROLLBACK, the table on node #2 should be empty
+#
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM t1;
+--source include/wait_condition.inc
+
+#
+# It should be possible to re-insert the values we just rolled back
+#
+
+--connection node_1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) >= 9 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) >= 10 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test b/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test
new file mode 100644
index 00000000000..c6c443a0828
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test
@@ -0,0 +1,55 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that a SR transaction that was just ROLLBACKed on one node can be
+# run against another node without any conflicts
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+ROLLBACK;
+
+#
+# After ROLLBACK, the table on node #2 should be empty
+#
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM t1;
+--source include/wait_condition.inc
+
+#
+# It should be possible to reissue the same transaction against node #2
+#
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+COMMIT;
+
+SELECT COUNT(*) = 5 FROM t1;
+
+--connection node_1
+SELECT COUNT(*) = 5 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_rollback_savepoint.test b/mysql-test/suite/galera_sr/t/galera_sr_rollback_savepoint.test
new file mode 100644
index 00000000000..93ff7a948c4
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_rollback_savepoint.test
@@ -0,0 +1,51 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that ROLLBACK TO SAVEPOINT works correctly with streaming replication
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+SAVEPOINT s1;
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 5 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+ROLLBACK TO SAVEPOINT s1;
+
+INSERT INTO t1 VALUES (21, 'c');
+INSERT INTO t1 VALUES (22, 'c');
+INSERT INTO t1 VALUES (23, 'c');
+INSERT INTO t1 VALUES (24, 'c');
+INSERT INTO t1 VALUES (25, 'c');
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1 WHERE f2 = 'a';
+SELECT COUNT(*) = 0 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 5 FROM t1 WHERE f2 = 'c';
+
+--connection node_1
+COMMIT;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_rollback_statement.test b/mysql-test/suite/galera_sr/t/galera_sr_rollback_statement.test
new file mode 100644
index 00000000000..74350faf5a2
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_rollback_statement.test
@@ -0,0 +1,61 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the case where a statement is rolled back due to an error while Streaming Replication
+# is in effect. We construct an INSERT ... SELECT statement that will fail with a duplicate
+# key error towards the end of the statement, after a portion has already been replicated via SR.
+#
+
+--disable_query_log
+--let $auto_increment_offset_orig = `SELECT @@auto_increment_offset`
+SET GLOBAL auto_increment_offset=1;
+--enable_query_log
+
+--connection node_1
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) ENGINE=InnoDB;
+
+INSERT INTO t1 (f2) SELECT REPEAT('a', 255) FROM ten AS a1, ten AS a2, ten AS a3;
+ALTER TABLE t1 CHANGE f1 f1 INTEGER;
+ALTER TABLE t1 DROP PRIMARY KEY;
+
+# This poison value is used to cause the INSERT ... SELECT below to fail
+INSERT INTO t1 VALUES (1, 'abc');
+
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+SET SESSION wsrep_trx_fragment_size = 1;
+
+--error ER_DUP_ENTRY
+INSERT INTO t2 SELECT * FROM t1;
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM t2;
+--source include/wait_condition.inc
+
+# Cluster continues to operate after the implicit ROLLBACK;
+--connection node_1
+INSERT INTO t2 VALUES (1, 'abc');
+
+--connection node_2
+INSERT INTO t2 VALUES (2, 'abc');
+
+--connection node_1
+SELECT COUNT(*) = 2 FROM t2;
+
+--connection node_2
+SELECT COUNT(*) = 2 FROM t2;
+
+--connection node_1
+
+--disable_query_log
+--eval SET GLOBAL auto_increment_offset=$auto_increment_offset_orig;
+--enable_query_log
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_sbr.test b/mysql-test/suite/galera_sr/t/galera_sr_sbr.test
new file mode 100644
index 00000000000..a24a520af60
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_sbr.test
@@ -0,0 +1,31 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that SR does not assert in the presence of statement-based replication events
+#
+
+--connection node_1
+CREATE TABLE t1 (id INT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 1;
+SET SESSION BINLOG_FORMAT='STATEMENT';
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+COMMIT;
+
+--connection node_2
+SELECT COUNT(*) = 5 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_shutdown_master.test b/mysql-test/suite/galera_sr/t/galera_sr_shutdown_master.test
new file mode 100644
index 00000000000..3f7407fe536
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_shutdown_master.test
@@ -0,0 +1,53 @@
+#
+# Shut down master (node #2) while an SR transaction is in progress
+#
+
+--source include/galera_cluster.inc
+
+# Save original auto_increment_offset values.
+--let $node_1=node_1
+--let $node_2=node_2
+--source ../galera/include/auto_increment_offset_save.inc
+
+--connection node_2
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE = InnoDB;
+
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1),(2),(3);
+
+--connection node_1
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--connection node_2
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Confirm that SR table on slave is empty
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_2
+--source include/start_mysqld.inc
+
+# SR table on master should be empty too
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+# Confirm that the INSERT can be re-issued
+INSERT INTO t1 VALUES (1),(2),(3);
+
+--connection node_1
+SELECT COUNT(*) = 3 FROM t1;
+
+DROP TABLE t1;
+
+--connection node_2
+CALL mtr.add_suppression("WSREP: Failed to replicate rollback fragment for ");
+
+# Restore original auto_increment_offset values.
+--source ../galera/include/auto_increment_offset_restore.inc
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_shutdown_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_shutdown_slave.test
new file mode 100644
index 00000000000..fa2df242ccc
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_shutdown_slave.test
@@ -0,0 +1,63 @@
+#
+# Shut down slave (node #2) while an SR transaction is in progress
+#
+
+--source include/galera_cluster.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE = InnoDB;
+
+# We start two transactions on the master so that we can commit one while the slave
+# is down and commit the other after the slave has rejoined
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (11),(12),(13);
+
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1b
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (21),(22),(23);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+--source include/wait_condition.inc
+
+--source include/shutdown_mysqld.inc
+
+--connection node_1
+--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+# Commit one transaction while the slave is down
+--connection node_1a
+INSERT INTO t1 VALUES (14),(15),(16);
+COMMIT;
+
+# Restart slave
+--connection node_2
+--source include/start_mysqld.inc
+
+# Confirm SR table on slave has entries
+SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 6 FROM t1 WHERE f1 IN (11,12,13,14,15,16);
+
+# Commit the second transaction on master after the slave has rejoined
+--connection node_1b
+INSERT INTO t1 VALUES (24),(25),(26);
+COMMIT;
+
+# Confirm that SR table on slave is empty
+--connection node_2
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+SELECT COUNT(*) = 12 FROM t1;
+
+# SR table on master should be empty too
+--connection node_1
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_small_gcache.cnf b/mysql-test/suite/galera_sr/t/galera_sr_small_gcache.cnf
new file mode 100644
index 00000000000..c8e17436e71
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_small_gcache.cnf
@@ -0,0 +1,6 @@
+!include ../galera_2nodes.cnf
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=16K'
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;gcache.size=16K'
+
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_small_gcache.test b/mysql-test/suite/galera_sr/t/galera_sr_small_gcache.test
new file mode 100644
index 00000000000..403b44286d9
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_small_gcache.test
@@ -0,0 +1,21 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# A simple test with a very low value for gcache.size - 16K
+#
+
+--connection node_1
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 SELECT 1 FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_2
+SELECT COUNT(*) = 10000 FROM t1;
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_table_contents.test b/mysql-test/suite/galera_sr/t/galera_sr_table_contents.test
new file mode 100644
index 00000000000..92d29fe4ca2
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_table_contents.test
@@ -0,0 +1,49 @@
+#
+# This test dumps the contents of the SR table under various circumstances
+#
+
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2),(3);
+
+CREATE TABLE t2 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1),(2),(3);
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--echo
+--echo Start of Simple Insert
+INSERT INTO t1 VALUES (4);
+--source suite/galera/include/galera_dump_sr_table.inc
+--echo End of Simple Insert
+--echo
+ROLLBACK;
+
+--echo Start of Multi-row Update
+UPDATE t1 SET f1 = f1 + 10;
+--source suite/galera/include/galera_dump_sr_table.inc
+--echo End of Multi-row Update
+--echo
+ROLLBACK;
+
+--echo Start of Multi-table Update
+UPDATE t1, t2 SET t1.f1 = t1.f1 + 100, t2.f1 = t2.f1 + 100;
+--source suite/galera/include/galera_dump_sr_table.inc
+--echo End of Multi-table Update
+--echo
+ROLLBACK;
+
+--echo Start of Savepoint
+INSERT INTO t1 VALUES (1000);
+SAVEPOINT X;
+INSERT INTO t1 VALUES (2000);
+ROLLBACK TO SAVEPOINT X;
+--source suite/galera/include/galera_dump_sr_table.inc
+--echo End of Savepoint
+--echo
+ROLLBACK;
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_transaction_replay.test b/mysql-test/suite/galera_sr/t/galera_sr_transaction_replay.test
new file mode 100644
index 00000000000..f44d67e5c8c
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_transaction_replay.test
@@ -0,0 +1,260 @@
+#
+# This test tests the operation of SR transaction replay. If a
+# potentially conflicting remote transaction arrives at
+# just the right time during the commit of a local transaction,
+# the local transaction will be aborted and replayed.
+#
+# This test is divided in two sections:
+# 1) Test the scenario where the last fragment does not have write set
+# payload, just commit flag is replicated
+# 2) Test the scenario where the last fragment has write set payload
+# and commit flag
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+--source include/galera_have_debug_sync.inc
+
+# Control connection for manipulating galera sync points
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_1
+
+--let $wsrep_local_replays_old = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1));
+
+#########################################################################
+#
+# 1) Replay without commit fragment write set payload
+#
+#########################################################################
+
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+
+--connection node_1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
+
+#
+# Block the commit from node_2
+#
+--connection node_1a
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_set_sync_point.inc
+
+#
+# Issue conflicting UPDATE from node_2 and wait until it hits the
+# apply monitor (but does not apply yet)
+#
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+
+--connection node_1a
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# Set a new sync point to block in local monitor on node_1 commit
+#
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = local_monitor_master_enter_sync
+--source include/galera_set_sync_point.inc
+
+#
+# Send the commit on node_1
+#
+--connection node_1
+--send COMMIT
+
+#
+# Wait until commit reaches sync point
+#
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--let $galera_sync_point = apply_monitor_slave_enter_sync local_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# Release conflicting slave transaction and wait until it has BF
+# aborted pending COMMIT
+#
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+
+--let $galera_sync_point = abort_trx_end local_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# Release both threads, local thread will now replay
+#
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+
+--let $galera_sync_point = local_monitor_master_enter_sync
+--source include/galera_signal_sync_point.inc
+
+#
+# Commit must succeed
+#
+--connection node_1
+--reap
+
+
+#
+# Check the outcome and that wsrep schema SR table is empty
+#
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+#
+# wsrep_local_replays has increased by 1
+#
+--let $wsrep_local_replays_new = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays'`
+--disable_query_log
+--eval SELECT $wsrep_local_replays_new - $wsrep_local_replays_old = 1 AS wsrep_local_replays;
+--enable_query_log
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DELETE FROM t1;
+
+#########################################################################
+#
+# 2) Replay with commit fragment write set payload
+#
+#########################################################################
+
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+
+--connection node_1
+SET AUTOCOMMIT=ON;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+
+#
+# Do first update SR on
+#
+UPDATE t1 SET f2 = 'x' WHERE f1 = 1;
+
+#
+# Disable SR for following statements
+#
+SET SESSION wsrep_trx_fragment_size = 0;
+
+UPDATE t1 SET f2 = 'b' WHERE f1 = 1;
+SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE;
+
+#
+# Block the commit from node_2
+#
+--connection node_1a
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_set_sync_point.inc
+
+#
+# Issue conflicting UPDATE from node_2 and wait until it hits the
+# apply monitor (but does not apply yet)
+#
+--connection node_2
+UPDATE t1 SET f2 = 'c' WHERE f1 = 2;
+
+--connection node_1a
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# Set a new sync point to block in local monitor on node_1 commit
+#
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = local_monitor_master_enter_sync
+--source include/galera_set_sync_point.inc
+
+#
+# Send the commit on node_1
+#
+--connection node_1
+--send COMMIT
+
+#
+# Wait until commit reaches sync point
+#
+--connection node_1a
+SET SESSION wsrep_sync_wait = 0;
+--let $galera_sync_point = apply_monitor_slave_enter_sync local_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# Release conflicting slave transaction and wait until it has BF
+# aborted pending COMMIT
+#
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_set_sync_point.inc
+
+--let $galera_sync_point = apply_monitor_slave_enter_sync
+--source include/galera_signal_sync_point.inc
+
+--let $galera_sync_point = abort_trx_end local_monitor_master_enter_sync
+--source include/galera_wait_sync_point.inc
+
+#
+# Release both threads, local thread will now replay
+#
+--source include/galera_clear_sync_point.inc
+--let $galera_sync_point = abort_trx_end
+--source include/galera_signal_sync_point.inc
+
+--let $galera_sync_point = local_monitor_master_enter_sync
+--source include/galera_signal_sync_point.inc
+
+#
+# Commit must succeed
+#
+--connection node_1
+--reap
+
+
+#
+# Check the outcome and that wsrep schema SR table is empty
+#
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+#
+# 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 = 2 AS wsrep_local_replays;
+--enable_query_log
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'b';
+SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+DELETE FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_unit_statements.test b/mysql-test/suite/galera_sr/t/galera_sr_unit_statements.test
new file mode 100644
index 00000000000..0cf05765838
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_unit_statements.test
@@ -0,0 +1,54 @@
+#
+# Test wsrep_fragment_unit = statements
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 3;
+SET SESSION wsrep_trx_fragment_unit = 'statements';
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+
+# Expect noting is replicated yet, so far we have 2 statements
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+INSERT INTO t1 VALUES (2);
+
+# Expect 2 rows in t1 and 1 fragment in SR table
+--connection node_2
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+
+ --connection node_1
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+# Expect 5 rows in t1 and 2 fragments in SR table
+--connection node_2
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+COMMIT;
+
+# Expect 5 rows in t1 and empty SR table
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) FROM t1;
+SELECT COUNT(*) FROM mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_v1_row_events-master.opt b/mysql-test/suite/galera_sr/t/galera_sr_v1_row_events-master.opt
new file mode 100644
index 00000000000..0b5f8bf7104
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_v1_row_events-master.opt
@@ -0,0 +1 @@
+--log-bin-use-v1-row-events=1 --wsrep-trx-fragment-size=1
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_v1_row_events.test b/mysql-test/suite/galera_sr/t/galera_sr_v1_row_events.test
new file mode 100644
index 00000000000..d3d4d2d0c14
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_v1_row_events.test
@@ -0,0 +1,27 @@
+#
+# Test that Galera SR continues to run even with --log-bin-use-v1-row-events=1
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT COUNT(*) = 1 FROM t1;
+
+--connection node_1
+COMMIT;
+
+SET AUTOCOMMIT=ON;
+UPDATE t1 SET f1 = 2 WHERE f1 = 1;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1 WHERE f1 = 2;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_ws_size.test b/mysql-test/suite/galera_sr/t/galera_sr_ws_size.test
new file mode 100644
index 00000000000..98f6e796ef6
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_ws_size.test
@@ -0,0 +1,70 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that SR transaction is cumulatively allowed to grow beyond repl.max_ws_size
+# if individual fragements are below that size
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(254)) ENGINE=InnoDB;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+
+SET SESSION wsrep_trx_fragment_size = 512;
+SET GLOBAL wsrep_provider_options='repl.max_ws_size=4096';
+
+#
+# Create a transaction larger than repl.max_ws_size
+#
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1;
+
+#
+# We expect that the transaction can proceed successfully
+#
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 10 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+# Commit succeeds
+COMMIT;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+SELECT COUNT(*) = 100 FROM t1;
+
+#
+# Cleanup
+#
+
+DROP TABLE t1;
+DROP TABLE ten;
+
+--connection node_1
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
+--enable_query_log
+
+call mtr.add_suppression('WSREP: transaction size limit.*');
+call mtr.add_suppression('WSREP: rbr write fail.*');
+call mtr.add_suppression('WSREP: Maximum writeset size exceeded by.*');
+call mtr.add_suppression('WSREP: transaction size exceeded.*');
diff --git a/mysql-test/suite/galera_sr/t/galera_sr_ws_size2.test b/mysql-test/suite/galera_sr/t/galera_sr_ws_size2.test
new file mode 100644
index 00000000000..2b9bc4819b8
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_sr_ws_size2.test
@@ -0,0 +1,62 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test that if wsrep_trx_fragment_size > repl.max_ws_size, no SR takes place and
+# the transaction is properly aborted.
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(254)) ENGINE=InnoDB;
+CREATE TABLE ten (f1 INTEGER);
+INSERT INTO ten VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
+
+--let $wsrep_trx_fragment_size_orig = `SELECT @@wsrep_trx_fragment_size`
+--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+
+SET SESSION wsrep_trx_fragment_size = 256;
+SET GLOBAL wsrep_provider_options='repl.max_ws_size=128';
+
+#
+# Create a transaction larger than repl.max_ws_size
+#
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+--error ER_ERROR_DURING_COMMIT,ER_ERROR_ON_WRITE,ER_BINLOG_ROW_LOGGING_FAILED
+INSERT INTO t1 (f2) SELECT REPEAT('x', 254) FROM ten AS a1, ten AS a2;
+
+#
+# We expect that the transaction can not complete successfully
+#
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--sleep 2
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+SELECT COUNT(*) = 0 FROM t1;
+
+#
+# Cleanup
+#
+--connection node_1
+--disable_query_log
+--eval SET GLOBAL wsrep_trx_fragment_size = $wsrep_trx_fragment_size_orig;
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
+--enable_query_log
+
+DROP TABLE t1;
+DROP TABLE ten;
+
+call mtr.add_suppression('WSREP: SR rollback replication failure.*');
+call mtr.add_suppression('WSREP: transaction size limit.*');
+call mtr.add_suppression('WSREP: SR rbr write fail.*');
+call mtr.add_suppression('WSREP: Maximum writeset size exceeded by.*');
+call mtr.add_suppression('WSREP: transaction size exceeded.*');
+call mtr.add_suppression('WSREP: fragment replication failed:');
+call mtr.add_suppression('WSREP: post commit failed for SR rollback');
+call mtr.add_suppression('WSREP: pre_commit for SR rollback returned 2, thd:*');
+call mtr.add_suppression('WSREP: wsrep_rollback failed to send SR ROLLBACK for *');
diff --git a/mysql-test/suite/galera_sr/t/galera_var_ignore_apply_errors_sr.test b/mysql-test/suite/galera_sr/t/galera_var_ignore_apply_errors_sr.test
new file mode 100644
index 00000000000..ea40f58db73
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/galera_var_ignore_apply_errors_sr.test
@@ -0,0 +1,38 @@
+#
+# Test option wsrep_ignore_apply_errors
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Delete row that does not exist using SR transaction
+#
+
+--connection node_2
+SET GLOBAL wsrep_ignore_apply_errors = 2;
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER);
+INSERT INTO t1 VALUES (2);
+SET GLOBAL wsrep_on = OFF;
+INSERT INTO t1 VALUES (1);
+SET GLOBAL wsrep_on = ON;
+SET SESSION wsrep_trx_fragment_size = 1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (3);
+DELETE FROM t1 WHERE f1 = 1;
+DELETE FROM t1 WHERE f1 = 2;
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 1 FROM t1;
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+
+SET SESSION wsrep_trx_fragment_size = 0;
+DROP TABLE t1;
+
+SET GLOBAL wsrep_ignore_apply_errors = 7;
+CALL mtr.add_suppression("Slave SQL: Could not execute Delete_rows event");
+CALL mtr.add_suppression("Can't find record in 't1'"); \ No newline at end of file
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep#215.test b/mysql-test/suite/galera_sr/t/mysql-wsrep#215.test
new file mode 100644
index 00000000000..81b4a718f68
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep#215.test
@@ -0,0 +1,175 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# Test the following sequence of events:
+#
+# 1. Node #1 begins a transaction
+# 2. Node #2 performs a conflicting insert
+# 3. Node #1 attempts to SR-replicate a conflicting transaction
+#
+
+# to sync node_1 appliers
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
+SET SESSION wsrep_trx_fragment_size = 2;
+SET SESSION wsrep_trx_fragment_unit = 'statements';
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--let $expected_cert_failures = `SELECT VARIABLE_VALUE + 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'`
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_1a
+SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_apply_cb';
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_2
+INSERT INTO t1 VALUES (1);
+
+--connection node_1a
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+--send INSERT INTO t1 VALUES (1);
+
+--connection node_1a
+# Wait for the above INSERT to fail certification
+--connection node_1a
+--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'
+--source include/wait_condition.inc
+
+SET GLOBAL DEBUG_DBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+
+COMMIT;
+
+SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1a
+SET DEBUG_SYNC = 'RESET';
+
+#
+# Similar test with BYTES unit
+#
+--connection node_1
+TRUNCATE TABLE t1;
+
+SET SESSION wsrep_trx_fragment_size = 10;
+SET SESSION wsrep_trx_fragment_unit = 'bytes';
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--let $expected_cert_failures = `SELECT VARIABLE_VALUE + 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'`
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_1a
+SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_apply_cb';
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_2
+INSERT INTO t1 VALUES (1);
+
+--connection node_1a
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+SELECT COUNT(*) = 0 FROM t1;
+--send INSERT INTO t1 VALUES (1)
+
+# Wait for the above INSERT to fail certification
+--connection node_1a
+--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'
+--source include/wait_condition.inc
+
+SET GLOBAL DEBUG_DBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+ROLLBACK;
+
+SELECT * FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT * FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1a
+SET DEBUG_SYNC = 'RESET';
+
+#
+# One more test with BYTES unit, but now fragment size is adjusted so
+# that second insert should trigger fragment replication.
+# Currently 200 bytes is good choice here, but this may change with
+# future MySQL versions.
+# => If this test fails after some MySQL merge, check if frgament size
+# needs to be tuned to spot at second insert statement.
+#
+--connection node_1
+TRUNCATE TABLE t1;
+
+SET SESSION wsrep_trx_fragment_size = 200;
+SET SESSION wsrep_trx_fragment_unit = 'bytes';
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+--let $expected_cert_failures = `SELECT VARIABLE_VALUE + 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'`
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+--connection node_1a
+SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_apply_cb';
+SET SESSION wsrep_sync_wait = 0;
+
+--connection node_2
+INSERT INTO t1 VALUES (1);
+
+--connection node_1a
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+INSERT INTO t1 VALUES (1);
+--send INSERT INTO t1 VALUES (2)
+
+# Wait for the above INSERT to fail certification
+--connection node_1a
+--let $wait_condition = SELECT VARIABLE_VALUE = $expected_cert_failures FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_cert_failures'
+--source include/wait_condition.inc
+
+SET GLOBAL DEBUG_DBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+--reap
+COMMIT;
+
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_2
+SELECT COUNT(*) = 1 FROM t1;
+SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log;
+
+--connection node_1a
+DROP TABLE t1;
+SET DEBUG_SYNC = 'RESET';
+
+--connection node_2
+CALL mtr.add_suppression("WSREP: Could not find applier context for");
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#136-master.opt b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#136-master.opt
new file mode 100644
index 00000000000..03fcb5d040d
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#136-master.opt
@@ -0,0 +1 @@
+--log-slave-updates --log-bin
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#136.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#136.test
new file mode 100644
index 00000000000..06e56d3c9cd
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#136.test
@@ -0,0 +1,41 @@
+# SR transactions are not binlogged #136
+
+--source include/galera_cluster.inc
+
+--connection node_1
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+
+--connection node_2
+SET GLOBAL wsrep_on=OFF;
+RESET MASTER;
+SET GLOBAL wsrep_on=ON;
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+COMMIT;
+
+SET SESSION wsrep_trx_fragment_size = 0;
+INSERT INTO t1 VALUES (3),(4);
+COMMIT;
+
+--connection node_1
+--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 256;
+
+--connection node_2
+# Wait for all updates to arrive before dumping binlog
+SELECT COUNT(*) = 4 FROM t1;
+
+--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 256;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#138.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#138.test
new file mode 100644
index 00000000000..3694dc9ad43
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#138.test
@@ -0,0 +1,25 @@
+# SR: two identical transactions have different value for the WSREP_FLAG_PA_UNSAFE flag
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+
+--connection node_2
+SELECT flags FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+ROLLBACK;
+INSERT INTO t1 VALUES (3),(4);
+
+--connection node_2
+SELECT flags FROM mysql.wsrep_streaming_log;
+
+--connection node_1
+ROLLBACK;
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#14.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#14.test
new file mode 100644
index 00000000000..deeb890fa0b
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#14.test
@@ -0,0 +1,21 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+
+COMMIT;
+
+DROP TABLE t1;
+
+--connection node_2
+--source include/galera_wait_ready.inc
+
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test
new file mode 100644
index 00000000000..5210b9ce99e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#148.test
@@ -0,0 +1,60 @@
+# statement rollback for SR transaction causes slave crash for inconsistency
+
+# We test the following:
+# 1. Create a transaction that is blocked by an SR transaction
+# 2. Force the SR transaction to have a statement rollback
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/have_debug_sync.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (6),(7),(8),(9),(10),(1);
+
+--connection node_2
+SET GLOBAL wsrep_slave_threads = 2;
+SET GLOBAL DEBUG = 'd,sync.wsrep_apply_cb';
+
+# Begin SR transaction
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+
+# Begin non-SR transaction that will block waiting for the SR transaction
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+--send INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
+
+# Cause the SR transaction to fail with a duplicate key error
+--connection node_1
+--send INSERT INTO t1 SELECT * FROM t2;
+
+# Continue and commit the non-SR transaction.
+--connection node_1a
+--reap
+INSERT INTO t1 VALUES (6), (7), (8), (9), (10);
+COMMIT;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK,ER_DUP_ENTRY
+--reap
+
+--connection node_2
+SET GLOBAL wsrep_slave_threads = 1;
+SET GLOBAL DEBUG = '';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+SET DEBUG_SYNC='now SIGNAL signal.wsrep_apply_cb';
+
+SELECT COUNT(*) = 10 FROM t1;
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#15.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#15.test
new file mode 100644
index 00000000000..4aaff058b30
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#15.test
@@ -0,0 +1,17 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (id INT) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+
+COMMIT;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.inc b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.inc
new file mode 100644
index 00000000000..29755ab6c2e
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.inc
@@ -0,0 +1,104 @@
+# --source include/galera_cluster.inc
+# --source include/have_debug_sync.inc
+
+#
+# This test attempts to catch a race condition between autocommit
+# transaction and transaction which is rolling back due to
+# deadlock.
+#
+# Test outline:
+# * Trx 1a makes updates
+# * SR trx 1b writes a row 3, then makes updates
+# * AC trx 1c will attempt to write row 3 and will wait for lock
+# held by 1b
+# * Sync point is set for 1b to delay SR rollback
+# * SR trx 1b makes an update which makes it conflict with trx 1a
+# * Slave shows BF - BF conflict and fails in applying write event
+
+--connection node_1
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 VARCHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1, 'x'), (2, 'x'), (4, 'x'), (5, 'x');
+
+# --connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+# --connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+# --connect node_1c, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--connection node_1a
+START TRANSACTION;
+
+UPDATE t1 SET f2 = 'a' WHERE f1 = 1;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 4;
+UPDATE t1 SET f2 = 'a' WHERE f1 = 5;
+
+
+--connection node_1b
+START TRANSACTION;
+SET SESSION wsrep_trx_fragment_size = 1;
+INSERT INTO t1 VALUES (3, 'b');
+UPDATE t1 SET f2 = 'b' WHERE f1 = 2;
+
+--connection node_2
+SELECT * FROM t1;
+
+# Will block, waiting for 1b
+--connection node_1c
+SET AUTOCOMMIT=ON;
+--send INSERT INTO t1 VALUES (3, 'c')
+
+--connection node_2
+SELECT * FROM t1;
+
+# Will block, waiting for 1b
+--connection node_1a
+--send UPDATE t1 SET f2 = 'a' WHERE f1 = 2
+
+# Will deadlock
+--connection node_1b
+SET DEBUG_SYNC = 'wsrep_before_SR_rollback SIGNAL wait WAIT_FOR continue';
+--send UPDATE t1 SET f2 = 'b' WHERE f1 = 1
+
+# Wait until 1b hits rollback
+--connection node_1
+SET DEBUG_SYNC = 'now WAIT_FOR wait';
+
+# UPDATE 12.06.2016: as of recent wsrep API changes, rollbacking thread no
+# longer queues ROLLBACKs and blocks on ROLLBACK replication before performing
+# the actual rollback. As a result this test is moot as both node_1a and node_1c
+# connections are hanging now until sync point is released. Thus sync point
+# release had to be moved above to release the connections. However it is not
+# impossible that further changes in the code may reintroduce the race, so
+# leaving the test as close to original as possible.
+#
+# --connection node_1a
+# --reap
+# COMMIT;
+#
+# --connection node_1c
+# --reap
+#
+# UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+
+--connection node_1
+SET DEBUG_SYNC = 'now SIGNAL continue';
+
+--connection node_1c
+--reap
+
+UPDATE t1 SET f2 = 'x' WHERE f1 = 3;
+
+--connection node_1a
+--reap
+COMMIT;
+
+--connection node_1b
+--error ER_LOCK_DEADLOCK
+--reap
+
+--connection node_1
+SELECT * FROM t1;
+--connection node_2
+SELECT * FROM t1;
+
+--connection node_1
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.test
new file mode 100644
index 00000000000..85d501288b0
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#165.test
@@ -0,0 +1,41 @@
+--source include/galera_cluster.inc
+--source include/have_debug_sync.inc
+
+#
+# This test attempts to catch a race condition between autocommit
+# transaction and transaction which is rolling back due to
+# deadlock.
+#
+# Since it is trying to catch a race condition which may not reliably
+# occur, several runs are necessary for certainty. Hence the body of
+# the test was placed into the .inc file and sourced several times below
+#
+# Test outline:
+# * Trx 1a makes updates
+# * SR trx 1b writes a row 3, then makes updates
+# * AC trx 1c will attempt to write row 3 and will wait for lock
+# held by 1b
+# * Sync point is set for 1b to delay SR rollback
+# * SR trx 1b makes an update which makes it conflict with trx 1a
+# * Slave shows BF - BF conflict and fails in applying write event
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connect node_1c, 127.0.0.1, root, , test, $NODE_MYPORT_1
+
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
+--source mysql-wsrep-features#165.inc
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#22.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#22.test
new file mode 100644
index 00000000000..544109dadee
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#22.test
@@ -0,0 +1,47 @@
+# Assertion `total_length + thd->wsrep_fragment_base == saved_pos' failed in wsrep_write_cache_inc() with ROLLBACK TO SAVEPOINT and SR
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB;
+SET AUTOCOMMIT=OFF;
+SET SESSION wsrep_trx_fragment_size=1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1, 'a');
+INSERT INTO t1 VALUES (2, 'a');
+INSERT INTO t1 VALUES (3, 'a');
+INSERT INTO t1 VALUES (4, 'a');
+INSERT INTO t1 VALUES (5, 'a');
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) = 5 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+SAVEPOINT s1;
+INSERT INTO t1 VALUES (11, 'b');
+INSERT INTO t1 VALUES (12, 'b');
+INSERT INTO t1 VALUES (13, 'b');
+INSERT INTO t1 VALUES (14, 'b');
+INSERT INTO t1 VALUES (15, 'b');
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 10 FROM t1;
+--source include/wait_condition.inc
+
+--connection node_1
+ROLLBACK TO SAVEPOINT s1;
+
+INSERT INTO t1 VALUES (21, 'c');
+
+COMMIT;
+
+--connection node_1
+SELECT COUNT(*) = 6 FROM t1;
+
+
+--connection node_2
+SELECT COUNT(*) = 6 FROM t1;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#27.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#27.test
new file mode 100644
index 00000000000..f9c09391f8f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#27.test
@@ -0,0 +1,29 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_2
+--sleep 2
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+
+--connection node_1
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test
new file mode 100644
index 00000000000..2349fe9979f
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#29.test
@@ -0,0 +1,23 @@
+#
+# mysql-wsrep-features#29 Unwarranted deadlock error with SR and a single-node cluster
+#
+
+SET SESSION wsrep_trx_fragment_size = 1;
+SET SESSION binlog_format = STATEMENT;
+
+create table t1 (id int not null, f_id int not null, f int not null,
+primary key(f_id, id)) engine=innodb;
+
+create table t2 (id int not null,s_id int not null,s varchar(200),
+primary key(id)) engine=innodb;
+
+INSERT INTO t1 VALUES (8, 1, 3);
+INSERT INTO t1 VALUES (1, 2, 1);
+INSERT INTO t2 VALUES (1, 0, '');
+INSERT INTO t2 VALUES (8, 1, '');
+
+DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id)
+WHERE mm.id IS NULL;
+
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#32-master.opt b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#32-master.opt
new file mode 100644
index 00000000000..a6ef074a120
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#32-master.opt
@@ -0,0 +1 @@
+--innodb-lock-wait-timeout=1
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#32.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#32.test
new file mode 100644
index 00000000000..72c7a7b5e82
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#32.test
@@ -0,0 +1,44 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# mysql-wsrep-features#32 Assertion `meta->gtid.seqno == wsrep_thd_trx_seqno(thd)' failed in wsrep_commit_cb with SR
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+--let $wait_condition = SELECT COUNT(*) > 0 FROM t1;
+--source include/wait_condition.inc
+
+SET AUTOCOMMIT=OFF;
+
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (6);
+
+--error ER_LOCK_WAIT_TIMEOUT
+INSERT INTO t1 VALUES (5);
+ROLLBACK;
+
+--connection node_1
+COMMIT;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#35.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#35.test
new file mode 100644
index 00000000000..c5cf1dea0ae
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#35.test
@@ -0,0 +1,48 @@
+--source include/have_debug_sync.inc
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
+
+# Block node #2's applier so that it is able to issue a conflicting INSERT before
+# node #1 INSERTs have been applied on it.
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+SELECT COUNT(*) = 0 FROM t1;
+SET SESSION wsrep_sync_wait = 0;
+SET GLOBAL debug = '+d,sync.wsrep_apply_cb';
+
+--connection node_1
+SET SESSION wsrep_trx_fragment_size = 1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+
+--connection node_2a
+SET SESSION debug_sync = "now WAIT_FOR sync.wsrep_apply_cb_reached";
+
+--connection node_2
+SET SESSION wsrep_sync_wait = 0;
+SELECT COUNT(*) = 0 FROM t1;
+--send INSERT INTO t1 VALUES (1);
+
+--connection node_1
+COMMIT;
+
+--connection node_2a
+SET GLOBAL debug = '';
+SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
+
+--connection node_2
+--error ER_DUP_ENTRY,ER_LOCK_DEADLOCK
+--reap
+ROLLBACK;
+
+DROP TABLE t1;
+
+--connection node_2a
+SET DEBUG_SYNC = "RESET";
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#8.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#8.test
new file mode 100644
index 00000000000..55210386044
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#8.test
@@ -0,0 +1,63 @@
+--source include/big_test.inc
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# InnoDB FULLTEXT indexes
+#
+
+SET SESSION wsrep_trx_fragment_size = 1;
+CREATE TABLE ten (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO ten VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
+
+#
+# Fulltext index creation causes the creation of multiple system tables
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 INT PRIMARY KEY AUTO_INCREMENT, f2 VARCHAR(100), FULLTEXT (f2)) ENGINE=InnoDB;
+
+--connection node_2
+SELECT COUNT(*) = 13 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE name LIKE 'test/%';
+
+#
+# Fulltext insertion causes a flurry of updates on those system tables
+#
+
+--connection node_1
+# Insert 10K rows
+INSERT INTO t1 (f2) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3, ten AS a4;
+
+--connection node_2
+SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('foobarbaz');
+
+UPDATE t1 SET f2 = 'abcdefjhk';
+
+--connection node_1
+SELECT COUNT(f2) = 10000 FROM t1 WHERE MATCH(f2) AGAINST ('abcdefjhk');
+
+--connection node_2
+
+DROP TABLE t1;
+
+#
+# Same on a table with no PK
+#
+
+--connection node_1
+CREATE TABLE t1 (f1 VARCHAR(100), FULLTEXT (f1)) ENGINE=InnoDB;
+
+--connection node_2
+# We insert only 1K rows here, because updates without a PK are very slow
+INSERT INTO t1 (f1) SELECT 'foobarbaz' FROM ten AS a1, ten AS a2, ten AS a3;
+
+--connection node_1
+SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('foobarbaz');
+
+UPDATE t1 SET f1 = 'abcdefjhk';
+
+--connection node_2
+SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('abcdefjhk');
+
+DROP TABLE t1;
+DROP TABLE ten;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#9.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#9.test
new file mode 100644
index 00000000000..cbecf40fadf
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#9.test
@@ -0,0 +1,44 @@
+#
+# mysql-wsrep-features#9 Hang in galera::ReplicatorSMM::cert with Streaming Replication
+# when running the galera_kill_ddl.test test
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+--source include/big_test.inc
+
+--connection node_1
+
+# Enable the master to continue running during the split-brain situation that
+# occurs when the slave is killed
+--let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options`
+SET GLOBAL wsrep_provider_options = 'pc.ignore_sb=true';
+
+SET SESSION wsrep_trx_fragment_size = 1;
+
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+--connection node_2
+--source include/kill_galera.inc
+
+--connection node_1
+ALTER TABLE t1 ADD COLUMN f2 INTEGER;
+
+--connection node_2
+--source include/start_mysqld.inc
+--source include/galera_wait_ready.inc
+
+--let $galera_connection_name = node_2a
+--let $galera_server_number = 2
+--source include/galera_connect.inc
+--connection node_2a
+
+SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1';
+SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
+
+--connection node_1
+--disable_query_log
+--eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig';
+--enable_query_log
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#93.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#93.test
new file mode 100644
index 00000000000..442a7113537
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#93.test
@@ -0,0 +1,29 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+#
+# This test sets a SAVEPOINT at the very beginning
+# of the transaction. When ROLLBACK TO SAVEPOINT is
+# issued, mysql performs a full rollback on SEs that
+# where not part of the transaction.
+# Test that SR transactions are rolled back, and
+# cleaned up properly in this case.
+#
+
+CREATE TABLE t1 (f1 INTEGER);
+SET SESSION WSREP_TRX_FRAGMENT_SIZE=1;
+
+START TRANSACTION;
+
+SAVEPOINT a;
+INSERT INTO t1 VALUES (1);
+ROLLBACK TO SAVEPOINT a;
+
+INSERT INTO t1 values (2);
+COMMIT;
+
+SELECT COUNT(*) = 0 from mysql.wsrep_streaming_log;
+--connection node_2
+SELECT COUNT(*) = 0 from mysql.wsrep_streaming_log;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/galera_sr/t/mysql-wsrep-features#96.test b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#96.test
new file mode 100644
index 00000000000..c773b310183
--- /dev/null
+++ b/mysql-test/suite/galera_sr/t/mysql-wsrep-features#96.test
@@ -0,0 +1,45 @@
+# mysql-wsrep-features#96 - "Sanity check failed" with SR and statement rolled back due to error
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+
+--connection node_1
+
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY);
+CREATE TABLE t2 (f2 VARCHAR(32));
+
+SET SESSION wsrep_trx_fragment_size=1;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+
+# This statement causes full transaction rollback
+# rather than just statement rollback, as it is run under SR
+
+--error ER_LOCK_DEADLOCK
+INSERT INTO t1 VALUES (2),(1);
+INSERT INTO t2 VALUES ('abc');
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 1 FROM t2;
+
+--connection node_1
+ROLLBACK;
+
+--connection node_2
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+
+SELECT COUNT(*) = 0 FROM t1;
+SELECT COUNT(*) = 0 FROM t2;
+
+--connection node_1
+DROP TABLE t1;
+DROP TABLE t2;
+
+
+
+
diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
index db932ae8223..ac83a0a8c7f 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result
@@ -211,6 +211,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME WSREP_IGNORE_APPLY_ERRORS
+SESSION_VALUE NULL
+GLOBAL_VALUE 7
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE 7
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE INT UNSIGNED
+VARIABLE_COMMENT Ignore replication errors
+NUMERIC_MIN_VALUE 0
+NUMERIC_MAX_VALUE 7
+NUMERIC_BLOCK_SIZE 1
+ENUM_VALUE_LIST NULL
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME WSREP_LOAD_DATA_SPLITTING
SESSION_VALUE NULL
GLOBAL_VALUE ON
@@ -218,7 +232,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE ON
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN
-VARIABLE_COMMENT To commit LOAD DATA transaction after every 10K rows inserted
+VARIABLE_COMMENT To commit LOAD DATA transaction after every 10K rows inserted (deprecating)
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
@@ -519,6 +533,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME WSREP_SR_STORE
+SESSION_VALUE NULL
+GLOBAL_VALUE table
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE table
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE ENUM
+VARIABLE_COMMENT Storage for streaming replication fragments
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST none,table
+READ_ONLY YES
+COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME WSREP_SST_AUTH
SESSION_VALUE NULL
GLOBAL_VALUE
@@ -617,3 +645,31 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME WSREP_TRX_FRAGMENT_SIZE
+SESSION_VALUE 0
+GLOBAL_VALUE 0
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE 0
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_COMMENT Size of transaction fragments for streaming replication (measured in units of 'wsrep_trx_fragment_unit')
+NUMERIC_MIN_VALUE 0
+NUMERIC_MAX_VALUE 2147483647
+NUMERIC_BLOCK_SIZE 1
+ENUM_VALUE_LIST NULL
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
+VARIABLE_NAME WSREP_TRX_FRAGMENT_UNIT
+SESSION_VALUE bytes
+GLOBAL_VALUE bytes
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE bytes
+VARIABLE_SCOPE SESSION
+VARIABLE_TYPE ENUM
+VARIABLE_COMMENT Unit for streaming replication transaction fragments' size: bytes, rows, statements
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST bytes,rows,statements
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
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
index b2e07c55b38..15949a14e39 100644
--- a/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result
+++ b/mysql-test/suite/sys_vars/r/wsrep_provider_options_basic.result
@@ -2,9 +2,6 @@
# wsrep_provider_options
#
call mtr.add_suppression("WSREP: Failed to get provider options");
-SET @@global.wsrep_provider = @@global.wsrep_provider;
-# save the initial value
-SET @wsrep_provider_options_global_saved = @@global.wsrep_provider_options;
# default
SELECT @@global.wsrep_provider_options;
@@global.wsrep_provider_options
@@ -16,18 +13,21 @@ 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';
+ERROR HY000: WSREP (galera) not started
SELECT @@global.wsrep_provider_options;
@@global.wsrep_provider_options
-name1=value1;name2=value2
+
SET @@global.wsrep_provider_options='hyphenated-name:value';
+ERROR HY000: WSREP (galera) not started
SELECT @@global.wsrep_provider_options;
@@global.wsrep_provider_options
-hyphenated-name:value
+
SET @@global.wsrep_provider_options=default;
+ERROR HY000: WSREP (galera) not started
SELECT @@global.wsrep_provider_options;
@@global.wsrep_provider_options
@@ -42,8 +42,5 @@ SET @@global.wsrep_provider_options=NULL;
Got one of the listed errors
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/t/wsrep_provider_options_basic.test b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test
index d2ea32a0637..6eb3a94b6a4 100644
--- a/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test
+++ b/mysql-test/suite/sys_vars/t/wsrep_provider_options_basic.test
@@ -6,11 +6,6 @@
call mtr.add_suppression("WSREP: Failed to get provider options");
-SET @@global.wsrep_provider = @@global.wsrep_provider;
-
---echo # save the initial value
-SET @wsrep_provider_options_global_saved = @@global.wsrep_provider_options;
-
--echo # default
SELECT @@global.wsrep_provider_options;
@@ -24,13 +19,13 @@ SELECT @@global.wsrep_provider_options;
--echo
--echo # valid values
---error 0,ER_WRONG_ARGUMENTS
+--error ER_WRONG_ARGUMENTS
SET @@global.wsrep_provider_options='name1=value1;name2=value2';
SELECT @@global.wsrep_provider_options;
---error 0,ER_WRONG_ARGUMENTS
+--error ER_WRONG_ARGUMENTS
SET @@global.wsrep_provider_options='hyphenated-name:value';
SELECT @@global.wsrep_provider_options;
---error 0,ER_WRONG_ARGUMENTS
+--error ER_WRONG_ARGUMENTS
SET @@global.wsrep_provider_options=default;
SELECT @@global.wsrep_provider_options;
@@ -43,9 +38,4 @@ SELECT @@global.wsrep_provider_options;
SET @@global.wsrep_provider_options=NULL;
SELECT @@global.wsrep_provider_options;
---echo
---echo # restore the initial value
---error 0,ER_WRONG_ARGUMENTS
-SET @@global.wsrep_provider_options = @wsrep_provider_options_global_saved;
-
--echo # End of test
diff --git a/mysql-test/suite/wsrep/disabled.def b/mysql-test/suite/wsrep/disabled.def
index 24d46cc39f0..61142398372 100644
--- a/mysql-test/suite/wsrep/disabled.def
+++ b/mysql-test/suite/wsrep/disabled.def
@@ -1,2 +1,3 @@
wsrep.foreign_key : Sporadic failure "WSREP has not yet prepared node for application use"
wsrep.pool_of_threads : Sporadic failure "WSREP has not yet prepared node for application use"
+wsrep.variables : Global wsrep_on manipulation causes debug asserts
diff --git a/mysql-test/suite/wsrep/my.cnf b/mysql-test/suite/wsrep/my.cnf
index 7e51b0750a1..e90686850a9 100644
--- a/mysql-test/suite/wsrep/my.cnf
+++ b/mysql-test/suite/wsrep/my.cnf
@@ -1,10 +1,8 @@
# Use default setting for mysqld processes
!include include/default_mysqld.cnf
-[mysqld]
-wsrep-on=1
-
[mysqld.1]
+wsrep-on=OFF
#galera_port=@OPT.port
#ist_port=@OPT.port
#sst_port=@OPT.port
diff --git a/mysql-test/suite/wsrep/r/wsrep-recover,binlogon.rdiff b/mysql-test/suite/wsrep/r/wsrep-recover,binlogon.rdiff
new file mode 100644
index 00000000000..8b1b1e4c035
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/wsrep-recover,binlogon.rdiff
@@ -0,0 +1,28 @@
+--- r/wsrep-recover.result 2019-01-11 16:22:46.329012579 +0200
++++ r/wsrep-recover.reject 2019-01-11 16:23:55.313137675 +0200
+@@ -48,19 +48,17 @@
+ SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_1";
+ connection default;
+ # Kill the server
+-Expect seqno 9
+-9
++Expect seqno 7
++7
+ disconnect con1;
+ disconnect con2;
+ disconnect con_ctrl;
+ connection default;
+-SELECT VARIABLE_VALUE `expect 10` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+-expect 10
+-10
+-Expect rows 5, 9, 10
++SELECT VARIABLE_VALUE `expect 8` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
++expect 8
++8
++Expect row 5
+ SELECT * FROM t1;
+ f1
+ 5
+-9
+-10
+ DROP TABLE t1;
diff --git a/mysql-test/suite/wsrep/r/wsrep-recover.result b/mysql-test/suite/wsrep/r/wsrep-recover.result
new file mode 100644
index 00000000000..10ad4e58fc5
--- /dev/null
+++ b/mysql-test/suite/wsrep/r/wsrep-recover.result
@@ -0,0 +1,66 @@
+# Kill the server
+Expect seqno 1
+1
+CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
+# Kill the server
+Expect seqno 3
+3
+INSERT INTO t1 VALUES (5);
+# Kill the server
+Expect seqno 5
+5
+SELECT VARIABLE_VALUE `expect 6` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+expect 6
+6
+connect con1, localhost, root;
+SET DEBUG_SYNC = "wsrep_after_certification SIGNAL after_certification_reached WAIT_FOR continue";
+INSERT INTO t1 VALUES (7);
+connect con_ctrl, localhost, root;
+SET DEBUG_SYNC = "now WAIT_FOR after_certification_reached";
+connect con2, localhost, root;
+SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached WAIT_FOR continue";
+INSERT INTO t1 VALUES (8);
+connection con_ctrl;
+SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached";
+connection default;
+# Kill the server
+Expect seqno 6
+6
+disconnect con1;
+disconnect con2;
+disconnect con_ctrl;
+connection default;
+SELECT VARIABLE_VALUE `expect 7` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+expect 7
+7
+connect con1, localhost, root;
+SET DEBUG_SYNC = "wsrep_after_certification SIGNAL after_certification_reached WAIT_FOR continue_after_certification";
+SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_1 WAIT_FOR continue_before_commit_order_1";
+INSERT INTO t1 VALUES (9);
+connect con_ctrl, localhost, root;
+SET DEBUG_SYNC = "now WAIT_FOR after_certification_reached";
+connect con2, localhost, root;
+SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_2 WAIT_FOR continue_before_commit_order_2";
+INSERT INTO t1 VALUES (10);
+connection con_ctrl;
+SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_2";
+SET DEBUG_SYNC = "now SIGNAL continue_after_certification";
+SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_1";
+connection default;
+# Kill the server
+Expect seqno 9
+9
+disconnect con1;
+disconnect con2;
+disconnect con_ctrl;
+connection default;
+SELECT VARIABLE_VALUE `expect 10` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+expect 10
+10
+Expect rows 5, 9, 10
+SELECT * FROM t1;
+f1
+5
+9
+10
+DROP TABLE t1;
diff --git a/mysql-test/suite/wsrep/suite.pm b/mysql-test/suite/wsrep/suite.pm
index 03e23b8d7cb..fbaf5aa2b22 100644
--- a/mysql-test/suite/wsrep/suite.pm
+++ b/mysql-test/suite/wsrep/suite.pm
@@ -9,9 +9,9 @@ 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/lib64/galera-3/libgalera_smm.so",
+ "/usr/lib64/galera-4/libgalera_smm.so",
"/usr/lib64/galera/libgalera_smm.so",
- "/usr/lib/galera-3/libgalera_smm.so",
+ "/usr/lib/galera-4/libgalera_smm.so",
"/usr/lib/galera/libgalera_smm.so";
return "No wsrep provider library" unless -f $provider;
diff --git a/mysql-test/suite/wsrep/t/binlog_format.cnf b/mysql-test/suite/wsrep/t/binlog_format.cnf
new file mode 100644
index 00000000000..7ec24c14d80
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/binlog_format.cnf
@@ -0,0 +1,8 @@
+!include ../my.cnf
+
+[mysqld.1]
+wsrep-on=ON
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep-cluster-address=gcomm://
+innodb_autoinc_lock_mode=2
+
diff --git a/mysql-test/suite/wsrep/t/binlog_format.opt b/mysql-test/suite/wsrep/t/binlog_format.opt
deleted file mode 100644
index e3f2470c6e5..00000000000
--- a/mysql-test/suite/wsrep/t/binlog_format.opt
+++ /dev/null
@@ -1 +0,0 @@
---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
index 07001b17a84..695859a2ad3 100644
--- a/mysql-test/suite/wsrep/t/binlog_format.test
+++ b/mysql-test/suite/wsrep/t/binlog_format.test
@@ -1,3 +1,4 @@
+--source include/have_innodb.inc
--source include/have_wsrep_provider.inc
--source include/have_binlog_format_row.inc
diff --git a/mysql-test/suite/wsrep/t/mdev_10186.cnf b/mysql-test/suite/wsrep/t/mdev_10186.cnf
new file mode 100644
index 00000000000..3c4ca003f76
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_10186.cnf
@@ -0,0 +1,6 @@
+!include ../my.cnf
+
+[mysqld.1]
+wsrep-on=OFF
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep-cluster-address=gcomm://
diff --git a/mysql-test/suite/wsrep/t/mdev_10186.opt b/mysql-test/suite/wsrep/t/mdev_10186.opt
deleted file mode 100644
index e2655959c62..00000000000
--- a/mysql-test/suite/wsrep/t/mdev_10186.opt
+++ /dev/null
@@ -1 +0,0 @@
---wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep-on=0
diff --git a/mysql-test/suite/wsrep/t/mdev_10186.test b/mysql-test/suite/wsrep/t/mdev_10186.test
index 98ea5192634..f86c69f8a5b 100644
--- a/mysql-test/suite/wsrep/t/mdev_10186.test
+++ b/mysql-test/suite/wsrep/t/mdev_10186.test
@@ -1,3 +1,4 @@
+--source include/have_innodb.inc
--source include/have_wsrep_provider.inc
--source include/have_binlog_format_row.inc
diff --git a/mysql-test/suite/wsrep/t/mdev_6832.cnf b/mysql-test/suite/wsrep/t/mdev_6832.cnf
new file mode 100644
index 00000000000..0bf01f81fc5
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_6832.cnf
@@ -0,0 +1,7 @@
+!include ../my.cnf
+
+[mysqld.1]
+wsrep-on=ON
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep-cluster-address=gcomm://
+
diff --git a/mysql-test/suite/wsrep/t/mdev_6832.opt b/mysql-test/suite/wsrep/t/mdev_6832.opt
deleted file mode 100644
index 16f8962dba2..00000000000
--- a/mysql-test/suite/wsrep/t/mdev_6832.opt
+++ /dev/null
@@ -1 +0,0 @@
---wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep-on=1
diff --git a/mysql-test/suite/wsrep/t/mdev_6832.test b/mysql-test/suite/wsrep/t/mdev_6832.test
index 9efccface57..226be1b788c 100644
--- a/mysql-test/suite/wsrep/t/mdev_6832.test
+++ b/mysql-test/suite/wsrep/t/mdev_6832.test
@@ -1,3 +1,4 @@
+--source include/have_innodb.inc
--source include/have_wsrep_provider.inc
--source include/have_binlog_format_row.inc
diff --git a/mysql-test/suite/wsrep/t/mdev_7798.cnf b/mysql-test/suite/wsrep/t/mdev_7798.cnf
new file mode 100644
index 00000000000..0bf01f81fc5
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/mdev_7798.cnf
@@ -0,0 +1,7 @@
+!include ../my.cnf
+
+[mysqld.1]
+wsrep-on=ON
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep-cluster-address=gcomm://
+
diff --git a/mysql-test/suite/wsrep/t/mdev_7798.opt b/mysql-test/suite/wsrep/t/mdev_7798.opt
deleted file mode 100644
index 1007d5c0b78..00000000000
--- a/mysql-test/suite/wsrep/t/mdev_7798.opt
+++ /dev/null
@@ -1 +0,0 @@
---wsrep-provider=$WSREP_PROVIDER --wsrep-cluster-address=gcomm:// --wsrep-on=1
diff --git a/mysql-test/suite/wsrep/t/mdev_7798.test b/mysql-test/suite/wsrep/t/mdev_7798.test
index 9dfff0959bc..b9938d936cc 100644
--- a/mysql-test/suite/wsrep/t/mdev_7798.test
+++ b/mysql-test/suite/wsrep/t/mdev_7798.test
@@ -1,3 +1,4 @@
+--source include/have_innodb.inc
--source include/have_wsrep_provider.inc
--source include/have_binlog_format_row.inc
diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.cnf b/mysql-test/suite/wsrep/t/pool_of_threads.cnf
new file mode 100644
index 00000000000..b63e3324796
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/pool_of_threads.cnf
@@ -0,0 +1,8 @@
+!include ../my.cnf
+
+[mysqld.1]
+wsrep-on=ON
+wsrep-provider=@ENV.WSREP_PROVIDER
+wsrep-cluster-address=gcomm://
+thread_handling=pool-of-threads
+
diff --git a/mysql-test/suite/wsrep/t/pool_of_threads.opt b/mysql-test/suite/wsrep/t/pool_of_threads.opt
deleted file mode 100644
index 814417e5b0f..00000000000
--- a/mysql-test/suite/wsrep/t/pool_of_threads.opt
+++ /dev/null
@@ -1 +0,0 @@
---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/wsrep-recover-step.inc b/mysql-test/suite/wsrep/t/wsrep-recover-step.inc
new file mode 100644
index 00000000000..22669438fe0
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/wsrep-recover-step.inc
@@ -0,0 +1,41 @@
+#
+# Macro to run wsrep recovery step. This is adapted from
+# suite/galera/include/galera_wsrep_recover.inc, with additional
+# option to pass binlog argument to recovery command. The macro
+# returns recovered position split in uuid and seqno parts.
+#
+# Arguments:
+#
+# wsrep_recover_binlog_opt - Binlog options to recovery command
+#
+# Return:
+#
+# wsrep_recover_start_position_uuid - UUID corresponding to recovered position
+# wsrep_recover_start_position_seqno - seqno corresponding to recovered position
+#
+
+--exec $MYSQLD --defaults-group-suffix=.1 --defaults-file=$MYSQLTEST_VARDIR/my.cnf --log-error=$MYSQL_TMP_DIR/galera_wsrep_recover.log --innodb --wsrep-recover $wsrep_recover_binlog_opt --core-file > $MYSQL_TMP_DIR/galera_wsrep_recover.log 2>&1
+
+--perl
+ use strict;
+ my $wsrep_start_position = `grep 'WSREP: Recovered position:' $ENV{MYSQL_TMP_DIR}/galera_wsrep_recover.log | sed 's/.*WSREP\:\ Recovered\ position://' | sed 's/^[ \t]*//'`;
+ chomp($wsrep_start_position);
+ die if $wsrep_start_position eq '';
+ open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/galera_wsrep_start_position.inc") or die;
+ my ($uuid, $seqno) = split /:/, $wsrep_start_position;
+ print FILE "--let \$wsrep_recover_start_position_uuid = $uuid\n";
+ print FILE "--let \$wsrep_recover_start_position_seqno = $seqno\n";
+ close FILE;
+EOF
+
+--source $MYSQL_TMP_DIR/galera_wsrep_start_position.inc
+
+if ($wsrep_recover_start_position_uuid == '') {
+ --die "Could not obtain start_position_uuid."
+}
+
+if ($wsrep_recover_start_position_seqno == '') {
+ --die "Could not obtain start_position_seqno."
+}
+
+--remove_file $MYSQL_TMP_DIR/galera_wsrep_start_position.inc
diff --git a/mysql-test/suite/wsrep/t/wsrep-recover.cnf b/mysql-test/suite/wsrep/t/wsrep-recover.cnf
new file mode 100644
index 00000000000..19986cd97bc
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/wsrep-recover.cnf
@@ -0,0 +1,9 @@
+!include ../my.cnf
+
+[mysqld.1]
+wsrep-on=ON
+binlog-format=ROW
+innodb-flush-log-at-trx-commit=1
+wsrep-cluster-address=gcomm://
+wsrep-provider=@ENV.WSREP_PROVIDER
+innodb-autoinc-lock-mode=2 \ No newline at end of file
diff --git a/mysql-test/suite/wsrep/t/wsrep-recover.combinations b/mysql-test/suite/wsrep/t/wsrep-recover.combinations
new file mode 100644
index 00000000000..1ce3b45aa1a
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/wsrep-recover.combinations
@@ -0,0 +1,4 @@
+[binlogon]
+log-bin
+
+[binlogoff]
diff --git a/mysql-test/suite/wsrep/t/wsrep-recover.test b/mysql-test/suite/wsrep/t/wsrep-recover.test
new file mode 100644
index 00000000000..8f00f19c27f
--- /dev/null
+++ b/mysql-test/suite/wsrep/t/wsrep-recover.test
@@ -0,0 +1,204 @@
+#
+# Verify that the wsrep XID gets updated in InnoDB rollback segment
+# properly and can be recovered with --wsrep-recover
+#
+# The test runs the following scenarios:
+#
+# 1) The server is started but no SQL is run
+# 2) DDL is executed
+# 3) INSERT is executed
+# 4) Two INSERTs are executed so that the first one in order will be
+# blocked after certification and the second one before entering
+# commit order critical section.
+# 5) Two DMLs are executed so that the prepare step is run out of order.
+# Both transactions are blocked before commit order critical section.
+#
+# After each scenario server is killed and the recovered position
+# is validated.
+#
+
+--source include/have_wsrep.inc
+--source include/have_innodb.inc
+--source include/have_wsrep_provider.inc
+--source include/have_debug_sync.inc
+
+#
+# Binlog option for recovery run. This must be set in the test because
+# combinations file causes log-bin option to be set from command line,
+# not via my.cnf.
+#
+--let $log_bin = `SELECT @@log_bin`
+if ($log_bin) {
+--let $wsrep_recover_binlog_opt = --log-bin
+}
+
+#
+# Scenario 1
+# The expected recovered seqno is 1 corresponding to initial cluster
+# configuration change.
+#
+--source include/kill_mysqld.inc
+--source wsrep-recover-step.inc
+--echo Expect seqno 1
+--echo $wsrep_recover_start_position_seqno
+
+--let $restart_parameters = --wsrep-start-position=$wsrep_recover_start_position_uuid:$wsrep_recover_start_position_seqno
+--source include/start_mysqld.inc
+--source include/wait_wsrep_ready.inc
+
+#
+# Senario 2
+# The expected recovered seqno is 3 corresponding to two configuration
+# change events and CREATE TABLE.
+#
+
+CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
+--source include/kill_mysqld.inc
+--source wsrep-recover-step.inc
+--echo Expect seqno 3
+--echo $wsrep_recover_start_position_seqno
+
+--let $restart_parameters = --wsrep-start-position=$wsrep_recover_start_position_uuid:$wsrep_recover_start_position_seqno
+--source include/start_mysqld.inc
+--source include/wait_wsrep_ready.inc
+
+#
+# Scenario 3
+# The expected recovered seqno is 5 corresponding to three configuration
+# change events, CREATE TABLE and INSERT.
+#
+# The expected wsrep_last_committed after the server is restarted is 6.
+#
+
+INSERT INTO t1 VALUES (5);
+--source include/kill_mysqld.inc
+--source wsrep-recover-step.inc
+--echo Expect seqno 5
+--echo $wsrep_recover_start_position_seqno
+--let $restart_parameters = --wsrep-start-position=$wsrep_recover_start_position_uuid:$wsrep_recover_start_position_seqno
+--source include/start_mysqld.inc
+--source include/wait_wsrep_ready.inc
+
+SELECT VARIABLE_VALUE `expect 6` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+
+#
+# Scenario 4
+#
+# This will cause the following
+#
+# Seqno 7 - the first INSERT is blocked after it is certified but before
+# it gets prepared
+# Seqno 8 - the second INSERT is blocked before it will be ordered for
+# commit, so it becomes prepared
+#
+# As an outcome, the recovery process should return seqno 6 because
+# the range of prepared transactions found after the crash recovery
+# is not continuous up to 8.
+#
+# The expected wsrep_last_committed after server is restarted is 7.
+#
+
+# Send INSERT which will block after certification
+--connect con1, localhost, root
+SET DEBUG_SYNC = "wsrep_after_certification SIGNAL after_certification_reached WAIT_FOR continue";
+--send INSERT INTO t1 VALUES (7)
+
+--connect con_ctrl, localhost, root
+SET DEBUG_SYNC = "now WAIT_FOR after_certification_reached";
+
+# Send INSERT which will block before commit order critical section
+--connect con2, localhost, root
+SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached WAIT_FOR continue";
+--send INSERT INTO t1 VALUES (8)
+
+--connection con_ctrl
+SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached";
+
+--connection default
+--source include/kill_mysqld.inc
+--source wsrep-recover-step.inc
+--echo Expect seqno 6
+--echo $wsrep_recover_start_position_seqno
+--let $restart_parameters = --wsrep-start-position=$wsrep_recover_start_position_uuid:$wsrep_recover_start_position_seqno
+--source include/start_mysqld.inc
+--source include/wait_wsrep_ready.inc
+
+--disconnect con1
+--disconnect con2
+--disconnect con_ctrl
+--connection default
+
+SELECT VARIABLE_VALUE `expect 7` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+
+#
+# Scenario 5
+#
+# This scenario will run two INSERTs in parallel so that they are
+# prepared out of order. The execution is stopped before commit
+# and the server is killed. The outcome of this scenario depends
+# on binlog settings:
+#
+# If binlog is off, the transactions will be recovered from InnoDB and
+# committed during recovery. The expected recovered seqno is 9, the
+# expected wsrep_last_committed after server is restarted is 10.
+#
+# If binlog is on, the transactions will be recovered from InnoDB but
+# will be rolled back since they are not logged yet in binlog. The
+# expected recovered seqno is 7, the expected wsrep_last_committed
+# after server is restarted is 8.
+#
+
+--connect con1, localhost, root
+SET DEBUG_SYNC = "wsrep_after_certification SIGNAL after_certification_reached WAIT_FOR continue_after_certification";
+SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_1 WAIT_FOR continue_before_commit_order_1";
+--send INSERT INTO t1 VALUES (9)
+
+--connect con_ctrl, localhost, root
+SET DEBUG_SYNC = "now WAIT_FOR after_certification_reached";
+
+--connect con2, localhost, root
+SET DEBUG_SYNC = "wsrep_before_commit_order_enter SIGNAL before_commit_order_reached_2 WAIT_FOR continue_before_commit_order_2";
+--send INSERT INTO t1 VALUES (10)
+
+--connection con_ctrl
+SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_2";
+SET DEBUG_SYNC = "now SIGNAL continue_after_certification";
+SET DEBUG_SYNC = "now WAIT_FOR before_commit_order_reached_1";
+
+--connection default
+--source include/kill_mysqld.inc
+--source wsrep-recover-step.inc
+if ($log_bin) {
+ --echo Expect seqno 7
+}
+if (!$log_bin) {
+ --echo Expect seqno 9
+}
+--echo $wsrep_recover_start_position_seqno
+--let $restart_parameters = --wsrep-start-position=$wsrep_recover_start_position_uuid:$wsrep_recover_start_position_seqno
+--source include/start_mysqld.inc
+--source include/wait_wsrep_ready.inc
+
+--disconnect con1
+--disconnect con2
+--disconnect con_ctrl
+--connection default
+
+if ($log_bin) {
+ SELECT VARIABLE_VALUE `expect 8` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+}
+if (!$log_bin) {
+ SELECT VARIABLE_VALUE `expect 10` FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_last_committed';
+}
+
+#
+# Final sanity check: The successful inserts into t1 should result
+if ($log_bin) {
+ --echo Expect row 5
+}
+if (!$log_bin) {
+ --echo Expect rows 5, 9, 10
+}
+SELECT * FROM t1;
+
+DROP TABLE t1;
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
index 70682178ca1..1c7a8ad4122 100644
--- a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
@@ -2,23 +2,26 @@
!include include/default_mysqld.cnf
[mysqld]
-wsrep-on=1
binlog-format=row
innodb-autoinc-lock-mode=2
innodb-locks-unsafe-for-binlog=1
-wsrep-cluster-address=gcomm://
wsrep_provider=@ENV.WSREP_PROVIDER
[mysqld.1]
#galera_port=@OPT.port
+#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
+wsrep-cluster-address=gcomm://
wsrep_provider_options='base_port=@mysqld.1.#galera_port'
wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
wsrep_node_name=test-node-1
[mysqld.2]
#galera_port=@OPT.port
+#ist_port=@OPT.port
#sst_port=@OPT.port
+wsrep-on=1
wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
wsrep_provider_options='base_port=@mysqld.2.#galera_port'
wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
index f33a628d428..f99f27f3539 100644
--- a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
@@ -1,8 +1,10 @@
+connection node_2;
+connection node_1;
# On node 1
connection node_1;
SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
-NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID GAP PROTOCOL_VERSION
-<IDX> Synced Primary 2 <CLUSTER_STATE_UUID> 0 <CLUSTER_CONF_ID> NO 3
+NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID PROTOCOL_VERSION
+<IDX> synced primary 2 <CLUSTER_STATE_UUID> 2 <CLUSTER_CONF_ID> 4
SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
INDEX UUID NAME ADDRESS
<IDX> <MEMBER_ID> test-node-1 <ADDRESS>
@@ -10,8 +12,8 @@ INDEX UUID NAME ADDRESS
# On node 2
connection node_2;
SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
-NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID GAP PROTOCOL_VERSION
-<IDX> Synced Primary 2 <CLUSTER_STATE_UUID> 0 <CLUSTER_CONF_ID> YES 3
+NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID PROTOCOL_VERSION
+<IDX> synced primary 2 <CLUSTER_STATE_UUID> 2 <CLUSTER_CONF_ID> 4
SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
INDEX UUID NAME ADDRESS
<IDX> <MEMBER_ID> test-node-1 <ADDRESS>
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
index 9268cb3e06b..2adc6811f3f 100644
--- a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
@@ -9,9 +9,9 @@ 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/lib64/galera-3/libgalera_smm.so",
+ "/usr/lib64/galera-4/libgalera_smm.so",
"/usr/lib64/galera/libgalera_smm.so",
- "/usr/lib/galera-3/libgalera_smm.so",
+ "/usr/lib/galera-4/libgalera_smm.so",
"/usr/lib/galera/libgalera_smm.so";
return "No wsrep provider library" unless -f $provider;
diff --git a/plugin/wsrep_info/plugin.cc b/plugin/wsrep_info/plugin.cc
index 428bcc5dcfc..18e41b20c98 100644
--- a/plugin/wsrep_info/plugin.cc
+++ b/plugin/wsrep_info/plugin.cc
@@ -52,37 +52,9 @@
#define COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO 5
/* Cluster membership changes */
#define COLUMN_WSREP_STATUS_CLUSTER_CONF_ID 6
-/* Gap between global and local states ? */
-#define COLUMN_WSREP_STATUS_GAP 7
/* Application protocol version */
-#define COLUMN_WSREP_STATUS_PROTO_VERSION 8
+#define COLUMN_WSREP_STATUS_PROTO_VERSION 7
-static const char* get_member_status(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";
- case WSREP_MEMBER_ERROR: return "Error";
- default: break;
- }
- return "UNKNOWN";
-}
-
-static const char* get_cluster_status(wsrep_view_status_t status)
-{
- switch (status)
- {
- case WSREP_VIEW_PRIMARY: return "Primary";
- case WSREP_VIEW_NON_PRIMARY: return "Non-primary";
- case WSREP_VIEW_DISCONNECTED: return "Disconnected";
- default: break;
- }
- return "UNKNOWN";
-}
static ST_FIELD_INFO wsrep_memb_fields[]=
{
@@ -107,7 +79,6 @@ static ST_FIELD_INFO wsrep_status_fields[]=
0, 0, 0, 0},
{"CLUSTER_CONF_ID", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
0, 0, 0, 0},
- {"GAP", 10, MYSQL_TYPE_STRING, 0, 0, 0, 0},
{"PROTOCOL_VERSION", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG,
0, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
@@ -122,25 +93,26 @@ static int wsrep_memb_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
wsrep_config_state->lock();
- Dynamic_array<wsrep_member_info_t> *memb_arr=
- wsrep_config_state->get_member_info();
+ const wsrep::view& view(wsrep_config_state->get_view_info());
+ const std::vector<wsrep::view::member>& members(view.members());
+
TABLE *table= tables->table;
- for (unsigned int i= 0; i < memb_arr->elements(); i ++)
+ for (unsigned int i= 0; i < members.size(); i++)
{
- wsrep_member_info_t memb= memb_arr->at(i);
-
table->field[COLUMN_WSREP_MEMB_INDEX]->store(i, 0);
- char uuid[40];
- wsrep_uuid_print(&memb.id, uuid, sizeof(uuid));
- table->field[COLUMN_WSREP_MEMB_UUID]->store(uuid, sizeof(uuid),
+ std::ostringstream os;
+ os << members[i].id();
+ table->field[COLUMN_WSREP_MEMB_UUID]->store(os.str().c_str(),
+ os.str().length(),
system_charset_info);
- table->field[COLUMN_WSREP_MEMB_NAME]->store(memb.name, strlen(memb.name),
+ table->field[COLUMN_WSREP_MEMB_NAME]->store(members[i].name().c_str(),
+ members[i].name().length(),
system_charset_info);
- table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(memb.incoming,
- strlen(memb.incoming),
+ table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(members[i].incoming().c_str(),
+ members[i].incoming().length(),
system_charset_info);
if (schema_table_store_record(thd, table))
@@ -177,35 +149,34 @@ static int wsrep_status_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
wsrep_config_state->lock();
- wsrep_view_info_t view= wsrep_config_state->get_view_info();
- wsrep_member_status_t status= wsrep_config_state->get_status();
+ const wsrep::view& view= wsrep_config_state->get_view_info();
+ enum wsrep::server_state::state status= wsrep_config_state->get_status();
TABLE *table= tables->table;
table->field[COLUMN_WSREP_STATUS_NODE_INDEX]
- ->store(view.my_idx, 0);
+ ->store(view.own_index(), 0);
table->field[COLUMN_WSREP_STATUS_NODE_STATUS]
- ->store(get_member_status(status), strlen(get_member_status(status)),
+ ->store(to_c_string(status),
+ strlen(to_c_string(status)),
system_charset_info);
table->field[COLUMN_WSREP_STATUS_CLUSTER_STATUS]
- ->store(get_cluster_status(view.status),
- strlen(get_cluster_status(view.status)),
+ ->store(to_c_string(view.status()),
+ strlen(to_c_string(view.status())),
system_charset_info);
- table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.memb_num, 0);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.members().size(), 0);
- char uuid[40];
- wsrep_uuid_print(&view.state_id.uuid, uuid, sizeof(uuid));
+ std::ostringstream os;
+ os << view.state_id().id();
table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID]
- ->store(uuid, sizeof(uuid), system_charset_info);
+ ->store(os.str().c_str(), os.str().length(), system_charset_info);
table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO]
- ->store(view.state_id.seqno, 0);
- table->field[COLUMN_WSREP_STATUS_CLUSTER_CONF_ID]->store(view.view, 0);
-
- const char *gap= (view.state_gap == true) ? "YES" : "NO";
- table->field[COLUMN_WSREP_STATUS_GAP]->store(gap, strlen(gap),
- system_charset_info);
- table->field[COLUMN_WSREP_STATUS_PROTO_VERSION]->store(view.proto_ver, 0);
+ ->store(view.state_id().seqno().get(), 0);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_CONF_ID]
+ ->store(view.view_seqno().get(), 0);
+ table->field[COLUMN_WSREP_STATUS_PROTO_VERSION]
+ ->store(view.protocol_version(), 0);
if (schema_table_store_record(thd, table))
rc= 1;
diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh
index 5797bdc68d7..5f09ac3c235 100644
--- a/scripts/mysqld_safe.sh
+++ b/scripts/mysqld_safe.sh
@@ -265,7 +265,16 @@ wsrep_recover_position() {
wsrep_start_position_opt="--wsrep_start_position=$start_pos"
fi
- [ $ret -eq 0 ] && rm $wr_logfile
+ if [ $ret -eq 0 ] ; then
+ local wr_logfile_permanent="$DATADIR/wsrep_recovery.ok"
+ else
+ local wr_logfile_permanent="$DATADIR/wsrep_recovery.fail"
+ fi
+ touch $wr_logfile_permanent
+ [ "$euid" = "0" ] && chown $user $wr_logfile_permanent
+ chmod 600 $wr_logfile_permanent
+ cat "$wr_logfile" >> $wr_logfile_permanent
+ rm -f "$wr_logfile"
return $ret
}
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh
index 5683b166163..321826b1975 100755
--- a/scripts/wsrep_sst_common.sh
+++ b/scripts/wsrep_sst_common.sh
@@ -50,7 +50,7 @@ case "$1" in
readonly WSREP_SST_OPT_HOST_UNESCAPED=$WSREP_SST_OPT_HOST
;;
esac
- remain=${WSREP_SST_OPT_ADDR#${WSREP_SST_OPT_HOST}}
+ remain=${WSREP_SST_OPT_ADDR#"${WSREP_SST_OPT_HOST}"}
remain=${remain#:}
readonly WSREP_SST_OPT_ADDR_PORT=${remain%%/*}
remain=${remain#*/}
diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh
index faa3f10639b..d36deb5759f 100644
--- a/scripts/wsrep_sst_mysqldump.sh
+++ b/scripts/wsrep_sst_mysqldump.sh
@@ -25,6 +25,7 @@ EINVAL=22
local_ip()
{
[ "$1" = "127.0.0.1" ] && return 0
+ [ "$1" = "127.0.0.2" ] && return 0
[ "$1" = "localhost" ] && return 0
[ "$1" = "[::1]" ] && return 0
[ "$1" = "$(hostname -s)" ] && return 0
@@ -138,8 +139,8 @@ then
# turned off for the session so that gtid state does not get altered while
# the dump gets replayed on joiner.
if [[ "$LOG_BIN" == 'ON' ]]; then
- RESET_MASTER="RESET MASTER;"
- SET_GTID_BINLOG_STATE="SET @@global.gtid_binlog_state='$GTID_BINLOG_STATE';"
+ RESET_MASTER="SET GLOBAL wsrep_on=OFF; RESET MASTER; SET GLOBAL wsrep_on=ON;"
+ SET_GTID_BINLOG_STATE="SET GLOBAL wsrep_on=OFF; SET @@global.gtid_binlog_state='$GTID_BINLOG_STATE'; SET GLOBAL wsrep_on=ON;"
SQL_LOG_BIN_OFF="SET @@session.sql_log_bin=OFF;"
fi
fi
diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh
index 6417ee7f704..12fb9d3ba38 100644
--- a/scripts/wsrep_sst_rsync.sh
+++ b/scripts/wsrep_sst_rsync.sh
@@ -269,8 +269,9 @@ EOF
cd $BINLOG_DIRNAME
if ! [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
- binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index)
then
+ binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_FILENAME}.index)
+ else
cd $BINLOG_INDEX_DIRNAME
binlog_files_full=$(tail -n $BINLOG_N_FILES ${BINLOG_INDEX_FILENAME}.index)
fi
@@ -508,9 +509,10 @@ EOF
for ii in $(ls -1 ${BINLOG_FILENAME}.*)
do
if ! [ -z $WSREP_SST_OPT_BINLOG_INDEX ]
- echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index
- then
- echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_INDEX_DIRNAME}/${BINLOG_INDEX_FILENAME}.index
+ then
+ echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_FILENAME}.index
+ else
+ echo ${BINLOG_DIRNAME}/${ii} >> ${BINLOG_INDEX_DIRNAME}/${BINLOG_INDEX_FILENAME}.index
fi
done
fi
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 697b794f39f..a22ce694805 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -16,21 +16,27 @@
IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY)
- SET(WSREP_INCLUDES ${CMAKE_SOURCE_DIR}/wsrep)
SET(WSREP_SOURCES
+ wsrep_client_service.cc
+ wsrep_high_priority_service.cc
+ wsrep_server_service.cc
+ wsrep_storage_service.cc
+ wsrep_server_state.cc
+ wsrep_utils.cc
+ wsrep_xid.cc
wsrep_check_opts.cc
- wsrep_hton.cc
- wsrep_mysqld.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
- wsrep_xid.cc
+ wsrep_schema.cc
+ wsrep_plugin.cc
+ service_wsrep.cc
)
- SET(WSREP_LIB wsrep)
+ SET(WSREP_LIB wsrep-lib wsrep_api_v26)
ELSE()
SET(WSREP_SOURCES wsrep_dummy.cc)
ENDIF()
@@ -42,7 +48,6 @@ ${PCRE_INCLUDES}
${ZLIB_INCLUDE_DIR}
${SSL_INCLUDE_DIRS}
${CMAKE_BINARY_DIR}/sql
-${WSREP_INCLUDES}
)
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index db056a9f08e..6327cd138de 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -32,7 +32,9 @@
#include "event_db_repository.h"
#include "sp_head.h"
#include "sql_show.h" // append_definer, append_identifier
-
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
/**
@addtogroup Event_Scheduler
@{
@@ -1353,6 +1355,10 @@ Event_job_data::execute(THD *thd, bool drop)
thd->reset_for_next_command();
+#ifdef WITH_WSREP
+ wsrep_open(thd);
+ wsrep_before_command(thd);
+#endif /* WITH_WSREP */
/*
MySQL parser currently assumes that current database is either
present in THD or all names in all statements are fully specified.
@@ -1527,6 +1533,10 @@ end:
if (save_sctx)
event_sctx.restore_security_context(thd, save_sctx);
#endif
+#ifdef WITH_WSREP
+ wsrep_after_command_ignore_result(thd);
+ wsrep_close(thd);
+#endif /* WITH_WSREP */
thd->lex->unit.cleanup();
thd->end_statement();
thd->cleanup_after_query();
diff --git a/sql/handler.cc b/sql/handler.cc
index 001055cd475..1b5aaebe3cf 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -54,8 +54,12 @@
#include "semisync_master.h"
#include "wsrep_mysqld.h"
-#include "wsrep.h"
+#ifdef WITH_WSREP
+#include "wsrep_binlog.h"
#include "wsrep_xid.h"
+#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h" /* wsrep transaction hooks */
+#endif /* WITH_WSREP */
/*
While we have legacy_db_type, we have this array to
@@ -251,6 +255,9 @@ handlerton *ha_checktype(THD *thd, handlerton *hton, bool no_substitute)
if (no_substitute)
return NULL;
+#ifdef WITH_WSREP
+ (void)wsrep_after_rollback(thd, false);
+#endif /* WITH_WSREP */
return ha_default_handlerton(thd);
} /* ha_checktype */
@@ -1199,17 +1206,28 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
static int prepare_or_error(handlerton *ht, THD *thd, bool all)
{
+ #ifdef WITH_WSREP
+ if (WSREP(thd) && ht->flags & HTON_WSREP_REPLICATION &&
+ wsrep_before_prepare(thd, all))
+ {
+ return(1);
+ }
+#endif /* WITH_WSREP */
+
int err= ht->prepare(ht, thd, all);
status_var_increment(thd->status_var.ha_prepare_count);
if (err)
{
- /* avoid sending error, if we're going to replay the transaction */
-#ifdef WITH_WSREP
- if (ht != wsrep_hton ||
- err == EMSGSIZE || thd->wsrep_conflict_state != MUST_REPLAY)
-#endif
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
}
+#ifdef WITH_WSREP
+ if (WSREP(thd) && ht->flags & HTON_WSREP_REPLICATION &&
+ wsrep_after_prepare(thd, all))
+ {
+ err= 1;
+ }
+#endif /* WITH_WSREP */
+
return err;
}
@@ -1394,7 +1412,7 @@ int ha_commit_trans(THD *thd, bool all)
}
#ifdef WITH_ARIA_STORAGE_ENGINE
- ha_maria::implicit_commit(thd, TRUE);
+ ha_maria::implicit_commit(thd, TRUE);
#endif
if (!ha_info)
@@ -1404,6 +1422,12 @@ int ha_commit_trans(THD *thd, bool all)
*/
if (is_real_trans)
thd->transaction.cleanup();
+#ifdef WITH_WSREP
+ if (WSREP(thd) && all && !error)
+ {
+ wsrep_commit_empty(thd, all);
+ }
+#endif /* WITH_WSREP */
DBUG_RETURN(0);
}
@@ -1489,7 +1513,28 @@ int ha_commit_trans(THD *thd, bool all)
if (trans->no_2pc || (rw_ha_count <= 1))
{
+#ifdef WITH_WSREP
+ /*
+ This commit will not go through log_and_order() where wsrep commit
+ ordering is normally done. Commit ordering must be done here.
+ */
+ bool run_wsrep_commit= (WSREP(thd) &&
+ rw_ha_count &&
+ wsrep_thd_is_local(thd) &&
+ wsrep_has_changes(thd, all));
+ if (run_wsrep_commit)
+ error= wsrep_before_commit(thd, all);
+ if (error)
+ {
+ ha_rollback_trans(thd, FALSE);
+ goto wsrep_err;
+ }
+#endif /* WITH_WSREP */
error= ha_commit_one_phase(thd, all);
+#ifdef WITH_WSREP
+ if (run_wsrep_commit)
+ error= wsrep_after_commit(thd, all);
+#endif /* WITH_WSREP */
goto done;
}
@@ -1521,10 +1566,14 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
#ifdef WITH_WSREP
- if (!error && WSREP_ON && wsrep_is_wsrep_xid(&thd->transaction.xid_state.xid))
+ if (!error && WSREP_ON)
{
- // xid was rewritten by wsrep
- xid= wsrep_xid_seqno(thd->transaction.xid_state.xid);
+ wsrep::seqno const s= wsrep_xid_seqno(thd->wsrep_xid);
+ if (!s.is_undefined())
+ {
+ // xid was rewritten by wsrep
+ xid= s.get();
+ }
}
#endif /* WITH_WSREP */
@@ -1533,18 +1582,35 @@ int ha_commit_trans(THD *thd, bool all)
error= commit_one_phase_2(thd, all, trans, is_real_trans);
goto done;
}
-
+#ifdef WITH_WSREP
+ if (wsrep_before_commit(thd, all))
+ goto wsrep_err;
+#endif /* WITH_WSREP */
DEBUG_SYNC(thd, "ha_commit_trans_before_log_and_order");
cookie= tc_log->log_and_order(thd, xid, all, need_prepare_ordered,
need_commit_ordered);
if (!cookie)
+ {
+ WSREP_DEBUG("log_and_order has failed %llu %d", thd->thread_id, cookie);
goto err;
-
+ }
DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order");
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
-
+#ifdef WITH_WSREP
+ if (error || wsrep_after_commit(thd, all))
+ {
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ if (thd->wsrep_trx().state() == wsrep::transaction::s_must_abort)
+ {
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ (void)tc_log->unlog(cookie, xid);
+ goto wsrep_err;
+ }
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ }
+#endif /* WITH_WSREP */
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (tc_log->unlog(cookie, xid))
{
@@ -1566,6 +1632,19 @@ done:
goto end;
/* Come here if error and we need to rollback. */
+#ifdef WITH_WSREP
+wsrep_err:
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ if (thd->wsrep_trx().state() == wsrep::transaction::s_must_abort)
+ {
+ WSREP_DEBUG("BF abort has happened after prepare & certify");
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ ha_rollback_trans(thd, TRUE);
+ }
+ else
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+
+#endif /* WITH_WSREP */
err:
error= 1; /* Transaction was rolled back */
/*
@@ -1575,7 +1654,11 @@ err:
*/
if (!(thd->rgi_slave && thd->rgi_slave->is_parallel_exec))
ha_rollback_trans(thd, all);
-
+ else
+ {
+ WSREP_DEBUG("rollback skipped %p %d",thd->rgi_slave,
+ thd->rgi_slave->is_parallel_exec);
+ }
end:
if (rw_trans && mdl_request.ticket)
{
@@ -1587,6 +1670,13 @@ end:
*/
thd->mdl_context.release_lock(mdl_request.ticket);
}
+#ifdef WITH_WSREP
+ if (WSREP(thd) && all && !error && (rw_ha_count == 0))
+ {
+ wsrep_commit_empty(thd, all);
+ }
+#endif /* WITH_WSREP */
+
DBUG_RETURN(error);
}
@@ -1744,6 +1834,9 @@ int ha_rollback_trans(THD *thd, bool all)
DBUG_RETURN(1);
}
+#ifdef WITH_WSREP
+ (void) wsrep_before_rollback(thd, all);
+#endif /* WITH_WSREP */
if (ha_info)
{
/* Close all cursors that can not survive ROLLBACK */
@@ -1759,9 +1852,9 @@ int ha_rollback_trans(THD *thd, bool all)
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
#ifdef WITH_WSREP
- WSREP_WARN("handlerton rollback failed, thd %llu %lld conf %d SQL %s",
- thd->thread_id, thd->query_id, thd->wsrep_conflict_state,
- thd->query());
+ WSREP_WARN("handlerton rollback failed, thd %lld %lld conf %d SQL %s",
+ thd->thread_id, thd->query_id, thd->wsrep_trx().state(),
+ thd->query());
#endif /* WITH_WSREP */
}
status_var_increment(thd->status_var.ha_rollback_count);
@@ -1780,6 +1873,15 @@ int ha_rollback_trans(THD *thd, bool all)
thd->transaction.xid_state.xa_state != XA_NOTR)
thd->transaction.xid_state.rm_error= thd->get_stmt_da()->sql_errno();
+#ifdef WITH_WSREP
+ if (thd->is_error())
+ {
+ WSREP_DEBUG("ha_rollback_trans(%lld, %s) rolled back: %s: %s; is_real %d",
+ thd->thread_id, all?"TRUE":"FALSE", WSREP_QUERY(thd),
+ thd->get_stmt_da()->message(), is_real_trans);
+ }
+ (void) wsrep_after_rollback(thd, all);
+#endif /* WITH_WSREP */
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
{
@@ -1913,6 +2015,28 @@ static char* xid_to_str(char *buf, XID *xid)
}
#endif
+#ifdef WITH_WSREP
+static my_xid wsrep_order_and_check_continuity(XID *list, int len)
+{
+ wsrep_sort_xid_array(list, len);
+ wsrep::gtid cur_position= wsrep_get_SE_checkpoint();
+ long long cur_seqno= cur_position.seqno().get();
+ for (int i= 0; i < len; ++i)
+ {
+ if (!wsrep_is_wsrep_xid(list + i) ||
+ wsrep_xid_seqno(list + i) != cur_seqno + 1)
+ {
+ WSREP_WARN("Discovered discontinuity in recovered wsrep "
+ "transaction XIDs. Truncating the recovery list to "
+ "%d entries", i);
+ break;
+ }
+ ++cur_seqno;
+ }
+ WSREP_INFO("Last wsrep seqno to be recovered %lld", cur_seqno);
+ return (cur_seqno < 0 ? 0 : cur_seqno);
+}
+#endif /* WITH_WSREP */
/**
recover() step of xa.
@@ -1950,10 +2074,32 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
{
sql_print_information("Found %d prepared transaction(s) in %s",
got, hton_name(hton)->str);
+#ifdef WITH_WSREP
+ /* If wsrep_on=ON, XIDs are first ordered and then the range of
+ recovered XIDs is checked for continuity. All the XIDs which
+ are in continuous range can be safely committed if binlog
+ is off since they have already ordered and certified in the
+ cluster.
+
+ The discontinuity of wsrep XIDs may happen because the GTID
+ is assigned for transaction in wsrep_before_prepare(), but the
+ commit order is entered in wsrep_before_commit(). This means that
+ transactions may run prepare step out of order and may
+ result in gap in wsrep XIDs. This can be the case for example
+ if we have T1 with seqno 1 and T2 with seqno 2 and the server
+ crashes after T2 finishes prepare step but before T1 starts
+ the prepare.
+ */
+ my_xid wsrep_limit= 0;
+ if (WSREP_ON)
+ {
+ wsrep_limit= wsrep_order_and_check_continuity(info->list, got);
+ }
+#endif /* WITH_WSREP */
for (int i=0; i < got; i ++)
{
my_xid x= IF_WSREP(WSREP_ON && wsrep_is_wsrep_xid(&info->list[i]) ?
- wsrep_xid_seqno(info->list[i]) :
+ wsrep_xid_seqno(&info->list[i]) :
info->list[i].get_my_xid(),
info->list[i].get_my_xid());
if (!x) // not "mine" - that is generated by external TM
@@ -1972,9 +2118,12 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
continue;
}
// recovery mode
- if (info->commit_list ?
- my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
- tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
+ if (IF_WSREP((wsrep_emulate_bin_log &&
+ wsrep_is_wsrep_xid(info->list + i) &&
+ x <= wsrep_limit), false) ||
+ (info->commit_list ?
+ my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
+ tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT))
{
#ifndef DBUG_OFF
int rc=
@@ -2332,11 +2481,26 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
{
int err;
handlerton *ht= ha_info->ht();
+#ifdef WITH_WSREP
+ if (WSREP(thd) && ht->flags & HTON_WSREP_REPLICATION)
+ {
+ WSREP_DEBUG("ha_rollback_to_savepoint: run before_rollbackha_rollback_trans hook");
+ (void) wsrep_before_rollback(thd, !thd->in_sub_stmt);
+
+ }
+#endif // WITH_WSREP
if ((err= ht->rollback(ht, thd, !thd->in_sub_stmt)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
+#ifdef WITH_WSREP
+ if (WSREP(thd) && ht->flags & HTON_WSREP_REPLICATION)
+ {
+ WSREP_DEBUG("ha_rollback_to_savepoint: run after_rollback hook");
+ (void) wsrep_after_rollback(thd, !thd->in_sub_stmt);
+ }
+#endif // WITH_WSREP
status_var_increment(thd->status_var.ha_rollback_count);
ha_info_next= ha_info->next();
ha_info->reset(); /* keep it conveniently zero-filled */
@@ -2353,6 +2517,16 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
*/
int ha_savepoint(THD *thd, SAVEPOINT *sv)
{
+#ifdef WITH_WSREP
+ /*
+ Register binlog hton for savepoint processing if wsrep binlog
+ emulation is on.
+ */
+ if (WSREP_EMULATE_BINLOG(thd) && wsrep_thd_is_local(thd))
+ {
+ wsrep_register_binlog_handler(thd, thd->in_multi_stmt_transaction_mode());
+ }
+#endif /* WITH_WSREP */
int error=0;
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
&thd->transaction.all);
@@ -5968,6 +6142,12 @@ bool handler::check_table_binlog_row_based(bool binlog_row)
return false;
if (unlikely((table->in_use->variables.sql_log_bin_off)))
return 0; /* Called by partitioning engine */
+#ifdef WITH_WSREP
+ if (!table->in_use->variables.sql_log_bin &&
+ wsrep_thd_is_applying(table->in_use))
+ return 0; /* wsrep patch sets sql_log_bin to silence binlogging
+ from high priority threads */
+#endif /* WITH_WSREP */
if (unlikely((!check_table_binlog_row_based_done)))
{
check_table_binlog_row_based_done= 1;
@@ -5998,12 +6178,12 @@ bool handler::check_table_binlog_row_based_internal(bool binlog_row)
Otherwise, return 'true' if binary logging is on.
*/
IF_WSREP(((WSREP_EMULATE_BINLOG(thd) &&
- (thd->wsrep_exec_mode != REPL_RECV)) ||
+ wsrep_thd_is_local(thd)) ||
((WSREP(thd) ||
(thd->variables.option_bits & OPTION_BIN_LOG)) &&
mysql_bin_log.is_open())),
- (thd->variables.option_bits & OPTION_BIN_LOG) &&
- mysql_bin_log.is_open()));
+ (thd->variables.option_bits & OPTION_BIN_LOG) &&
+ mysql_bin_log.is_open()));
}
@@ -6128,23 +6308,9 @@ int binlog_log_row(TABLE* table, const uchar *before_record,
/* only InnoDB tables will be replicated through binlog emulation */
if ((WSREP_EMULATE_BINLOG(thd) &&
- table->file->partition_ht()->db_type != DB_TYPE_INNODB) ||
- (thd->wsrep_ignore_table == true))
+ !(table->file->partition_ht()->flags & HTON_WSREP_REPLICATION)) ||
+ thd->wsrep_ignore_table == true)
return 0;
-
- /* enforce wsrep_max_ws_rows */
- if (WSREP(thd) && table->s->tmp_table == NO_TMP_TABLE)
- {
- thd->wsrep_affected_rows++;
- if (wsrep_max_ws_rows &&
- thd->wsrep_exec_mode != REPL_RECV &&
- thd->wsrep_affected_rows > wsrep_max_ws_rows)
- {
- trans_rollback_stmt(thd) || trans_rollback(thd);
- my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
- return ER_ERROR_DURING_COMMIT;
- }
- }
#endif
if (!table->file->check_table_binlog_row_based(1))
@@ -6256,6 +6422,27 @@ int handler::ha_reset()
DBUG_RETURN(reset());
}
+#ifdef WITH_WSREP
+static int wsrep_after_row(THD *thd)
+{
+ DBUG_ENTER("wsrep_after_row");
+ /* enforce wsrep_max_ws_rows */
+ thd->wsrep_affected_rows++;
+ if (wsrep_max_ws_rows &&
+ wsrep_thd_is_local(thd) &&
+ thd->wsrep_affected_rows > wsrep_max_ws_rows)
+ {
+ trans_rollback_stmt(thd) || trans_rollback(thd);
+ my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
+ DBUG_RETURN(ER_ERROR_DURING_COMMIT);
+ }
+ else if (wsrep_after_row(thd, false))
+ {
+ DBUG_RETURN(ER_LOCK_DEADLOCK);
+ }
+ DBUG_RETURN(0);
+}
+#endif /* WITH_WSREP */
int handler::ha_write_row(uchar *buf)
{
@@ -6278,7 +6465,15 @@ int handler::ha_write_row(uchar *buf)
{
rows_changed++;
error= binlog_log_row(table, 0, buf, log_func);
+#ifdef WITH_WSREP
+ if (table_share->tmp_table == NO_TMP_TABLE &&
+ WSREP(ha_thd()) && (error= wsrep_after_row(ha_thd())))
+ {
+ DBUG_RETURN(error);
+ }
+#endif /* WITH_WSREP */
}
+
DEBUG_SYNC_C("ha_write_row_end");
DBUG_RETURN(error);
}
@@ -6310,6 +6505,13 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data)
{
rows_changed++;
error= binlog_log_row(table, old_data, new_data, log_func);
+#ifdef WITH_WSREP
+ if (table_share->tmp_table == NO_TMP_TABLE &&
+ WSREP(ha_thd()) && (error= wsrep_after_row(ha_thd())))
+ {
+ return error;
+ }
+#endif /* WITH_WSREP */
}
return error;
}
@@ -6365,6 +6567,13 @@ int handler::ha_delete_row(const uchar *buf)
{
rows_changed++;
error= binlog_log_row(table, buf, 0, log_func);
+#ifdef WITH_WSREP
+ if (table_share->tmp_table == NO_TMP_TABLE &&
+ WSREP(ha_thd()) && (error= wsrep_after_row(ha_thd())))
+ {
+ return error;
+ }
+#endif /* WITH_WSREP */
}
return error;
}
@@ -6554,7 +6763,7 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
DBUG_ENTER("ha_abort_transaction");
if (!WSREP(bf_thd) &&
!(bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU &&
- bf_thd->wsrep_exec_mode == TOTAL_ORDER)) {
+ wsrep_thd_is_toi(bf_thd))) {
DBUG_RETURN(0);
}
@@ -6570,54 +6779,6 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
DBUG_RETURN(0);
}
-
-void ha_fake_trx_id(THD *thd)
-{
- DBUG_ENTER("ha_fake_trx_id");
-
- bool no_fake_trx_id= true;
-
- if (!WSREP(thd))
- {
- DBUG_VOID_RETURN;
- }
-
- if (thd->wsrep_ws_handle.trx_id != WSREP_UNDEFINED_TRX_ID)
- {
- WSREP_DEBUG("fake trx id skipped: %" PRIu64, thd->wsrep_ws_handle.trx_id);
- DBUG_VOID_RETURN;
- }
-
- /* Try statement transaction if standard one is not set. */
- THD_TRANS *trans= (thd->transaction.all.ha_list) ? &thd->transaction.all :
- &thd->transaction.stmt;
-
- Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
-
- for (; ha_info; ha_info= ha_info_next)
- {
- handlerton *hton= ha_info->ht();
- if (hton->fake_trx_id)
- {
- hton->fake_trx_id(hton, thd);
-
- /* Got a fake trx id. */
- no_fake_trx_id= false;
-
- /*
- We need transaction ID from just one storage engine providing
- fake_trx_id (which will most likely be the case).
- */
- break;
- }
- ha_info_next= ha_info->next();
- }
-
- if (unlikely(no_fake_trx_id))
- WSREP_WARN("Cannot get fake transaction ID from storage engine.");
-
- DBUG_VOID_RETURN;
-}
#endif /* WITH_WSREP */
diff --git a/sql/handler.h b/sql/handler.h
index fc6246c38a1..f5a7051a4e2 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1485,7 +1485,6 @@ struct handlerton
THD *victim_thd, my_bool signal);
int (*set_checkpoint)(handlerton *hton, const XID* xid);
int (*get_checkpoint)(handlerton *hton, XID* xid);
- void (*fake_trx_id)(handlerton *hton, THD *thd);
/*
Optional clauses in the CREATE/ALTER TABLE
*/
@@ -1682,6 +1681,9 @@ handlerton *ha_default_tmp_handlerton(THD *thd);
// Engine needs to access the main connect string in partitions
#define HTON_CAN_READ_CONNECT_STRING_IN_PARTITION (1 <<12)
+/* can be replicated by wsrep replication provider plugin */
+#define HTON_WSREP_REPLICATION (1 << 13)
+
class Ha_trx_info;
struct THD_TRANS
@@ -4837,9 +4839,6 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv);
int ha_release_savepoint(THD *thd, SAVEPOINT *sv);
#ifdef WITH_WSREP
int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal);
-void ha_fake_trx_id(THD *thd);
-#else
-inline void ha_fake_trx_id(THD *thd) { }
#endif
/* these are called by storage engines */
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 87bf69f3c96..ba7a704e29b 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -3193,6 +3193,45 @@ protected:
};
#endif
+#ifdef WITH_WSREP
+class Create_func_wsrep_last_written_gtid : public Create_func_arg0
+{
+public:
+ virtual Item *create_builder(THD *thd);
+
+ static Create_func_wsrep_last_written_gtid s_singleton;
+
+protected:
+ Create_func_wsrep_last_written_gtid() {}
+ virtual ~Create_func_wsrep_last_written_gtid() {}
+};
+
+
+class Create_func_wsrep_last_seen_gtid : public Create_func_arg0
+{
+public:
+ virtual Item *create_builder(THD *thd);
+
+ static Create_func_wsrep_last_seen_gtid s_singleton;
+
+protected:
+ Create_func_wsrep_last_seen_gtid() {}
+ virtual ~Create_func_wsrep_last_seen_gtid() {}
+};
+
+
+class Create_func_wsrep_sync_wait_upto : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_wsrep_sync_wait_upto s_singleton;
+
+protected:
+ Create_func_wsrep_sync_wait_upto() {}
+ virtual ~Create_func_wsrep_sync_wait_upto() {}
+};
+#endif /* WITH_WSREP */
#ifdef HAVE_SPATIAL
class Create_func_x : public Create_func_arg1
@@ -6905,6 +6944,63 @@ Create_func_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
#endif
+#ifdef WITH_WSREP
+Create_func_wsrep_last_written_gtid
+Create_func_wsrep_last_written_gtid::s_singleton;
+
+Item*
+Create_func_wsrep_last_written_gtid::create_builder(THD *thd)
+{
+ thd->lex->safe_to_cache_query= 0;
+ return new (thd->mem_root) Item_func_wsrep_last_written_gtid(thd);
+}
+
+
+Create_func_wsrep_last_seen_gtid
+Create_func_wsrep_last_seen_gtid::s_singleton;
+
+Item*
+Create_func_wsrep_last_seen_gtid::create_builder(THD *thd)
+{
+ thd->lex->safe_to_cache_query= 0;
+ return new (thd->mem_root) Item_func_wsrep_last_seen_gtid(thd);
+}
+
+
+Create_func_wsrep_sync_wait_upto
+Create_func_wsrep_sync_wait_upto::s_singleton;
+
+Item*
+Create_func_wsrep_sync_wait_upto::create_native(THD *thd,
+ LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+ Item *param_1, *param_2;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count)
+ {
+ case 1:
+ param_1= item_list->pop();
+ func= new (thd->mem_root) Item_func_wsrep_sync_wait_upto(thd, param_1);
+ break;
+ case 2:
+ param_1= item_list->pop();
+ param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_wsrep_sync_wait_upto(thd, param_1, param_2);
+ break;
+ default:
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ thd->lex->safe_to_cache_query= 0;
+ return func;
+}
+#endif /* WITH_WSREP */
#ifdef HAVE_SPATIAL
Create_func_x Create_func_x::s_singleton;
@@ -7347,6 +7443,11 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)},
{ { STRING_WITH_LEN("WEEKOFYEAR") }, BUILDER(Create_func_weekofyear)},
{ { STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
+#ifdef WITH_WSREP
+ { { STRING_WITH_LEN("WSREP_LAST_WRITTEN_GTID") }, BUILDER(Create_func_wsrep_last_written_gtid)},
+ { { STRING_WITH_LEN("WSREP_LAST_SEEN_GTID") }, BUILDER(Create_func_wsrep_last_seen_gtid)},
+ { { STRING_WITH_LEN("WSREP_SYNC_WAIT_UPTO_GTID") }, BUILDER(Create_func_wsrep_sync_wait_upto)},
+#endif /* WITH_WSREP */
{ { STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
{ { STRING_WITH_LEN("Y") }, GEOM_BUILDER(Create_func_y)},
{ { STRING_WITH_LEN("YEARWEEK") }, BUILDER(Create_func_year_week)},
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c73cfc7953a..a10f381b1dc 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2451,7 +2451,7 @@ void Item_func_rand::seed_random(Item *arg)
THD *thd= current_thd;
if (WSREP(thd))
{
- if (thd->wsrep_exec_mode==REPL_RECV)
+ if (wsrep_thd_is_applying(thd))
tmp= thd->wsrep_rand;
else
tmp= thd->wsrep_rand= (uint32) arg->val_int();
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 8cc539f3d12..77e870b297d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -5264,3 +5264,102 @@ String *Item_temptable_rowid::val_str(String *str)
str_value.set((char*)(table->file->ref), max_length, &my_charset_bin);
return &str_value;
}
+#ifdef WITH_WSREP
+
+#include "wsrep_mysqld.h"
+
+String *Item_func_wsrep_last_written_gtid::val_str_ascii(String *str)
+{
+ wsrep::gtid gtid= current_thd->wsrep_cs().last_written_gtid();
+ if (gtid_str.alloc(wsrep::gtid_c_str_len()))
+ {
+ my_error(ER_OUTOFMEMORY, wsrep::gtid_c_str_len());
+ null_value= true;
+ return NULL;
+ }
+
+ ssize_t gtid_len= gtid_print_to_c_str(gtid, (char*) gtid_str.ptr(),
+ wsrep::gtid_c_str_len());
+ if (gtid_len < 0)
+ {
+ my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
+ "wsrep_gtid_print failed");
+ null_value= true;
+ return NULL;
+ }
+ gtid_str.length(gtid_len);
+ return &gtid_str;
+}
+
+String *Item_func_wsrep_last_seen_gtid::val_str_ascii(String *str)
+{
+ /* TODO: Should call Wsrep_server_state.instance().last_committed_gtid()
+ instead. */
+ wsrep::gtid gtid= Wsrep_server_state::instance().provider().last_committed_gtid();
+ if (gtid_str.alloc(wsrep::gtid_c_str_len()))
+ {
+ my_error(ER_OUTOFMEMORY, wsrep::gtid_c_str_len());
+ null_value= true;
+ return NULL;
+ }
+ ssize_t gtid_len= wsrep::gtid_print_to_c_str(gtid, (char*) gtid_str.ptr(),
+ wsrep::gtid_c_str_len());
+ if (gtid_len < 0)
+ {
+ my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), func_name(),
+ "wsrep_gtid_print failed");
+ null_value= true;
+ return NULL;
+ }
+ gtid_str.length(gtid_len);
+ return &gtid_str;
+}
+
+longlong Item_func_wsrep_sync_wait_upto::val_int()
+{
+ int timeout= -1;
+ String* gtid_str= args[0]->val_str(&value);
+ if (gtid_str == NULL)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ return 0LL;
+ }
+
+ if (arg_count == 2)
+ {
+ timeout= args[1]->val_int();
+ }
+
+ wsrep_gtid_t gtid;
+ int gtid_len= wsrep_gtid_scan(gtid_str->ptr(), gtid_str->length(), &gtid);
+ if (gtid_len < 0)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), func_name());
+ return 0LL;
+ }
+
+ if (gtid.seqno == WSREP_SEQNO_UNDEFINED &&
+ wsrep_uuid_compare(&gtid.uuid, &WSREP_UUID_UNDEFINED) == 0)
+ {
+ return 1LL;
+ }
+
+ enum wsrep::provider::status status=
+ wsrep_sync_wait_upto(current_thd, &gtid, timeout);
+
+ if (status)
+ {
+ int err;
+ switch (status) {
+ case wsrep::provider::error_transaction_missing:
+ err= ER_WRONG_ARGUMENTS;
+ break;
+ default:
+ err= ER_LOCK_WAIT_TIMEOUT;
+ }
+ my_error(err, MYF(0), func_name());
+ return 0LL;
+ }
+ return 1LL;
+}
+#endif /* WITH_WSREP */
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 762a3c2559e..2ead0f44e49 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1804,5 +1804,56 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_temptable_rowid>(thd, this); }
};
+#ifdef WITH_WSREP
+
+#include "wsrep_api.h"
+
+class Item_func_wsrep_last_written_gtid: public Item_str_ascii_func
+{
+ String gtid_str;
+public:
+ Item_func_wsrep_last_written_gtid(THD *thd): Item_str_ascii_func(thd) {}
+ const char *func_name() const { return "wsrep_last_written_gtid"; }
+ String *val_str_ascii(String *);
+ bool fix_length_and_dec()
+ {
+ max_length= WSREP_GTID_STR_LEN;
+ maybe_null= true;
+ return FALSE;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_wsrep_last_written_gtid>(thd, this); }
+};
+
+class Item_func_wsrep_last_seen_gtid: public Item_str_ascii_func
+{
+ String gtid_str;
+public:
+ Item_func_wsrep_last_seen_gtid(THD *thd): Item_str_ascii_func(thd) {}
+ const char *func_name() const { return "wsrep_last_seen_gtid"; }
+ String *val_str_ascii(String *);
+ bool fix_length_and_dec()
+ {
+ max_length= WSREP_GTID_STR_LEN;
+ maybe_null= true;
+ return FALSE;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_wsrep_last_seen_gtid>(thd, this); }
+};
+
+class Item_func_wsrep_sync_wait_upto: public Item_int_func
+{
+ String value;
+public:
+ Item_func_wsrep_sync_wait_upto(THD *thd, Item *a): Item_int_func(thd, a) {}
+ Item_func_wsrep_sync_wait_upto(THD *thd, Item *a, Item* b): Item_int_func(thd, a, b) {}
+ const Type_handler *type_handler() const { return &type_handler_string; }
+ const char *func_name() const { return "wsrep_sync_wait_upto_gtid"; }
+ longlong val_int();
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_wsrep_sync_wait_upto>(thd, this); }
+};
+#endif /* WITH_WSREP */
#endif /* ITEM_STRFUNC_INCLUDED */
diff --git a/sql/lock.cc b/sql/lock.cc
index 1564059bb20..c1140eddaae 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -1100,20 +1100,16 @@ void Global_read_lock::unlock_global_read_lock(THD *thd)
#ifdef WITH_WSREP
if (m_state == GRL_ACQUIRED_AND_BLOCKS_COMMIT)
{
- if (WSREP(thd) || wsrep_node_is_donor())
+ Wsrep_server_state& server_state= Wsrep_server_state::instance();
+ if (server_state.state() == Wsrep_server_state::s_donor)
{
+ /* TODO: maybe redundant here?: */
wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
- wsrep->resume(wsrep);
- /* resync here only if we did implicit desync earlier */
- if (!wsrep_desync && wsrep_node_is_synced())
- {
- int ret = wsrep->resync(wsrep);
- if (ret != WSREP_OK)
- {
- WSREP_WARN("resync failed %d for FTWRL: db: %s, query: %s",
- ret, thd->get_db(), thd->query());
- }
- }
+ server_state.resume();
+ }
+ else if (WSREP(thd))
+ {
+ server_state.resume_and_resync();
}
}
#endif /* WITH_WSREP */
@@ -1159,62 +1155,30 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
#ifdef WITH_WSREP
+
/* Native threads should bail out before wsrep oprations to follow.
- Donor servicing thread is an exception, it should pause provider but not desync,
- as it is already desynced in donor state
+ Donor servicing thread is an exception, it should pause provider
+ but not desync, as it is already desynced in donor state
*/
- if (!WSREP(thd) && !wsrep_node_is_donor())
+ Wsrep_server_state& server_state= Wsrep_server_state::instance();
+ if (!WSREP(thd) && server_state.state() != Wsrep_server_state::s_donor)
{
DBUG_RETURN(FALSE);
}
- /* if already desynced or donor, avoid double desyncing
- if not in PC and synced, desyncing is not possible either
- */
- if (wsrep_desync || !wsrep_node_is_synced())
+ wsrep::seqno paused_seqno;
+ if (server_state.state() == Wsrep_server_state::s_donor)
{
- WSREP_DEBUG("desync set upfont, skipping implicit desync for FTWRL: %d",
- wsrep_desync);
+ paused_seqno= server_state.pause();
}
else
{
- int rcode;
- WSREP_DEBUG("running implicit desync for node");
- rcode = wsrep->desync(wsrep);
- if (rcode != WSREP_OK)
- {
- WSREP_WARN("FTWRL desync failed %d for schema: %s, query: %s",
- rcode, thd->get_db(), thd->query());
- my_message(ER_LOCK_DEADLOCK, "wsrep desync failed for FTWRL", MYF(0));
- DBUG_RETURN(TRUE);
- }
- }
-
- long long ret = wsrep->pause(wsrep);
- if (ret >= 0)
- {
- wsrep_locked_seqno= ret;
+ paused_seqno= server_state.desync_and_pause();
}
- else if (ret != -ENOSYS) /* -ENOSYS - no provider */
+ WSREP_INFO("Server paused at: %lld", paused_seqno.get());
+ if (paused_seqno.get() >= 0)
{
- 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));
-
- /*
- For some reason Galera wants to crash here in debug build.
- It is equivalent of original assertion.
- */
- DBUG_ASSERT(0);
- wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
- my_error(ER_LOCK_DEADLOCK, MYF(0));
- DBUG_RETURN(TRUE);
- }
+ wsrep_locked_seqno= paused_seqno.get();
}
#endif /* WITH_WSREP */
DBUG_RETURN(FALSE);
diff --git a/sql/log.cc b/sql/log.cc
index a56117a4ac1..68e34513d40 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -55,10 +55,14 @@
#include "sql_show.h"
#include "my_pthread.h"
#include "semisync_master.h"
-#include "wsrep_mysqld.h"
#include "sp_rcontext.h"
#include "sp_head.h"
+#include "wsrep_mysqld.h"
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
+
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
#define MAX_TIME_SIZE 32
@@ -1703,7 +1707,7 @@ static int binlog_close_connection(handlerton *hton, THD *thd)
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
#ifdef WITH_WSREP
if (cache_mngr && !cache_mngr->trx_cache.empty()) {
- IO_CACHE* cache= get_trans_log(thd);
+ IO_CACHE* cache= cache_mngr->get_binlog_cache_log(true);
uchar *buf;
size_t len=0;
wsrep_write_cache_buf(cache, &buf, &len);
@@ -2297,8 +2301,17 @@ 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
+ /* for streaming replication, we must replicate savepoint rollback so that
+ slaves can maintain SR transactions
+ */
+ if (unlikely(thd->wsrep_trx().is_streaming() ||
+ (trans_has_updated_non_trans_table(thd)) ||
+ (thd->variables.option_bits & OPTION_KEEP_LOG)))
+#else
if (unlikely(trans_has_updated_non_trans_table(thd) ||
(thd->variables.option_bits & OPTION_KEEP_LOG)))
+#endif /* WITH_WSREP */
{
char buf[1024];
String log_query(buf, sizeof(buf), &my_charset_bin);
@@ -5970,7 +5983,9 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
DBUG_PRINT("enter", ("standalone: %d", standalone));
#ifdef WITH_WSREP
- if (WSREP(thd) && thd->wsrep_trx_meta.gtid.seqno != -1 && wsrep_gtid_mode && !thd->variables.gtid_seq_no)
+ if (WSREP(thd) &&
+ (wsrep_thd_trx_seqno(thd) > 0) &&
+ wsrep_gtid_mode && !thd->variables.gtid_seq_no)
{
domain_id= wsrep_gtid_domain_id;
} else {
@@ -6287,7 +6302,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate)
*/
/* applier and replayer can skip writing binlog events */
if ((WSREP_EMULATE_BINLOG(thd) &&
- IF_WSREP(thd->wsrep_exec_mode != REPL_RECV, 0)) || is_open())
+ IF_WSREP(thd->wsrep_cs().mode() == wsrep::client_state::m_local, 0)) || is_open())
{
my_off_t UNINIT_VAR(my_org_b_tell);
#ifdef HAVE_REPLICATION
@@ -7670,7 +7685,11 @@ bool
MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
{
int is_leader= queue_for_group_commit(entry);
-
+#ifdef WITH_WSREP
+ if (is_leader >= 0 &&
+ wsrep_ordered_commit(entry->thd, entry->all, wsrep_apply_error()))
+ return true;
+#endif /* WITH_WSREP */
/*
The first in the queue handles group commit for all; the others just wait
to be signalled when group commit is done.
@@ -10592,7 +10611,10 @@ maria_declare_plugin(binlog)
maria_declare_plugin_end;
#ifdef WITH_WSREP
-IO_CACHE * get_trans_log(THD * thd)
+#include "wsrep_trans_observer.h"
+#include "wsrep_mysqld.h"
+
+IO_CACHE *wsrep_get_trans_cache(THD * thd)
{
DBUG_ASSERT(binlog_hton->slot != HA_SLOT_UNDEF);
binlog_cache_mngr *cache_mngr = (binlog_cache_mngr*)
@@ -10605,17 +10627,10 @@ IO_CACHE * get_trans_log(THD * thd)
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_trx_reset(THD * thd)
+void wsrep_thd_binlog_trx_reset(THD * thd)
{
+ DBUG_ENTER("wsrep_thd_binlog_trx_reset");
+ WSREP_DEBUG("wsrep_thd_binlog_reset");
/*
todo: fix autocommit select to not call the caller
*/
@@ -10634,6 +10649,7 @@ void thd_binlog_trx_reset(THD * thd)
}
}
thd->clear_binlog_table_maps();
+ DBUG_VOID_RETURN;
}
@@ -10646,4 +10662,78 @@ void thd_binlog_rollback_stmt(THD * thd)
if (cache_mngr)
cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
}
+
+bool wsrep_stmt_rollback_is_safe(THD* thd)
+{
+ bool ret(true);
+
+ DBUG_ENTER("wsrep_binlog_stmt_rollback_is_safe");
+
+ binlog_cache_mngr *cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+
+ if (binlog_hton && cache_mngr)
+ {
+ binlog_cache_data * trx_cache = &cache_mngr->trx_cache;
+ if (thd->wsrep_sr().fragments_certified() > 0 &&
+ (trx_cache->get_prev_position() == MY_OFF_T_UNDEF ||
+ trx_cache->get_prev_position() < thd->wsrep_sr().bytes_certified()))
+ {
+ WSREP_DEBUG("statement rollback is not safe for streaming replication"
+ " pre-stmt_pos: %llu, frag repl pos: %lu\n"
+ "Thread: %llu, SQL: %s",
+ trx_cache->get_prev_position(),
+ thd->wsrep_sr().bytes_certified(),
+ thd->thread_id, thd->query());
+ ret = false;
+ }
+ }
+ DBUG_RETURN(ret);
+}
+
+void wsrep_register_binlog_handler(THD *thd, bool trx)
+{
+ DBUG_ENTER("register_binlog_handler");
+ /*
+ If this is the first call to this function while processing a statement,
+ the transactional cache does not have a savepoint defined. So, in what
+ follows:
+ . an implicit savepoint is defined;
+ . callbacks are registered;
+ . binary log is set as read/write.
+
+ The savepoint allows for truncating the trx-cache transactional changes
+ fail. Callbacks are necessary to flush caches upon committing or rolling
+ back a statement or a transaction. However, notifications do not happen
+ if the binary log is set as read/write.
+ */
+ //binlog_cache_mngr *cache_mngr= thd_get_cache_mngr(thd);
+ binlog_cache_mngr *cache_mngr=
+ (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+ /* cache_mngr may be missing e.g. in mtr test ev51914.test */
+ if (cache_mngr && cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
+ {
+ /*
+ Set an implicit savepoint in order to be able to truncate a trx-cache.
+ */
+ my_off_t pos= 0;
+ binlog_trans_log_savepos(thd, &pos);
+ cache_mngr->trx_cache.set_prev_position(pos);
+
+ /*
+ Set callbacks in order to be able to call commmit or rollback.
+ */
+ if (trx)
+ trans_register_ha(thd, TRUE, binlog_hton);
+ trans_register_ha(thd, FALSE, binlog_hton);
+
+ /*
+ Set the binary log as read/write otherwise callbacks are not called.
+ */
+ thd->ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
+ }
+ DBUG_VOID_RETURN;
+}
+
#endif /* WITH_WSREP */
diff --git a/sql/log.h b/sql/log.h
index 7dfdb36c442..42fcfcc3ab6 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -18,7 +18,6 @@
#define LOG_H
#include "handler.h" /* my_xid */
-#include "wsrep.h"
#include "wsrep_mysqld.h"
#include "rpl_constants.h"
@@ -1212,6 +1211,10 @@ static inline TC_LOG *get_tc_log_implementation()
return &tc_log_mmap;
}
+#ifdef WITH_WSREP
+IO_CACHE* wsrep_get_trans_cache(THD *);
+void wsrep_thd_binlog_trx_reset(THD * thd);
+#endif /* WITH_WSREP */
class Gtid_list_log_event;
const char *
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7a0d0beb5ad..ed2b25929e4 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -5780,6 +5780,14 @@ compare_errors:
"unexpected success or fatal error"),
thd->get_db(), query_arg);
thd->is_slave_error= 1;
+#ifdef WITH_WSREP
+ if (thd->wsrep_apply_toi && wsrep_must_ignore_error(thd))
+ {
+ thd->clear_error(1);
+ thd->killed= NOT_KILLED;
+ thd->wsrep_has_ignored_error= true;
+ }
+#endif /* WITH_WSREP */
}
/*
@@ -11287,13 +11295,13 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
{
WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d "
"wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)",
- thd->get_stmt_da()->sql_errno(),
- thd->is_fatal_error,
- thd->wsrep_exec_mode,
- thd->wsrep_conflict_state,
- (long long)wsrep_thd_trx_seqno(thd));
+ thd->get_stmt_da()->sql_errno(),
+ thd->is_fatal_error,
+ thd->wsrep_cs().mode(),
+ thd->wsrep_trx().state(),
+ (long long) wsrep_thd_trx_seqno(thd));
}
-#endif
+#endif /* WITH_WSREP */
if ((thd->is_slave_error || thd->is_fatal_error) &&
!is_parallel_retry_error(rgi, actual_error))
{
@@ -11430,10 +11438,10 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
#ifdef HAVE_QUERY_CACHE
#ifdef WITH_WSREP
/*
- Moved invalidation right before the call to rows_event_stmt_cleanup(),
- to avoid query cache being polluted with stale entries.
+ 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)))
+ if (! (WSREP(thd) && wsrep_thd_is_applying(thd)))
{
#endif /* WITH_WSREP */
query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
@@ -11546,6 +11554,13 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
bool ignored_error= (idempotent_error == 0 ?
ignored_error_code(actual_error) : 0);
+#ifdef WITH_WSREP
+ if (WSREP(thd) && wsrep_ignored_error_code(this, actual_error))
+ {
+ idempotent_error= true;
+ thd->wsrep_has_ignored_error= true;
+ }
+#endif /* WITH_WSREP */
if (idempotent_error || ignored_error)
{
if (global_system_variables.log_warnings)
@@ -11633,7 +11648,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
restore_empty_query_table_list(thd->lex);
#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
- if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
+ if (WSREP(thd) && wsrep_thd_is_applying(thd))
{
query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
}
diff --git a/sql/mdl.cc b/sql/mdl.cc
index 19468a124c6..ccd7a71e9f4 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -24,9 +24,6 @@
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
#include <mysql/psi/mysql_stage.h>
-#include "wsrep_mysqld.h"
-#include "wsrep_thd.h"
-
#ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_MDL_wait_LOCK_wait_status;
@@ -1218,10 +1215,9 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
wsrep_thd_is_BF(ticket->get_ctx()->get_thd(), false))
{
Ticket_iterator itw(ticket->get_lock()->m_waiting);
- Ticket_iterator itg(ticket->get_lock()->m_granted);
DBUG_ASSERT(WSREP_ON);
- MDL_ticket *waiting, *granted;
+ MDL_ticket *waiting;
MDL_ticket *prev=NULL;
bool added= false;
@@ -1240,20 +1236,8 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket)
}
/* Otherwise, insert the ticket at the back of the waiting list. */
- if (!added) m_list.push_back(ticket);
-
- while ((granted= itg++))
- {
- if (granted->get_ctx() != ticket->get_ctx() &&
- granted->is_incompatible_when_granted(ticket->get_type()))
- {
- if (!wsrep_grant_mdl_exception(ticket->get_ctx(), granted,
- &ticket->get_lock()->key))
- {
- WSREP_DEBUG("MDL victim killed at add_ticket");
- }
- }
- }
+ if (!added)
+ m_list.push_back(ticket);
}
else
#endif /* WITH_WSREP */
@@ -1709,6 +1693,12 @@ MDL_lock::MDL_backup_lock::m_waiting_incompatible[MDL_BACKUP_END]=
Check if request for the metadata lock can be satisfied given its
current state.
+ New lock request can be satisfied iff:
+ - There are no incompatible types of satisfied requests
+ in other contexts
+ - There are no waiting requests which have higher priority
+ than this request when priority was not ignored.
+
@param type_arg The requested lock type.
@param requestor_ctx The MDL context of the requestor.
@param ignore_lock_priority Ignore lock priority.
@@ -1726,78 +1716,72 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg,
MDL_context *requestor_ctx,
bool ignore_lock_priority) const
{
- 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];
- bool wsrep_can_grant= TRUE;
+#ifdef WITH_WSREP
/*
- New lock request can be satisfied iff:
- - There are no incompatible types of satisfied requests
- in other contexts
- - There are no waiting requests which have higher priority
- than this request when priority was not ignored.
+ Approve lock request in BACKUP namespace for BF threads.
+ We should get rid of this code and forbid FTWRL/BACKUP statements
+ when wsrep is active.
*/
- if (ignore_lock_priority || !(m_waiting.bitmap() & waiting_incompat_map))
+ if ((wsrep_thd_is_toi(requestor_ctx->get_thd()) ||
+ wsrep_thd_is_applying(requestor_ctx->get_thd())) &&
+ key.mdl_namespace() == MDL_key::BACKUP)
{
- if (! (m_granted.bitmap() & granted_incompat_map))
- can_grant= TRUE;
- else
+ bool waiting_incompatible= m_waiting.bitmap() & waiting_incompat_map;
+ bool granted_incompatible= m_granted.bitmap() & granted_incompat_map;
+ if (waiting_incompatible || granted_incompatible)
{
- Ticket_iterator it(m_granted);
- MDL_ticket *ticket;
+ WSREP_DEBUG("global lock granted for BF%s: %lu %s",
+ waiting_incompatible ? " (waiting queue)" : "",
+ thd_get_thread_id(requestor_ctx->get_thd()),
+ wsrep_thd_query(requestor_ctx->get_thd()));
+ }
+ return true;
+ }
+#endif /* WITH_WSREP */
- /* Check that the incompatible lock belongs to some other context. */
- while ((ticket= it++))
+ if (!ignore_lock_priority && (m_waiting.bitmap() & waiting_incompat_map))
+ return false;
+
+ if (m_granted.bitmap() & granted_incompat_map)
+ {
+ Ticket_iterator it(m_granted);
+ bool can_grant= true;
+
+ /* Check that the incompatible lock belongs to some other context. */
+ while (auto ticket= it++)
+ {
+ if (ticket->get_ctx() != requestor_ctx &&
+ ticket->is_incompatible_when_granted(type_arg))
{
- if (ticket->get_ctx() != requestor_ctx &&
- ticket->is_incompatible_when_granted(type_arg))
- {
+ can_grant= false;
#ifdef WITH_WSREP
- if (wsrep_thd_is_BF(requestor_ctx->get_thd(),false) &&
- key.mdl_namespace() == MDL_key::BACKUP)
- {
- WSREP_DEBUG("global lock granted for BF: %lu %s",
- thd_get_thread_id(requestor_ctx->get_thd()),
- wsrep_thd_query(requestor_ctx->get_thd()));
- can_grant = true;
- }
- else if (!wsrep_grant_mdl_exception(requestor_ctx, ticket, &key))
+ /*
+ non WSREP threads must report conflict immediately
+ note: RSU processing wsrep threads, have wsrep_on==OFF
+ */
+ if (WSREP(requestor_ctx->get_thd()) ||
+ requestor_ctx->get_thd()->wsrep_cs().mode() ==
+ wsrep::client_state::m_rsu)
+ {
+ wsrep_handle_mdl_conflict(requestor_ctx, ticket, &key);
+ if (wsrep_log_conflicts)
{
- 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" );
- }
+ auto key= ticket->get_key();
+ WSREP_INFO("MDL conflict db=%s table=%s ticket=%d solved by abort",
+ key->db_name(), key->name(), ticket->get_type());
}
- else
- can_grant= TRUE;
- /* Continue loop */
-#else
- break;
-#endif /* WITH_WSREP */
+ continue;
}
+#endif /* WITH_WSREP */
+ break;
}
- if ((ticket == NULL) && wsrep_can_grant)
- can_grant= TRUE; /* Incompatible locks are our own. */
- }
- }
- else
- {
- if (wsrep_thd_is_BF(requestor_ctx->get_thd(), false) &&
- key.mdl_namespace() == MDL_key::BACKUP)
- {
- WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s",
- thd_get_thread_id(requestor_ctx->get_thd()),
- wsrep_thd_query(requestor_ctx->get_thd()));
- can_grant = true;
}
+ return can_grant;
}
- return can_grant;
+ return true;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a7e29811dd1..216b5d1c622 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -72,8 +72,10 @@
#include "debug_sync.h"
#include "wsrep_mysqld.h"
#include "wsrep_var.h"
+#ifdef WITH_WSREP
#include "wsrep_thd.h"
#include "wsrep_sst.h"
+#endif /* WITH_WSREP */
#include "proxy_protocol.h"
#include "sql_callback.h"
@@ -1599,7 +1601,7 @@ static void close_connections(void)
error= mysql_cond_timedwait(&COND_start_thread, &LOCK_start_thread,
&abstime);
if (error != EINTR)
- break;
+ break;
}
#ifdef EXTRA_DEBUG
if (error != 0 && error != ETIMEDOUT && !count++)
@@ -1661,11 +1663,12 @@ static void close_connections(void)
#ifdef WITH_WSREP
/* skip wsrep system threads as well */
- if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier))
+ if (WSREP(tmp) && (wsrep_thd_is_applying(tmp) || tmp->wsrep_applier))
continue;
#endif
tmp->set_killed(KILL_SERVER_HARD);
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
+ if (WSREP(tmp)) mysql_mutex_lock(&tmp->LOCK_thd_data);
mysql_mutex_lock(&tmp->LOCK_thd_kill);
if (tmp->mysys_var)
{
@@ -1690,6 +1693,7 @@ static void close_connections(void)
mysql_mutex_unlock(&tmp->mysys_var->mutex);
}
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
+ if (WSREP(tmp)) mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
@@ -1759,7 +1763,7 @@ static void close_connections(void)
* 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)
+ if (WSREP(tmp) && wsrep_thd_is_applying(tmp))
{
sql_print_information("closing wsrep system thread");
tmp->set_killed(KILL_CONNECTION);
@@ -1782,6 +1786,12 @@ static void close_connections(void)
mysql_mutex_unlock(&LOCK_thread_count);
}
end_slave();
+#ifdef WITH_WSREP
+ if (wsrep_inited == 1)
+ {
+ wsrep_deinit(true);
+ }
+#endif
/* All threads has now been aborted */
DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
mysql_mutex_lock(&LOCK_thread_count);
@@ -1936,17 +1946,16 @@ static void kill_server(int sig)
else
sql_print_error(ER_DEFAULT(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
+#ifdef WITH_WSREP
/* Stop wsrep threads in case they are running. */
if (wsrep_running_threads > 0)
{
- wsrep_stop_replication(NULL);
+ wsrep_shutdown_replication();
}
+#endif
close_connections();
- if (wsrep_inited == 1)
- wsrep_deinit(true);
-
if (sig != MYSQL_KILL_SIGNAL &&
sig != 0)
unireg_abort(1); /* purecov: inspected */
@@ -2028,8 +2037,8 @@ extern "C" void unireg_abort(int exit_code)
disable_log_notes= 1;
#ifdef WITH_WSREP
- /* Check if wsrep class is used. If yes, then cleanup wsrep */
- if (wsrep)
+ if (WSREP_ON &&
+ Wsrep_server_state::instance().state() != wsrep::server_state::s_disconnected)
{
/*
This is an abort situation, we cannot expect to gracefully close all
@@ -2037,15 +2046,19 @@ extern "C" void unireg_abort(int exit_code)
*/
wsrep_close_client_connections(FALSE);
shutdown_in_progress= 1;
- wsrep->disconnect(wsrep);
+ Wsrep_server_state::instance().disconnect();
WSREP_INFO("Service disconnected.");
wsrep_close_threads(NULL); /* 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.");
-
+ }
+ if (WSREP_ON)
+ {
/* In bootstrap mode we deinitialize wsrep here. */
- if (opt_bootstrap && wsrep_inited)
- wsrep_deinit(true);
+ if (opt_bootstrap || wsrep_recovery)
+ {
+ if (wsrep_inited) wsrep_deinit(true);
+ }
}
#endif // WITH_WSREP
@@ -2073,6 +2086,9 @@ static void mysqld_exit(int exit_code)
rpl_deinit_gtid_waiting();
rpl_deinit_gtid_slave_state();
wait_for_signal_thread_to_end();
+#ifdef WITH_WSREP
+ wsrep_deinit_server();
+#endif /* WITH_WSREP */
mysql_audit_finalize();
clean_up_mutexes();
clean_up_error_log_mutex();
@@ -2309,9 +2325,6 @@ static void clean_up_mutexes()
****************************************************************************/
#ifdef EMBEDDED_LIBRARY
-static void set_ports()
-{
-}
void close_connection(THD *thd, uint sql_errno)
{
}
@@ -2805,12 +2818,14 @@ void unlink_thd(THD *thd)
thd->add_status_to_global();
unlink_not_visible_thd(thd);
+#ifdef WITH_WSREP
/*
Do not decrement when its wsrep system thread. wsrep_applier is set for
applier as well as rollbacker threads.
*/
- if (IF_WSREP(!thd->wsrep_applier, 1))
- dec_connection_count(thd->scheduler);
+ if (!thd->wsrep_applier)
+#endif /* WITH_WSREP */
+ dec_connection_count(thd->scheduler);
thd->free_connection();
@@ -5239,7 +5254,9 @@ static int init_server_components()
wsrep_thr_init();
#endif
- if (WSREP_ON && !wsrep_recovery && !opt_abort) /* WSREP BEFORE SE */
+#ifdef WITH_WSREP
+ if (wsrep_init_server()) unireg_abort(1);
+ if (WSREP_ON && !wsrep_recovery && !opt_abort)
{
if (opt_bootstrap) // bootsrap option given - disable wsrep functionality
{
@@ -5272,6 +5289,7 @@ static int init_server_components()
}
}
}
+#endif /* WITH_WSREP */
if (opt_bin_log)
{
@@ -5848,8 +5866,7 @@ int mysqld_main(int argc, char **argv)
set_user(mysqld_user, user_info);
}
- if (WSREP_ON && wsrep_check_opts())
- global_system_variables.wsrep_on= 0;
+ if (WSREP_ON && wsrep_check_opts()) unireg_abort(1);
/*
The subsequent calls may take a long time : e.g. innodb log read.
@@ -5949,24 +5966,11 @@ int mysqld_main(int argc, char **argv)
}
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 */
- if (wsrep_sst_continue())
- {
- WSREP_ERROR("Failed to signal the wsrep provider to continue.");
- }
- }
- else
+ wsrep_init_globals();
+ if (!wsrep_before_SE())
{
wsrep_init_startup (false);
}
-
wsrep_create_appliers(wsrep_slave_threads - 1);
}
}
@@ -8096,6 +8100,20 @@ SHOW_VAR status_vars[]= {
{"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC},
#endif
#ifdef WITH_WSREP
+ {"wsrep_connected", (char*) &wsrep_connected, SHOW_BOOL},
+ {"wsrep_ready", (char*) &wsrep_show_ready, SHOW_FUNC},
+ {"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_provider_capabilities", (char*) &wsrep_provider_capabilities, SHOW_CHAR_PTR},
+ {"wsrep_thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH},
+ {"wsrep_cluster_capabilities", (char*) &wsrep_cluster_capabilities, SHOW_CHAR_PTR},
{"wsrep", (char*) &wsrep_show_status, SHOW_FUNC},
#endif
{NullS, NullS, SHOW_LONG}
@@ -9558,7 +9576,9 @@ void refresh_status(THD *thd)
reset_status_vars();
#ifdef WITH_WSREP
if (WSREP_ON)
- wsrep->stats_reset(wsrep);
+ {
+ Wsrep_server_state::instance().provider().reset_status();
+ }
#endif /* WITH_WSREP */
/* Reset the counters of all key caches (default and named). */
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 7eee9283989..38eb8ac99f7 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -551,8 +551,26 @@ static uchar *net_store_length_fast(uchar *packet, size_t length)
void Protocol::end_statement()
{
- /* sanity check*/
- DBUG_ASSERT_IF_WSREP(!(WSREP(thd) && thd->wsrep_conflict_state == REPLAYING));
+#ifdef WITH_WSREP
+ /*
+ Commented out: This sanity check does not hold in general.
+ Thd->LOCK_thd_data() must be unlocked before sending response
+ to client, so BF abort may sneak in here.
+ DBUG_ASSERT(!WSREP(thd) || thd->wsrep_conflict_state() == NO_CONFLICT);
+ */
+
+ /*
+ sanity check, don't send end statement while replaying
+ */
+ DBUG_ASSERT(thd->wsrep_trx().state() != wsrep::transaction::s_replaying);
+ if (WSREP(thd) && thd->wsrep_trx().state() ==
+ wsrep::transaction::s_replaying)
+ {
+ WSREP_ERROR("attempting net_end_statement while replaying");
+ return;
+ }
+#endif /* WITH_WSREP */
+
DBUG_ENTER("Protocol::end_statement");
DBUG_ASSERT(! thd->get_stmt_da()->is_sent());
bool error= FALSE;
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index 94c1f08e4e3..84661fa513d 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -329,6 +329,7 @@ unpack_row(rpl_group_info *rgi,
(int) (pack_ptr - old_pack_ptr)));
if (!pack_ptr)
{
+#ifdef WITH_WSREP
if (WSREP_ON)
{
/*
@@ -344,7 +345,7 @@ unpack_row(rpl_group_info *rgi,
(table_found) ? "found" : "not found", row_end
);
}
-
+#endif /* WITH_WSREP */
rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT,
rgi->gtid_info(),
"Could not read field '%s' of table '%s.%s'",
diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc
new file mode 100644
index 00000000000..f4cf49b9b84
--- /dev/null
+++ b/sql/service_wsrep.cc
@@ -0,0 +1,255 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#include "mariadb.h"
+
+#include "mysql/service_wsrep.h"
+#include "wsrep/key.hpp"
+#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h"
+#include "sql_class.h"
+#include "debug_sync.h"
+
+extern "C" my_bool wsrep_on(const THD *thd)
+{
+ return my_bool(WSREP(thd));
+}
+
+extern "C" void wsrep_thd_LOCK(const THD *thd)
+{
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+}
+
+extern "C" void wsrep_thd_UNLOCK(const THD *thd)
+{
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+}
+
+extern "C" const char* wsrep_thd_client_state_str(const THD *thd)
+{
+ return wsrep::to_c_string(thd->wsrep_cs().state());
+}
+
+extern "C" const char* wsrep_thd_client_mode_str(const THD *thd)
+{
+ return wsrep::to_c_string(thd->wsrep_cs().mode());
+}
+
+extern "C" const char* wsrep_thd_transaction_state_str(const THD *thd)
+{
+ return wsrep::to_c_string(thd->wsrep_cs().transaction().state());
+}
+
+
+extern "C" const char *wsrep_thd_query(const THD *thd)
+{
+ return thd ? thd->query() : NULL;
+}
+
+extern "C" query_id_t wsrep_thd_transaction_id(const THD *thd)
+{
+ return thd->wsrep_cs().transaction().id().get();
+}
+
+extern "C" long long wsrep_thd_trx_seqno(const THD *thd)
+{
+ const wsrep::client_state& cs= thd->wsrep_cs();
+ if (cs.mode() == wsrep::client_state::m_toi)
+ {
+ return cs.toi_meta().seqno().get();
+ }
+ else
+ {
+ return cs.transaction().ws_meta().seqno().get();
+ }
+}
+
+extern "C" void wsrep_thd_self_abort(THD *thd)
+{
+ thd->wsrep_cs().bf_abort(wsrep::seqno(0));
+}
+
+extern "C" const char* wsrep_get_sr_table_name()
+{
+ return wsrep_sr_table_name_full;
+}
+
+extern "C" my_bool wsrep_get_debug()
+{
+ return wsrep_debug;
+}
+
+extern "C" my_bool wsrep_thd_is_local(const THD *thd)
+{
+ return thd->wsrep_cs().mode() == wsrep::client_state::m_local;
+}
+
+extern "C" my_bool wsrep_thd_is_applying(const THD *thd)
+{
+ return thd->wsrep_cs().mode() == wsrep::client_state::m_high_priority;
+}
+
+extern "C" my_bool wsrep_thd_is_toi(const THD *thd)
+{
+ return thd->wsrep_cs().mode() == wsrep::client_state::m_toi;
+}
+
+extern "C" my_bool wsrep_thd_is_local_toi(const THD *thd)
+{
+ return thd->wsrep_cs().mode() == wsrep::client_state::m_toi &&
+ thd->wsrep_cs().toi_mode() == wsrep::client_state::m_local;
+
+}
+
+extern "C" my_bool wsrep_thd_is_in_rsu(const THD *thd)
+{
+ return thd->wsrep_cs().mode() == wsrep::client_state::m_rsu;
+}
+
+extern "C" my_bool wsrep_thd_is_BF(const THD *thd, my_bool sync)
+{
+ my_bool status = FALSE;
+ if (thd && WSREP(thd))
+ {
+ if (sync) mysql_mutex_lock(&thd->LOCK_thd_data);
+ status = (wsrep_thd_is_applying(thd) || wsrep_thd_is_toi(thd));
+ if (sync) mysql_mutex_unlock(&thd->LOCK_thd_data);
+ }
+ return status;
+}
+
+extern "C" my_bool wsrep_thd_is_SR(const THD *thd)
+{
+ return thd && thd->wsrep_cs().transaction().is_streaming();
+}
+
+extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
+ THD *victim_thd)
+{
+ DBUG_ASSERT(victim_thd);
+ if (!victim_thd || !wsrep_on(bf_thd)) return;
+
+ WSREP_DEBUG("handle rollback, for deadlock: thd %llu trx_id %lu frags %lu conf %s",
+ victim_thd->thread_id,
+ victim_thd->wsrep_trx_id(),
+ victim_thd->wsrep_sr().fragments_certified(),
+ wsrep_thd_transaction_state_str(victim_thd));
+ if (bf_thd) victim_thd->store_globals();
+ if (!bf_thd)
+ {
+ DEBUG_SYNC(victim_thd, "wsrep_before_SR_rollback");
+ }
+ if (bf_thd)
+ {
+ wsrep_bf_abort(bf_thd, victim_thd);
+ }
+ else
+ {
+ wsrep_thd_self_abort(victim_thd);
+ }
+ if (bf_thd) bf_thd->store_globals();
+}
+
+extern "C" my_bool wsrep_thd_bf_abort(const THD *bf_thd, THD *victim_thd,
+ my_bool signal)
+{
+ if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
+ {
+ WSREP_DEBUG("BF abort for non active transaction");
+ wsrep_start_transaction(victim_thd, victim_thd->wsrep_next_trx_id());
+ }
+ my_bool ret= wsrep_bf_abort(bf_thd, victim_thd);
+ /*
+ Send awake signal if victim was BF aborted or does not
+ have wsrep on. Note that this should never interrupt RSU
+ as RSU has paused the provider.
+ */
+ if ((ret || !wsrep_on(victim_thd)) && signal)
+ victim_thd->awake(KILL_QUERY);
+ return ret;
+}
+
+extern "C" my_bool wsrep_thd_skip_locking(const THD *thd)
+{
+ return thd && thd->wsrep_skip_locking;
+}
+
+extern "C" my_bool wsrep_thd_order_before(const THD *left, const THD *right)
+{
+ if (wsrep_thd_trx_seqno(left) < wsrep_thd_trx_seqno(right)) {
+ WSREP_DEBUG("BF conflict, order: %lld %lld\n",
+ (long long)wsrep_thd_trx_seqno(left),
+ (long long)wsrep_thd_trx_seqno(right));
+ return TRUE;
+ }
+ WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
+ (long long)wsrep_thd_trx_seqno(left),
+ (long long)wsrep_thd_trx_seqno(right));
+ return FALSE;
+}
+
+extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd)
+{
+ mysql_mutex_assert_owner(&thd->LOCK_thd_data);
+ if (thd != 0)
+ {
+ const wsrep::client_state& cs(thd->wsrep_cs());
+ const enum wsrep::transaction::state tx_state(cs.transaction().state());
+ switch (tx_state)
+ {
+ case wsrep::transaction::s_must_abort:
+ return (cs.state() == wsrep::client_state::s_exec ||
+ cs.state() == wsrep::client_state::s_result);
+ case wsrep::transaction::s_aborting:
+ case wsrep::transaction::s_aborted:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+static inline enum wsrep::key::type
+map_key_type(enum Wsrep_service_key_type type)
+{
+ switch (type)
+ {
+ case WSREP_SERVICE_KEY_SHARED: return wsrep::key::shared;
+ case WSREP_SERVICE_KEY_REFERENCE: return wsrep::key::reference;
+ case WSREP_SERVICE_KEY_UPDATE: return wsrep::key::update;
+ case WSREP_SERVICE_KEY_EXCLUSIVE: return wsrep::key::exclusive;
+ }
+ return wsrep::key::exclusive;
+}
+
+extern "C" int wsrep_thd_append_key(THD *thd,
+ const struct wsrep_key* key,
+ int n_keys,
+ enum Wsrep_service_key_type key_type)
+{
+ Wsrep_client_state& client_state(thd->wsrep_cs());
+ DBUG_ASSERT(client_state.transaction().active());
+ int ret= 0;
+ for (int i= 0; i < n_keys && ret == 0; ++i)
+ {
+ wsrep::key wsrep_key(map_key_type(key_type));
+ for (size_t kp= 0; kp < key[i].key_parts_num; ++kp)
+ {
+ wsrep_key.append_key_part(key[i].key_parts[kp].ptr, key[i].key_parts[kp].len);
+ }
+ ret= client_state.append_key(wsrep_key);
+ }
+ return ret;
+}
diff --git a/sql/slave.cc b/sql/slave.cc
index 5fbe0c77661..f31021bc71e 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -53,6 +53,9 @@
// Create_file_log_event,
// Format_description_log_event
#include "wsrep_mysqld.h"
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h"
+#endif
#ifdef HAVE_REPLICATION
@@ -1201,6 +1204,11 @@ terminate_slave_thread(THD *thd,
int error __attribute__((unused));
DBUG_PRINT("loop", ("killing slave thread"));
+#ifdef WITH_WSREP
+ /* awake_no_mutex() requires LOCK_thd_data to be locked if wsrep
+ is enabled */
+ if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data);
+#endif /* WITH_WSREP */
mysql_mutex_lock(&thd->LOCK_thd_kill);
#ifndef DONT_USE_THR_ALARM
/*
@@ -1214,6 +1222,9 @@ terminate_slave_thread(THD *thd,
thd->awake_no_mutex(NOT_KILLED);
mysql_mutex_unlock(&thd->LOCK_thd_kill);
+#ifdef WITH_WSREP
+ if (WSREP(thd)) mysql_mutex_unlock(&thd->LOCK_thd_data);
+#endif /* WITH_WSREP */
/*
There is a small chance that slave thread might miss the first
@@ -3943,14 +3954,20 @@ apply_event_and_update_pos_apply(Log_event* ev, THD* thd, rpl_group_info *rgi,
exec_res= ev->apply_event(rgi);
#ifdef WITH_WSREP
- if (exec_res && thd->wsrep_conflict_state != NO_CONFLICT)
+ if (WSREP_ON)
+ {
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ if (exec_res &&
+ thd->wsrep_trx().state() != wsrep::transaction::s_executing)
{
- WSREP_DEBUG("SQL apply failed, res %d conflict state: %d",
- exec_res, thd->wsrep_conflict_state);
+ WSREP_DEBUG("SQL apply failed, res %d conflict state: %s",
+ exec_res, wsrep_thd_transaction_state_str(thd));
rli->abort_slave= 1;
rli->report(ERROR_LEVEL, ER_UNKNOWN_COM_ERROR, rgi->gtid_info(),
"Node has dropped from cluster");
}
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ }
#endif
#ifndef DBUG_OFF
@@ -4243,6 +4260,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
}
if (ev)
{
+#ifdef WITH_WSREP
+ if (wsrep_before_statement(thd))
+ {
+ WSREP_INFO("Wsrep before statement error");
+ DBUG_RETURN(1);
+ }
+#endif /* WITH_WSREP */
int exec_res;
Log_event_type typ= ev->get_type_code();
@@ -4274,9 +4298,9 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
rli->until_condition == Relay_log_info::UNTIL_RELAY_POS) &&
(ev->server_id != global_system_variables.server_id ||
rli->replicate_same_server_id) &&
- rli->is_until_satisfied((rli->get_flag(Relay_log_info::IN_TRANSACTION) || !ev->log_pos)
- ? rli->group_master_log_pos
- : ev->log_pos - ev->data_written))
+ rli->is_until_satisfied((rli->get_flag(Relay_log_info::IN_TRANSACTION) || !ev->log_pos)
+ ? rli->group_master_log_pos
+ : ev->log_pos - ev->data_written))
{
sql_print_information("Slave SQL thread stopped because it reached its"
" UNTIL position %llu", rli->until_pos());
@@ -4287,6 +4311,9 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
rli->abort_slave= 1;
rli->stop_for_until= true;
mysql_mutex_unlock(&rli->data_lock);
+#ifdef WITH_WSREP
+ wsrep_after_statement(thd);
+#endif /* WITH_WSREP */
delete ev;
DBUG_RETURN(1);
}
@@ -4324,7 +4351,12 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
if (res == 0)
rli->event_relay_log_pos= rli->future_event_relay_log_pos;
if (res >= 0)
+ {
+#ifdef WITH_WSREP
+ wsrep_after_statement(thd);
+#endif /* WITH_WSREP */
DBUG_RETURN(res);
+ }
/*
Else we proceed to execute the event non-parallel.
This is the case for pre-10.0 events without GTID, and for handling
@@ -4359,6 +4391,9 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
"aborted because of out-of-memory error");
mysql_mutex_unlock(&rli->data_lock);
delete ev;
+#ifdef WITH_WSREP
+ wsrep_after_statement(thd);
+#endif /* WITH_WSREP */
DBUG_RETURN(1);
}
@@ -4373,6 +4408,9 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
"thread aborted because of out-of-memory error");
mysql_mutex_unlock(&rli->data_lock);
delete ev;
+#ifdef WITH_WSREP
+ wsrep_after_statement(thd);
+#endif /* WITH_WSREP */
DBUG_RETURN(1);
}
/*
@@ -4401,13 +4439,17 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
retry.
*/
if (unlikely(exec_res == 2))
+ {
+#ifdef WITH_WSREP
+ wsrep_after_statement(thd);
+#endif /* WITH_WSREP */
DBUG_RETURN(1);
-
+ }
#ifdef WITH_WSREP
mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state == NO_CONFLICT)
- {
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ enum wsrep::client_error wsrep_error= thd->wsrep_cs().current_error();
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ if (wsrep_error == wsrep::e_success)
#endif /* WITH_WSREP */
if (slave_trans_retries)
{
@@ -4420,8 +4462,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
We were in a transaction which has been rolled back because of a
temporary error;
let's seek back to BEGIN log event and retry it all again.
- Note, if lock wait timeout (innodb_lock_wait_timeout exceeded)
- there is no rollback since 5.0.13 (ref: manual).
+ Note, if lock wait timeout (innodb_lock_wait_timeout exceeded)
+ there is no rollback since 5.0.13 (ref: manual).
We have to not only seek but also
a) init_master_info(), to seek back to hot relay log's start
@@ -4482,13 +4524,11 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
serial_rgi->trans_retries));
}
}
-#ifdef WITH_WSREP
- }
- else
- mysql_mutex_unlock(&thd->LOCK_thd_data);
-#endif /* WITH_WSREP */
thread_safe_increment64(&rli->executed_entries);
+#ifdef WITH_WSREP
+ wsrep_after_statement(thd);
+#endif /* WITH_WSREP */
DBUG_RETURN(exec_res);
}
mysql_mutex_unlock(&rli->data_lock);
@@ -5415,12 +5455,6 @@ pthread_handler_t handle_slave_sql(void *arg)
}
#endif
-#ifdef WITH_WSREP
- thd->wsrep_exec_mode= LOCAL_STATE;
- /* synchronize with wsrep replication */
- if (WSREP_ON)
- wsrep_ready_wait();
-#endif
DBUG_PRINT("master_info",("log_file_name: %s position: %llu",
rli->group_master_log_name,
rli->group_master_log_pos));
@@ -5517,7 +5551,14 @@ pthread_handler_t handle_slave_sql(void *arg)
goto err;
}
mysql_mutex_unlock(&rli->data_lock);
-
+#ifdef WITH_WSREP
+ wsrep_open(thd);
+ if (wsrep_before_command(thd))
+ {
+ WSREP_WARN("Slave SQL wsrep_before_command() failed");
+ goto err;
+ }
+#endif /* WITH_WSREP */
/* Read queries from the IO/THREAD until this thread is killed */
thd->set_command(COM_SLAVE_SQL);
@@ -5554,10 +5595,16 @@ pthread_handler_t handle_slave_sql(void *arg)
if (exec_relay_log_event(thd, rli, serial_rgi))
{
#ifdef WITH_WSREP
- if (thd->wsrep_conflict_state != NO_CONFLICT)
+ if (WSREP_ON)
{
- wsrep_node_dropped= TRUE;
- rli->abort_slave= TRUE;
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+
+ if (thd->wsrep_cs().current_error())
+ {
+ wsrep_node_dropped = TRUE;
+ rli->abort_slave = TRUE;
+ }
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
#endif /* WITH_WSREP */
@@ -5590,6 +5637,10 @@ pthread_handler_t handle_slave_sql(void *arg)
"log '%s' at position %llu%s", RPL_LOG_NAME,
rli->group_master_log_pos, tmp.c_ptr_safe());
}
+#ifdef WITH_WSREP
+ wsrep_after_command_before_result(thd);
+ wsrep_after_command_after_result(thd);
+#endif /* WITH_WSREP */
err_before_start:
@@ -5708,17 +5759,17 @@ err_during_init:
"SQL slave will continue");
wsrep_node_dropped= FALSE;
mysql_mutex_unlock(&rli->run_lock);
- WSREP_DEBUG("wsrep_conflict_state now: %d", thd->wsrep_conflict_state);
- WSREP_INFO("slave restart: %d", thd->wsrep_conflict_state);
- thd->wsrep_conflict_state= NO_CONFLICT;
goto wsrep_restart_point;
- } else {
+ }
+ 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.");
+ "automatically restarted when node joins back to cluster");
wsrep_restart_slave_activated= TRUE;
}
}
+ wsrep_close(thd);
#endif /* WITH_WSREP */
/*
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 56b4fc8c948..8345a9efe61 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -44,6 +44,9 @@
#include "transaction.h" // trans_commit_stmt
#include "sql_audit.h"
#include "debug_sync.h"
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
/*
Sufficient max length of printed destinations and frame offsets (all uints).
@@ -1324,6 +1327,13 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
sql_digest_state *parent_digest= thd->m_digest;
thd->m_digest= NULL;
+#ifdef WITH_WSREP
+ if (WSREP(thd) && thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ thd->set_wsrep_next_trx_id(thd->query_id);
+ WSREP_DEBUG("assigned new next trx ID for SP, trx id: %lu", thd->wsrep_next_trx_id());
+ }
+#endif /* WITH_WSREP */
err_status= i->execute(thd, &ip);
thd->m_digest= parent_digest;
@@ -3566,6 +3576,24 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp)
(char *)thd->security_ctx->host_or_ip,
3);
int res= mysql_execute_command(thd);
+#ifdef WITH_WSREP
+ if ((thd->is_fatal_error || thd->killed_errno()) &&
+ (thd->wsrep_trx().state() == wsrep::transaction::s_executing))
+ {
+ /*
+ SP was killed, and it is not due to a wsrep conflict.
+ We skip after_command hook at this point because
+ otherwise it clears the error, and cleans up the
+ whole transaction. For now we just return and finish
+ our handling once we are back to mysql_parse.
+ */
+ WSREP_DEBUG("Skipping after_command hook for killed SP");
+ }
+ else
+ {
+ (void) wsrep_after_statement(thd);
+ }
+#endif /* WITH_WSREP */
MYSQL_QUERY_EXEC_DONE(res);
*nextp= m_ip+1;
return res;
@@ -4503,8 +4531,8 @@ int
sp_instr_error::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_error::execute");
-
my_message(m_errcode, ER_THD(thd, m_errcode), MYF(0));
+ WSREP_DEBUG("sp_instr_error: %s %d", ER_THD(thd, m_errcode), thd->is_error());
*nextp= m_ip+1;
DBUG_RETURN(-1);
}
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index fe6fc9148bd..2edae501ccc 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3461,7 +3461,6 @@ wsrep_error_label:
WSREP_TO_ISOLATION_END;
thd->set_query(query_save);
- thd->wsrep_exec_mode = LOCAL_STATE;
}
#endif /* WITH_WSREP */
thd->restore_stmt_binlog_format(save_binlog_format);
@@ -3613,7 +3612,6 @@ wsrep_error_label:
WSREP_TO_ISOLATION_END;
thd->set_query(query_save);
- thd->wsrep_exec_mode = LOCAL_STATE;
}
#endif /* WITH_WSREP */
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 05a71d7785d..4e5ac6e9381 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -476,6 +476,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
thd->work_part_info= 0;
#endif
+#ifdef WITH_WSREP
if (WSREP(thd) &&
(!thd->is_current_stmt_binlog_format_row() ||
!thd->find_temporary_table(first_table)))
@@ -487,6 +488,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
thd->variables.auto_increment_offset = 1;
thd->variables.auto_increment_increment = 1;
}
+#endif
result= mysql_alter_table(thd, &select_lex->db, &lex->name,
&create_info,
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1b4ffd0c61e..ad7ff34190a 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -62,7 +62,11 @@
#include <io.h>
#endif
#include "wsrep_mysqld.h"
+#ifdef WITH_WSREP
#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
+
bool
No_such_table_error_handler::handle_condition(THD *,
@@ -4410,13 +4414,14 @@ restart:
}
}
+#ifdef WITH_WSREP
if (WSREP_ON &&
wsrep_replicate_myisam &&
(*start) &&
(*start)->table &&
(*start)->table->file->ht == myisam_hton &&
- wsrep_thd_exec_mode(thd) == LOCAL_STATE &&
- !is_stat_table(&(*start)->db, &(*start)->alias) &&
+ wsrep_thd_is_local(thd) &&
+ !is_stat_table(&(*start)->db, &(*start)->alias) &&
thd->get_command() != COM_STMT_PREPARE &&
((thd->lex->sql_command == SQLCOM_INSERT ||
thd->lex->sql_command == SQLCOM_INSERT_SELECT ||
@@ -4427,8 +4432,12 @@ restart:
thd->lex->sql_command == SQLCOM_LOAD ||
thd->lex->sql_command == SQLCOM_DELETE)))
{
- WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start));
+ wsrep_before_rollback(thd, true);
+ wsrep_after_rollback(thd, true);
+ wsrep_after_statement(thd);
+ WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start));
}
+#endif /* WITH_WSREP */
error:
#ifdef WITH_WSREP
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fa2f866a3f6..87e377c1819 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -66,8 +66,11 @@
#include "sql_callback.h"
#include "lock.h"
#include "wsrep_mysqld.h"
-#include "wsrep_thd.h"
#include "sql_connect.h"
+#ifdef WITH_WSREP
+#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
@@ -639,16 +642,42 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
xid_hash_pins(0),
m_tmp_tables_locked(false)
#ifdef WITH_WSREP
- ,
+ ,
wsrep_applier(is_wsrep_applier),
wsrep_applier_closing(false),
wsrep_client_thread(false),
- wsrep_apply_toi(false),
+ 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_mysql_replicated(0),
+ wsrep_TOI_pre_query(NULL),
+ wsrep_TOI_pre_query_len(0),
wsrep_po_handle(WSREP_PO_INITIALIZER),
wsrep_po_cnt(0),
wsrep_apply_format(0),
- wsrep_ignore_table(false)
-#endif
+ wsrep_apply_toi(false),
+ wsrep_rbr_buf(NULL),
+ wsrep_sync_wait_gtid(WSREP_GTID_UNDEFINED),
+ wsrep_affected_rows(0),
+ wsrep_has_ignored_error(false),
+ wsrep_replicate_GTID(false),
+ wsrep_ignore_table(false),
+
+/* wsrep-lib */
+ m_wsrep_next_trx_id(WSREP_UNDEFINED_TRX_ID),
+ m_wsrep_mutex(LOCK_thd_data),
+ m_wsrep_cond(COND_wsrep_thd),
+ m_wsrep_client_service(this, m_wsrep_client_state),
+ m_wsrep_client_state(this,
+ m_wsrep_mutex,
+ m_wsrep_cond,
+ Wsrep_server_state::instance(),
+ m_wsrep_client_service,
+ wsrep::client_id(thread_id))
+#endif /*WITH_WSREP */
{
ulong tmp;
bzero(&variables, sizeof(variables));
@@ -771,22 +800,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
*scramble= '\0';
#ifdef WITH_WSREP
- 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_mysql_replicated = 0;
- wsrep_TOI_pre_query = NULL;
- wsrep_TOI_pre_query_len = 0;
+ mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL);
wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */
- wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
- wsrep_affected_rows = 0;
- wsrep_replicate_GTID = false;
- wsrep_skip_wsrep_GTID = false;
#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -1049,10 +1064,25 @@ Sql_condition* THD::raise_condition(uint sql_errno,
is_slave_error= 1; // needed to catch query errors during replication
- if (!da->is_error())
+#ifdef WITH_WSREP
+ /*
+ With wsrep we allow converting BF abort error to warning if
+ errors are ignored.
+ */
+ if (!is_fatal_error &&
+ no_errors &&
+ (wsrep_trx().bf_aborted() || wsrep_retry_counter))
{
- set_row_count_func(-1);
- da->set_error_status(sql_errno, msg, sqlstate, ucid, cond);
+ WSREP_DEBUG("BF abort error converted to warning");
+ }
+ else
+#endif /* WITH_WSREP */
+ {
+ if (!da->is_error())
+ {
+ set_row_count_func(-1);
+ da->set_error_status(sql_errno, msg, sqlstate, ucid, cond);
+ }
}
}
@@ -1113,6 +1143,13 @@ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size)
extern "C"
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
{
+#ifdef WITH_WSREP
+ if (!thd->wsrep_xid.is_null())
+ {
+ *xid = *(MYSQL_XID *) &thd->wsrep_xid;
+ }
+ else
+#endif /* WITH_WSREP */
*xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid;
}
@@ -1221,12 +1258,9 @@ void THD::init(bool skip_lock)
first_successful_insert_id_in_cur_stmt= 0;
current_backup_stage= BACKUP_FINISHED;
#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_xid.null();
+ wsrep_skip_locking= FALSE;
wsrep_converted_lock_session= false;
wsrep_retry_counter= 0;
wsrep_rgi= NULL;
@@ -1235,10 +1269,10 @@ void THD::init(bool skip_lock)
wsrep_mysql_replicated = 0;
wsrep_TOI_pre_query = NULL;
wsrep_TOI_pre_query_len = 0;
- wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
+ wsrep_rbr_buf = NULL;
wsrep_affected_rows = 0;
+ m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
wsrep_replicate_GTID = false;
- wsrep_skip_wsrep_GTID = false;
#endif /* WITH_WSREP */
if (variables.sql_log_bin)
@@ -1467,6 +1501,13 @@ void THD::cleanup(void)
#error xid_state in the cache should be replaced by the allocated value
}
#endif
+#ifdef WITH_WSREP
+ if (wsrep_cs().state() != wsrep::client_state::s_none)
+ {
+ wsrep_cs().cleanup();
+ }
+ wsrep_client_thread= false;
+#endif /* WITH_WSREP */
mysql_ha_cleanup(this);
locked_tables_list.unlock_locked_tables(this);
@@ -1587,6 +1628,9 @@ void THD::reset_for_reuse()
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
+#ifdef WITH_WSREP
+ wsrep_free_status(this);
+#endif /* WITH_WSREP */
}
@@ -1613,15 +1657,21 @@ THD::~THD()
THD is not deleted while they access it. The following mutex_lock
ensures that no one else is using this THD and it's now safe to delete
*/
+ if (WSREP(this)) mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
mysql_mutex_unlock(&LOCK_thd_kill);
+ if (WSREP(this)) mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef WITH_WSREP
- delete wsrep_rgi;
-#endif
if (!free_connection_done)
free_connection();
+#ifdef WITH_WSREP
+ if (wsrep_rgi != NULL) {
+ delete wsrep_rgi;
+ wsrep_rgi = NULL;
+ }
+ mysql_cond_destroy(&COND_wsrep_thd);
+#endif
mdl_context.destroy();
free_root(&transaction.mem_root,MYF(0));
@@ -1803,6 +1853,7 @@ void THD::awake_no_mutex(killed_state state_to_set)
DBUG_PRINT("enter", ("this: %p current_thd: %p state: %d",
this, current_thd, (int) state_to_set));
THD_CHECK_SENTRY(this);
+ if (WSREP(this)) mysql_mutex_assert_owner(&LOCK_thd_data);
mysql_mutex_assert_owner(&LOCK_thd_kill);
print_aborted_warning(3, "KILLED");
@@ -1835,7 +1886,8 @@ void THD::awake_no_mutex(killed_state state_to_set)
}
/* Interrupt target waiting inside a storage engine. */
- if (state_to_set != NOT_KILLED)
+ if (IF_WSREP(state_to_set != NOT_KILLED && !wsrep_is_bf_aborted(this),
+ state_to_set != NOT_KILLED))
ha_kill_query(this, thd_kill_level(this));
/* Broadcast a condition to kick the target if it is waiting on it. */
@@ -1988,12 +2040,6 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
if (!thd_table->needs_reopen())
{
signalled|= mysql_lock_abort_for_thread(this, thd_table);
- if (WSREP(this) && wsrep_thd_is_BF(this, FALSE))
- {
- WSREP_DEBUG("remove_table_from_cache: %llu",
- (unsigned long long) this->real_id);
- wsrep_abort_thd((void *)this, (void *)in_use, FALSE);
- }
}
}
}
@@ -2225,12 +2271,6 @@ void THD::cleanup_after_query()
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= INVOKER_NONE;
-#ifdef WITH_WSREP
- if (TOTAL_ORDER == wsrep_exec_mode)
- {
- wsrep_exec_mode = LOCAL_STATE;
- }
-#endif /* WITH_WSREP */
#ifndef EMBEDDED_LIBRARY
if (rgi_slave)
@@ -2238,7 +2278,6 @@ void THD::cleanup_after_query()
#endif
#ifdef WITH_WSREP
- wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
if (!in_active_multi_stmt_transaction())
wsrep_affected_rows= 0;
#endif /* WITH_WSREP */
@@ -5007,8 +5046,9 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd)
if (WSREP(thd))
{
/* for wsrep binlog format is meaningful also when binlogging is off */
- return (int) thd->wsrep_binlog_format();
+ return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
}
+
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
return (int) thd->variables.binlog_format;
return BINLOG_FORMAT_UNSPEC;
@@ -5491,6 +5531,10 @@ void THD::set_query_and_id(char *query_arg, uint32 query_length_arg,
set_query_inner(query_arg, query_length_arg, cs);
mysql_mutex_unlock(&LOCK_thd_data);
query_id= new_query_id;
+#ifdef WITH_WSREP
+ set_wsrep_next_trx_id(query_id);
+ WSREP_DEBUG("assigned new next query and trx id: %lu", wsrep_next_trx_id());
+#endif /* WITH_WSREP */
}
/** Assign a new value to thd->mysys_var. */
@@ -5936,9 +5980,27 @@ int THD::decide_logging_format(TABLE_LIST *tables)
binlogging is off, or if the statement is filtered out from the
binlog by filtering rules.
*/
+#ifdef WITH_WSREP
+ if (WSREP_CLIENT_NNULL(this) && variables.wsrep_trx_fragment_size > 0)
+ {
+ if (!is_current_stmt_binlog_format_row())
+ {
+ my_message(ER_NOT_SUPPORTED_YET,
+ "Streaming replication not supported with "
+ "binlog_format=STATEMENT", MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+
+ if ((WSREP_EMULATE_BINLOG_NNULL(this) ||
+ (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG))) &&
+ !(wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
+ !binlog_filter->db_ok(db.str)))
+#else
if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
!(wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
!binlog_filter->db_ok(db.str)))
+#endif /* WITH_WSREP */
{
if (is_bulk_op())
@@ -6260,7 +6322,8 @@ 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
*/
- if (IF_WSREP((!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1))
+ if (IF_WSREP((!WSREP(this) ||
+ wsrep_cs().mode() == wsrep::client_state::m_local),1))
{
my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 69fabee708c..55eceda6c9f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -60,8 +60,18 @@ void set_thd_stage_info(void *thd,
#include "my_apc.h"
#include "rpl_gtid.h"
+
#include "wsrep_mysqld.h"
+#ifdef WITH_WSREP
+/* wsrep-lib */
+#include "wsrep_client_service.h"
+#include "wsrep_client_state.h"
+#include "wsrep_mutex.h"
+#include "wsrep_condition_variable.h"
+class Wsrep_applier_service;
+
+#endif /* WITH_WSREP */
class Reprepare_observer;
class Relay_log_info;
struct rpl_group_info;
@@ -712,10 +722,12 @@ typedef struct system_variables
my_bool wsrep_on;
my_bool wsrep_causal_reads;
+ uint wsrep_sync_wait;
+ ulong wsrep_retry_autocommit;
+ ulonglong wsrep_trx_fragment_size;
+ ulong wsrep_trx_fragment_unit;
+ ulong wsrep_OSU_method;
my_bool wsrep_dirty_reads;
- uint wsrep_sync_wait;
- ulong wsrep_retry_autocommit;
- ulong wsrep_OSU_method;
double long_query_time_double, max_statement_time_double;
my_bool pseudo_slave_mode;
@@ -2235,7 +2247,7 @@ public:
- thd->db (used in SHOW PROCESSLIST)
Is locked when THD is deleted.
*/
- mysql_mutex_t LOCK_thd_data;
+ mutable mysql_mutex_t LOCK_thd_data;
/*
Protects:
- kill information
@@ -3196,7 +3208,6 @@ public:
mysql_bin_log.start_union_events() call.
*/
bool unioned_events_trans;
-
/*
'queries' (actually SP statements) that run under inside this binlog
union have thd->query_id >= first_query_id.
@@ -3204,7 +3215,6 @@ public:
query_id_t first_query_id;
} binlog_evt_union;
- mysql_cond_t COND_wsrep_thd;
/**
Internal parser state.
Note that since the parser is not re-entrant, we keep only one parser
@@ -3287,9 +3297,18 @@ public:
void awake_no_mutex(killed_state state_to_set);
void awake(killed_state state_to_set)
{
+ bool wsrep_on_local= WSREP_ON;
+ /*
+ mutex locking order (LOCK_thd_data - LOCK_thd_kill)) requires
+ to grab LOCK_thd_data here
+ */
+ if (wsrep_on_local)
+ mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
awake_no_mutex(state_to_set);
mysql_mutex_unlock(&LOCK_thd_kill);
+ if (wsrep_on_local)
+ mysql_mutex_unlock(&LOCK_thd_data);
}
/** Disconnect the associated communication endpoint. */
@@ -4497,6 +4516,13 @@ public:
void set_query_id(query_id_t new_query_id)
{
query_id= new_query_id;
+#ifdef WITH_WSREP
+ if (WSREP(this))
+ {
+ set_wsrep_next_trx_id(query_id);
+ WSREP_DEBUG("assigned new next trx id: %lu", wsrep_next_trx_id());
+ }
+#endif /* WITH_WSREP */
}
void set_open_tables(TABLE *open_tables_arg)
{
@@ -4752,52 +4778,114 @@ private:
public:
inline ulong wsrep_binlog_format() const
{
- return WSREP_FORMAT(variables.binlog_format);
+ return WSREP_BINLOG_FORMAT(variables.binlog_format);
}
#ifdef WITH_WSREP
- const bool wsrep_applier; /* dedicated slave applier thread */
+ bool wsrep_applier; /* dedicated slave applier thread */
bool wsrep_applier_closing; /* applier marked to close */
bool wsrep_client_thread; /* to identify client threads*/
- bool wsrep_PA_safe;
- bool wsrep_converted_lock_session;
- bool wsrep_apply_toi; /* applier processing in TOI */
- 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;
- wsrep_trx_meta_t wsrep_trx_meta;
+ XID wsrep_xid;
+
+ /** This flag denotes that record locking should be skipped during INSERT
+ and gap locking during SELECT. Only used by the streaming replication thread
+ that only modifies the wsrep_schema.SR table. */
+ my_bool wsrep_skip_locking;
+
+ mysql_cond_t COND_wsrep_thd;
+
+ // changed from wsrep_seqno_t to wsrep_trx_meta_t in wsrep API rev 75
uint32 wsrep_rand;
- Relay_log_info *wsrep_rli;
rpl_group_info *wsrep_rgi;
- wsrep_ws_handle_t wsrep_ws_handle;
+ bool wsrep_converted_lock_session;
+ char wsrep_info[128]; /* string for dynamic proc info */
ulong wsrep_retry_counter; // of autocommit
- char *wsrep_retry_query;
+ 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
+ enum wsrep_consistency_check_mode
wsrep_consistency_check;
+ std::vector<wsrep::provider::status_variable> wsrep_status_vars;
int wsrep_mysql_replicated;
- const char *wsrep_TOI_pre_query; /* a query to apply before
- the actual TOI query */
+ const char* wsrep_TOI_pre_query; /* a query to apply before
+ the actual TOI query */
size_t wsrep_TOI_pre_query_len;
wsrep_po_handle_t wsrep_po_handle;
size_t wsrep_po_cnt;
#ifdef GTID_SUPPORT
+ my_bool wsrep_po_in_trans;
rpl_sid wsrep_po_sid;
-#endif /* GTID_SUPPORT */
+#endif /* GTID_SUPPORT */
void *wsrep_apply_format;
- char wsrep_info[128]; /* string for dynamic proc info */
+ bool wsrep_apply_toi; /* applier processing in TOI */
+ uchar* wsrep_rbr_buf;
+ wsrep_gtid_t wsrep_sync_wait_gtid;
+ // wsrep_gtid_t wsrep_last_written_gtid;
+ ulong wsrep_affected_rows;
+ bool wsrep_has_ignored_error;
+ bool wsrep_replicate_GTID;
+
/*
When enabled, do not replicate/binlog updates from the current table that's
being processed. At the moment, it is used to keep mysql.gtid_slave_pos
table updates from being replicated to other nodes via galera replication.
*/
bool wsrep_ignore_table;
- wsrep_gtid_t wsrep_sync_wait_gtid;
- ulong wsrep_affected_rows;
- bool wsrep_replicate_GTID;
- bool wsrep_skip_wsrep_GTID;
+
+
+ /*
+ Transaction id:
+ * m_wsrep_next_trx_id is assigned on the first query after
+ wsrep_next_trx_id() return WSREP_UNDEFINED_TRX_ID
+ * Each storage engine must assign value of wsrep_next_trx_id()
+ when the transaction starts.
+ * Effective transaction id is returned via wsrep_trx_id()
+ */
+ /*
+ Return effective transaction id
+ */
+ wsrep_trx_id_t wsrep_trx_id() const
+ {
+ return m_wsrep_client_state.transaction().id().get();
+ }
+
+
+ /*
+ Set next trx id
+ */
+ void set_wsrep_next_trx_id(query_id_t query_id)
+ {
+ m_wsrep_next_trx_id = (wsrep_trx_id_t) query_id;
+ }
+ /*
+ Return next trx id
+ */
+ wsrep_trx_id_t wsrep_next_trx_id() const
+ {
+ return m_wsrep_next_trx_id;
+ }
+
+private:
+ wsrep_trx_id_t m_wsrep_next_trx_id; /* cast from query_id_t */
+ /* wsrep-lib */
+ Wsrep_mutex m_wsrep_mutex;
+ Wsrep_condition_variable m_wsrep_cond;
+ Wsrep_client_service m_wsrep_client_service;
+ Wsrep_client_state m_wsrep_client_state;
+
+public:
+ Wsrep_client_state& wsrep_cs() { return m_wsrep_client_state; }
+ const Wsrep_client_state& wsrep_cs() const { return m_wsrep_client_state; }
+ const wsrep::transaction& wsrep_trx() const
+ { return m_wsrep_client_state.transaction(); }
+ const wsrep::streaming_context& wsrep_sr() const
+ { return m_wsrep_client_state.transaction().streaming_context(); }
+ /* Pointer to applier service for streaming THDs. This is needed to
+ be able to delete applier service object in case of background
+ rollback. */
+ Wsrep_applier_service* wsrep_applier_service;
#endif /* WITH_WSREP */
/* Handling of timeouts for commands */
@@ -6304,7 +6392,7 @@ public:
be rolled back or that do not expect any previously metadata
locked tables.
*/
-#define CF_IMPLICT_COMMIT_BEGIN (1U << 6)
+#define CF_IMPLICIT_COMMIT_BEGIN (1U << 6)
/**
Implicitly commit after the SQL statement.
@@ -6322,7 +6410,7 @@ public:
before and after every DDL statement and any statement that
modifies our currently non-transactional system tables.
*/
-#define CF_AUTO_COMMIT_TRANS (CF_IMPLICT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
+#define CF_AUTO_COMMIT_TRANS (CF_IMPLICIT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
/**
Diagnostic statement.
@@ -6398,6 +6486,14 @@ public:
*/
#define CF_DB_CHANGE (1U << 22)
+#ifdef WITH_WSREP
+/**
+ DDL statement that may be subject to error filtering.
+*/
+#define CF_WSREP_MAY_IGNORE_ERRORS (1U << 23)
+#endif /* WITH_WSREP */
+
+
/* Bits in server_command_flags */
/**
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b48070b9c8f..ec46d84c7ce 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -37,7 +37,11 @@
// reset_host_errors
#include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
#include "sql_callback.h"
+
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h" /* wsrep open/close */
#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
#include "proxy_protocol.h"
HASH global_user_stats, global_client_stats, global_table_stats;
@@ -1177,17 +1181,6 @@ 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: %lld code: %d",
- (longlong) thd->thread_id, rcode);
- }
- }
- thd->wsrep_client_thread= 0;
-#endif
plugin_thdvar_cleanup(thd);
if (thd->user_connect)
@@ -1322,7 +1315,7 @@ bool thd_prepare_connection(THD *thd)
prepare_new_connection_state(thd);
#ifdef WITH_WSREP
- thd->wsrep_client_thread= 1;
+ thd->wsrep_client_thread= true;
#endif /* WITH_WSREP */
return FALSE;
}
@@ -1395,6 +1388,9 @@ void do_handle_one_connection(CONNECT *connect)
create_user= FALSE;
goto end_thread;
}
+#ifdef WITH_WSREP
+ wsrep_open(thd);
+#endif /* WITH_WSREP */
while (thd_is_connection_alive(thd))
{
@@ -1405,13 +1401,9 @@ void do_handle_one_connection(CONNECT *connect)
end_connection(thd);
#ifdef WITH_WSREP
- if (WSREP(thd))
- {
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_EXITING;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif
+ wsrep_close(thd);
+#endif /* WITH_WSREP */
+
end_thread:
close_connection(thd);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index f5e4185db92..785d7c12bd2 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -82,6 +82,10 @@
#include "debug_sync.h"
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h" /* wsrep_start_transction() */
+#endif /* WITH_WSREP */
+
#ifndef EMBEDDED_LIBRARY
static bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
TABLE_LIST *table_list);
@@ -3934,10 +3938,13 @@ bool select_insert::prepare_eof()
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
- error= (IF_WSREP((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));
+#ifdef WITH_WSREP
+ error= (thd->wsrep_cs().current_error()) ? -1 :
+ (thd->locked_tables_mode <= LTM_LOCK_TABLES) ?
+#else
+ error= (thd->locked_tables_mode <= LTM_LOCK_TABLES) ?
+#endif /* WITH_WSREP */
+ table->file->ha_end_bulk_insert() : 0;
if (likely(!error) && unlikely(thd->is_error()))
error= thd->get_stmt_da()->sql_errno();
@@ -4534,9 +4541,16 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
/* suppress_use */ FALSE,
errcode);
}
-
- ha_fake_trx_id(thd);
-
+#ifdef WITH_WSREP
+ if (thd->wsrep_trx().active())
+ {
+ WSREP_DEBUG("transaction already started for CTAS");
+ }
+ else
+ {
+ wsrep_start_transaction(thd, thd->wsrep_next_trx_id());
+ }
+#endif
return result;
}
@@ -4594,10 +4608,18 @@ bool select_create::send_eof()
if (!table->s->tmp_table)
{
#ifdef WITH_WSREP
- if (WSREP_ON)
+ if (WSREP(thd))
{
+ if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ wsrep_start_transaction(thd, thd->wsrep_next_trx_id());
+ }
+ DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ WSREP_DEBUG("CTAS key append for trx: %lu thd %llu query %lld ",
+ thd->wsrep_trx_id(), thd->thread_id, thd->query_id);
+
/*
- append table level exclusive key for CTAS
+ append table level exclusive key for CTAS
*/
wsrep_key_arr_t key_arr= {0, 0};
wsrep_prepare_keys_for_isolation(thd,
@@ -4605,38 +4627,34 @@ bool select_create::send_eof()
create_table->table_name.str,
table_list,
&key_arr);
- int rcode = wsrep->append_key(
- wsrep,
- &thd->wsrep_ws_handle,
- key_arr.keys, //&wkey,
- key_arr.keys_len,
- WSREP_KEY_EXCLUSIVE,
- false);
+ int rcode= wsrep_thd_append_key(thd, key_arr.keys, key_arr.keys_len,
+ WSREP_SERVICE_KEY_EXCLUSIVE);
wsrep_keys_free(&key_arr);
- if (rcode) {
+ if (rcode)
+ {
DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
WSREP_ERROR("Appending table key for CTAS failed: %s, %d",
(wsrep_thd_query(thd)) ?
wsrep_thd_query(thd) : "void", rcode);
- return true;
+ DBUG_RETURN(true);
}
/* If commit fails, we should be able to reset the OK status. */
- thd->get_stmt_da()->set_overwrite_status(TRUE);
+ thd->get_stmt_da()->set_overwrite_status(true);
}
#endif /* WITH_WSREP */
trans_commit_stmt(thd);
if (!(thd->variables.option_bits & OPTION_GTID_BEGIN))
trans_commit_implicit(thd);
#ifdef WITH_WSREP
- if (WSREP_ON)
+ if (WSREP(thd))
{
thd->get_stmt_da()->set_overwrite_status(FALSE);
mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state != NO_CONFLICT)
+ if (wsrep_current_error(thd))
{
- WSREP_DEBUG("select_create commit failed, thd: %lld err: %d %s",
- (longlong) thd->thread_id, thd->wsrep_conflict_state,
- thd->query());
+ WSREP_DEBUG("select_create commit failed, thd: %llu err: %s %s",
+ thd->thread_id,
+ wsrep_thd_transaction_state_str(thd), WSREP_QUERY(thd));
mysql_mutex_unlock(&thd->LOCK_thd_data);
abort_result_set();
DBUG_RETURN(true);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 416180f0006..24de741cefd 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1860,7 +1860,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
else
{
#ifdef WITH_WSREP
- if (WSREP(thd) && version == 99997 && thd->wsrep_exec_mode == LOCAL_STATE)
+ if (WSREP(thd) && version == 99997 && wsrep_thd_is_local(thd))
{
WSREP_DEBUG("consistency check: %s", thd->query());
thd->wsrep_consistency_check= CONSISTENCY_CHECK_DECLARED;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index dd6e723c953..c95ef72a308 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -42,6 +42,8 @@
#include "sql_derived.h"
#include "sql_show.h"
+#include "wsrep_mysqld.h"
+
extern "C" int _my_b_net_read(IO_CACHE *info, uchar *Buffer, size_t Count);
class XML_TAG {
@@ -106,7 +108,7 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table,
{
DBUG_ENTER("wsrep_load_data_split");
- if (!wsrep_load_data_splitting || !wsrep_on(thd)
+ if (!wsrep_load_data_splitting || !WSREP(thd)
|| !info.records || (info.records % 10000)
|| !thd->transaction.stmt.ha_list
|| thd->transaction.stmt.ha_list->ht() != binlog_hton
@@ -116,13 +118,10 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table,
if (handlerton* hton= thd->transaction.stmt.ha_list->next()->ht())
{
- if (hton->db_type != DB_TYPE_INNODB)
+ if (!(hton->flags & HTON_WSREP_REPLICATION))
DBUG_RETURN(false);
WSREP_DEBUG("intermediate transaction commit in LOAD DATA");
- if (wsrep_run_wsrep_commit(thd, true) != WSREP_TRX_OK) DBUG_RETURN(true);
- if (binlog_hton->commit(binlog_hton, thd, true)) DBUG_RETURN(true);
- wsrep_post_commit(thd, true);
- hton->commit(hton, thd, true);
+ wsrep_tc_log_commit(thd);
table->file->extra(HA_EXTRA_FAKE_START_STMT);
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 65b52b5b5da..34c690416ad 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -111,13 +111,16 @@
#include "wsrep.h"
#include "wsrep_mysqld.h"
+#ifdef WITH_WSREP
#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h" /* wsrep transaction hooks */
-static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
+static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
Parser_state *parser_state,
bool is_com_multi,
bool is_next_command);
+#endif /* WITH_WSREP */
/**
@defgroup Runtime_Environment Runtime Environment
@{
@@ -884,6 +887,16 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_REVOKE_ALL]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_INSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS;
sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS;
+#ifdef WITH_WSREP
+ /*
+ Statements for which some errors are ignored when
+ wsrep_ignore_apply_errors = WSREP_IGNORE_ERRORS_ON_RECONCILING_DDL
+ */
+ sql_command_flags[SQLCOM_DROP_DB]|= CF_WSREP_MAY_IGNORE_ERRORS;
+ sql_command_flags[SQLCOM_DROP_TABLE]|= CF_WSREP_MAY_IGNORE_ERRORS;
+ sql_command_flags[SQLCOM_DROP_INDEX]|= CF_WSREP_MAY_IGNORE_ERRORS;
+ sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_WSREP_MAY_IGNORE_ERRORS;
+#endif /* WITH_WSREP */
}
bool sqlcom_can_generate_row_events(const THD *thd)
@@ -1208,28 +1221,11 @@ 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_thd_data);
- thd->wsrep_query_state= QUERY_IDLE;
- if (thd->wsrep_conflict_state==MUST_ABORT)
- {
- wsrep_client_rollback(thd);
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif /* WITH_WSREP */
-
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
@@ -1270,29 +1266,6 @@ bool do_command(THD *thd)
DEBUG_SYNC(thd, "before_do_command_net_read");
packet_length= my_net_read_packet(net, 1);
-#ifdef WITH_WSREP
- if (WSREP(thd)) {
- mysql_mutex_lock(&thd->LOCK_thd_data);
-
- /* 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_thd_data);
- my_sleep(1000);
- mysql_mutex_lock(&thd->LOCK_thd_data);
- }
- thd->store_globals();
- }
- else if (thd->wsrep_conflict_state == ABORTED)
- {
- thd->store_globals();
- }
-
- thd->wsrep_query_state= QUERY_EXEC;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif /* WITH_WSREP */
if (unlikely(packet_length == packet_error))
{
@@ -1300,20 +1273,6 @@ bool do_command(THD *thd)
net->error,
vio_description(net->vio)));
-#ifdef WITH_WSREP
- if (WSREP(thd))
- {
- mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state == MUST_ABORT)
- {
- DBUG_PRINT("wsrep",("aborted for wsrep rollback: %lu",
- (ulong) thd->real_id));
- wsrep_client_rollback(thd);
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif /* WITH_WSREP */
-
/* Instrument this broken statement as "statement/com/error" */
thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
com_statement_info[COM_END].
@@ -1364,13 +1323,52 @@ bool do_command(THD *thd)
command= fetch_command(thd, packet);
#ifdef WITH_WSREP
+ /*
+ Aborted by background rollbacker thread.
+ Handle error here and jump straight to out
+ */
+ if (wsrep_before_command(thd))
+ {
+ thd->store_globals();
+ WSREP_LOG_THD(thd, "enter found BF aborted");
+ DBUG_ASSERT(!thd->mdl_context.has_locks());
+ DBUG_ASSERT(!thd->get_stmt_da()->is_set());
+ /* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */
+ if (command != COM_STMT_CLOSE &&
+ command != COM_QUIT)
+ {
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ WSREP_DEBUG("Deadlock error for: %s", thd->query());
+ thd->reset_killed();
+ thd->mysys_var->abort = 0;
+ thd->wsrep_retry_counter = 0;
+
+ /* Instrument this broken statement as "statement/com/error" */
+ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
+ com_statement_info[COM_END].
+ m_key);
+
+ thd->protocol->end_statement();
+
+ /* Mark the statement completed. */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+ return_value= FALSE;
+
+ wsrep_after_command_before_result(thd);
+ goto out;
+ }
+ }
+
if (WSREP(thd))
{
/*
- Bail out if DB snapshot has not been installed.
- */
- if (!thd->wsrep_applier &&
- (!wsrep_ready || wsrep_reject_queries != WSREP_REJECT_NONE) &&
+ * 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->wsrep_applier) &&
+ (!wsrep_ready_get() || wsrep_reject_queries != WSREP_REJECT_NONE) &&
(server_command_flags[command] & CF_SKIP_WSREP_CHECK) == 0)
{
my_message(ER_UNKNOWN_COM_ERROR,
@@ -1383,11 +1381,11 @@ bool do_command(THD *thd)
thd->m_digest= NULL;
return_value= FALSE;
+ wsrep_after_command_before_result(thd);
goto out;
}
}
-#endif
-
+#endif /* WITH_WSREP */
/* Restore read timeout value */
my_net_set_read_timeout(net, thd->variables.net_read_timeout);
@@ -1395,37 +1393,6 @@ bool do_command(THD *thd)
DBUG_ASSERT(!thd->apc_target.is_enabled());
return_value= dispatch_command(command, thd, packet+1,
(uint) (packet_length-1), FALSE, FALSE);
-#ifdef WITH_WSREP
- if (WSREP(thd))
- {
- while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
- {
- WSREP_DEBUG("Retry autocommit for: %s\n", thd->wsrep_retry_query);
- CHARSET_INFO *current_charset = thd->variables.character_set_client;
- if (!is_supported_parser_charset(current_charset))
- {
- /* Do not use non-supported parser character sets */
- WSREP_WARN("Current client character set is non-supported parser "
- "character set: %s", current_charset->csname);
- thd->variables.character_set_client = &my_charset_latin1;
- WSREP_WARN("For retry temporally setting character set to : %s",
- my_charset_latin1.csname);
- }
- thd->clear_error();
- return_value= dispatch_command(command, thd, thd->wsrep_retry_query,
- thd->wsrep_retry_query_len, FALSE, FALSE);
- thd->variables.character_set_client = current_charset;
- }
-
- if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING)
- {
- my_free(thd->wsrep_retry_query);
- thd->wsrep_retry_query = NULL;
- thd->wsrep_retry_query_len = 0;
- thd->wsrep_retry_command = COM_CONNECT;
- }
- }
-#endif /* WITH_WSREP */
DBUG_ASSERT(!thd->apc_target.is_enabled());
out:
@@ -1433,6 +1400,13 @@ out:
/* The statement instrumentation must be closed in all cases. */
DBUG_ASSERT(thd->m_digest == NULL);
DBUG_ASSERT(thd->m_statement_psi == NULL);
+#ifdef WITH_WSREP
+ if (packet_length != packet_error)
+ {
+ /* there was a command to process, and before_command() has been called */
+ wsrep_after_command_after_result(thd);
+ }
+#endif /* WITH_WSREP */
DBUG_RETURN(return_value);
}
#endif /* EMBEDDED_LIBRARY */
@@ -1498,6 +1472,36 @@ static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables)
DBUG_RETURN(FALSE);
}
+#ifdef WITH_WSREP
+static my_bool wsrep_read_only_option(THD *thd, TABLE_LIST *all_tables)
+{
+ int opt_readonly_saved = opt_readonly;
+ ulong flag_saved = (ulong)(thd->security_ctx->master_access & SUPER_ACL);
+
+ opt_readonly = 0;
+ thd->security_ctx->master_access &= ~SUPER_ACL;
+
+ my_bool ret = !deny_updates_if_read_only_option(thd, all_tables);
+
+ opt_readonly = opt_readonly_saved;
+ thd->security_ctx->master_access |= flag_saved;
+
+ return ret;
+}
+
+static void wsrep_copy_query(THD *thd)
+{
+ thd->wsrep_retry_command = thd->get_command();
+ thd->wsrep_retry_query_len = thd->query_length();
+ if (thd->wsrep_retry_query) {
+ my_free(thd->wsrep_retry_query);
+ }
+ thd->wsrep_retry_query = (char *)my_malloc(
+ thd->wsrep_retry_query_len + 1, MYF(0));
+ strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len);
+ thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0';
+}
+#endif /* WITH_WSREP */
/**
check COM_MULTI packet
@@ -1580,41 +1584,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* keep it withing 1 byte */
compile_time_assert(COM_END == 255);
-#ifdef WITH_WSREP
- if (WSREP(thd))
- {
- if (!thd->in_multi_stmt_transaction_mode())
- {
- thd->wsrep_PA_safe= true;
- }
-
- mysql_mutex_lock(&thd->LOCK_thd_data);
- 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);
- }
- /* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */
- if (thd->wsrep_conflict_state == ABORTED &&
- command != COM_STMT_CLOSE && command != COM_QUIT)
- {
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
- MYF(0));
- WSREP_DEBUG("Deadlock error for: %s", thd->query());
- thd->reset_killed();
- thd->mysys_var->abort = 0;
- thd->wsrep_conflict_state = NO_CONFLICT;
- thd->wsrep_retry_counter = 0;
- goto dispatch_end;
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif /* WITH_WSREP */
#if defined(ENABLED_PROFILING)
thd->profiling.start_new_query();
#endif
@@ -1661,6 +1630,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
thd->set_query_id(get_query_id());
}
+#ifdef WITH_WSREP
+ if (WSREP(thd) && thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ thd->set_wsrep_next_trx_id(thd->query_id);
+ WSREP_DEBUG("assigned new next trx id: %lu", thd->wsrep_next_trx_id());
+ }
+#endif /* WITH_WSREP */
if (!(server_command_flags[command] & CF_SKIP_QUESTIONS))
statistic_increment(thd->status_var.questions, &LOCK_status);
@@ -1844,10 +1820,24 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (unlikely(parser_state.init(thd, thd->query(), thd->query_length())))
break;
+#ifdef WITH_WSREP
if (WSREP_ON)
- wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
- is_com_multi, is_next_command);
+ {
+ if (wsrep_mysql_parse(thd, thd->query(), thd->query_length(),
+ &parser_state,
+ is_com_multi, is_next_command))
+ {
+ WSREP_DEBUG("Deadlock error for: %s", thd->query());
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ thd->killed = NOT_KILLED;
+ thd->mysys_var->abort = 0;
+ thd->wsrep_retry_counter = 0;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ goto dispatch_end;
+ }
+ }
else
+#endif /* WITH_WSREP */
mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
is_com_multi, is_next_command);
@@ -1929,17 +1919,32 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
*/
statistic_increment(thd->status_var.questions, &LOCK_status);
- if(!WSREP(thd))
- thd->set_time(); /* Reset the query start time. */
+ if (!WSREP(thd))
+ thd->set_time(); /* Reset the query start time. */
parser_state.reset(beginning_of_next_stmt, length);
+#ifdef WITH_WSREP
if (WSREP_ON)
- wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state,
- is_com_multi, is_next_command);
+ {
+ if (wsrep_mysql_parse(thd, beginning_of_next_stmt,
+ length, &parser_state,
+ is_com_multi, is_next_command))
+ {
+ WSREP_DEBUG("Deadlock error for: %s", thd->query());
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ thd->killed = NOT_KILLED;
+ thd->mysys_var->abort = 0;
+ thd->wsrep_retry_counter = 0;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+
+ goto dispatch_end;
+ }
+ }
else
- mysql_parse(thd, beginning_of_next_stmt, length, &parser_state,
- is_com_multi, is_next_command);
+#endif /* WITH_WSREP */
+ mysql_parse(thd, beginning_of_next_stmt, length, &parser_state,
+ is_com_multi, is_next_command);
}
@@ -2376,7 +2381,26 @@ com_multi_end:
#ifdef WITH_WSREP
dispatch_end:
-
+ /*
+ BF aborted before sending response back to client
+ */
+ if (thd->killed == KILL_QUERY)
+ {
+ WSREP_DEBUG("THD is killed at dispatch_end");
+ }
+ wsrep_after_command_before_result(thd);
+ if (wsrep_current_error(thd) &&
+ !(command == COM_STMT_PREPARE ||
+ command == COM_STMT_FETCH ||
+ command == COM_STMT_SEND_LONG_DATA ||
+ command == COM_STMT_CLOSE
+ ))
+ {
+ /* todo: Pass wsrep client state current error to override */
+ wsrep_override_error(thd, wsrep_current_error(thd),
+ wsrep_current_error_status(thd));
+ WSREP_LOG_THD(thd, "leave");
+ }
if (WSREP(thd))
{
/*
@@ -2387,9 +2411,10 @@ com_multi_end:
|| thd->get_stmt_da()->is_disabled());
/* wsrep BF abort in query exec phase */
mysql_mutex_lock(&thd->LOCK_thd_data);
- do_end_of_statement= thd->wsrep_conflict_state != REPLAYING &&
- thd->wsrep_conflict_state != RETRY_AUTOCOMMIT &&
- !thd->killed;
+ do_end_of_statement=
+ thd->wsrep_trx().state() != wsrep::transaction::s_replaying
+ && !thd->killed;
+
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
else
@@ -3423,7 +3448,7 @@ mysql_execute_command(THD *thd)
} /* endif unlikely slave */
#endif
#ifdef WITH_WSREP
- if (wsrep && WSREP(thd))
+ if (WSREP(thd))
{
/*
change LOCK TABLE WRITE to transaction
@@ -3453,8 +3478,8 @@ mysql_execute_command(THD *thd)
* allow SET and SHOW queries and reads from information schema
* and dirty reads (if configured)
*/
- if (!thd->wsrep_applier &&
- !(wsrep_ready && wsrep_reject_queries == WSREP_REJECT_NONE) &&
+ if (!(thd->wsrep_applier) &&
+ !(wsrep_ready_get() && wsrep_reject_queries == WSREP_REJECT_NONE) &&
!(thd->variables.wsrep_dirty_reads &&
(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) == 0) &&
!wsrep_tables_accessible_when_detached(all_tables) &&
@@ -3619,7 +3644,7 @@ mysql_execute_command(THD *thd)
not run in it's own transaction it may simply never appear on
the slave in case the outside transaction rolls back.
*/
- if (stmt_causes_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
+ if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_BEGIN))
{
/*
Note that this should never happen inside of stored functions
@@ -3642,6 +3667,13 @@ mysql_execute_command(THD *thd)
}
}
thd->transaction.stmt.mark_trans_did_ddl();
+#ifdef WITH_WSREP
+ /* Clean up the previous transaction on implicit commit */
+ if (wsrep_thd_is_local(thd) && wsrep_after_statement(thd))
+ {
+ goto error;
+ }
+#endif /* WITH_WSREP */
}
#ifndef DBUG_OFF
@@ -3690,6 +3722,33 @@ mysql_execute_command(THD *thd)
/* Start timeouts */
thd->set_query_timer();
+#ifdef WITH_WSREP
+ /*
+ Always start a new transaction for a wsrep THD unless the
+ current command is DDL or explicit BEGIN. This will guarantee that
+ the THD is BF abortable even if it does not generate any
+ changes and takes only read locks. If the statement does not
+ start a multi STMT transaction, the wsrep_transaction is
+ committed as empty at the end of this function.
+
+ Transaction is started for BEGIN in trans_begin(), for DDL the
+ implicit commit took care of committing previous transaction
+ above and a new transaction should not be started.
+
+ Do not start transaction for stored procedures, it will be handled
+ internally in SP processing.
+ */
+ if (WSREP(thd) &&
+ wsrep_thd_is_local(thd) &&
+ lex->sql_command != SQLCOM_BEGIN &&
+ lex->sql_command != SQLCOM_CALL &&
+ lex->sql_command != SQLCOM_EXECUTE &&
+ !(sql_command_flags[lex->sql_command] & CF_AUTO_COMMIT_TRANS))
+ {
+ wsrep_start_trx_if_not_started(thd);
+ }
+#endif /* WITH_WSREP */
+
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
@@ -3749,12 +3808,16 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_STORAGE_ENGINES:
case SQLCOM_SHOW_PROFILE:
case SQLCOM_SELECT:
- {
+ {
#ifdef WITH_WSREP
- if (lex->sql_command == SQLCOM_SELECT)
- WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ)
- else
- WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW)
+ if (lex->sql_command == SQLCOM_SELECT)
+ {
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ);
+ }
+ else
+ {
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
+ }
#endif /* WITH_WSREP */
thd->status_var.last_query_cost= 0.0;
@@ -4555,9 +4618,7 @@ end_with_restore_list:
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
ha_rows found= 0, updated= 0;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (WSREP_CLIENT(thd) &&
- wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
- goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
if (update_precheck(thd, all_tables))
break;
@@ -4706,9 +4767,7 @@ end_with_restore_list:
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (WSREP_CLIENT(thd) &&
- wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE))
- goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE);
/*
Since INSERT DELAYED doesn't support temporary tables, we could
@@ -4766,9 +4825,7 @@ end_with_restore_list:
select_insert *sel_result;
bool explain= MY_TEST(lex->describe);
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (WSREP_CLIENT(thd) &&
- wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE))
- goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
if ((res= insert_precheck(thd, all_tables)))
break;
@@ -4888,9 +4945,7 @@ end_with_restore_list:
WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
select_result *sel_result=lex->result;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if (WSREP_CLIENT(thd) &&
- wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
- goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
if ((res= delete_precheck(thd, all_tables)))
break;
@@ -4950,9 +5005,7 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
multi_delete *result;
- if (WSREP_CLIENT(thd) &&
- wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE))
- goto error;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE);
if ((res= multi_delete_precheck(thd, all_tables)))
break;
@@ -5793,6 +5846,7 @@ end_with_restore_list:
thd->mdl_context.release_transactional_locks();
WSREP_DEBUG("BEGIN failed, MDL released: %lld",
(longlong) thd->thread_id);
+ WSREP_DEBUG("stmt_da, sql_errno: %d", (thd->get_stmt_da()->is_error()) ? thd->get_stmt_da()->sql_errno() : 0);
goto error;
}
my_ok(thd);
@@ -5832,20 +5886,7 @@ end_with_restore_list:
thd->set_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 */
+ my_ok(thd);
break;
}
case SQLCOM_ROLLBACK:
@@ -5881,17 +5922,7 @@ end_with_restore_list:
/* Disconnect the current client connection. */
if (tx_release)
thd->set_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 */
+ my_ok(thd);
break;
}
case SQLCOM_RELEASE_SAVEPOINT:
@@ -6338,7 +6369,6 @@ finish:
DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
thd->in_multi_stmt_transaction_mode());
-
lex->unit.cleanup();
/* close/reopen tables that were marked to need reopen under LOCK TABLES */
@@ -6364,25 +6394,6 @@ finish:
THD_STAGE_INFO(thd, stage_rollback);
trans_rollback_stmt(thd);
}
-#ifdef WITH_WSREP
- if (thd->spcont &&
- (thd->wsrep_conflict_state == MUST_ABORT ||
- thd->wsrep_conflict_state == ABORTED ||
- thd->wsrep_conflict_state == CERT_FAILURE))
- {
- /*
- The error was cleared, but THD was aborted by wsrep and
- wsrep_conflict_state is still set accordingly. This
- situation is expected if we are running a stored procedure
- that declares a handler that catches ER_LOCK_DEADLOCK error.
- In which case the error may have been cleared in method
- sp_rcontext::handle_sql_condition().
- */
- trans_rollback_stmt(thd);
- thd->wsrep_conflict_state= NO_CONFLICT;
- thd->killed= NOT_KILLED;
- }
-#endif /* WITH_WSREP */
else
{
/* If commit fails, we should be able to reset the OK status. */
@@ -6398,9 +6409,6 @@ finish:
/* Free tables. Set stage 'closing tables' */
close_thread_tables(thd);
-#ifdef WITH_WSREP
- thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
-#endif /* WITH_WSREP */
#ifndef DBUG_OFF
@@ -6462,9 +6470,10 @@ finish:
TRANSACT_TRACKER(add_trx_state_from_thd(thd));
- WSREP_TO_ISOLATION_END;
-
#ifdef WITH_WSREP
+ thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK;
+
+ WSREP_TO_ISOLATION_END;
/*
Force release of transactional locks if not in active MST and wsrep is on.
*/
@@ -6477,11 +6486,26 @@ finish:
(longlong) thd->thread_id);
thd->mdl_context.release_transactional_locks();
}
+
+ /*
+ Current command did not start multi STMT transaction and the command
+ did not cause commit to happen (e.g. read only). Commit the wsrep
+ transaction as empty.
+ */
+ if (!thd->in_active_multi_stmt_transaction() &&
+ !thd->in_sub_stmt &&
+ thd->wsrep_trx().active() &&
+ thd->wsrep_trx().state() == wsrep::transaction::s_executing)
+ {
+ wsrep_commit_empty(thd, true);
+ }
+
+ /* assume PA safety for next transaction */
+ thd->wsrep_PA_safe= true;
#endif /* WITH_WSREP */
DBUG_RETURN(res || thd->is_error());
-}
-
+ }
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
{
@@ -6607,6 +6631,7 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
bool res;
system_status_var old_status_var= thd->status_var;
thd->initial_status_var= &old_status_var;
+ WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW);
if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE,
UINT_MAX, FALSE)))
res= execute_sqlcom_select(thd, all_tables);
@@ -6625,6 +6650,10 @@ static bool execute_show_status(THD *thd, TABLE_LIST *all_tables)
offsetof(STATUS_VAR, last_cleared_system_status_var));
mysql_mutex_unlock(&LOCK_status);
return res;
+#ifdef WITH_WSREP
+wsrep_error_label: /* see WSREP_SYNC_WAIT() macro above */
+ return true;
+#endif /* WITH_WSREP */
}
@@ -7654,7 +7683,7 @@ void THD::reset_for_next_command(bool do_clear_error)
use autoinc values passed in binlog events, not the values forced by
the cluster.
*/
- if (WSREP(this) && wsrep_exec_mode == LOCAL_STATE &&
+ if (WSREP(this) && wsrep_thd_is_local(this) &&
!slave_thread && wsrep_auto_increment_control)
{
variables.auto_increment_offset=
@@ -7872,144 +7901,155 @@ void mysql_init_multi_delete(LEX *lex)
lex->query_tables_last= &lex->query_tables;
}
-static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
+#ifdef WITH_WSREP
+static void wsrep_prepare_for_autocommit_retry(THD* thd,
+ char* rawbuf,
+ uint length,
+ Parser_state* parser_state)
+{
+ thd->clear_error();
+ close_thread_tables(thd);
+ thd->wsrep_retry_counter++; // grow
+ wsrep_copy_query(thd);
+ thd->set_time();
+ parser_state->reset(rawbuf, length);
+
+ /* PSI end */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+
+ /* DTRACE end */
+ if (MYSQL_QUERY_DONE_ENABLED())
+ {
+ MYSQL_QUERY_DONE(thd->is_error());
+ }
+
+ /* SHOW PROFILE end */
+#if defined(ENABLED_PROFILING)
+ thd->profiling.finish_current_query();
+#endif
+
+ /* SHOW PROFILE begin */
+#if defined(ENABLED_PROFILING)
+ thd->profiling.start_new_query("continuing");
+ thd->profiling.set_query_source(rawbuf, length);
+#endif
+
+ /* DTRACE begin */
+ MYSQL_QUERY_START(rawbuf, thd->thread_id,
+ thd->get_db(),
+ &thd->security_ctx->priv_user[0],
+ (char *) thd->security_ctx->host_or_ip);
+
+ /* Performance Schema Interface instrumentation, begin */
+ thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
+ com_statement_info[thd->get_command()].m_key);
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(),
+ thd->query_length());
+
+ DBUG_ASSERT(thd->wsrep_trx().active() == false);
+ thd->wsrep_cs().reset_error();
+ thd->set_query_id(next_query_id());
+}
+
+static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
Parser_state *parser_state,
bool is_com_multi,
bool is_next_command)
{
-#ifdef WITH_WSREP
bool is_autocommit=
!thd->in_multi_stmt_transaction_mode() &&
- thd->wsrep_conflict_state == NO_CONFLICT &&
- !thd->wsrep_applier;
-
+ wsrep_read_only_option(thd, thd->lex->query_tables);
+ bool retry_autocommit;
do
{
- if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT)
- {
- thd->wsrep_conflict_state= NO_CONFLICT;
- /* Performance Schema Interface instrumentation, begin */
- thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi,
- com_statement_info[thd->get_command()].m_key);
- MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(),
- thd->query_length());
-
- DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
- {
- const char act[]=
- "now "
- "SIGNAL wsrep_retry_autocommit_reached "
- "WAIT_FOR wsrep_retry_autocommit_continue";
- DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
- });
- WSREP_DEBUG("Retry autocommit query: %s", thd->query());
- }
-
- mysql_parse(thd, rawbuf, length, parser_state, is_com_multi,
- is_next_command);
-
- if (WSREP(thd)) {
- /* wsrep BF abort in query exec phase */
- mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state == MUST_ABORT) {
- wsrep_client_rollback(thd);
-
- WSREP_DEBUG("abort in exec query state, avoiding autocommit");
- }
+ retry_autocommit= false;
+ mysql_parse(thd, rawbuf, length, parser_state, is_com_multi, is_next_command);
- if (thd->wsrep_conflict_state == MUST_REPLAY)
- {
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- if (thd->lex->explain)
- delete_explain_query(thd->lex);
- mysql_mutex_lock(&thd->LOCK_thd_data);
+ /*
+ Convert all ER_QUERY_INTERRUPTED errors to ER_LOCK_DEADLOCK
+ if the transaction was BF aborted. This can happen when the
+ transaction is being BF aborted via thd->awake() while it is
+ still executing.
- wsrep_replay_transaction(thd);
- }
+ Note that this must be done before wsrep_after_statement() call
+ since it clears the transaction for autocommit queries.
+ */
+ if (((thd->get_stmt_da()->is_error() &&
+ thd->get_stmt_da()->sql_errno() == ER_QUERY_INTERRUPTED) ||
+ !thd->get_stmt_da()->is_set()) &&
+ thd->wsrep_trx().bf_aborted())
+ {
+ WSREP_DEBUG("overriding error: %d with DEADLOCK",
+ (thd->get_stmt_da()->is_error()) ?
+ thd->get_stmt_da()->sql_errno() : 0);
- /* setting error code for BF aborted trxs */
- if (thd->wsrep_conflict_state == ABORTED ||
- thd->wsrep_conflict_state == CERT_FAILURE)
- {
- thd->reset_for_next_command();
- if (is_autocommit &&
- thd->lex->sql_command != SQLCOM_SELECT &&
- (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
- {
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- WSREP_DEBUG("wsrep retrying AC query: %s",
- (thd->query()) ? thd->query() : "void");
-
- /* Performance Schema Interface instrumentation, end */
- MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
- thd->m_statement_psi= NULL;
- thd->m_digest= NULL;
- // Released thd->LOCK_thd_data above as below could end up
- // close_thread_tables()/close_open_tables()/close_thread_table()/mysql_mutex_lock(&thd->LOCK_thd_data)
- close_thread_tables(thd);
-
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_conflict_state= RETRY_AUTOCOMMIT;
- thd->wsrep_retry_counter++; // grow
- wsrep_copy_query(thd);
- thd->set_time();
- parser_state->reset(rawbuf, length);
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
- else
- {
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- // This does dirty read to wsrep variables but it is only a debug code
- WSREP_DEBUG("%s, thd: %lld is_AC: %d, retry: %lu - %lu SQL: %s",
- (thd->wsrep_conflict_state == ABORTED) ?
- "BF Aborted" : "cert failure",
- (longlong) thd->thread_id, is_autocommit,
- thd->wsrep_retry_counter,
- thd->variables.wsrep_retry_autocommit, thd->query());
- my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction",
- MYF(0));
-
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_conflict_state= NO_CONFLICT;
- if (thd->wsrep_conflict_state != REPLAYING)
- thd->wsrep_retry_counter= 0; // reset
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
+ thd->killed = NOT_KILLED;
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ }
- thd->reset_killed();
+ if (wsrep_after_statement(thd) && is_autocommit)
+ {
+ thd->reset_for_next_command();
+ thd->killed= NOT_KILLED;
+ if (is_autocommit &&
+ thd->lex->sql_command != SQLCOM_SELECT &&
+ thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)
+ {
+ DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit",
+ {
+ const char act[]=
+ "now "
+ "SIGNAL wsrep_retry_autocommit_reached "
+ "WAIT_FOR wsrep_retry_autocommit_continue";
+ DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
+ });
+ WSREP_DEBUG("wsrep retrying AC query: %lu %s",
+ thd->wsrep_retry_counter, WSREP_QUERY(thd));
+ wsrep_prepare_for_autocommit_retry(thd, rawbuf, length, parser_state);
+ if (thd->lex->explain)
+ delete_explain_query(thd->lex);
+ retry_autocommit= true;
}
else
{
- set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ WSREP_DEBUG("%s, thd: %llu is_AC: %d, retry: %lu - %lu SQL: %s",
+ wsrep_thd_transaction_state_str(thd),
+ thd->thread_id,
+ is_autocommit,
+ thd->wsrep_retry_counter,
+ thd->variables.wsrep_retry_autocommit,
+ WSREP_QUERY(thd));
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ thd->killed= NOT_KILLED;
+ thd->wsrep_retry_counter= 0; // reset
}
}
-
- /* If retry is requested clean up explain structure */
- if ((thd->wsrep_conflict_state == RETRY_AUTOCOMMIT ||
- thd->wsrep_conflict_state == MUST_REPLAY )
- && thd->lex->explain)
+ else
{
- delete_explain_query(thd->lex);
+ set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok
}
-
- } while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT);
+ } while (retry_autocommit);
if (thd->wsrep_retry_query)
{
- WSREP_DEBUG("releasing retry_query: conf %d sent %d kill %d errno %d SQL %s",
- thd->wsrep_conflict_state,
- thd->get_stmt_da()->is_sent(),
+ WSREP_DEBUG("releasing retry_query: "
+ "conf %s sent %d kill %d errno %d SQL %s",
+ wsrep_thd_transaction_state_str(thd),
+ thd->get_stmt_da()->is_sent(),
thd->killed,
- thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0,
+ thd->get_stmt_da()->is_error() ?
+ thd->get_stmt_da()->sql_errno() : 0,
thd->wsrep_retry_query);
my_free(thd->wsrep_retry_query);
thd->wsrep_retry_query = NULL;
thd->wsrep_retry_query_len = 0;
thd->wsrep_retry_command = COM_CONNECT;
}
-#endif /* WITH_WSREP */
+ return false;
}
+#endif /* WITH_WSREP */
/*
@@ -8961,6 +9001,7 @@ THD *find_thread_by_id(longlong id, bool query_id)
continue;
if (id == (query_id ? tmp->query_id : (longlong) tmp->thread_id))
{
+ if (WSREP(tmp)) mysql_mutex_lock(&tmp->LOCK_thd_data);
mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
break;
}
@@ -8989,7 +9030,7 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
uint error= (type == KILL_TYPE_QUERY ? ER_NO_SUCH_QUERY : ER_NO_SUCH_THREAD);
DBUG_ENTER("kill_one_thread");
DBUG_PRINT("enter", ("id: %lld signal: %u", id, (uint) kill_signal));
-
+ WSREP_DEBUG("kill_one_thread %llu", thd->thread_id);
if (id && (tmp= find_thread_by_id(id, type == KILL_TYPE_QUERY)))
{
/*
@@ -9013,9 +9054,14 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
faster and do a harder kill than KILL_SYSTEM_THREAD;
*/
+#ifdef WITH_WSREP
if (((thd->security_ctx->master_access & SUPER_ACL) ||
thd->security_ctx->user_matches(tmp->security_ctx)) &&
- !wsrep_thd_is_BF(tmp, false))
+ !wsrep_thd_is_BF(tmp, false) && !tmp->wsrep_applier)
+#else
+ if ((thd->security_ctx->master_access & SUPER_ACL) ||
+ thd->security_ctx->user_matches(tmp->security_ctx))
+#endif /* WITH_WSREP */
{
tmp->awake_no_mutex(kill_signal);
error=0;
@@ -9024,6 +9070,7 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR :
ER_KILL_DENIED_ERROR);
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
+ if (WSREP(tmp)) mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
DBUG_PRINT("exit", ("%d", error));
DBUG_RETURN(error);
@@ -9081,7 +9128,10 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user,
DBUG_RETURN(ER_KILL_DENIED_ERROR);
}
if (!threads_to_kill.push_back(tmp, thd->mem_root))
+ {
+ if (WSREP(tmp)) mysql_mutex_lock(&tmp->LOCK_thd_data);
mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
+ }
}
}
mysql_mutex_unlock(&LOCK_thread_count);
@@ -9103,6 +9153,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user,
*/
next_ptr= it2++;
mysql_mutex_unlock(&ptr->LOCK_thd_kill);
+ if (WSREP(ptr)) mysql_mutex_unlock(&ptr->LOCK_thd_data);
(*rows)++;
} while ((ptr= next_ptr));
}
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index c730490a499..8893ea361e3 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -142,47 +142,35 @@ static struct thd_error_context_service_st thd_error_context_handler= {
};
static struct wsrep_service_st wsrep_handler = {
- get_wsrep,
- get_wsrep_certify_nonPK,
- get_wsrep_debug,
- get_wsrep_drupal_282555_workaround,
get_wsrep_recovery,
- get_wsrep_load_data_splitting,
- get_wsrep_log_conflicts,
- get_wsrep_protocol_version,
- wsrep_aborting_thd_contains,
- wsrep_aborting_thd_enqueue,
wsrep_consistency_check,
wsrep_is_wsrep_xid,
wsrep_xid_seqno,
wsrep_xid_uuid,
- wsrep_lock_rollback,
wsrep_on,
- wsrep_post_commit,
- wsrep_prepare_key,
- wsrep_run_wsrep_commit,
+ wsrep_prepare_key_for_innodb,
wsrep_thd_LOCK,
wsrep_thd_UNLOCK,
- wsrep_thd_awake,
- wsrep_thd_conflict_state,
- wsrep_thd_conflict_state_str,
- wsrep_thd_exec_mode,
- wsrep_thd_exec_mode_str,
- wsrep_thd_get_conflict_state,
- wsrep_thd_is_BF,
- wsrep_thd_is_wsrep,
wsrep_thd_query,
- wsrep_thd_query_state,
- wsrep_thd_query_state_str,
wsrep_thd_retry_counter,
- wsrep_thd_set_conflict_state,
wsrep_thd_ignore_table,
wsrep_thd_trx_seqno,
- wsrep_thd_ws_handle,
- wsrep_trx_is_aborting,
- wsrep_trx_order_before,
- wsrep_unlock_rollback,
- wsrep_set_data_home_dir
+ wsrep_thd_is_aborting,
+ wsrep_set_data_home_dir,
+ wsrep_thd_is_BF,
+ wsrep_thd_is_local,
+ wsrep_thd_self_abort,
+ wsrep_thd_append_key,
+ wsrep_thd_client_state_str,
+ wsrep_thd_client_mode_str,
+ wsrep_thd_transaction_state_str,
+ wsrep_thd_transaction_id,
+ wsrep_thd_bf_abort,
+ wsrep_thd_order_before,
+ wsrep_handle_SR_rollback,
+ wsrep_thd_skip_locking,
+ wsrep_get_sr_table_name,
+ wsrep_get_debug
};
static struct thd_specifics_service_st thd_specifics_handler=
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index cb822fc2e98..c8cc64dba7e 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -4218,30 +4218,6 @@ reexecute:
error= execute(expanded_query, open_cursor) || thd->is_error();
thd->m_reprepare_observer= NULL;
-#ifdef WITH_WSREP
-
- if (WSREP_ON)
- {
- mysql_mutex_lock(&thd->LOCK_thd_data);
- switch (thd->wsrep_conflict_state)
- {
- case CERT_FAILURE:
- WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %lld err: %d",
- (longlong) thd->thread_id,
- thd->get_stmt_da()->sql_errno() );
- thd->wsrep_conflict_state = NO_CONFLICT;
- break;
-
- case MUST_REPLAY:
- (void) wsrep_replay_transaction(thd);
- break;
-
- default:
- break;
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif /* WITH_WSREP */
if (unlikely(error) &&
(sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) &&
@@ -4414,30 +4390,6 @@ reexecute:
error= execute(expanded_query, open_cursor) || thd->is_error();
thd->m_reprepare_observer= NULL;
-#ifdef WITH_WSREP
-
- if (WSREP_ON)
- {
- mysql_mutex_lock(&thd->LOCK_thd_data);
- switch (thd->wsrep_conflict_state)
- {
- case CERT_FAILURE:
- WSREP_DEBUG("PS execute fail for CERT_FAILURE: thd: %lld err: %d",
- (longlong) thd->thread_id,
- thd->get_stmt_da()->sql_errno() );
- thd->wsrep_conflict_state = NO_CONFLICT;
- break;
-
- case MUST_REPLAY:
- (void) wsrep_replay_transaction(thd);
- break;
-
- default:
- break;
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
-#endif /* WITH_WSREP */
if (unlikely(error) &&
(sql_command_flags[lex->sql_command] & CF_REEXECUTION_FRAGILE) &&
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 2ee175293de..1847416368a 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3845,6 +3845,17 @@ int reset_master(THD* thd, rpl_gtid *init_state, uint32 init_state_len,
return 1;
}
+#ifdef WITH_WSREP
+ if (WSREP_ON)
+ {
+ /* RESET MASTER will initialize GTID sequence, and that would happen locally
+ in this node, so better reject it
+ */
+ my_message(ER_NOT_ALLOWED_COMMAND,
+ "RESET MASTER not allowed when node is in cluster", MYF(0));
+ return 1;
+ }
+#endif /* WITH_WSREP */
bool ret= 0;
/* Temporarily disable master semisync before reseting master. */
repl_semisync_master.before_reset_master();
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f200f6f8c6d..11cfce172c5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2611,9 +2611,6 @@ err:
/* Chop of the last comma */
built_non_trans_tmp_query.chop();
built_non_trans_tmp_query.append(" /* generated by server */");
-#ifdef WITH_WSREP
- thd->wsrep_skip_wsrep_GTID = true;
-#endif /* WITH_WSREP */
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_non_trans_tmp_query.ptr(),
built_non_trans_tmp_query.length(),
@@ -2626,9 +2623,6 @@ err:
/* Chop of the last comma */
built_trans_tmp_query.chop();
built_trans_tmp_query.append(" /* generated by server */");
-#ifdef WITH_WSREP
- thd->wsrep_skip_wsrep_GTID = true;
-#endif /* WITH_WSREP */
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_trans_tmp_query.ptr(),
built_trans_tmp_query.length(),
@@ -2643,9 +2637,6 @@ err:
built_query.append(" /* generated by server */");
int error_code = non_tmp_error ? thd->get_stmt_da()->sql_errno()
: 0;
-#ifdef WITH_WSREP
- thd->wsrep_skip_wsrep_GTID = false;
-#endif /* WITH_WSREP */
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_query.ptr(),
built_query.length(),
@@ -2694,9 +2685,6 @@ err:
}
end:
-#ifdef WITH_WSREP
- thd->wsrep_skip_wsrep_GTID = false;
-#endif /* WITH_WSREP */
DBUG_RETURN(error);
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index b79c1a1adb1..33af220ae67 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -507,8 +507,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
#ifdef WITH_WSREP
- if (thd->wsrep_exec_mode == LOCAL_STATE)
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
#endif
/* We should have only one table in table list. */
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index 798e929170c..389276d0bcf 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -416,9 +416,11 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
{
bool hton_can_recreate;
+#ifdef WITH_WSREP
if (WSREP(thd) &&
wsrep_to_isolation_begin(thd, table_ref->db.str, table_ref->table_name.str, 0))
DBUG_RETURN(TRUE);
+#endif /* WITH_WSREP */
if (lock_table(thd, table_ref, &hton_can_recreate))
DBUG_RETURN(TRUE);
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 37b3d65e20a..df681e31d19 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -5519,7 +5519,7 @@ static Sys_var_ulong Sys_wsrep_mysql_replication_bundle(
static Sys_var_mybool Sys_wsrep_load_data_splitting(
"wsrep_load_data_splitting", "To commit LOAD DATA "
- "transaction after every 10K rows inserted",
+ "transaction after every 10K rows inserted (deprecating)",
GLOBAL_VAR(wsrep_load_data_splitting),
CMD_LINE(OPT_ARG), DEFAULT(TRUE));
@@ -5539,12 +5539,48 @@ static Sys_var_mybool Sys_wsrep_restart_slave(
"wsrep_restart_slave", "Should MariaDB slave be restarted automatically, when node joins back to cluster",
GLOBAL_VAR(wsrep_restart_slave), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
+static Sys_var_ulonglong Sys_wsrep_trx_fragment_size(
+ "wsrep_trx_fragment_size",
+ "Size of transaction fragments for streaming replication (measured in "
+ "units of 'wsrep_trx_fragment_unit')",
+ SESSION_VAR(wsrep_trx_fragment_size), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, WSREP_MAX_WS_SIZE), DEFAULT(0), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(wsrep_trx_fragment_size_check),
+ ON_UPDATE(wsrep_trx_fragment_size_update));
+
+extern const char *wsrep_fragment_units[];
+
+static Sys_var_enum Sys_wsrep_trx_fragment_unit(
+ "wsrep_trx_fragment_unit",
+ "Unit for streaming replication transaction fragments' size: bytes, "
+ "rows, statements",
+ SESSION_VAR(wsrep_trx_fragment_unit), CMD_LINE(REQUIRED_ARG),
+ wsrep_fragment_units,
+ DEFAULT(WSREP_FRAG_BYTES),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(0),
+ ON_UPDATE(wsrep_trx_fragment_unit_update));
+
+extern const char *wsrep_SR_store_types[];
+static Sys_var_enum Sys_wsrep_SR_store(
+ "wsrep_SR_store", "Storage for streaming replication fragments",
+ READ_ONLY GLOBAL_VAR(wsrep_SR_store_type), CMD_LINE(REQUIRED_ARG),
+ wsrep_SR_store_types, DEFAULT(WSREP_SR_STORE_TABLE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG);
+
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);
+static Sys_var_uint Sys_wsrep_ignore_apply_errors (
+ "wsrep_ignore_apply_errors", "Ignore replication errors",
+ GLOBAL_VAR(wsrep_ignore_apply_errors), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(WSREP_IGNORE_ERRORS_NONE, WSREP_IGNORE_ERRORS_MAX),
+ DEFAULT(7), BLOCK_SIZE(1));
+
static Sys_var_uint Sys_wsrep_gtid_domain_id(
"wsrep_gtid_domain_id", "When wsrep_gtid_mode is set, this value is "
"used as gtid_domain_id for galera transactions and also copied to the "
diff --git a/sql/table.cc b/sql/table.cc
index 488d05b1a22..01f96b5f93b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -247,6 +247,13 @@ TABLE_CATEGORY get_table_category(const LEX_CSTRING *db,
DBUG_ASSERT(db != NULL);
DBUG_ASSERT(name != NULL);
+#ifdef WITH_WSREP
+ if (my_strcasecmp(system_charset_info, db->str, "mysql") == 0 &&
+ my_strcasecmp(system_charset_info, name->str, "wsrep_streaming_log") == 0)
+ {
+ return TABLE_CATEGORY_INFORMATION;
+ }
+#endif /* WITH_WSREP */
if (is_infoschema_db(db))
return TABLE_CATEGORY_INFORMATION;
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 13614d36a73..4d61d2a120d 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -24,6 +24,9 @@
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_acl.h"
#include "semisync_master.h"
+#ifdef WITH_WSREP
+#include "wsrep_trans_observer.h"
+#endif /* WITH_WSREP */
#ifndef EMBEDDED_LIBRARY
/**
@@ -135,8 +138,6 @@ static bool xa_trans_force_rollback(THD *thd)
by ha_rollback()/THD::transaction::cleanup().
*/
thd->transaction.xid_state.rm_error= 0;
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
if (ha_rollback_trans(thd, true))
{
my_error(ER_XAER_RMERR, MYF(0));
@@ -184,14 +185,16 @@ bool trans_begin(THD *thd, uint flags)
(thd->variables.option_bits & OPTION_TABLE_LOCK))
{
thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= MY_TEST(ha_commit_trans(thd, TRUE));
- if (WSREP_ON)
- wsrep_post_commit(thd, TRUE);
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_local(thd))
+ {
+ res= res || wsrep_after_statement(thd);
+ }
+#endif /* WITH_WSREP */
}
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
@@ -252,9 +255,14 @@ bool trans_begin(THD *thd, uint flags)
}
#ifdef WITH_WSREP
- thd->wsrep_PA_safe= true;
- if (WSREP_CLIENT(thd) && wsrep_sync_wait(thd))
- DBUG_RETURN(TRUE);
+ if (wsrep_thd_is_local(thd))
+ {
+ if (wsrep_sync_wait(thd))
+ DBUG_RETURN(TRUE);
+ if (!thd->tx_read_only &&
+ wsrep_start_transaction(thd, thd->wsrep_next_trx_id()))
+ DBUG_RETURN(TRUE);
+ }
#endif /* WITH_WSREP */
thd->variables.option_bits|= OPTION_BEGIN;
@@ -299,8 +307,6 @@ bool trans_commit(THD *thd)
if (trans_check(thd))
DBUG_RETURN(TRUE);
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
@@ -311,8 +317,6 @@ bool trans_commit(THD *thd)
mysql_mutex_assert_not_owner(&LOCK_after_binlog_sync);
mysql_mutex_assert_not_owner(&LOCK_commit_ordered);
- if (WSREP_ON)
- wsrep_post_commit(thd, TRUE);
/*
if res is non-zero, then ha_commit_trans has rolled back the
transaction, so the hooks for rollback will be called.
@@ -368,14 +372,10 @@ 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;
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
res= MY_TEST(ha_commit_trans(thd, TRUE));
- if (WSREP_ON)
- wsrep_post_commit(thd, TRUE);
}
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
@@ -409,14 +409,9 @@ bool trans_rollback(THD *thd)
int res;
DBUG_ENTER("trans_rollback");
-#ifdef WITH_WSREP
- thd->wsrep_PA_safe= true;
-#endif /* WITH_WSREP */
if (trans_check(thd))
DBUG_RETURN(TRUE);
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
thd->server_status&=
~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY);
DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
@@ -515,14 +510,10 @@ bool trans_commit_stmt(THD *thd)
if (thd->transaction.stmt.ha_list)
{
- if (WSREP_ON)
- wsrep_register_hton(thd, FALSE);
res= ha_commit_trans(thd, FALSE);
if (! thd->in_active_multi_stmt_transaction())
{
trans_reset_one_shot_chistics(thd);
- if (WSREP_ON)
- wsrep_post_commit(thd, FALSE);
}
}
@@ -578,8 +569,6 @@ bool trans_rollback_stmt(THD *thd)
if (thd->transaction.stmt.ha_list)
{
- if (WSREP_ON)
- wsrep_register_hton(thd, FALSE);
ha_rollback_trans(thd, FALSE);
if (! thd->in_active_multi_stmt_transaction())
trans_reset_one_shot_chistics(thd);
@@ -733,7 +722,8 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_CSTRING name)
logging is off.
*/
bool mdl_can_safely_rollback_to_savepoint=
- (!(mysql_bin_log.is_open() && thd->variables.sql_log_bin) ||
+ (!((WSREP_EMULATE_BINLOG_NNULL(thd) || mysql_bin_log.is_open())
+ && thd->variables.sql_log_bin) ||
ha_rollback_to_savepoint_can_release_mdl(thd));
if (ha_rollback_to_savepoint(thd, sv))
@@ -944,13 +934,9 @@ bool trans_xa_commit(THD *thd)
}
else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
{
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
int r= ha_commit_trans(thd, TRUE);
if ((res= MY_TEST(r)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
- if (WSREP_ON)
- wsrep_post_commit(thd, TRUE);
}
else if (xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
{
@@ -969,8 +955,6 @@ bool trans_xa_commit(THD *thd)
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
{
- if (WSREP_ON)
- wsrep_register_hton(thd, TRUE);
ha_rollback_trans(thd, TRUE);
my_error(ER_XAER_RMERR, MYF(0));
}
diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc
index 1f50ee55711..2c4dab3bd20 100644
--- a/sql/wsrep_applier.cc
+++ b/sql/wsrep_applier.cc
@@ -14,12 +14,17 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "mariadb.h"
+#include "mysql/service_wsrep.h"
+#include "wsrep_applier.h"
+
#include "wsrep_priv.h"
#include "wsrep_binlog.h" // wsrep_dump_rbr_buf()
#include "wsrep_xid.h"
+#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h"
+#include "slave.h" // opt_log_slave_updates
#include "log_event.h" // class THD, EVENT_LEN_OFFSET, etc.
-#include "wsrep_applier.h"
#include "debug_sync.h"
/*
@@ -27,7 +32,6 @@
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)
@@ -35,7 +39,7 @@ static Log_event* wsrep_read_log_event(
DBUG_ENTER("wsrep_read_log_event");
char *head= (*arg_buf);
- uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
+ uint data_len= uint4korr(head + EVENT_LEN_OFFSET);
char *buf= (*arg_buf);
const char *error= 0;
Log_event *res= 0;
@@ -62,12 +66,13 @@ 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;
+ delete (Format_description_log_event*)thd->wsrep_apply_format;
}
thd->wsrep_apply_format= ev;
}
-Format_description_log_event* wsrep_get_apply_format(THD* thd)
+Format_description_log_event*
+wsrep_get_apply_format(THD* thd)
{
if (thd->wsrep_apply_format)
{
@@ -79,45 +84,77 @@ Format_description_log_event* wsrep_get_apply_format(THD* thd)
return thd->wsrep_rgi->rli->relay_log.description_event_for_exec;
}
-static wsrep_cb_status_t wsrep_apply_events(THD* thd,
- const void* events_buf,
- size_t buf_len)
+void wsrep_apply_error::store(const THD* const thd)
{
- char *buf= (char *)events_buf;
- int rcode= 0;
- int event= 1;
- Log_event_type typ;
+ Diagnostics_area::Sql_condition_iterator it=
+ thd->get_stmt_da()->sql_conditions();
+ const Sql_condition* cond;
- DBUG_ENTER("wsrep_apply_events");
+ static size_t const max_len= 2*MAX_SLAVE_ERRMSG; // 2x so that we have enough
+
+ if (NULL == str_)
+ {
+ // this must be freeable by standard free()
+ str_= static_cast<char*>(malloc(max_len));
+ if (NULL == str_)
+ {
+ WSREP_ERROR("Failed to allocate %zu bytes for error buffer.", max_len);
+ len_= 0;
+ return;
+ }
+ }
+ else
+ {
+ /* This is possible when we invoke rollback after failed applying.
+ * In this situation DA should not be reset yet and should contain
+ * all previous errors from applying and new ones from rollbacking,
+ * so we just overwrite is from scratch */
+ }
- if (thd->killed == KILL_CONNECTION &&
- thd->wsrep_conflict_state != REPLAYING)
+ char* slider= str_;
+ const char* const buf_end= str_ + max_len - 1; // -1: leave space for \0
+
+ for (cond= it++; cond && slider < buf_end; cond= it++)
{
- WSREP_INFO("applier has been aborted, skipping apply_rbr: %lld",
- (long long) wsrep_thd_trx_seqno(thd));
- DBUG_RETURN(WSREP_CB_FAILURE);
+ uint const err_code= cond->get_sql_errno();
+ const char* const err_str= cond->get_message_text();
+
+ slider+= my_snprintf(slider, buf_end - slider, " %s, Error_code: %d;",
+ err_str, err_code);
}
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_EXEC;
- if (thd->wsrep_conflict_state!= REPLAYING)
- thd->wsrep_conflict_state= NO_CONFLICT;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ *slider= '\0';
+ len_= slider - str_ + 1; // +1: add \0
+
+ WSREP_DEBUG("Error buffer for thd %llu seqno %lld, %zu bytes: %s",
+ thd->thread_id, (long long)wsrep_thd_trx_seqno(thd),
+ len_, str_ ? str_ : "(null)");
+}
+
+int wsrep_apply_events(THD* thd,
+ Relay_log_info* rli,
+ 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 (!buf_len) WSREP_DEBUG("empty rbr buffer to apply: %lld",
(long long) wsrep_thd_trx_seqno(thd));
- while(buf_len)
+ while (buf_len)
{
int exec_res;
Log_event* ev= wsrep_read_log_event(&buf, &buf_len,
- wsrep_get_apply_format(thd));
-
+ 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;
+ rcode= WSREP_ERR_BAD_EVENT;
goto error;
}
@@ -147,9 +184,12 @@ static wsrep_cb_status_t wsrep_apply_events(THD* thd,
thd->set_server_id(ev->server_id);
thd->set_time(); // time the query
thd->transaction.start_time.reset(thd);
+ //#define mariadb_10_4_0
+#ifdef mariadb_10_4_0
wsrep_xid_init(&thd->transaction.xid_state.xid,
thd->wsrep_trx_meta.gtid.uuid,
thd->wsrep_trx_meta.gtid.seqno);
+#endif
thd->lex->current_select= 0;
if (!ev->when)
{
@@ -162,13 +202,13 @@ static wsrep_cb_status_t wsrep_apply_events(THD* thd,
(thd->variables.option_bits & ~OPTION_SKIP_REPLICATION) |
(ev->flags & LOG_EVENT_SKIP_REPLICATION_F ? OPTION_SKIP_REPLICATION : 0);
- ev->thd = thd;
- exec_res = ev->apply_event(thd->wsrep_rgi);
+ ev->thd= thd;
+ exec_res= ev->apply_event(thd->wsrep_rgi);
DBUG_PRINT("info", ("exec_event result: %d", exec_res));
if (exec_res)
{
- WSREP_WARN("RBR event %d %s apply warning: %d, %lld",
+ WSREP_WARN("Event %d %s apply failed: %d, seqno %lld",
event, ev->get_type_str(), exec_res,
(long long) wsrep_thd_trx_seqno(thd));
rcode= exec_res;
@@ -178,230 +218,14 @@ static wsrep_cb_status_t wsrep_apply_events(THD* thd,
}
event++;
- if (thd->wsrep_conflict_state!= NO_CONFLICT &&
- thd->wsrep_conflict_state!= REPLAYING)
- WSREP_WARN("conflict state after RBR event applying: %d, %lld",
- thd->wsrep_query_state, (long long)wsrep_thd_trx_seqno(thd));
-
- if (thd->wsrep_conflict_state == MUST_ABORT) {
- WSREP_WARN("RBR event apply failed, rolling back: %lld",
- (long long) wsrep_thd_trx_seqno(thd));
- trans_rollback(thd);
- thd->locked_tables_list.unlock_locked_tables(thd);
- /* Release transactional metadata locks. */
- thd->mdl_context.release_transactional_locks();
- thd->wsrep_conflict_state= NO_CONFLICT;
- DBUG_RETURN(WSREP_CB_FAILURE);
- }
-
delete_or_keep_event_post_apply(thd->wsrep_rgi, typ, ev);
}
- error:
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_query_state= QUERY_IDLE;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
-
- assert(thd->wsrep_exec_mode== REPL_RECV);
-
+error:
if (thd->killed == KILL_CONNECTION)
WSREP_INFO("applier aborted: %lld", (long long)wsrep_thd_trx_seqno(thd));
- if (rcode) DBUG_RETURN(WSREP_CB_FAILURE);
- DBUG_RETURN(WSREP_CB_SUCCESS);
-}
-
-wsrep_cb_status_t wsrep_apply_cb(void* const ctx,
- const void* const buf,
- size_t const buf_len,
- uint32_t const flags,
- const wsrep_trx_meta_t* meta)
-{
- THD* const thd((THD*)ctx);
-
- assert(thd->wsrep_apply_toi == false);
-
- // Allow tests to block the applier thread using the DBUG facilities.
- DBUG_EXECUTE_IF("sync.wsrep_apply_cb",
- {
- const char act[]=
- "now "
- "SIGNAL sync.wsrep_apply_cb_reached "
- "WAIT_FOR signal.wsrep_apply_cb";
- DBUG_ASSERT(!debug_sync_set_action(thd,
- STRING_WITH_LEN(act)));
- };);
-
- thd->wsrep_trx_meta = *meta;
-
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Applying write set %lld: %p, %zu",
- (long long)wsrep_thd_trx_seqno(thd), buf, buf_len);
- thd_proc_info(thd, thd->wsrep_info);
-#else
- thd_proc_info(thd, "Applying write set");
-#endif /* WSREP_PROC_INFO */
-
- /* tune FK and UK checking policy */
- if (wsrep_slave_UK_checks == FALSE)
- thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
-
- if (wsrep_slave_FK_checks == FALSE)
- thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
-
- /* With galera we assume that the master has done the constraint checks */
- thd->variables.option_bits|= OPTION_NO_CHECK_CONSTRAINT_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_with_header(thd, buf, buf_len);
- }
-
- if (thd->has_thd_temporary_tables())
- {
- WSREP_DEBUG("Applier %lld has temporary tables. Closing them now..",
- thd->thread_id);
- thd->close_temporary_tables();
- }
-
- return rcode;
-}
-
-static wsrep_cb_status_t wsrep_commit(THD* const thd)
-{
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Committing %lld", (long long)wsrep_thd_trx_seqno(thd));
- thd_proc_info(thd, thd->wsrep_info);
-#else
- thd_proc_info(thd, "Committing");
-#endif /* WSREP_PROC_INFO */
-
- wsrep_cb_status_t const rcode(trans_commit(thd) ?
- WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
-
- if (WSREP_CB_SUCCESS == rcode)
- {
- thd->wsrep_rgi->cleanup_context(thd, false);
-#ifdef GTID_SUPPORT
- thd->variables.gtid_next.set_automatic();
-#endif /* GTID_SUPPORT */
- if (thd->wsrep_apply_toi)
- {
- wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
- thd->wsrep_trx_meta.gtid.seqno);
- }
- }
-
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Committed %lld", (long long) wsrep_thd_trx_seqno(thd));
- thd_proc_info(thd, thd->wsrep_info);
-#else
- thd_proc_info(thd, "Committed");
-#endif /* WSREP_PROC_INFO */
-
- return rcode;
-}
-
-static wsrep_cb_status_t wsrep_rollback(THD* const thd)
-{
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Rolling back %lld", (long long)wsrep_thd_trx_seqno(thd));
- thd_proc_info(thd, thd->wsrep_info);
-#else
- thd_proc_info(thd, "Rolling back");
-#endif /* WSREP_PROC_INFO */
-
- wsrep_cb_status_t const rcode(trans_rollback(thd) ?
- WSREP_CB_FAILURE : WSREP_CB_SUCCESS);
-
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Rolled back %lld", (long long)wsrep_thd_trx_seqno(thd));
- thd_proc_info(thd, thd->wsrep_info);
-#else
- thd_proc_info(thd, "Rolled back");
-#endif /* WSREP_PROC_INFO */
-
- return rcode;
-}
-
-wsrep_cb_status_t wsrep_commit_cb(void* const ctx,
- uint32_t const flags,
- const wsrep_trx_meta_t* meta,
- wsrep_bool_t* const exit,
- bool const commit)
-{
- THD* const thd((THD*)ctx);
-
- assert(meta->gtid.seqno == wsrep_thd_trx_seqno(thd));
-
- wsrep_cb_status_t rcode;
-
- if (commit)
- rcode = wsrep_commit(thd);
- else
- rcode = wsrep_rollback(thd);
-
- /* Cleanup */
wsrep_set_apply_format(thd, NULL);
- thd->mdl_context.release_transactional_locks();
- thd->reset_query(); /* Mutex protected */
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
- if (wsrep_slave_count_change < 0 && commit && WSREP_CB_SUCCESS == rcode)
- {
- mysql_mutex_lock(&LOCK_wsrep_slave_threads);
- if (wsrep_slave_count_change < 0)
- {
- wsrep_slave_count_change++;
- *exit = true;
- }
- mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
- }
-
- if (thd->wsrep_applier)
- {
- /* From trans_begin() */
- thd->variables.option_bits|= OPTION_BEGIN;
- thd->server_status|= SERVER_STATUS_IN_TRANS;
- thd->wsrep_apply_toi= false;
- }
-
- return rcode;
-}
-
-
-wsrep_cb_status_t wsrep_unordered_cb(void* const ctx,
- const void* const data,
- size_t const size)
-{
- return WSREP_CB_SUCCESS;
+ DBUG_RETURN(rcode);
}
diff --git a/sql/wsrep_applier.h b/sql/wsrep_applier.h
index f19d2d46d0c..a8da2acbb9a 100644
--- a/sql/wsrep_applier.h
+++ b/sql/wsrep_applier.h
@@ -1,4 +1,4 @@
-/* Copyright 2013 Codership Oy <http://www.codership.com>
+/* Copyright 2013-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
@@ -17,28 +17,57 @@
#define WSREP_APPLIER_H
#include <my_config.h>
-#include "../wsrep/wsrep_api.h"
-void wsrep_set_apply_format(THD* thd, Format_description_log_event* ev);
-Format_description_log_event* wsrep_get_apply_format(THD* thd);
+#include "sql_class.h" // THD class
+
+int wsrep_apply_events(THD* thd,
+ Relay_log_info* rli,
+ const void* events_buf,
+ size_t buf_len);
-/* wsrep callback prototypes */
-extern "C" {
-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);
+/* Applier error codes, when nothing better is available. */
+#define WSREP_RET_SUCCESS 0 // Success
+#define WSREP_ERR_GENERIC 1 // When in doubt (MySQL default error code)
+#define WSREP_ERR_BAD_EVENT 2 // Can't parse event
+#define WSREP_ERR_NOT_FOUND 3 // Key. table, schema not found
+#define WSREP_ERR_EXISTS 4 // Key, table, schema already exists
+#define WSREP_ERR_WRONG_TYPE 5 // Incompatible data type
+#define WSREP_ERR_FAILED 6 // Operation failed for some internal reason
+#define WSREP_ERR_ABORTED 7 // Operation was aborted externally
-wsrep_cb_status_t wsrep_commit_cb(void *ctx,
- uint32_t flags,
- const wsrep_trx_meta_t* meta,
- wsrep_bool_t* exit,
- bool commit);
+class wsrep_apply_error
+{
+public:
+ wsrep_apply_error() : str_(NULL), len_(0) {};
+ ~wsrep_apply_error() { ::free(str_); }
+ /* stores the current THD error info from the diagnostic area. Works only
+ * once, subsequent invocations are ignored in order to preserve the original
+ * condition. */
+ void store(const THD* thd);
+ const char* c_str() const { return str_; }
+ size_t length() const { return len_; }
+ bool is_null() const { return (c_str() == NULL && length() == 0); }
+ wsrep_buf_t get_buf() const
+ {
+ wsrep_buf_t ret= { c_str(), length() };
+ return ret;
+ }
+private:
+ char* str_;
+ size_t len_;
+};
+
+class Format_description_log_event;
+void wsrep_set_apply_format(THD*, Format_description_log_event*);
+Format_description_log_event* wsrep_get_apply_format(THD* thd);
+int wsrep_apply(void* ctx,
+ uint32_t flags,
+ const wsrep_buf_t* buf,
+ const wsrep_trx_meta_t* meta,
+ wsrep_apply_error& err);
-wsrep_cb_status_t wsrep_unordered_cb(void* ctx,
- const void* data,
- size_t size);
+wsrep_cb_status_t wsrep_unordered_cb(void* ctx,
+ const wsrep_buf_t* data);
-} /* extern "C" */
#endif /* WSREP_APPLIER_H */
diff --git a/sql/wsrep_binlog.cc b/sql/wsrep_binlog.cc
index 0cbcdcd64aa..b02692d14fe 100644
--- a/sql/wsrep_binlog.cc
+++ b/sql/wsrep_binlog.cc
@@ -14,12 +14,15 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "mariadb.h"
+#include "mysql/service_wsrep.h"
#include "wsrep_binlog.h"
#include "wsrep_priv.h"
#include "log.h"
#include "log_event.h"
#include "wsrep_applier.h"
+#include "transaction.h"
+
extern handlerton *binlog_hton;
/*
Write the contents of a cache to a memory buffer.
@@ -40,10 +43,10 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
DBUG_RETURN(ER_ERROR_ON_WRITE);
}
- uint length = my_b_bytes_in_cache(cache);
- if (unlikely(0 == length)) length = my_b_fill(cache);
+ uint length= my_b_bytes_in_cache(cache);
+ if (unlikely(0 == length)) length= my_b_fill(cache);
- size_t total_length = 0;
+ size_t total_length= 0;
if (likely(length > 0)) do
{
@@ -60,7 +63,7 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
wsrep_max_ws_size, total_length);
goto error;
}
- uchar* tmp = (uchar *)my_realloc(*buf, total_length,
+ uchar* tmp= (uchar *)my_realloc(*buf, total_length,
MYF(MY_ALLOW_ZERO_PTR));
if (!tmp)
{
@@ -68,17 +71,17 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len)
*buf_len, length);
goto error;
}
- *buf = tmp;
+ *buf= tmp;
memcpy(*buf + *buf_len, cache->read_pos, length);
- *buf_len = total_length;
+ *buf_len= total_length;
if (cache->file < 0)
{
cache->read_pos= cache->read_end;
break;
}
- } while ((length = my_b_fill(cache)));
+ } while ((length= my_b_fill(cache)));
if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
{
@@ -111,130 +114,6 @@ 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));
- DBUG_DUMP("buff", (uchar*) data, len);
- 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));
- DBUG_ENTER("wsrep_write_cache_once");
-
- if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
- {
- WSREP_ERROR("failed to initialize io-cache");
- DBUG_RETURN(ER_ERROR_ON_WRITE);
- }
-
- int err(WSREP_OK);
-
- size_t total_length(0);
- uchar stack_buf[STACK_SIZE]; /* to avoid dynamic allocations for few data*/
- uchar* heap_buf(NULL);
- uchar* buf(stack_buf);
- size_t allocated(sizeof(stack_buf));
- size_t used(0);
-
- uint length(my_b_bytes_in_cache(cache));
- if (unlikely(0 == length)) length = my_b_fill(cache);
-
- if (likely(length > 0)) do
- {
- total_length += length;
- /*
- Bail out if buffer grows too large.
- A temporary fix to avoid allocating indefinitely large buffer,
- not a real limit on a writeset size which includes other things
- like header and keys.
- */
- if (unlikely(total_length > wsrep_max_ws_size))
- {
- WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
- wsrep_max_ws_size, total_length);
- err = WSREP_TRX_SIZE_EXCEEDED;
- goto cleanup;
- }
-
- if (total_length > allocated)
- {
- size_t const new_size(heap_size(total_length));
- uchar* tmp = (uchar *)my_realloc(heap_buf, new_size,
- MYF(MY_ALLOW_ZERO_PTR));
- if (!tmp)
- {
- WSREP_ERROR("could not (re)allocate buffer: %zu + %u",
- allocated, length);
- err = WSREP_TRX_SIZE_EXCEEDED;
- goto cleanup;
- }
-
- heap_buf = tmp;
- buf = heap_buf;
- allocated = new_size;
-
- if (used <= STACK_SIZE && used > 0) // there's data in stack_buf
- {
- DBUG_ASSERT(buf == stack_buf);
- memcpy(heap_buf, stack_buf, used);
- }
- }
-
- memcpy(buf + used, cache->read_pos, length);
- used = total_length;
- if (cache->file < 0)
- {
- cache->read_pos= cache->read_end;
- break;
- }
- } while ((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_with_header(thd, buf, used);
- }
-
- my_free(heap_buf);
- DBUG_RETURN(err);
-}
-
/*
Write the contents of a cache to wsrep provider.
@@ -243,62 +122,58 @@ cleanup:
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,
+static int wsrep_write_cache_inc(THD* const thd,
IO_CACHE* const cache,
size_t* const len)
{
- my_off_t const saved_pos(my_b_tell(cache));
- DBUG_ENTER("wsrep_write_cache_inc");
-
- if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
- {
- WSREP_ERROR("failed to initialize io-cache");
- DBUG_RETURN(WSREP_TRX_ERROR);
- }
+ DBUG_ENTER("wsrep_write_cache_inc");
+ my_off_t const saved_pos(my_b_tell(cache));
- int err(WSREP_OK);
+ if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().bytes_certified(), 0, 0))
+ {
+ WSREP_ERROR("failed to initialize io-cache");
+ DBUG_RETURN(1);;
+ }
- size_t total_length(0);
+ int ret= 0;
+ size_t total_length(0);
- uint length(my_b_bytes_in_cache(cache));
- if (unlikely(0 == length)) length = my_b_fill(cache);
+ uint length(my_b_bytes_in_cache(cache));
+ if (unlikely(0 == length)) length= my_b_fill(cache);
- if (likely(length > 0)) do
+ 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;
-
- if (cache->file < 0)
- {
- cache->read_pos= cache->read_end;
- break;
- }
- } while ((length = my_b_fill(cache)));
-
- if (WSREP_OK == err) *len = total_length;
+ 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);
+ ret= 1;
+ goto cleanup;
+ }
+ if (thd->wsrep_cs().append_data(wsrep::const_buffer(cache->read_pos, length)))
+ goto cleanup;
+ cache->read_pos= cache->read_end;
+ } while ((cache->file >= 0) && (length= my_b_fill(cache)));
+ }
+ if (ret == 0)
+ {
+ assert(total_length + thd->wsrep_sr().bytes_certified() == saved_pos);
+ }
cleanup:
- if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
- {
- WSREP_ERROR("failed to reinitialize io-cache");
- }
-
- DBUG_RETURN(err);
+ *len= total_length;
+ if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
+ {
+ WSREP_ERROR("failed to reinitialize io-cache");
+ }
+ DBUG_RETURN(ret);
}
/*
@@ -307,17 +182,11 @@ cleanup:
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,
+int wsrep_write_cache(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);
- }
+ return wsrep_write_cache_inc(thd, cache, len);
}
void wsrep_dump_rbr_buf(THD *thd, const void* rbr_buf, size_t buf_len)
@@ -383,80 +252,17 @@ int wsrep_binlog_close_connection(THD* thd)
int wsrep_binlog_savepoint_set(THD *thd, void *sv)
{
if (!wsrep_emulate_bin_log) return 0;
- int rcode = binlog_hton->savepoint_set(binlog_hton, thd, sv);
+ int rcode= binlog_hton->savepoint_set(binlog_hton, thd, sv);
return rcode;
}
int wsrep_binlog_savepoint_rollback(THD *thd, void *sv)
{
if (!wsrep_emulate_bin_log) return 0;
- int rcode = binlog_hton->savepoint_rollback(binlog_hton, thd, sv);
+ int rcode= binlog_hton->savepoint_rollback(binlog_hton, thd, sv);
return rcode;
}
-#if 0
-void wsrep_dump_rbr_direct(THD* thd, IO_CACHE* cache)
-{
- char filename[PATH_MAX]= {0};
- int len= snprintf(filename, PATH_MAX, "%s/GRA_%lld_%lld.log",
- wsrep_data_home_dir, (longlong) thd->thread_id,
- (longlong) 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;
- }
-
- if (cache->file < 0)
- {
- cache->read_pos= cache->read_end;
- break;
- }
- } while ((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);
-}
-#endif
-
void thd_binlog_flush_pending_rows_event(THD *thd, bool stmt_end)
{
thd->binlog_flush_pending_rows_event(stmt_end);
@@ -544,3 +350,31 @@ cleanup1:
DBUG_VOID_RETURN;
}
+#include "log_event.h"
+
+int wsrep_write_skip_event(THD* thd)
+{
+ DBUG_ENTER("wsrep_write_skip_event");
+ Ignorable_log_event skip_event(thd);
+ int ret= mysql_bin_log.write_event(&skip_event);
+ if (ret)
+ {
+ WSREP_WARN("wsrep_write_skip_event: write to binlog failed: %d", ret);
+ }
+ if (!ret && (ret= trans_commit_stmt(thd)))
+ {
+ WSREP_WARN("wsrep_write_skip_event: statt commit failed");
+ }
+ DBUG_RETURN(ret);
+}
+
+int wsrep_write_dummy_event_low(THD *thd, const char *msg)
+{
+ ::abort();
+ return 0;
+}
+
+int wsrep_write_dummy_event(THD *orig_thd, const char *msg)
+{
+ return 0;
+}
diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h
index 864813d5c98..4cef38c85d3 100644
--- a/sql/wsrep_binlog.h
+++ b/sql/wsrep_binlog.h
@@ -16,6 +16,7 @@
#ifndef WSREP_BINLOG_H
#define WSREP_BINLOG_H
+#include "my_global.h"
#include "sql_class.h" // THD, IO_CACHE
#define HEAP_PAGE_SIZE 65536 /* 64K */
@@ -38,23 +39,39 @@ int wsrep_write_cache_buf(IO_CACHE *cache, uchar **buf, size_t *buf_len);
@param len total amount of data written
@return wsrep error status
*/
-int wsrep_write_cache (wsrep_t* const wsrep,
- THD* const thd,
- IO_CACHE* const cache,
- size_t* const len);
+int wsrep_write_cache(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);
-
/* Dump replication buffer along with header to a file */
void wsrep_dump_rbr_buf_with_header(THD *thd, const void *rbr_buf,
size_t buf_len);
int wsrep_binlog_close_connection(THD* thd);
-int wsrep_binlog_savepoint_set(THD *thd, void *sv);
-int wsrep_binlog_savepoint_rollback(THD *thd, void *sv);
+
+/**
+ Write a skip event into binlog.
+
+ @param thd Thread object pointer
+ @return Zero in case of success, non-zero on failure.
+*/
+int wsrep_write_skip_event(THD* thd);
+
+/*
+ Write dummy event into binlog in place of unused GTID.
+ The binlog write is done in thd context.
+*/
+int wsrep_write_dummy_event_low(THD *thd, const char *msg);
+/*
+ Write dummy event to binlog in place of unused GTID and
+ commit. The binlog write and commit are done in temporary
+ thd context, the original thd state is not altered.
+*/
+int wsrep_write_dummy_event(THD* thd, const char *msg);
+
+void wsrep_register_binlog_handler(THD *thd, bool trx);
#endif /* WSREP_BINLOG_H */
diff --git a/sql/wsrep_check_opts.cc b/sql/wsrep_check_opts.cc
index 0b7a9ca6252..7b8067ef238 100644
--- a/sql/wsrep_check_opts.cc
+++ b/sql/wsrep_check_opts.cc
@@ -33,7 +33,7 @@ int wsrep_check_opts()
autoinc_lock_mode->val_int(&is_null, 0, OPT_GLOBAL, 0) != 2)
{
WSREP_ERROR("Parallel applying (wsrep_slave_threads > 1) requires"
- " innodb_autoinc_lock_mode = 2.");
+ " innodb_autoinc_lock_mode= 2.");
return 1;
}
}
@@ -88,7 +88,7 @@ int wsrep_check_opts()
{
if (global_system_variables.binlog_format != BINLOG_FORMAT_ROW)
{
- WSREP_ERROR("Only binlog_format = 'ROW' is currently supported. "
+ WSREP_ERROR("Only binlog_format= 'ROW' is currently supported. "
"Configured value: '%s'. Please adjust your "
"configuration.",
binlog_format_names[global_system_variables.binlog_format]);
diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc
new file mode 100644
index 00000000000..994fa97db60
--- /dev/null
+++ b/sql/wsrep_client_service.cc
@@ -0,0 +1,307 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "wsrep_client_service.h"
+#include "wsrep_high_priority_service.h"
+#include "wsrep_applier.h" /* wsrep_apply_events() */
+#include "wsrep_binlog.h" /* wsrep_dump_rbr_buf() */
+#include "wsrep_schema.h" /* remove_fragments() */
+#include "wsrep_thd.h"
+#include "wsrep_xid.h"
+#include "wsrep_trans_observer.h"
+
+#include "sql_base.h" /* close_temporary_table() */
+#include "sql_class.h" /* THD */
+#include "sql_parse.h" /* stmt_causes_implicit_commit() */
+#include "rpl_filter.h" /* binlog_filter */
+#include "rpl_rli.h" /* Relay_log_info */
+#include "slave.h" /* opt_log_slave_updates */
+#include "transaction.h" /* trans_commit()... */
+#include "log.h" /* stmt_has_updated_trans_table() */
+//#include "debug_sync.h"
+#include "mysql/service_debug_sync.h"
+namespace
+{
+
+void debug_sync_caller(THD* thd, const char* sync_point)
+{
+#ifdef ENABLED_DEBUG_SYNC_OUT
+ debug_sync_set_action(thd, sync_point, strlen(sync_point));
+#endif
+#ifdef ENABLED_DEBUG_SYNC
+ if (debug_sync_service) debug_sync_service(thd,sync_point,strlen(sync_point));
+#endif
+
+}
+}
+
+Wsrep_client_service::Wsrep_client_service(THD* thd,
+ Wsrep_client_state& client_state)
+ : wsrep::client_service()
+ , m_thd(thd)
+ , m_client_state(client_state)
+{ }
+
+void Wsrep_client_service::store_globals()
+{
+ DBUG_ENTER("Wsrep_client_service::store_globals");
+ m_thd->store_globals();
+ DBUG_VOID_RETURN;
+}
+
+void Wsrep_client_service::reset_globals()
+{
+ DBUG_ENTER("Wsrep_client_service::reset_globals");
+ m_thd->reset_globals();
+ DBUG_VOID_RETURN;
+}
+
+bool Wsrep_client_service::interrupted() const
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ mysql_mutex_lock(&m_thd->LOCK_thd_data);
+
+ /* wsrep state can be interrupted only if THD was explicitly killed,
+ for wsrep conflicts, we use deadlock error only
+ */
+ bool ret= (m_thd->killed != NOT_KILLED &&
+ m_thd->wsrep_trx().state() != wsrep::transaction::s_must_abort &&
+ m_thd->wsrep_trx().state() != wsrep::transaction::s_aborting &&
+ m_thd->wsrep_trx().state() != wsrep::transaction::s_aborted);
+ mysql_mutex_unlock(&m_thd->LOCK_thd_data);
+ if (ret)
+ {
+ WSREP_DEBUG("wsrep state is interrupted, THD::killed %d trx state %d",
+ m_thd->killed, m_thd->wsrep_trx().state());
+ }
+ return ret;
+}
+
+int Wsrep_client_service::prepare_data_for_replication()
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_ENTER("Wsrep_client_service::prepare_data_for_replication");
+ size_t data_len= 0;
+ IO_CACHE* cache= wsrep_get_trans_cache(m_thd);
+
+ if (cache)
+ {
+ m_thd->binlog_flush_pending_rows_event(true);
+ if (wsrep_write_cache(m_thd, cache, &data_len))
+ {
+ WSREP_ERROR("rbr write fail, data_len: %zu",
+ data_len);
+ // wsrep_override_error(m_thd, ER_ERROR_DURING_COMMIT);
+ DBUG_RETURN(1);
+ }
+ }
+
+ if (data_len == 0)
+ {
+ if (m_thd->get_stmt_da()->is_ok() &&
+ m_thd->get_stmt_da()->affected_rows() > 0 &&
+ !binlog_filter->is_on() &&
+ !m_thd->wsrep_trx().is_streaming())
+ {
+ WSREP_DEBUG("empty rbr buffer, query: %s, "
+ "affected rows: %llu, "
+ "changed tables: %d, "
+ "sql_log_bin: %d",
+ WSREP_QUERY(m_thd),
+ m_thd->get_stmt_da()->affected_rows(),
+ stmt_has_updated_trans_table(m_thd),
+ m_thd->variables.sql_log_bin);
+ }
+ else
+ {
+ WSREP_DEBUG("empty rbr buffer, query: %s", WSREP_QUERY(m_thd));
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+void Wsrep_client_service::cleanup_transaction()
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ if (WSREP_EMULATE_BINLOG(m_thd)) wsrep_thd_binlog_trx_reset(m_thd);
+ m_thd->wsrep_affected_rows= 0;
+}
+
+
+int Wsrep_client_service::prepare_fragment_for_replication(wsrep::mutable_buffer& buffer)
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ THD* thd= m_thd;
+ DBUG_ENTER("Wsrep_client_service::prepare_fragment_for_replication");
+ IO_CACHE* cache= wsrep_get_trans_cache(thd);
+ thd->binlog_flush_pending_rows_event(true);
+
+ if (!cache)
+ {
+ DBUG_RETURN(0);
+ }
+
+ const my_off_t saved_pos(my_b_tell(cache));
+ if (reinit_io_cache(cache, READ_CACHE, thd->wsrep_sr().bytes_certified(), 0, 0))
+ {
+ DBUG_RETURN(1);
+ }
+
+ int ret= 0;
+ size_t total_length= 0;
+ size_t length= my_b_bytes_in_cache(cache);
+
+ if (!length)
+ {
+ length= my_b_fill(cache);
+ }
+
+ if (length > 0)
+ {
+ do
+ {
+ total_length+= length;
+ if (total_length > wsrep_max_ws_size)
+ {
+ WSREP_WARN("transaction size limit (%lu) exceeded: %zu",
+ wsrep_max_ws_size, total_length);
+ ret= 1;
+ goto cleanup;
+ }
+
+ buffer.push_back(reinterpret_cast<const char*>(cache->read_pos),
+ reinterpret_cast<const char*>(cache->read_pos + length));
+ cache->read_pos= cache->read_end;
+ }
+ while (cache->file >= 0 && (length= my_b_fill(cache)));
+ }
+ DBUG_ASSERT(total_length == buffer.size());
+cleanup:
+ if (reinit_io_cache(cache, WRITE_CACHE, saved_pos, 0, 0))
+ {
+ WSREP_WARN("Failed to reinitialize IO cache");
+ ret= 1;
+ }
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_client_service::remove_fragments()
+{
+ DBUG_ENTER("Wsrep_client_service::remove_fragments");
+ if (wsrep_schema->remove_fragments(m_thd,
+ Wsrep_server_state::instance().id(),
+ m_thd->wsrep_trx().id(),
+ m_thd->wsrep_sr().fragments()))
+ {
+ WSREP_DEBUG("Failed to remove fragments from SR storage for transaction "
+ "%llu, %llu",
+ m_thd->thread_id, m_thd->wsrep_trx().id().get());
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+bool Wsrep_client_service::statement_allowed_for_streaming() const
+{
+ /*
+ Todo: Decide if implicit commit is allowed with streaming
+ replication.
+ !stmt_causes_implicit_commit(m_thd, CF_IMPLICIT_COMMIT_BEGIN);
+ */
+ return true;
+}
+
+size_t Wsrep_client_service::bytes_generated() const
+{
+ IO_CACHE* cache= wsrep_get_trans_cache(m_thd);
+ if (cache)
+ {
+ m_thd->binlog_flush_pending_rows_event(true);
+ return my_b_tell(cache);
+ }
+ return 0;
+}
+
+void Wsrep_client_service::will_replay()
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ ++wsrep_replaying;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+}
+
+enum wsrep::provider::status Wsrep_client_service::replay()
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ Wsrep_replayer_service replayer_service(m_thd);
+ wsrep::provider& provider(m_thd->wsrep_cs().provider());
+ mysql_mutex_lock(&m_thd->LOCK_thd_data);
+ m_thd->killed= NOT_KILLED;
+ mysql_mutex_unlock(&m_thd->LOCK_thd_data);
+ enum wsrep::provider::status ret=
+ provider.replay(m_thd->wsrep_trx().ws_handle(), &replayer_service);
+ replayer_service.replay_status(ret);
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ --wsrep_replaying;
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ return ret;
+}
+
+void Wsrep_client_service::wait_for_replayers(wsrep::unique_lock<wsrep::mutex>& lock)
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ lock.unlock();
+ mysql_mutex_lock(&LOCK_wsrep_replaying);
+ while (wsrep_replaying > 0)
+ {
+ mysql_cond_wait(&COND_wsrep_replaying, &LOCK_wsrep_replaying);
+ }
+ mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ lock.lock();
+}
+
+void Wsrep_client_service::debug_sync(const char* sync_point)
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ debug_sync_caller(m_thd, sync_point);
+}
+
+void Wsrep_client_service::debug_crash(const char* crash_point)
+{
+ // DBUG_ASSERT(m_thd == current_thd);
+ DBUG_EXECUTE_IF(crash_point, DBUG_SUICIDE(); );
+}
+
+int Wsrep_client_service::bf_rollback()
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_ENTER("Wsrep_client_service::rollback");
+
+ int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd));
+ if (m_thd->locked_tables_mode && m_thd->lock)
+ {
+ m_thd->locked_tables_list.unlock_locked_tables(m_thd);
+ m_thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
+ }
+ if (m_thd->global_read_lock.is_acquired())
+ {
+ m_thd->global_read_lock.unlock_global_read_lock(m_thd);
+ }
+ m_thd->mdl_context.release_transactional_locks();
+ m_thd->mdl_context.release_explicit_locks();
+
+ DBUG_RETURN(ret);
+}
diff --git a/sql/wsrep_client_service.h b/sql/wsrep_client_service.h
new file mode 100644
index 00000000000..43edae3441d
--- /dev/null
+++ b/sql/wsrep_client_service.h
@@ -0,0 +1,63 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/** @file wsrep_client_service.h
+
+ This file provides declaratios for client service implementation.
+ See wsrep/client_service.hpp for interface documentation.
+*/
+
+#ifndef WSREP_CLIENT_SERVICE_H
+#define WSREP_CLIENT_SERVICE_H
+
+/* wsrep-lib */
+#include "wsrep/client_service.hpp"
+#include "wsrep/client_state.hpp"
+#include "wsrep/exception.hpp" /* not_implemented_error, remove when finished */
+
+class THD;
+class Wsrep_client_state;
+class Wsrep_high_priority_context;
+
+class Wsrep_client_service : public wsrep::client_service
+{
+public:
+ Wsrep_client_service(THD*, Wsrep_client_state&);
+
+ bool interrupted() const;
+ void reset_globals();
+ void store_globals();
+ int prepare_data_for_replication();
+ void cleanup_transaction();
+ bool statement_allowed_for_streaming() const;
+ size_t bytes_generated() const;
+ int prepare_fragment_for_replication(wsrep::mutable_buffer&);
+ int remove_fragments();
+ void emergency_shutdown()
+ { throw wsrep::not_implemented_error(); }
+ void will_replay();
+ enum wsrep::provider::status replay();
+ void wait_for_replayers(wsrep::unique_lock<wsrep::mutex>&);
+ void debug_sync(const char*);
+ void debug_crash(const char*);
+ int bf_rollback();
+private:
+ friend class Wsrep_server_service;
+ THD* m_thd;
+ Wsrep_client_state& m_client_state;
+};
+
+
+#endif /* WSREP_CLIENT_SERVICE_H */
diff --git a/sql/wsrep_client_state.h b/sql/wsrep_client_state.h
new file mode 100644
index 00000000000..403bfa81365
--- /dev/null
+++ b/sql/wsrep_client_state.h
@@ -0,0 +1,47 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_CLIENT_STATE_H
+#define WSREP_CLIENT_STATE_H
+
+/* wsrep-lib */
+#include "wsrep/client_state.hpp"
+#include "my_global.h"
+
+class THD;
+
+class Wsrep_client_state : public wsrep::client_state
+{
+public:
+ Wsrep_client_state(THD* thd,
+ wsrep::mutex& mutex,
+ wsrep::condition_variable& cond,
+ wsrep::server_state& server_state,
+ wsrep::client_service& client_service,
+ const wsrep::client_id& id)
+ : wsrep::client_state(mutex,
+ cond,
+ server_state,
+ client_service,
+ id,
+ wsrep::client_state::m_local)
+ , m_thd(thd)
+ { }
+ THD* thd() { return m_thd; }
+private:
+ THD* m_thd;
+};
+
+#endif /* WSREP_CLIENT_STATE_H */
diff --git a/sql/wsrep_condition_variable.h b/sql/wsrep_condition_variable.h
new file mode 100644
index 00000000000..4412154e67b
--- /dev/null
+++ b/sql/wsrep_condition_variable.h
@@ -0,0 +1,54 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_CONDITION_VARIABLE_H
+#define WSREP_CONDITION_VARIABLE_H
+
+/* wsrep-lib */
+#include "wsrep/condition_variable.hpp"
+
+/* implementation */
+#include "my_pthread.h"
+
+class Wsrep_condition_variable : public wsrep::condition_variable
+{
+public:
+
+ Wsrep_condition_variable(mysql_cond_t& cond)
+ : m_cond(cond)
+ { }
+ ~Wsrep_condition_variable()
+ { }
+
+ void notify_one()
+ {
+ mysql_cond_signal(&m_cond);
+ }
+
+ void notify_all()
+ {
+ mysql_cond_broadcast(&m_cond);
+ }
+
+ void wait(wsrep::unique_lock<wsrep::mutex>& lock)
+ {
+ mysql_mutex_t* mutex= static_cast<mysql_mutex_t*>(lock.mutex().native());
+ mysql_cond_wait(&m_cond, mutex);
+ }
+private:
+ mysql_cond_t& m_cond;
+};
+
+#endif /* WSREP_CONDITION_VARIABLE_H */
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 9a4bbd01bcd..916788483ab 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -17,16 +17,10 @@
#include <sql_class.h>
#include <mysql/service_wsrep.h>
-my_bool wsrep_thd_is_BF(THD *, my_bool)
+my_bool wsrep_thd_is_BF(const THD *, my_bool)
{ return 0; }
-int wsrep_trx_order_before(THD *, THD *)
-{ return 0; }
-
-enum wsrep_conflict_state wsrep_thd_conflict_state(THD *, my_bool)
-{ return NO_CONFLICT; }
-
-int wsrep_is_wsrep_xid(const XID*)
+int wsrep_is_wsrep_xid(const void* xid)
{ return 0; }
long long wsrep_xid_seqno(const XID* x)
@@ -34,111 +28,99 @@ long long wsrep_xid_seqno(const XID* x)
const unsigned char* wsrep_xid_uuid(const XID*)
{
- static const unsigned char uuid[16] = {0};
+ static const unsigned char uuid[16]= {0};
return uuid;
}
+bool wsrep_prepare_key_for_innodb(THD* thd, const uchar*, size_t, const uchar*, size_t, struct wsrep_buf*, size_t*)
+{ return 1; }
+
bool wsrep_prepare_key(const uchar*, size_t, const uchar*, size_t, struct wsrep_buf*, size_t*)
{ return 0; }
struct wsrep *get_wsrep()
{ return 0; }
-my_bool get_wsrep_certify_nonPK()
-{ return 0; }
-
-my_bool get_wsrep_debug()
-{ return 0; }
-
-my_bool get_wsrep_drupal_282555_workaround()
-{ return 0; }
-
-my_bool get_wsrep_load_data_splitting()
-{ return 0; }
-
my_bool get_wsrep_recovery()
{ return 0; }
-my_bool get_wsrep_log_conflicts()
-{ return 0; }
-
-long get_wsrep_protocol_version()
-{ return 0; }
-
-my_bool wsrep_aborting_thd_contains(THD *)
-{ return 0; }
-
-void wsrep_aborting_thd_enqueue(THD *)
-{ }
-
bool wsrep_consistency_check(THD *)
{ return 0; }
void wsrep_lock_rollback()
{ }
-int wsrep_on(THD *thd)
+my_bool wsrep_on(const THD *)
{ return 0; }
-void wsrep_post_commit(THD*, bool)
-{ }
-
-enum wsrep_trx_status wsrep_run_wsrep_commit(THD *, bool)
-{ return WSREP_TRX_ERROR; }
-
-void wsrep_thd_LOCK(THD *)
-{ }
-
-void wsrep_thd_UNLOCK(THD *)
+void wsrep_thd_LOCK(const THD *)
{ }
-void wsrep_thd_awake(THD *, my_bool)
+void wsrep_thd_UNLOCK(const THD *)
{ }
const char *wsrep_thd_conflict_state_str(THD *)
{ return 0; }
-enum wsrep_exec_mode wsrep_thd_exec_mode(THD *)
-{ return LOCAL_STATE; }
-
const char *wsrep_thd_exec_mode_str(THD *)
{ return NULL; }
-enum wsrep_conflict_state wsrep_thd_get_conflict_state(THD *)
-{ return NO_CONFLICT; }
+const char *wsrep_thd_query(const THD *)
+{ return 0; }
-my_bool wsrep_thd_is_wsrep(THD *)
+const char *wsrep_thd_query_state_str(THD *)
{ return 0; }
-char *wsrep_thd_query(THD *)
+int wsrep_thd_retry_counter(const THD *)
{ return 0; }
-enum wsrep_query_state wsrep_thd_query_state(THD *)
-{ return QUERY_IDLE; }
+bool wsrep_thd_ignore_table(THD *)
+{ return 0; }
-const char *wsrep_thd_query_state_str(THD *)
+long long wsrep_thd_trx_seqno(const THD *)
+{ return -1; }
+
+my_bool wsrep_thd_is_aborting(const THD *)
{ return 0; }
-int wsrep_thd_retry_counter(THD *)
+void wsrep_set_data_home_dir(const char *)
+{ }
+
+my_bool wsrep_thd_is_local(const THD *)
{ return 0; }
-void wsrep_thd_set_conflict_state(THD *, enum wsrep_conflict_state)
+void wsrep_thd_self_abort(THD *)
{ }
-bool wsrep_thd_ignore_table(THD *)
+int wsrep_thd_append_key(THD *, const struct wsrep_key*, int, enum Wsrep_service_key_type)
{ return 0; }
-longlong wsrep_thd_trx_seqno(THD *)
-{ return -1; }
+const char* wsrep_thd_client_state_str(const THD*)
+{ return 0; }
-struct wsrep_ws_handle* wsrep_thd_ws_handle(THD *)
+const char* wsrep_thd_client_mode_str(const THD*)
{ return 0; }
-int wsrep_trx_is_aborting(THD *)
+const char* wsrep_thd_transaction_state_str(const THD*)
{ return 0; }
-void wsrep_unlock_rollback()
-{ }
+query_id_t wsrep_thd_transaction_id(const THD *)
+{ return 0; }
-void wsrep_set_data_home_dir(const char *)
+my_bool wsrep_thd_bf_abort(const THD *, THD *, my_bool)
+{ return 0; }
+
+my_bool wsrep_thd_order_before(const THD*, const THD *)
+{ return 0; }
+
+void wsrep_handle_SR_rollback(THD*, THD*)
{ }
+
+my_bool wsrep_thd_skip_locking(const THD*)
+{ return 0;}
+
+const char* wsrep_get_sr_table_name()
+{ return 0; }
+
+my_bool wsrep_get_debug()
+{ return 0;}
diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc
new file mode 100644
index 00000000000..f1637e2ece0
--- /dev/null
+++ b/sql/wsrep_high_priority_service.cc
@@ -0,0 +1,649 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "wsrep_high_priority_service.h"
+#include "wsrep_applier.h"
+#include "wsrep_binlog.h"
+#include "wsrep_schema.h"
+#include "wsrep_xid.h"
+#include "wsrep_trans_observer.h"
+
+#include "sql_class.h" /* THD */
+#include "transaction.h"
+#include "debug_sync.h"
+/* RLI */
+#include "rpl_rli.h"
+#define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1
+#define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2
+#include "slave.h"
+#include "rpl_mi.h"
+
+namespace
+{
+/*
+ Scoped mode for applying non-transactional write sets (TOI)
+ */
+class Wsrep_non_trans_mode
+{
+public:
+ Wsrep_non_trans_mode(THD* thd, const wsrep::ws_meta& ws_meta)
+ : m_thd(thd)
+ , m_option_bits(thd->variables.option_bits)
+ , m_server_status(thd->server_status)
+ {
+ m_thd->variables.option_bits&= ~OPTION_BEGIN;
+ m_thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ m_thd->wsrep_cs().enter_toi(ws_meta);
+ }
+ ~Wsrep_non_trans_mode()
+ {
+ m_thd->variables.option_bits= m_option_bits;
+ m_thd->server_status= m_server_status;
+ m_thd->wsrep_cs().leave_toi();
+ }
+private:
+ Wsrep_non_trans_mode(const Wsrep_non_trans_mode&);
+ Wsrep_non_trans_mode& operator=(const Wsrep_non_trans_mode&);
+ THD* m_thd;
+ ulonglong m_option_bits;
+ uint m_server_status;
+};
+}
+
+static rpl_group_info* wsrep_relay_group_init(THD* thd, const char* log_fname)
+{
+ Relay_log_info* rli= new Relay_log_info(false);
+
+ if (!rli->relay_log.description_event_for_exec)
+ {
+ rli->relay_log.description_event_for_exec=
+ new Format_description_log_event(4);
+ }
+
+ static LEX_CSTRING connection_name= { STRING_WITH_LEN("wsrep") };
+
+ /*
+ Master_info's constructor initializes rpl_filter by either an already
+ constructed Rpl_filter object from global 'rpl_filters' list if the
+ specified connection name is same, or it constructs a new Rpl_filter
+ object and adds it to rpl_filters. This object is later destructed by
+ Mater_info's destructor by looking it up based on connection name in
+ rpl_filters list.
+
+ However, since all Master_info objects created here would share same
+ connection name ("wsrep"), destruction of any of the existing Master_info
+ objects (in wsrep_return_from_bf_mode()) would free rpl_filter referenced
+ by any/all existing Master_info objects.
+
+ In order to avoid that, we have added a check in Master_info's destructor
+ to not free the "wsrep" rpl_filter. It will eventually be freed by
+ free_all_rpl_filters() when server terminates.
+ */
+ rli->mi= new Master_info(&connection_name, false);
+
+ struct rpl_group_info *rgi= new rpl_group_info(rli);
+ rgi->thd= rli->sql_driver_thd= thd;
+
+ if ((rgi->deferred_events_collecting= rli->mi->rpl_filter->is_on()))
+ {
+ rgi->deferred_events= new Deferred_log_events(rli);
+ }
+
+ return rgi;
+}
+
+static void wsrep_setup_uk_and_fk_checks(THD* thd)
+{
+ /* Tune FK and UK checking policy. These are reset back to original
+ in Wsrep_high_priority_service destructor. */
+ 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;
+}
+
+/****************************************************************************
+ High priority service
+*****************************************************************************/
+
+Wsrep_high_priority_service::Wsrep_high_priority_service(THD* thd)
+ : wsrep::high_priority_service(Wsrep_server_state::instance())
+ , wsrep::high_priority_context(thd->wsrep_cs())
+ , m_thd(thd)
+ , m_rli()
+{
+ LEX_CSTRING db_str= { NULL, 0 };
+ m_shadow.option_bits = thd->variables.option_bits;
+ m_shadow.server_status= thd->server_status;
+ m_shadow.vio = thd->net.vio;
+ m_shadow.tx_isolation = thd->variables.tx_isolation;
+ m_shadow.db = (char *)thd->db.str;
+ m_shadow.db_length = thd->db.length;
+ m_shadow.user_time = thd->user_time;
+ m_shadow.row_count_func= thd->get_row_count_func();
+ m_shadow.wsrep_applier= thd->wsrep_applier;
+
+ /* Disable general logging on applier threads */
+ thd->variables.option_bits |= OPTION_LOG_OFF;
+ /* Enable binlogging if opt_log_slave_updates is set */
+ if (opt_log_slave_updates)
+ thd->variables.option_bits|= OPTION_BIN_LOG;
+ else
+ thd->variables.option_bits&= ~(OPTION_BIN_LOG);
+
+ thd->net.vio= 0;
+ thd->reset_db(&db_str);
+ thd->clear_error();
+ thd->variables.tx_isolation= ISO_READ_COMMITTED;
+ thd->tx_isolation = ISO_READ_COMMITTED;
+
+ /* From trans_begin() */
+ thd->variables.option_bits|= OPTION_BEGIN;
+ thd->server_status|= SERVER_STATUS_IN_TRANS;
+
+ /* Make THD wsrep_applier so that it cannot be killed */
+ thd->wsrep_applier= true;
+
+ if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init(thd, "wsrep_relay");
+
+ m_rgi= thd->wsrep_rgi;
+ m_rgi->thd= thd;
+ m_rli= m_rgi->rli;
+ thd_proc_info(thd, "wsrep applier idle");
+}
+
+Wsrep_high_priority_service::~Wsrep_high_priority_service()
+{
+ THD* thd= m_thd;
+ thd->variables.option_bits = m_shadow.option_bits;
+ thd->server_status = m_shadow.server_status;
+ thd->net.vio = m_shadow.vio;
+ thd->variables.tx_isolation= m_shadow.tx_isolation;
+ LEX_CSTRING db_str= { m_shadow.db, m_shadow.db_length };
+ thd->reset_db(&db_str);
+ thd->user_time = m_shadow.user_time;
+
+ if (thd->wsrep_rgi && thd->wsrep_rgi->rli)
+ delete thd->wsrep_rgi->rli->mi;
+ if (thd->wsrep_rgi)
+ delete thd->wsrep_rgi->rli;
+ delete thd->wsrep_rgi;
+ thd->wsrep_rgi= NULL;
+
+ thd->set_row_count_func(m_shadow.row_count_func);
+ thd->wsrep_applier = m_shadow.wsrep_applier;
+}
+
+int Wsrep_high_priority_service::start_transaction(
+ const wsrep::ws_handle& ws_handle, const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER(" Wsrep_high_priority_service::start_transaction");
+ DBUG_RETURN(m_thd->wsrep_cs().start_transaction(ws_handle, ws_meta));
+}
+
+const wsrep::transaction& Wsrep_high_priority_service::transaction() const
+{
+ DBUG_ENTER(" Wsrep_high_priority_service::transaction");
+ DBUG_RETURN(m_thd->wsrep_trx());
+}
+
+void Wsrep_high_priority_service::adopt_transaction(const wsrep::transaction& transaction)
+{
+ DBUG_ENTER(" Wsrep_high_priority_service::adopt_transaction");
+ m_thd->wsrep_cs().adopt_transaction(transaction);
+ DBUG_VOID_RETURN;
+}
+
+
+int Wsrep_high_priority_service::append_fragment_and_commit(
+ const wsrep::ws_handle& ws_handle,
+ const wsrep::ws_meta& ws_meta,
+ const wsrep::const_buffer& data)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::append_fragment_and_commit");
+ int ret= start_transaction(ws_handle, ws_meta);
+ /*
+ Start transaction explicitly to avoid early commit via
+ trans_commit_stmt() in append_fragment()
+ */
+ ret= ret || trans_begin(m_thd);
+ ret= ret || wsrep_schema->append_fragment(m_thd,
+ ws_meta.server_id(),
+ ws_meta.transaction_id(),
+ ws_meta.seqno(),
+ ws_meta.flags(),
+ data);
+
+ /*
+ Note: The commit code below seems to be identical to
+ Wsrep_storage_service::commit(). Consider implementing
+ common utility function to deal with commit.
+ */
+ const bool do_binlog_commit= (opt_log_slave_updates &&
+ wsrep_gtid_mode &&
+ m_thd->variables.gtid_seq_no);
+ /*
+ Write skip event into binlog if gtid_mode is on. This is to
+ maintain gtid continuity.
+ */
+ if (do_binlog_commit)
+ {
+ ret= wsrep_write_skip_event(m_thd);
+ }
+
+ if (!ret)
+ {
+ ret= m_thd->wsrep_cs().prepare_for_ordering(ws_handle,
+ ws_meta, true);
+ }
+
+ if (!ret)
+ {
+ DBUG_ASSERT(wsrep_thd_trx_seqno(m_thd) > 0);
+ if (!do_binlog_commit)
+ {
+ ret= wsrep_before_commit(m_thd, true);
+ }
+ ret= ret || trans_commit(m_thd);
+ if (!do_binlog_commit)
+ {
+ if (opt_log_slave_updates)
+ {
+ ret= ret || wsrep_ordered_commit(m_thd, true, wsrep_apply_error());
+ }
+ ret= ret || wsrep_after_commit(m_thd, true);
+ }
+ }
+ m_thd->wsrep_cs().after_applying();
+ m_thd->mdl_context.release_transactional_locks();
+
+ thd_proc_info(m_thd, "wsrep applier committed");
+
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_high_priority_service::remove_fragments(const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::remove_fragments");
+ int ret= wsrep_schema->remove_fragments(m_thd,
+ ws_meta.server_id(),
+ ws_meta.transaction_id(),
+ m_thd->wsrep_sr().fragments());
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_high_priority_service::commit(const wsrep::ws_handle& ws_handle,
+ const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::commit");
+ THD* thd= m_thd;
+ DBUG_ASSERT(thd->wsrep_trx().active());
+ thd->wsrep_cs().prepare_for_ordering(ws_handle, ws_meta, true);
+ thd_proc_info(thd, "committing");
+
+ int ret= 0;
+ const bool is_ordered= !ws_meta.seqno().is_undefined();
+ /* If opt_log_slave_updates is not on, applier does not write
+ anything to binlog cache and neither wsrep_before_commit()
+ nor wsrep_after_commit() we be reached from binlog code
+ path for applier. Therefore run wsrep_before_commit()
+ and wsrep_after_commit() here. wsrep_ordered_commit()
+ will be called from wsrep_ordered_commit_if_no_binlog(). */
+ if (!opt_log_slave_updates && !opt_bin_log && is_ordered)
+ {
+ if (m_thd->transaction.all.no_2pc == false)
+ {
+ ret= wsrep_before_prepare(thd, true);
+ ret= ret || wsrep_after_prepare(thd, true);
+ }
+ ret= ret || wsrep_before_commit(thd, true);
+ }
+ ret= ret || trans_commit(thd);
+
+ if (ret == 0)
+ {
+ m_rgi->cleanup_context(thd, 0);
+ }
+
+ if (ret == 0 && !opt_log_slave_updates && !opt_bin_log && is_ordered)
+ {
+ ret= wsrep_after_commit(thd, true);
+ }
+
+ m_thd->mdl_context.release_transactional_locks();
+
+ thd_proc_info(thd, "wsrep applier committed");
+
+ if (!is_ordered)
+ {
+ /* Wsrep commit was not ordered so it does not go through commit time
+ hooks and remains active. Roll it back to make cleanup happen
+ in after_applying() call. */
+ m_thd->wsrep_cs().before_rollback();
+ m_thd->wsrep_cs().after_rollback();
+ }
+
+ must_exit_= check_exit_status();
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_high_priority_service::rollback(const wsrep::ws_handle& ws_handle,
+ const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::rollback");
+ m_thd->wsrep_cs().prepare_for_ordering(ws_handle, ws_meta, false);
+ int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd));
+ m_thd->mdl_context.release_transactional_locks();
+ m_thd->mdl_context.release_explicit_locks();
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_high_priority_service::apply_toi(const wsrep::ws_meta& ws_meta,
+ const wsrep::const_buffer& data)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::apply_toi");
+ THD* thd= m_thd;
+ Wsrep_non_trans_mode non_trans_mode(thd, ws_meta);
+
+ wsrep::client_state& client_state(thd->wsrep_cs());
+ DBUG_ASSERT(client_state.in_toi());
+
+ thd_proc_info(thd, "wsrep applier toi");
+
+ WSREP_DEBUG("Wsrep_high_priority_service::apply_toi: %lld",
+ client_state.toi_meta().seqno().get());
+
+ int ret= wsrep_apply_events(thd, m_rli, data.data(), data.size());
+ if (ret != 0 || thd->wsrep_has_ignored_error)
+ {
+ wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
+ thd->wsrep_has_ignored_error= false;
+ /* todo: error voting */
+ }
+ trans_commit(thd);
+
+ thd->close_temporary_tables();
+ wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
+
+ must_exit_= check_exit_status();
+
+ DBUG_RETURN(ret);
+}
+
+void Wsrep_high_priority_service::store_globals()
+{
+ DBUG_ENTER("Wsrep_high_priority_service::store_globals");
+ /* In addition to calling THD::store_globals(), call
+ wsrep::client_state::store_globals() to gain ownership of
+ the client state */
+ m_thd->store_globals();
+ m_thd->wsrep_cs().store_globals();
+ DBUG_VOID_RETURN;
+}
+
+void Wsrep_high_priority_service::reset_globals()
+{
+ DBUG_ENTER("Wsrep_high_priority_service::reset_globals");
+ m_thd->reset_globals();
+ DBUG_VOID_RETURN;
+}
+
+void Wsrep_high_priority_service::switch_execution_context(wsrep::high_priority_service& orig_high_priority_service)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::switch_execution_context");
+ Wsrep_high_priority_service&
+ orig_hps= static_cast<Wsrep_high_priority_service&>(orig_high_priority_service);
+ m_thd->thread_stack= orig_hps.m_thd->thread_stack;
+ DBUG_VOID_RETURN;
+}
+
+int Wsrep_high_priority_service::log_dummy_write_set(const wsrep::ws_handle& ws_handle,
+ const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_high_priority_service::log_dummy_write_set");
+ int ret= 0;
+ DBUG_PRINT("info",
+ ("Wsrep_high_priority_service::log_dummy_write_set: seqno=%lld",
+ ws_meta.seqno().get()));
+ m_thd->wsrep_cs().start_transaction(ws_handle, ws_meta);
+ WSREP_DEBUG("Log dummy write set %lld", ws_meta.seqno().get());
+ if (!(opt_log_slave_updates && wsrep_gtid_mode && m_thd->variables.gtid_seq_no))
+ {
+ m_thd->wsrep_cs().before_rollback();
+ m_thd->wsrep_cs().after_rollback();
+ }
+ m_thd->wsrep_cs().after_applying();
+ DBUG_RETURN(ret);
+}
+
+void Wsrep_high_priority_service::debug_crash(const char* crash_point)
+{
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_EXECUTE_IF(crash_point, DBUG_SUICIDE(););
+}
+
+/****************************************************************************
+ Applier service
+*****************************************************************************/
+
+Wsrep_applier_service::Wsrep_applier_service(THD* thd)
+ : Wsrep_high_priority_service(thd)
+{
+ thd->wsrep_applier_service= this;
+ thd->wsrep_cs().open(wsrep::client_id(thd->thread_id));
+ thd->wsrep_cs().before_command();
+ thd->wsrep_cs().debug_log_level(wsrep_debug);
+
+}
+
+Wsrep_applier_service::~Wsrep_applier_service()
+{
+ m_thd->wsrep_cs().after_command_before_result();
+ m_thd->wsrep_cs().after_command_after_result();
+ m_thd->wsrep_cs().close();
+ m_thd->wsrep_cs().cleanup();
+}
+
+int Wsrep_applier_service::apply_write_set(const wsrep::ws_meta& ws_meta,
+ const wsrep::const_buffer& data)
+{
+ DBUG_ENTER("Wsrep_applier_service::apply_write_set");
+ THD* thd= m_thd;
+
+ thd->variables.option_bits |= OPTION_BEGIN;
+ thd->variables.option_bits |= OPTION_NOT_AUTOCOMMIT;
+ DBUG_ASSERT(thd->wsrep_trx().active());
+ DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_executing);
+
+ thd_proc_info(thd, "applying write set");
+ /* moved dbug sync point here, after possible THD switch for SR transactions
+ has ben done
+ */
+ /* Allow tests to block the applier thread using the DBUG facilities */
+ DBUG_EXECUTE_IF("sync.wsrep_apply_cb",
+ {
+ const char act[]=
+ "now "
+ "SIGNAL sync.wsrep_apply_cb_reached "
+ "WAIT_FOR signal.wsrep_apply_cb";
+ DBUG_ASSERT(!debug_sync_set_action(thd,
+ STRING_WITH_LEN(act)));
+ };);
+
+ wsrep_setup_uk_and_fk_checks(thd);
+
+ int ret= wsrep_apply_events(thd, m_rli, data.data(), data.size());
+
+ if (ret || thd->wsrep_has_ignored_error)
+ {
+ wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
+ }
+
+ thd->close_temporary_tables();
+ if (!ret && !(ws_meta.flags() & wsrep::provider::flag::commit))
+ {
+ thd->wsrep_cs().fragment_applied(ws_meta.seqno());
+ }
+ thd_proc_info(thd, "wsrep applied write set");
+ DBUG_RETURN(ret);
+}
+
+void Wsrep_applier_service::after_apply()
+{
+ DBUG_ENTER("Wsrep_applier_service::after_apply");
+ wsrep_after_apply(m_thd);
+ DBUG_VOID_RETURN;
+}
+
+bool Wsrep_applier_service::check_exit_status() const
+{
+ bool ret= false;
+ mysql_mutex_lock(&LOCK_wsrep_slave_threads);
+ if (wsrep_slave_count_change < 0)
+ {
+ ++wsrep_slave_count_change;
+ ret= true;
+ }
+ mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
+ return ret;
+}
+
+/****************************************************************************
+ Replayer service
+*****************************************************************************/
+
+Wsrep_replayer_service::Wsrep_replayer_service(THD* thd)
+ : Wsrep_high_priority_service(thd)
+ , m_da_shadow()
+ , m_replay_status()
+{
+ /* Response must not have been sent to client */
+ DBUG_ASSERT(!thd->get_stmt_da()->is_sent());
+ /* PS reprepare observer should have been removed already
+ open_table() will fail if we have dangling observer here */
+ DBUG_ASSERT(!thd->m_reprepare_observer);
+ /* Replaying should happen always from after_statement() hook
+ after rollback, which should guarantee that there are no
+ transactional locks */
+ DBUG_ASSERT(!thd->mdl_context.has_transactional_locks());
+
+ /* Make a shadow copy of diagnostics area and reset */
+ m_da_shadow.status= thd->get_stmt_da()->status();
+ if (m_da_shadow.status == Diagnostics_area::DA_OK)
+ {
+ m_da_shadow.affected_rows= thd->get_stmt_da()->affected_rows();
+ m_da_shadow.last_insert_id= thd->get_stmt_da()->last_insert_id();
+ strmake(m_da_shadow.message, thd->get_stmt_da()->message(),
+ sizeof(m_da_shadow.message) - 1);
+ }
+ thd->get_stmt_da()->reset_diagnostics_area();
+
+ /* Release explicit locks */
+ if (thd->locked_tables_mode && thd->lock)
+ {
+ WSREP_WARN("releasing table lock for replaying (%llu)",
+ thd->thread_id);
+ thd->locked_tables_list.unlock_locked_tables(thd);
+ thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
+ }
+
+ /*
+ Replaying will call MYSQL_START_STATEMENT when handling
+ BEGIN Query_log_event so end statement must be called before
+ replaying.
+ */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+ thd_proc_info(thd, "wsrep replaying trx");
+}
+
+Wsrep_replayer_service::~Wsrep_replayer_service()
+{
+ THD* thd= m_thd;
+ DBUG_ASSERT(!thd->get_stmt_da()->is_sent());
+ DBUG_ASSERT(!thd->get_stmt_da()->is_set());
+ if (m_replay_status == wsrep::provider::success)
+ {
+ DBUG_ASSERT(thd->wsrep_cs().current_error() == wsrep::e_success);
+ thd->killed= NOT_KILLED;
+ if (m_da_shadow.status == Diagnostics_area::DA_OK)
+ {
+ my_ok(thd,
+ m_da_shadow.affected_rows,
+ m_da_shadow.last_insert_id,
+ m_da_shadow.message);
+ }
+ else
+ {
+ my_ok(thd);
+ }
+ }
+ else if (m_replay_status == wsrep::provider::error_certification_failed)
+ {
+ DBUG_ASSERT(thd->wsrep_cs().current_error() == wsrep::e_deadlock_error);
+ }
+ else
+ {
+ DBUG_ASSERT(0);
+ WSREP_ERROR("trx_replay failed for: %d, schema: %s, query: %s",
+ m_replay_status,
+ thd->db.str, WSREP_QUERY(thd));
+ unireg_abort(1);
+ }
+}
+
+int Wsrep_replayer_service::apply_write_set(const wsrep::ws_meta& ws_meta,
+ const wsrep::const_buffer& data)
+{
+ DBUG_ENTER("Wsrep_replayer_service::apply_write_set");
+ THD* thd= m_thd;
+
+ DBUG_ASSERT(thd->wsrep_trx().active());
+ DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_replaying);
+
+ wsrep_setup_uk_and_fk_checks(thd);
+
+ int ret= 0;
+ if (!wsrep::starts_transaction(ws_meta.flags()))
+ {
+ DBUG_ASSERT(thd->wsrep_trx().is_streaming());
+ ret= wsrep_schema->replay_transaction(thd,
+ m_rli,
+ ws_meta,
+ thd->wsrep_sr().fragments());
+ }
+
+ ret= ret || wsrep_apply_events(thd, m_rli, data.data(), data.size());
+
+ if (ret || thd->wsrep_has_ignored_error)
+ {
+ wsrep_dump_rbr_buf_with_header(thd, data.data(), data.size());
+ }
+
+ thd->close_temporary_tables();
+ if (!ret && !(ws_meta.flags() & wsrep::provider::flag::commit))
+ {
+ thd->wsrep_cs().fragment_applied(ws_meta.seqno());
+ }
+
+ thd_proc_info(thd, "wsrep replayed write set");
+ DBUG_RETURN(ret);
+}
diff --git a/sql/wsrep_high_priority_service.h b/sql/wsrep_high_priority_service.h
new file mode 100644
index 00000000000..4012ca60a3e
--- /dev/null
+++ b/sql/wsrep_high_priority_service.h
@@ -0,0 +1,118 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_HIGH_PRIORITY_SERVICE_H
+#define WSREP_HIGH_PRIORITY_SERVICE_H
+
+#include "wsrep/high_priority_service.hpp"
+#include "wsrep/client_state.hpp"
+#include "my_global.h"
+#include "sql_error.h" /* Diagnostics area */
+#include "sql_class.h" /* rpl_group_info */
+
+class THD;
+class Relay_log_info;
+class Wsrep_server_service;
+
+class Wsrep_high_priority_service :
+ public wsrep::high_priority_service,
+ public wsrep::high_priority_context
+{
+public:
+ Wsrep_high_priority_service(THD*);
+ ~Wsrep_high_priority_service();
+ int start_transaction(const wsrep::ws_handle&,
+ const wsrep::ws_meta&);
+ const wsrep::transaction& transaction() const;
+ void adopt_transaction(const wsrep::transaction&);
+ int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&) = 0;
+ int append_fragment_and_commit(const wsrep::ws_handle&,
+ const wsrep::ws_meta&,
+ const wsrep::const_buffer&);
+ int remove_fragments(const wsrep::ws_meta&);
+ int commit(const wsrep::ws_handle&, const wsrep::ws_meta&);
+ int rollback(const wsrep::ws_handle&, const wsrep::ws_meta&);
+ int apply_toi(const wsrep::ws_meta&, const wsrep::const_buffer&);
+ void store_globals();
+ void reset_globals();
+ void switch_execution_context(wsrep::high_priority_service&);
+ int log_dummy_write_set(const wsrep::ws_handle&,
+ const wsrep::ws_meta&);
+
+ virtual bool check_exit_status() const = 0;
+ void debug_crash(const char*);
+protected:
+ friend Wsrep_server_service;
+ THD* m_thd;
+ Relay_log_info* m_rli;
+ rpl_group_info* m_rgi;
+ struct shadow
+ {
+ ulonglong option_bits;
+ uint server_status;
+ struct st_vio* vio;
+ ulong tx_isolation;
+ char* db;
+ size_t db_length;
+ //struct timeval user_time;
+ my_hrtime_t user_time;
+ longlong row_count_func;
+ bool wsrep_applier;
+} m_shadow;
+};
+
+class Wsrep_applier_service : public Wsrep_high_priority_service
+{
+public:
+ Wsrep_applier_service(THD*);
+ ~Wsrep_applier_service();
+ int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&);
+ void after_apply();
+ bool is_replaying() const { return false; }
+ bool check_exit_status() const;
+};
+
+class Wsrep_replayer_service : public Wsrep_high_priority_service
+{
+public:
+ Wsrep_replayer_service(THD*);
+ ~Wsrep_replayer_service();
+ int apply_write_set(const wsrep::ws_meta&, const wsrep::const_buffer&);
+ void after_apply() { }
+ bool is_replaying() const { return true; }
+ void replay_status(enum wsrep::provider::status status)
+ { m_replay_status = status; }
+ enum wsrep::provider::status replay_status() const
+ { return m_replay_status; }
+ /* Replayer should never be forced to exit */
+ bool check_exit_status() const { return false; }
+private:
+ struct da_shadow
+ {
+ enum Diagnostics_area::enum_diagnostics_status status;
+ ulonglong affected_rows;
+ ulonglong last_insert_id;
+ char message[MYSQL_ERRMSG_SIZE];
+ da_shadow()
+ : status()
+ , affected_rows()
+ , last_insert_id()
+ , message()
+ { }
+ } m_da_shadow;
+ enum wsrep::provider::status m_replay_status;
+};
+
+#endif /* WSREP_HIGH_PRIORITY_SERVICE_H */
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
deleted file mode 100644
index 8110faf7d11..00000000000
--- a/sql/wsrep_hton.cc
+++ /dev/null
@@ -1,658 +0,0 @@
-/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
-
-#include "mariadb.h"
-#include <mysqld.h>
-#include "sql_base.h"
-#include "rpl_filter.h"
-#include <sql_class.h>
-#include "wsrep_mysqld.h"
-#include "wsrep_binlog.h"
-#include "wsrep_xid.h"
-#include <cstdio>
-#include <cstdlib>
-#include "debug_sync.h"
-
-extern handlerton *binlog_hton;
-extern int binlog_close_connection(handlerton *hton, THD *thd);
-extern ulonglong thd_to_trx_id(THD *thd);
-
-extern "C" int thd_binlog_format(const MYSQL_THD thd);
-// todo: share interface with ha_innodb.c
-
-/*
- Cleanup after local transaction commit/rollback, replay or TOI.
-*/
-void wsrep_cleanup_transaction(THD *thd)
-{
- if (!WSREP(thd)) return;
-
- if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd);
- thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID;
- thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
- thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
- thd->wsrep_exec_mode= LOCAL_STATE;
- thd->wsrep_affected_rows= 0;
- thd->wsrep_skip_wsrep_GTID= false;
- return;
-}
-
-/*
- wsrep hton
-*/
-handlerton *wsrep_hton;
-
-
-/*
- Registers wsrep hton at commit time if transaction has registered htons
- for supported engine types.
-
- Hton should not be registered for TOTAL_ORDER operations.
-
- Registration is needed for both LOCAL_MODE and REPL_RECV transactions to run
- commit in 2pc so that wsrep position gets properly recorded in storage
- engines.
-
- Note that all hton calls should immediately return for threads that are
- in REPL_RECV mode as their states are controlled by wsrep appliers or
- replaying code. Only threads in LOCAL_MODE should run wsrep callbacks
- from hton methods.
-*/
-void wsrep_register_hton(THD* thd, bool all)
-{
- if (WSREP(thd) && thd->wsrep_exec_mode != TOTAL_ORDER &&
- !thd->wsrep_apply_toi)
- {
- if (thd->wsrep_exec_mode == LOCAL_STATE &&
- (thd_sql_command(thd) == SQLCOM_OPTIMIZE ||
- thd_sql_command(thd) == SQLCOM_ANALYZE ||
- thd_sql_command(thd) == SQLCOM_REPAIR) &&
- thd->lex->no_write_to_binlog == 1)
- {
- WSREP_DEBUG("Skipping wsrep_register_hton for LOCAL sql admin command : %s",
- thd->query());
- return;
- }
-
- THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
- for (Ha_trx_info *i= trans->ha_list; i; i = i->next())
- {
- if ((i->ht()->db_type == DB_TYPE_INNODB) ||
- (i->ht()->db_type == DB_TYPE_TOKUDB))
- {
- trans_register_ha(thd, all, wsrep_hton);
-
- /* follow innodb read/write settting
- * but, as an exception: CTAS with empty result set will not be
- * replicated unless we declare wsrep hton as read/write here
- */
- if (i->is_trx_read_write() ||
- ((thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
- thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) &&
- thd->wsrep_exec_mode == LOCAL_STATE))
- {
- thd->ha_data[wsrep_hton->slot].ha_info[all].set_trx_read_write();
- }
- break;
- }
- }
- }
-}
-
-/*
- Calls wsrep->post_commit() for locally executed transactions that have
- got seqno from provider (must commit) and don't require replaying.
- */
-void wsrep_post_commit(THD* thd, bool all)
-{
- if (!WSREP(thd)) return;
-
- switch (thd->wsrep_exec_mode)
- {
- case LOCAL_COMMIT:
- {
- DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED);
- if (wsrep && wsrep->post_commit(wsrep, &thd->wsrep_ws_handle))
- {
- DBUG_PRINT("wsrep", ("set committed fail"));
- WSREP_WARN("set committed fail: %llu %d",
- (long long)thd->real_id, thd->get_stmt_da()->status());
- }
- wsrep_cleanup_transaction(thd);
- break;
- }
- case LOCAL_STATE:
- {
- /* non-InnoDB statements may have populated events in stmt cache
- => cleanup
- */
- WSREP_DEBUG("cleanup transaction for LOCAL_STATE");
- /*
- Run post-rollback hook to clean up in the case if
- some keys were populated for the transaction in provider
- but during commit time there was no write set to replicate.
- This may happen when client sets the SAVEPOINT and immediately
- rolls back to savepoint after first operation.
- */
- if (all && thd->wsrep_conflict_state != MUST_REPLAY &&
- wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
- {
- WSREP_WARN("post_rollback fail: %llu %d",
- (long long)thd->thread_id, thd->get_stmt_da()->status());
- }
- wsrep_cleanup_transaction(thd);
- break;
- }
- default: break;
- }
-}
-
-/*
- wsrep exploits binlog's caches even if binlogging itself is not
- activated. In such case connection close needs calling
- actual binlog's method.
- Todo: split binlog hton from its caches to use ones by wsrep
- without referring to binlog's stuff.
-*/
-static int
-wsrep_close_connection(handlerton* hton, THD* thd)
-{
- DBUG_ENTER("wsrep_close_connection");
-
- if (thd->wsrep_exec_mode == REPL_RECV)
- {
- DBUG_RETURN(0);
- }
-
- if (wsrep_emulate_bin_log && thd_get_ha_data(thd, binlog_hton) != NULL)
- binlog_hton->close_connection (binlog_hton, thd);
- DBUG_RETURN(0);
-}
-
-/*
- prepare/wsrep_run_wsrep_commit can fail in two ways
- - certification test or an equivalent. As a result,
- the current transaction just rolls back
- Error codes:
- WSREP_TRX_CERT_FAIL, WSREP_TRX_SIZE_EXCEEDED, WSREP_TRX_ERROR
- - a post-certification failure makes this server unable to
- commit its own WS and therefore the server must abort
-*/
-static int wsrep_prepare(handlerton *hton, THD *thd, bool all)
-{
- DBUG_ENTER("wsrep_prepare");
-
- if (thd->wsrep_exec_mode == REPL_RECV)
- {
- DBUG_RETURN(0);
- }
-
- DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
- DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
- DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
-
- if ((all ||
- !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
- (thd->variables.wsrep_on && !wsrep_trans_cache_is_empty(thd)))
- {
- int res= wsrep_run_wsrep_commit(thd, all);
- if (res != 0)
- {
- if (res == WSREP_TRX_SIZE_EXCEEDED)
- res= EMSGSIZE;
- else
- res= EDEADLK; // for a better error message
- }
- DBUG_RETURN (res);
- }
- DBUG_RETURN(0);
-}
-
-static int wsrep_savepoint_set(handlerton *hton, THD *thd, void *sv)
-{
- DBUG_ENTER("wsrep_savepoint_set");
-
- if (thd->wsrep_exec_mode == REPL_RECV)
- {
- DBUG_RETURN(0);
- }
-
- if (!wsrep_emulate_bin_log) DBUG_RETURN(0);
- int rcode = wsrep_binlog_savepoint_set(thd, sv);
- DBUG_RETURN(rcode);
-}
-
-static int wsrep_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
-{
- DBUG_ENTER("wsrep_savepoint_rollback");
-
- if (thd->wsrep_exec_mode == REPL_RECV)
- {
- DBUG_RETURN(0);
- }
-
- if (!wsrep_emulate_bin_log) DBUG_RETURN(0);
- int rcode = wsrep_binlog_savepoint_rollback(thd, sv);
- DBUG_RETURN(rcode);
-}
-
-static int wsrep_rollback(handlerton *hton, THD *thd, bool all)
-{
- DBUG_ENTER("wsrep_rollback");
-
- if (thd->wsrep_exec_mode == REPL_RECV)
- {
- DBUG_RETURN(0);
- }
-
- mysql_mutex_lock(&thd->LOCK_thd_data);
- switch (thd->wsrep_exec_mode)
- {
- case TOTAL_ORDER:
- case REPL_RECV:
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- WSREP_DEBUG("Avoiding wsrep rollback for failed DDL: %s", thd->query());
- DBUG_RETURN(0);
- default: break;
- }
-
- if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
- thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY)
- {
- if (wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
- {
- DBUG_PRINT("wsrep", ("setting rollback fail"));
- WSREP_ERROR("settting rollback fail: thd: %llu, schema: %s, SQL: %s",
- (long long)thd->real_id, thd->get_db(), thd->query());
- }
- wsrep_cleanup_transaction(thd);
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- 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_thd_data);
- if ((all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
- (thd->variables.wsrep_on && thd->wsrep_conflict_state != MUST_REPLAY))
- {
- if (thd->wsrep_exec_mode == LOCAL_COMMIT)
- {
- DBUG_ASSERT(thd->ha_data[wsrep_hton->slot].ha_info[all].is_trx_read_write());
- /*
- Call to wsrep->post_commit() (moved to wsrep_post_commit()) must
- be done only after commit has done for all involved htons.
- */
- DBUG_PRINT("wsrep", ("commit"));
- }
- else
- {
- /*
- Transaction didn't go through wsrep->pre_commit() so just roll back
- possible changes to clean state.
- */
- if (WSREP_PROVIDER_EXISTS) {
- if (wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle))
- {
- DBUG_PRINT("wsrep", ("setting rollback fail"));
- WSREP_ERROR("settting rollback fail: thd: %llu, schema: %s, SQL: %s",
- (long long)thd->real_id, thd->get_db(),
- thd->query());
- }
- }
- wsrep_cleanup_transaction(thd);
- }
- }
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- 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, bool all)
-{
- int rcode= -1;
- size_t data_len= 0;
- IO_CACHE *cache;
- int replay_round= 0;
- DBUG_ENTER("wsrep_run_wsrep_commit");
-
- if (thd->get_stmt_da()->is_error()) {
- WSREP_DEBUG("commit issue, error: %d %s",
- thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
- }
-
- DEBUG_SYNC(thd, "wsrep_before_replication");
-
- if (thd->slave_thread && !opt_log_slave_updates) DBUG_RETURN(WSREP_TRX_OK);
-
- if (thd->wsrep_exec_mode == REPL_RECV) {
-
- mysql_mutex_lock(&thd->LOCK_thd_data);
- 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_thd_data);
- //
- // 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_thd_data);
- }
-
- 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_thd_data);
- if (thd->wsrep_conflict_state == MUST_ABORT) {
- DBUG_PRINT("wsrep", ("replicate commit fail"));
- thd->wsrep_conflict_state = ABORTED;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- 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);
-
- DBUG_PRINT("info", ("wsrep_replaying: %d wsrep_conflict_state: %d killed: %d shutdown_in_progress: %d",
- (int) wsrep_replaying, (int) thd->wsrep_conflict_state,
- (int) thd->killed,
- (int) shutdown_in_progress));
-
- 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_thd_data);
-
- 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: %lld "
- "conflict: %d (round: %d)",
- wsrep_replaying, (longlong) 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_thd_data);
- 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_thd_data);
- 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_thd_data);
-
- 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);
- }
- }
-
- DBUG_PRINT("info", ("rcode: %d wsrep_conflict_state: %d",
- rcode, thd->wsrep_conflict_state));
-
- if (data_len == 0)
- {
- if (thd->get_stmt_da()->is_ok() &&
- thd->get_stmt_da()->affected_rows() > 0 &&
- !binlog_filter->is_on())
- {
- WSREP_DEBUG("empty rbr buffer, query: %s, "
- "affected rows: %llu, "
- "changed tables: %d, "
- "sql_log_bin: %d, "
- "wsrep status (%d %d %d)",
- thd->query(), thd->get_stmt_da()->affected_rows(),
- stmt_has_updated_trans_table(thd), thd->variables.sql_log_bin,
- thd->wsrep_exec_mode, thd->wsrep_query_state,
- thd->wsrep_conflict_state);
- }
- else
- {
- WSREP_DEBUG("empty rbr buffer, query: %s", thd->query());
- }
- thd->wsrep_query_state= QUERY_EXEC;
- DBUG_RETURN(WSREP_TRX_OK);
- }
-
- if (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id)
- {
- WSREP_WARN("SQL statement was ineffective thd: %lld buf: %zu\n"
- "schema: %s \n"
- "QUERY: %s\n"
- " => Skipping replication",
- (longlong) thd->thread_id, data_len,
- thd->get_db(), thd->query());
- rcode = WSREP_TRX_FAIL;
- }
- else if (!rcode)
- {
- if (WSREP_OK == rcode && wsrep)
- 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);
-
- DBUG_PRINT("info", ("rcode after pre_commit: %d", rcode));
-
- if (rcode == WSREP_TRX_MISSING) {
- WSREP_WARN("Transaction missing in provider, thd: %lld schema: %s SQL: %s",
- (longlong) thd->thread_id,
- thd->get_db(), thd->query());
- rcode = WSREP_TRX_FAIL;
- } else if (rcode == WSREP_BF_ABORT) {
- WSREP_DEBUG("thd: %lld seqno: %lld BF aborted by provider, will replay",
- (longlong) thd->thread_id,
- (longlong) thd->wsrep_trx_meta.gtid.seqno);
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_conflict_state = MUST_REPLAY;
- DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0);
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- mysql_mutex_lock(&LOCK_wsrep_replaying);
- wsrep_replaying++;
- WSREP_DEBUG("replaying increased: %d, thd: %lld",
- wsrep_replaying, (longlong) 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_thd_data);
-
- DEBUG_SYNC(thd, "wsrep_after_replication");
-
- DBUG_PRINT("info", ("rcode: %d wsrep_conflict_state: %d",
- rcode, thd->wsrep_conflict_state));
-
- 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: %llu seqno: %lld conflict state %d after post commit",
- (longlong) thd->thread_id,
- (longlong) 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);
- /* fall through */
- case WSREP_TRX_FAIL:
- WSREP_DEBUG("commit failed for reason: %d", rcode);
- 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_thd_data);
-
- DBUG_RETURN(WSREP_TRX_CERT_FAIL);
-
- case WSREP_SIZE_EXCEEDED:
- WSREP_ERROR("transaction size exceeded");
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- DBUG_RETURN(WSREP_TRX_SIZE_EXCEEDED);
- case WSREP_CONN_FAIL:
- WSREP_ERROR("connection failure");
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- DBUG_RETURN(WSREP_TRX_ERROR);
- default:
- WSREP_ERROR("unknown connection failure");
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- DBUG_RETURN(WSREP_TRX_ERROR);
- }
-
- thd->wsrep_query_state= QUERY_EXEC;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
-
- 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=(legacy_db_type)0;
- 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
- return 0;
-}
-
-
-struct st_mysql_storage_engine wsrep_storage_engine=
-{ MYSQL_HANDLERTON_INTERFACE_VERSION };
-
-
-maria_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 */
- "1.0", /* string version */
- MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
-}
-maria_declare_plugin_end;
diff --git a/sql/wsrep_mutex.h b/sql/wsrep_mutex.h
new file mode 100644
index 00000000000..3454b44e0ec
--- /dev/null
+++ b/sql/wsrep_mutex.h
@@ -0,0 +1,50 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_MUTEX_H
+#define WSREP_MUTEX_H
+
+/* wsrep-lib */
+#include "wsrep/mutex.hpp"
+
+/* implementation */
+#include "my_pthread.h"
+
+class Wsrep_mutex : public wsrep::mutex
+{
+public:
+ Wsrep_mutex(mysql_mutex_t& mutex)
+ : m_mutex(mutex)
+ { }
+
+ void lock()
+ {
+ mysql_mutex_lock(&m_mutex);
+ }
+
+ void unlock()
+ {
+ mysql_mutex_unlock(&m_mutex);
+ }
+
+ void* native()
+ {
+ return &m_mutex;
+ }
+private:
+ mysql_mutex_t& m_mutex;
+};
+
+#endif /* WSREP_MUTEX_H */
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 58b30a1e77f..73f201f12ca 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -14,7 +14,12 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
#include "sql_plugin.h" /* wsrep_plugins_pre_init() */
+#include "my_global.h"
+#include "wsrep_server_state.h"
+
+#include "mariadb.h"
#include <mysqld.h>
+#include <transaction.h>
#include <sql_class.h>
#include <sql_parse.h>
#include <sql_base.h> /* find_temporary_table() */
@@ -33,26 +38,32 @@
#include "wsrep_var.h"
#include "wsrep_binlog.h"
#include "wsrep_applier.h"
+#include "wsrep_schema.h"
#include "wsrep_xid.h"
+#include "wsrep_trans_observer.h"
+#include "mysql/service_wsrep.h"
#include <cstdio>
#include <cstdlib>
+#include <string>
#include "log_event.h"
#include <slave.h>
-wsrep_t *wsrep = NULL;
-/*
- wsrep_emulate_bin_log is a flag to tell that binlog has not been configured.
- wsrep needs to get binlog events from transaction cache even when binlog is
- not enabled, wsrep_emulate_bin_log opens needed code paths to make this
- possible
-*/
-my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
+#include <sstream>
+
+/* wsrep-lib */
+Wsrep_server_state* Wsrep_server_state::m_instance;
+
+my_bool wsrep_emulate_bin_log = FALSE; // activating parts of binlog interface
#ifdef GTID_SUPPORT
/* Sidno in global_sid_map corresponding to group uuid */
rpl_sidno wsrep_sidno= -1;
#endif /* GTID_SUPPORT */
my_bool wsrep_preordered_opt= FALSE;
+/* Streaming Replication */
+const char *wsrep_fragment_units[]= { "bytes", "rows", "statements", NullS };
+const char *wsrep_SR_store_types[]= { "none", "table", NullS };
+
/*
* Begin configuration options
*/
@@ -82,7 +93,7 @@ my_bool wsrep_certify_nonPK; // Certify, even when no primary
my_bool wsrep_recovery; // Recovery
my_bool wsrep_replicate_myisam; // Enable MyISAM replication
my_bool wsrep_log_conflicts;
-my_bool wsrep_load_data_splitting; // Commit load data every 10K intervals
+my_bool wsrep_load_data_splitting= 0; // Commit load data every 10K intervals
my_bool wsrep_slave_UK_checks; // Slave thread does UK checks
my_bool wsrep_slave_FK_checks; // Slave thread does FK checks
my_bool wsrep_restart_slave; // Should mysql slave thread be
@@ -107,7 +118,13 @@ my_bool wsrep_restart_slave_activated= 0; // Node has dropped, and slave
bool wsrep_new_cluster= false; // Bootstrap the cluster?
int wsrep_slave_count_change= 0; // No. of appliers to stop/start
int wsrep_to_isolation= 0; // No. of active TO isolation threads
-long wsrep_max_protocol_version= 3; // Maximum protocol version to use
+long wsrep_max_protocol_version= 4; // Maximum protocol version to use
+long int wsrep_protocol_version= wsrep_max_protocol_version;
+ulong wsrep_trx_fragment_unit= WSREP_FRAG_BYTES;
+ // unit for fragment size
+ulong wsrep_SR_store_type= WSREP_SR_STORE_TABLE;
+uint wsrep_ignore_apply_errors= 0;
+
/*
* End configuration options
@@ -123,29 +140,33 @@ 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;
mysql_mutex_t LOCK_wsrep_config_state;
+mysql_mutex_t LOCK_wsrep_SR_pool;
+mysql_mutex_t LOCK_wsrep_SR_store;
int wsrep_replaying= 0;
-ulong wsrep_running_threads = 0; // # of currently running wsrep threads
+ulong wsrep_running_threads= 0; // # of currently running wsrep threads
ulong my_bind_addr;
#ifdef HAVE_PSI_INTERFACE
-PSI_mutex_key key_LOCK_wsrep_rollback,
+PSI_mutex_key
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,
- key_LOCK_wsrep_config_state;
+ key_LOCK_wsrep_config_state,
+ key_LOCK_wsrep_SR_pool,
+ key_LOCK_wsrep_SR_store,
+ key_LOCK_wsrep_thd_queue;
-PSI_cond_key key_COND_wsrep_rollback,
+PSI_cond_key key_COND_wsrep_thd,
key_COND_wsrep_replaying, key_COND_wsrep_ready, key_COND_wsrep_sst,
- key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread;
+ key_COND_wsrep_sst_init, key_COND_wsrep_sst_thread,
+ key_COND_wsrep_thd_queue;
+
PSI_file_key key_file_wsrep_gra_log;
@@ -156,11 +177,12 @@ static PSI_mutex_info wsrep_mutexes[]=
{ &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_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},
- { &key_LOCK_wsrep_config_state, "LOCK_wsrep_config_state", PSI_FLAG_GLOBAL}
+ { &key_LOCK_wsrep_config_state, "LOCK_wsrep_config_state", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_SR_pool, "LOCK_wsrep_SR_pool", PSI_FLAG_GLOBAL},
+ { &key_LOCK_wsrep_SR_store, "LOCK_wsrep_SR_store", PSI_FLAG_GLOBAL}
};
static PSI_cond_info wsrep_conds[]=
@@ -169,7 +191,7 @@ static PSI_cond_info wsrep_conds[]=
{ &key_COND_wsrep_sst, "COND_wsrep_sst", PSI_FLAG_GLOBAL},
{ &key_COND_wsrep_sst_init, "COND_wsrep_sst_init", PSI_FLAG_GLOBAL},
{ &key_COND_wsrep_sst_thread, "wsrep_sst_thread", 0},
- { &key_COND_wsrep_rollback, "COND_wsrep_rollback", PSI_FLAG_GLOBAL},
+ { &key_COND_wsrep_thd, "THD::COND_wsrep_thd", 0},
{ &key_COND_wsrep_replaying, "COND_wsrep_replaying", PSI_FLAG_GLOBAL}
};
@@ -179,310 +201,219 @@ static PSI_file_info wsrep_files[]=
};
#endif
-my_bool wsrep_inited = 0; // initialized ?
+my_bool wsrep_inited= 0; // initialized ?
-static wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED;
+static wsrep_uuid_t node_uuid= WSREP_UUID_UNDEFINED;
+static wsrep_uuid_t cluster_uuid= WSREP_UUID_UNDEFINED;
static char cluster_uuid_str[40]= { 0, };
-static const char* cluster_status_str[WSREP_VIEW_MAX] =
-{
- "Primary",
- "non-Primary",
- "Disconnected"
-};
static char provider_name[256]= { 0, };
static char provider_version[256]= { 0, };
static char provider_vendor[256]= { 0, };
/*
- * wsrep status variables
+ * Wsrep status variables. LOCK_status must be locked When modifying
+ * these 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;
+my_bool wsrep_connected = FALSE;
+my_bool wsrep_ready = FALSE;
+const char* wsrep_cluster_state_uuid= cluster_uuid_str;
+long long wsrep_cluster_conf_id = WSREP_SEQNO_UNDEFINED;
+const char* wsrep_cluster_status = "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;
+char* wsrep_provider_capabilities = NULL;
+char* wsrep_cluster_capabilities = NULL;
/* End wsrep status variables */
-wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED;
-wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED;
-long wsrep_protocol_version = 3;
-
wsp::Config_state *wsrep_config_state;
-// 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;
+wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED;
+wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED;
+wsp::node_status local_status;
-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:
+/*
+ */
+Wsrep_schema *wsrep_schema= 0;
+
+static void wsrep_log_cb(wsrep::log::level level, const char *msg)
+{
+ /*
+ Silence all wsrep related logging from lib and provider if
+ wsrep is not enabled.
+ */
+ if (WSREP_ON)
+ {
+ switch (level) {
+ case wsrep::log::info:
+ sql_print_information("WSREP: %s", msg);
+ break;
+ case wsrep::log::warning:
+ sql_print_warning("WSREP: %s", msg);
+ break;
+ case wsrep::log::error:
sql_print_error("WSREP: %s", msg);
break;
- case WSREP_LOG_DEBUG:
- if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
- default:
- break;
+ case wsrep::log::debug:
+ if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
+ default:
+ break;
+ }
}
}
-void wsrep_log(void (*fun)(const char *, ...), const char *format, ...)
+void wsrep_init_sidno(const wsrep::id& uuid)
{
- va_list args;
- char msg[1024];
- va_start(args, format);
- vsnprintf(msg, sizeof(msg) - 1, format, args);
- va_end(args);
- (fun)("WSREP: %s", msg);
-}
-
-
-static void wsrep_log_states (wsrep_log_level_t const level,
- const wsrep_uuid_t* const group_uuid,
- wsrep_seqno_t const group_seqno,
- const wsrep_uuid_t* const node_uuid,
- wsrep_seqno_t const node_seqno)
-{
- char uuid_str[37];
- char msg[256];
-
- wsrep_uuid_print (group_uuid, uuid_str, sizeof(uuid_str));
- snprintf (msg, 255, "WSREP: Group state: %s:%lld",
- uuid_str, (long long)group_seqno);
- wsrep_log_cb (level, msg);
-
- wsrep_uuid_print (node_uuid, uuid_str, sizeof(uuid_str));
- snprintf (msg, 255, "WSREP: Local state: %s:%lld",
- uuid_str, (long long)node_seqno);
- wsrep_log_cb (level, msg);
-}
-
-#ifdef GTID_SUPPORT
-void wsrep_init_sidno(const wsrep_uuid_t& wsrep_uuid)
-{
- /* generate new Sid map entry from inverted uuid */
- rpl_sid sid;
- wsrep_uuid_t ltid_uuid;
-
- for (size_t i= 0; i < sizeof(ltid_uuid.data); ++i)
+ /*
+ Protocol versions starting from 4 use group gtid as it is.
+ For lesser protocol versions generate new Sid map entry from inverted
+ uuid.
+ */
+ rpl_gtid sid;
+ if (wsrep_protocol_version >= 4)
{
- ltid_uuid.data[i] = ~wsrep_uuid.data[i];
+ memcpy((void*)&sid, (const uchar*)uuid.data(),16);
}
-
- sid.copy_from(ltid_uuid.data);
+ else
+ {
+ wsrep_uuid_t ltid_uuid;
+ for (size_t i= 0; i < sizeof(ltid_uuid.data); ++i)
+ {
+ ltid_uuid.data[i]= ~((const uchar*)uuid.data())[i];
+ }
+ memcpy((void*)&sid, (const uchar*)ltid_uuid.data,16);
+ }
+#ifdef GTID_SUPPORT
global_sid_lock->wrlock();
wsrep_sidno= global_sid_map->add_sid(sid);
WSREP_INFO("Initialized wsrep sidno %d", wsrep_sidno);
global_sid_lock->unlock();
+#endif
}
-#endif /* GTID_SUPPORT */
-static wsrep_cb_status_t
-wsrep_view_handler_cb (void* app_ctx,
- void* recv_ctx,
- const wsrep_view_info_t* view,
- const char* state,
- size_t state_len,
- void** sst_req,
- size_t* sst_req_len)
+void wsrep_init_schema()
{
- *sst_req = NULL;
- *sst_req_len = 0;
-
- wsrep_member_status_t memb_status= wsrep_config_state->get_status();
-
- 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);
- memb_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;
- }
+ DBUG_ASSERT(!wsrep_schema);
- switch (view->proto_ver)
+ WSREP_INFO("wsrep_init_schema_and_SR %p", wsrep_schema);
+ if (!wsrep_schema)
{
- case 0:
- case 1:
- case 2:
- case 3:
- // version change
- if (view->proto_ver != wsrep_protocol_version)
- {
- my_bool wsrep_ready_saved= wsrep_ready_get();
- wsrep_ready_set(FALSE);
- WSREP_INFO("closing client connections for "
- "protocol change %ld -> %d",
- wsrep_protocol_version, view->proto_ver);
- wsrep_close_client_connections(TRUE);
- wsrep_protocol_version= view->proto_ver;
- wsrep_ready_set(wsrep_ready_saved);
- }
- break;
- default:
- WSREP_ERROR("Unsupported application protocol version: %d",
- view->proto_ver);
- unireg_abort(1);
- }
-
- if (view->state_gap)
- {
- WSREP_WARN("Gap in state sequence. Need state transfer.");
-
- /* After that wsrep will call wsrep_sst_prepare. */
- /* keep ready flag 0 until we receive the snapshot */
- wsrep_ready_set(FALSE);
-
- /* Close client connections to ensure that they don't interfere
- * with SST. Necessary only if storage engines are initialized
- * before SST.
- * TODO: Just killing all ongoing transactions should be enough
- * since wsrep_ready is OFF and no new transactions can start.
- */
- if (!wsrep_before_SE())
+ wsrep_schema= new Wsrep_schema();
+ if (wsrep_schema->init())
{
- WSREP_DEBUG("[debug]: closing client connections for PRIM");
- wsrep_close_client_connections(FALSE);
+ WSREP_ERROR("Failed to init wsrep schema");
+ unireg_abort(1);
}
+ }
+}
- ssize_t const req_len= wsrep_sst_prepare (sst_req);
+void wsrep_deinit_schema()
+{
+ delete wsrep_schema;
+ wsrep_schema= 0;
+}
- if (req_len < 0)
+void wsrep_recover_sr_from_storage(THD *orig_thd)
+{
+ switch (wsrep_SR_store_type)
+ {
+ case WSREP_SR_STORE_TABLE:
+ if (!wsrep_schema)
{
- WSREP_ERROR("SST preparation failed: %zd (%s)", -req_len,
- strerror(-req_len));
- memb_status= WSREP_MEMBER_UNDEFINED;
+ WSREP_ERROR("Wsrep schema not initialized when trying to recover "
+ "streaming transactions");
+ unireg_abort(1);
}
- else
+ if (wsrep_schema->recover_sr_transactions(orig_thd))
{
- assert(sst_req != NULL);
- *sst_req_len= req_len;
- memb_status= WSREP_MEMBER_JOINER;
+ WSREP_ERROR("Failed to recover SR transactions from schema");
+ unireg_abort(1);
}
+ break;
+ default:
+ /* */
+ WSREP_ERROR("Unsupported wsrep SR store type: %lu", wsrep_SR_store_type);
+ unireg_abort(1);
+ break;
}
- 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)
+}
+
+/** Export the WSREP provider's capabilities as a human readable string.
+ * The result is saved in a dynamically allocated string of the form:
+ * :cap1:cap2:cap3:
+ */
+static void wsrep_capabilities_export(wsrep_cap_t const cap, char** str)
+{
+ static const char* names[] =
+ {
+ /* Keep in sync with wsrep/wsrep_api.h WSREP_CAP_* macros. */
+ "MULTI_MASTER",
+ "CERTIFICATION",
+ "PARALLEL_APPLYING",
+ "TRX_REPLAY",
+ "ISOLATION",
+ "PAUSE",
+ "CAUSAL_READS",
+ "CAUSAL_TRX",
+ "INCREMENTAL_WRITESET",
+ "SESSION_LOCKS",
+ "DISTRIBUTED_LOCKS",
+ "CONSISTENCY_CHECK",
+ "UNORDERED",
+ "ANNOTATION",
+ "PREORDERED",
+ "STREAMING",
+ "SNAPSHOT",
+ "NBO",
+ };
+
+ std::string s;
+ for (size_t i= 0; i < sizeof(names) / sizeof(names[0]); ++i)
+ {
+ if (cap & (1ULL << i))
{
- if (wsrep_before_SE())
+ if (s.empty())
{
- 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();
+ s= ":";
}
- else
- {
- local_uuid= cluster_uuid;
- local_seqno= view->state_id.seqno;
- }
- /* Init storage engine XIDs from first view */
- wsrep_set_SE_checkpoint(local_uuid, local_seqno);
-#ifdef GTID_SUPPORT
- wsrep_init_sidno(local_uuid);
-#endif /* GTID_SUPPORT */
- memb_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);
+ s += names[i];
+ s += ":";
}
}
- if (wsrep_auto_increment_control)
- {
- global_system_variables.auto_increment_offset= view->my_idx + 1;
- global_system_variables.auto_increment_increment= view->memb_num;
- }
+ /* A read from the string pointed to by *str may be started at any time,
+ * so it must never point to free(3)d memory or non '\0' terminated string. */
- { /* 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;
- }
+ char* const previous= *str;
-out:
- if (view->status == WSREP_VIEW_PRIMARY) wsrep_startup= FALSE;
- wsrep_config_state->set(memb_status, view);
+ *str= strdup(s.c_str());
- return WSREP_CB_SUCCESS;
+ if (previous != NULL)
+ {
+ free(previous);
+ }
}
-my_bool wsrep_ready_set (my_bool x)
+/* Verifies that SE position is consistent with the group position
+ * and initializes other variables */
+void wsrep_verify_SE_checkpoint(const wsrep_uuid_t& uuid,
+ wsrep_seqno_t const seqno)
{
- WSREP_DEBUG("Setting wsrep_ready to %d", x);
- if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
- my_bool ret= (wsrep_ready != x);
- if (ret)
- {
- wsrep_ready= x;
- mysql_cond_signal (&COND_wsrep_ready);
- }
- mysql_mutex_unlock (&LOCK_wsrep_ready);
- return ret;
}
+/*
+ Wsrep is considered ready if
+ 1) Provider is not loaded (native mode)
+ 2) Server has reached synced state
+ 3) Server is in joiner mode and mysqldump SST method has been
+ specified
+ See Wsrep_server_service::log_state_change() for further details.
+ */
my_bool wsrep_ready_get (void)
{
if (mysql_mutex_lock (&LOCK_wsrep_ready)) abort();
@@ -499,178 +430,67 @@ int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
-// Wait until wsrep has reached ready state
-void wsrep_ready_wait ()
+void wsrep_update_cluster_state_uuid(const char* uuid)
{
- 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);
+ strncpy(cluster_uuid_str, uuid, sizeof(cluster_uuid_str) - 1);
}
-static void wsrep_synced_cb(void* app_ctx)
+static void wsrep_init_position()
{
- WSREP_INFO("Synchronized with group, ready for connections");
- my_bool signal_main= wsrep_ready_set(TRUE);
- wsrep_config_state->set(WSREP_MEMBER_SYNCED);
-
- if (signal_main)
- {
- wsrep_SE_init_grab();
- // Signal mysqld init thread to continue
- wsrep_sst_complete (&local_uuid, local_seqno, false);
- // and wait for SE initialization
- wsrep_SE_init_wait();
- }
- if (wsrep_restart_slave_activated)
- {
- int rcode;
- WSREP_INFO("MariaDB slave restart");
- wsrep_restart_slave_activated= FALSE;
-
- mysql_mutex_lock(&LOCK_active_mi);
- if ((rcode = start_slave_threads(0,
- 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()
+/****************************************************************************
+ Helpers for wsrep_init()
+ ****************************************************************************/
+static std::string wsrep_server_name()
{
- /* read XIDs from storage engines */
- wsrep_uuid_t uuid;
- wsrep_seqno_t seqno;
- wsrep_get_SE_checkpoint(uuid, seqno);
-
- if (!memcmp(&uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)))
- {
- WSREP_INFO("Read nil XID from storage engines, skipping position init");
- return;
- }
-
- char uuid_str[40] = {0, };
- wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str));
- WSREP_INFO("Initial position: %s:%lld", uuid_str, (long long)seqno);
-
- if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(local_uuid)) &&
- local_seqno == WSREP_SEQNO_UNDEFINED)
- {
- // Initial state
- local_uuid= uuid;
- local_seqno= seqno;
- }
- else if (memcmp(&local_uuid, &uuid, sizeof(local_uuid)) ||
- local_seqno != seqno)
- {
- WSREP_WARN("Initial position was provided by configuration or SST, "
- "avoiding override");
- }
+ std::string ret(wsrep_node_name ? wsrep_node_name : "");
+ return ret;
}
-extern char* my_bind_addr_str;
-
-int wsrep_init()
+static std::string wsrep_server_id()
{
- int rcode= -1;
- DBUG_ASSERT(wsrep_inited == 0);
-
- if (strcmp(wsrep_start_position, WSREP_START_POSITION_ZERO) &&
- wsrep_start_position_init(wsrep_start_position))
- {
- return 1;
- }
-
- wsrep_sst_auth_init();
-
- wsrep_ready_set(FALSE);
- assert(wsrep_provider);
-
- wsrep_init_position();
-
- if ((rcode= wsrep_load(wsrep_provider, &wsrep, wsrep_log_cb)) != WSREP_OK)
- {
- if (strcasecmp(wsrep_provider, WSREP_NONE))
- {
- WSREP_ERROR("wsrep_load(%s) failed: %s (%d). Reverting to no provider.",
- wsrep_provider, strerror(rcode), rcode);
- strcpy((char*)wsrep_provider, WSREP_NONE); // damn it's a dirty hack
- return wsrep_init();
- }
- else /* this is for recursive call above */
- {
- WSREP_ERROR("Could not revert to no provider: %s (%d). Need to abort.",
- strerror(rcode), rcode);
- unireg_abort(1);
- }
- }
+ /* using empty server_id, which enables view change handler to
+ set final server_id later on
+ */
+ std::string ret("");
+ return ret;
+}
- 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);
- }
+static std::string wsrep_server_node_address()
+{
+ std::string ret;
if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
- wsrep_data_home_dir = mysql_real_data_home;
+ wsrep_data_home_dir= mysql_real_data_home;
/* Initialize node address */
- 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))
+ char node_addr[512]= {0, };
+ const size_t node_addr_max= sizeof(node_addr) - 1;
+ size_t guess_ip_ret= wsrep_guess_ip(node_addr, node_addr_max);
+ if (!(guess_ip_ret > 0 && guess_ip_ret < node_addr_max))
{
WSREP_WARN("Failed to guess base node address. Set it explicitly via "
"wsrep_node_address.");
- node_addr[0]= '\0';
+ }
+ else
+ {
+ ret= node_addr;
}
}
else
{
- strncpy(node_addr, wsrep_node_address, node_addr_max);
+ ret= wsrep_node_address;
}
+ return ret;
+}
- /* Initialize node's incoming address */
+static std::string wsrep_server_incoming_address()
+{
+ std::string ret;
+ const std::string node_addr(wsrep_server_node_address());
char inc_addr[512]= { 0, };
size_t const inc_addr_max= sizeof (inc_addr);
@@ -685,7 +505,8 @@ int wsrep_init()
bool is_ipv6= false;
unsigned int my_bind_ip= INADDR_ANY; // default if not set
- if (my_bind_addr_str && strlen(my_bind_addr_str))
+ if (my_bind_addr_str && strlen(my_bind_addr_str) &&
+ strcmp(my_bind_addr_str, "*") != 0)
{
my_bind_ip= wsrep_check_ip(my_bind_addr_str, &is_ipv6);
}
@@ -704,22 +525,28 @@ int wsrep_init()
}
else /* mysqld binds to 0.0.0.0, try taking IP from wsrep_node_address. */
{
- size_t const node_addr_len= strlen(node_addr);
- if (node_addr_len > 0)
+ if (node_addr.size())
{
- wsp::Address addr(node_addr);
-
- if (!addr.is_valid())
+ size_t const ip_len= wsrep_host_len(node_addr.c_str(), node_addr.size());
+ if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
{
- WSREP_DEBUG("Could not parse node address : %s", node_addr);
- WSREP_WARN("Guessing address for incoming client connections failed. "
- "Try setting wsrep_node_incoming_address explicitly.");
- goto done;
+ memcpy (inc_addr, node_addr.c_str(), 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';
+ }
+ }
- const char *fmt= (addr.is_ipv6()) ? "[%s]:%u" : "%s:%u";
- snprintf(inc_addr, inc_addr_max, fmt, addr.get_address(),
- (int) mysqld_port);
+ if (!strlen(inc_addr))
+ {
+ WSREP_WARN("Guessing address for incoming client connections failed. "
+ "Try setting wsrep_node_incoming_address explicitly.");
+ WSREP_INFO("Node addr: %s", node_addr.c_str());
}
}
}
@@ -743,52 +570,178 @@ int wsrep_init()
snprintf(inc_addr, inc_addr_max, fmt, addr.get_address(), port);
}
+
+ done:
+ ret= wsrep_node_incoming_address;
+ return ret;
+}
-done:
- struct wsrep_init_args wsrep_args;
+static std::string wsrep_server_working_dir()
+{
+ std::string ret;
+ if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
+ {
+ ret= mysql_real_data_home;
+ }
+ else
+ {
+ ret= wsrep_data_home_dir;
+ }
+ return ret;
+}
- struct wsrep_gtid const state_id = { local_uuid, local_seqno };
+static wsrep::gtid wsrep_server_initial_position()
+{
+ wsrep::gtid ret;
+ WSREP_INFO("Server initial position: %s", wsrep_start_position);
+ std::istringstream is(wsrep_start_position);
+ is >> ret;
+ return ret;
+}
- 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;
+/*
+ Intitialize provider specific status variables
+ */
+static void wsrep_init_provider_status_variables()
+{
+ const wsrep::provider& provider=
+ Wsrep_server_state::instance().provider();
+ strncpy(provider_name,
+ provider.name().c_str(), sizeof(provider_name) - 1);
+ strncpy(provider_version,
+ provider.version().c_str(), sizeof(provider_version) - 1);
+ strncpy(provider_vendor,
+ provider.vendor().c_str(), sizeof(provider_vendor) - 1);
+}
+
+int wsrep_init_server()
+{
+ wsrep::log::logger_fn(wsrep_log_cb);
+ try
+ {
+ std::string server_name;
+ std::string server_id;
+ std::string node_address;
+ std::string incoming_address;
+ std::string working_dir;
+ wsrep::gtid initial_position;
+
+ server_name= wsrep_server_name();
+ server_id= wsrep_server_id();
+ node_address= wsrep_server_node_address();
+ incoming_address= wsrep_server_incoming_address();
+ working_dir= wsrep_server_working_dir();
+ initial_position= wsrep_server_initial_position();
+
+ Wsrep_server_state::init_once(server_name,
+ incoming_address,
+ node_address,
+ working_dir,
+ initial_position,
+ wsrep_max_protocol_version);
+ }
+ catch (const wsrep::runtime_error& e)
+ {
+ WSREP_ERROR("Failed to init wsrep server %s", e.what());
+ return 1;
+ }
+ catch (const std::exception& e)
+ {
+ WSREP_ERROR("Failed to init wsrep server %s", e.what());
+ }
+ return 0;
+}
- wsrep_args.state_id = &state_id;
+void wsrep_init_globals()
+{
+ wsrep_init_sidno(Wsrep_server_state::instance().connected_gtid().id());
+ wsrep_init_schema();
+ if (WSREP_ON)
+ {
+ Wsrep_server_state::instance().initialized();
+ }
+}
- 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;
+void wsrep_deinit_server()
+{
+ wsrep_deinit_schema();
+ Wsrep_server_state::destroy();
+}
- rcode = wsrep->init(wsrep, &wsrep_args);
+int wsrep_init()
+{
+ assert(wsrep_provider);
- if (rcode)
+ wsrep_init_position();
+ wsrep_sst_auth_init();
+
+ if (strlen(wsrep_provider)== 0 ||
+ !strcmp(wsrep_provider, WSREP_NONE))
{
- 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;
+ // enable normal operation in case no provider is specified
+ global_system_variables.wsrep_on= 0;
+ int err= Wsrep_server_state::instance().load_provider(wsrep_provider, wsrep_provider_options ? wsrep_provider_options : "");
+ if (err)
+ {
+ DBUG_PRINT("wsrep",("wsrep::init() failed: %d", err));
+ WSREP_ERROR("wsrep::init() failed: %d, must shutdown", err);
+ }
+ else
+ {
+ wsrep_init_provider_status_variables();
+ }
+ return err;
}
- return rcode;
-}
+ global_system_variables.wsrep_on= 1;
+
+ if (wsrep_gtid_mode && opt_bin_log && !opt_log_slave_updates)
+ {
+ WSREP_ERROR("Option --log-slave-updates is required if "
+ "binlog is enabled, GTID mode is on and wsrep provider "
+ "is specified");
+ return 1;
+ }
+
+ if (!wsrep_data_home_dir || strlen(wsrep_data_home_dir) == 0)
+ wsrep_data_home_dir= mysql_real_data_home;
+
+ if (Wsrep_server_state::instance().load_provider(wsrep_provider,
+ wsrep_provider_options))
+ {
+ WSREP_ERROR("Failed to load provider");
+ return 1;
+ }
+
+ if (!wsrep_provider_is_SR_capable() &&
+ global_system_variables.wsrep_trx_fragment_size > 0)
+ {
+ WSREP_ERROR("The WSREP provider (%s) does not support streaming "
+ "replication but wsrep_trx_fragment_size is set to a "
+ "value other than 0 (%llu). Cannot continue. Either set "
+ "wsrep_trx_fragment_size to 0 or use wsrep_provider that "
+ "supports streaming replication.",
+ wsrep_provider, global_system_variables.wsrep_trx_fragment_size);
+ Wsrep_server_state::instance().unload_provider();
+ return 1;
+ }
+ wsrep_inited= 1;
+
+ wsrep_init_provider_status_variables();
+ wsrep_capabilities_export(Wsrep_server_state::instance().provider().capabilities(),
+ &wsrep_provider_capabilities);
+
+ WSREP_DEBUG("SR storage init for: %s",
+ (wsrep_SR_store_type == WSREP_SR_STORE_TABLE) ? "table" : "void");
+ return 0;
+}
/* Initialize wsrep thread LOCKs and CONDs */
void wsrep_thr_init()
{
DBUG_ENTER("wsrep_thr_init");
- wsrep_config_state = new wsp::Config_state;
+ wsrep_config_state= new wsp::Config_state;
#ifdef HAVE_PSI_INTERFACE
mysql_mutex_register("sql", wsrep_mutexes, array_elements(wsrep_mutexes));
mysql_cond_register("sql", wsrep_conds, array_elements(wsrep_conds));
@@ -801,25 +754,24 @@ void wsrep_thr_init()
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);
mysql_mutex_init(key_LOCK_wsrep_config_state, &LOCK_wsrep_config_state, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_wsrep_SR_pool,
+ &LOCK_wsrep_SR_pool, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_LOCK_wsrep_SR_store,
+ &LOCK_wsrep_SR_store, MY_MUTEX_INIT_FAST);
DBUG_VOID_RETURN;
}
-void wsrep_init_startup (bool first)
+void wsrep_init_startup (bool sst_first)
{
if (wsrep_init()) unireg_abort(1);
- wsrep_thr_lock_init(
- (wsrep_thd_is_brute_force_fun)wsrep_thd_is_BF,
- (wsrep_abort_thd_fun)wsrep_abort_thd,
- wsrep_debug, wsrep_convert_LOCK_to_trx,
- (wsrep_on_fun)wsrep_on);
+ wsrep_thr_lock_init(wsrep_thd_is_BF, wsrep_thd_bf_abort,
+ wsrep_debug, wsrep_convert_LOCK_to_trx, wsrep_on);
/*
Pre-initialize global_system_variables.table_plugin with a dummy engine
@@ -838,28 +790,54 @@ void wsrep_init_startup (bool first)
/* Skip replication start if no cluster address */
if (!wsrep_cluster_address || wsrep_cluster_address[0] == 0) return;
- if (first) wsrep_sst_grab(); // do it so we can wait for SST below
-
+ /*
+ Read value of wsrep_new_cluster before wsrep_start_replication(),
+ the value is reset to FALSE inside wsrep_start_replication.
+ */
if (!wsrep_start_replication()) unireg_abort(1);
wsrep_create_rollbacker();
wsrep_create_appliers(1);
- if (first && !wsrep_sst_wait()) unireg_abort(1);// wait until SST is completed
+ Wsrep_server_state& server_state= Wsrep_server_state::instance();
+ /*
+ If the SST happens before server initialization, wait until the server
+ state reaches initializing. This indicates that
+ either SST was not necessary or SST has been delivered.
+
+ With mysqldump SST (!sst_first) wait until the server reaches
+ joiner state and procedd to accepting connections.
+ */
+ if (sst_first)
+ {
+ server_state.wait_until_state(Wsrep_server_state::s_initializing);
+ }
+ else
+ {
+ server_state.wait_until_state(Wsrep_server_state::s_joiner);
+ }
}
void wsrep_deinit(bool free_options)
{
DBUG_ASSERT(wsrep_inited == 1);
- wsrep_unload(wsrep);
- wsrep= 0;
+ WSREP_DEBUG("wsrep_deinit");
+
+ Wsrep_server_state::instance().unload_provider();
provider_name[0]= '\0';
provider_version[0]= '\0';
provider_vendor[0]= '\0';
wsrep_inited= 0;
+ if (wsrep_provider_capabilities != NULL)
+ {
+ char* p= wsrep_provider_capabilities;
+ wsrep_provider_capabilities= NULL;
+ free(p);
+ }
+
if (free_options)
{
wsrep_sst_auth_free();
@@ -871,28 +849,37 @@ void wsrep_thr_deinit()
{
if (!wsrep_config_state)
return; // Never initialized
+ WSREP_DEBUG("wsrep_thr_deinit");
mysql_mutex_destroy(&LOCK_wsrep_ready);
mysql_cond_destroy(&COND_wsrep_ready);
mysql_mutex_destroy(&LOCK_wsrep_sst);
mysql_cond_destroy(&COND_wsrep_sst);
mysql_mutex_destroy(&LOCK_wsrep_sst_init);
mysql_cond_destroy(&COND_wsrep_sst_init);
- mysql_mutex_destroy(&LOCK_wsrep_rollback);
- mysql_cond_destroy(&COND_wsrep_rollback);
mysql_mutex_destroy(&LOCK_wsrep_replaying);
mysql_cond_destroy(&COND_wsrep_replaying);
mysql_mutex_destroy(&LOCK_wsrep_slave_threads);
mysql_mutex_destroy(&LOCK_wsrep_desync);
mysql_mutex_destroy(&LOCK_wsrep_config_state);
+ mysql_mutex_destroy(&LOCK_wsrep_SR_pool);
+ mysql_mutex_destroy(&LOCK_wsrep_SR_store);
+
delete wsrep_config_state;
wsrep_config_state= 0; // Safety
+
+ if (wsrep_cluster_capabilities != NULL)
+ {
+ char* p= wsrep_cluster_capabilities;
+ wsrep_cluster_capabilities= NULL;
+ free(p);
+ }
}
void wsrep_recover()
{
char uuid_str[40];
- if (!memcmp(&local_uuid, &WSREP_UUID_UNDEFINED, sizeof(wsrep_uuid_t)) &&
+ if (wsrep_uuid_compare(&local_uuid, &WSREP_UUID_UNDEFINED) == 0 &&
local_seqno == -2)
{
wsrep_uuid_print(&local_uuid, uuid_str, sizeof(uuid_str));
@@ -900,43 +887,60 @@ void wsrep_recover()
uuid_str, (long long)local_seqno);
return;
}
- wsrep_uuid_t uuid;
- wsrep_seqno_t seqno;
- wsrep_get_SE_checkpoint(uuid, seqno);
- wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str));
- WSREP_INFO("Recovered position: %s:%lld", uuid_str, (long long)seqno);
+ wsrep::gtid gtid= wsrep_get_SE_checkpoint();
+ std::ostringstream oss;
+ oss << gtid;
+ WSREP_INFO("Recovered position: %s", oss.str().c_str());
}
void wsrep_stop_replication(THD *thd)
{
WSREP_INFO("Stop replication");
- if (!wsrep)
+ if (Wsrep_server_state::instance().state() !=
+ Wsrep_server_state::s_disconnected)
{
- WSREP_INFO("Provider was not loaded, in stop replication");
- return;
+ WSREP_DEBUG("Disconnect provider");
+ Wsrep_server_state::instance().disconnect();
+ Wsrep_server_state::instance().wait_until_state(Wsrep_server_state::s_disconnected);
}
- /* disconnect from group first to get wsrep_ready == FALSE */
- WSREP_DEBUG("Provider disconnect");
- wsrep->disconnect(wsrep);
+ /* my connection, should not terminate with wsrep_close_client_connection(),
+ make transaction to rollback
+ */
+ if (thd && !thd->wsrep_applier) trans_rollback(thd);
+ wsrep_close_client_connections(TRUE, thd);
+
+ /* wait until appliers have stopped */
+ wsrep_wait_appliers_close(thd);
+
+ node_uuid= WSREP_UUID_UNDEFINED;
+}
- wsrep_connected= FALSE;
+void wsrep_shutdown_replication()
+{
+ WSREP_INFO("Shutdown replication");
+ if (Wsrep_server_state::instance().state() != wsrep::server_state::s_disconnected)
+ {
+ WSREP_DEBUG("Disconnect provider");
+ Wsrep_server_state::instance().disconnect();
+ Wsrep_server_state::instance().wait_until_state(Wsrep_server_state::s_disconnected);
+ }
wsrep_close_client_connections(TRUE);
/* wait until appliers have stopped */
- wsrep_wait_appliers_close(thd);
+ wsrep_wait_appliers_close(NULL);
+ node_uuid= WSREP_UUID_UNDEFINED;
- return;
+ /* Undocking the thread specific data. */
+ my_pthread_setspecific_ptr(THR_THD, NULL);
}
bool wsrep_start_replication()
{
- wsrep_status_t rcode;
-
- /* wsrep provider must be loaded. */
- DBUG_ASSERT(wsrep);
+ int rcode;
+ WSREP_DEBUG("wsrep_start_replication");
/*
if provider is trivial, don't even try to connect,
@@ -945,34 +949,27 @@ bool wsrep_start_replication()
if (!WSREP_PROVIDER_EXISTS)
{
// enable normal operation in case no provider is specified
- wsrep_ready_set(TRUE);
return true;
}
if (!wsrep_cluster_address || wsrep_cluster_address[0]== 0)
{
// if provider is non-trivial, but no address is specified, wait for address
- wsrep_ready_set(FALSE);
return true;
}
- bool const bootstrap= wsrep_new_cluster;
+ bool const bootstrap(TRUE == wsrep_new_cluster);
+ wsrep_new_cluster= FALSE;
WSREP_INFO("Start replication");
- if (wsrep_new_cluster)
+ if ((rcode= Wsrep_server_state::instance().connect(
+ wsrep_cluster_name,
+ wsrep_cluster_address,
+ wsrep_sst_donor,
+ bootstrap)))
{
- WSREP_INFO("'wsrep-new-cluster' option used, bootstrapping the cluster");
- wsrep_new_cluster= false;
- }
-
- if ((rcode = wsrep->connect(wsrep,
- wsrep_cluster_name,
- wsrep_cluster_address,
- wsrep_sst_donor,
- bootstrap)))
- {
- DBUG_PRINT("wsrep",("wsrep->connect(%s) failed: %d",
+ DBUG_PRINT("wsrep",("wsrep_ptr->connect(%s) failed: %d",
wsrep_cluster_address, rcode));
WSREP_ERROR("wsrep::connect(%s) failed: %d",
wsrep_cluster_address, rcode);
@@ -980,15 +977,12 @@ bool wsrep_start_replication()
}
else
{
- wsrep_connected= TRUE;
-
- char* opts= wsrep->options_get(wsrep);
- if (opts)
+ try
{
- wsrep_provider_options_init(opts);
- free(opts);
+ std::string opts= Wsrep_server_state::instance().provider().options();
+ wsrep_provider_options_init(opts.c_str());
}
- else
+ catch (const wsrep::runtime_error&)
{
WSREP_WARN("Failed to get wsrep options");
}
@@ -999,40 +993,50 @@ bool wsrep_start_replication()
bool wsrep_must_sync_wait (THD* thd, uint mask)
{
- return (thd->variables.wsrep_sync_wait & mask) &&
+ bool ret;
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ ret= (thd->variables.wsrep_sync_wait & mask) &&
+ thd->wsrep_client_thread &&
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;
+ thd->wsrep_trx().state() !=
+ wsrep::transaction::s_replaying &&
+ thd->wsrep_cs().sync_wait_gtid().is_undefined();
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ return ret;
}
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))
+ WSREP_DEBUG("wsrep_sync_wait: thd->variables.wsrep_sync_wait= %u, "
+ "mask= %u, thd->variables.wsrep_on= %d",
+ thd->variables.wsrep_sync_wait, mask,
+ thd->variables.wsrep_on);
+ /*
+ This allows autocommit SELECTs and a first SELECT after SET AUTOCOMMIT=0
+ TODO: modify to check if thd has locked any rows.
+ */
+ if (thd->wsrep_cs().sync_wait(-1))
{
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
+ /*
+ 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)
+ switch (thd->wsrep_cs().current_error())
{
- case WSREP_NOT_IMPLEMENTED:
+ case wsrep::e_not_supported_error:
msg= "synchronous reads by wsrep backend. "
- "Please unset wsrep_causal_reads variable.";
+ "Please unset wsrep_causal_reads variable.";
err= ER_NOT_SUPPORTED_YET;
break;
default:
@@ -1050,6 +1054,27 @@ bool wsrep_sync_wait (THD* thd, uint mask)
return false;
}
+enum wsrep::provider::status
+wsrep_sync_wait_upto (THD* thd,
+ wsrep_gtid_t* upto,
+ int timeout)
+{
+ DBUG_ASSERT(upto);
+ enum wsrep::provider::status ret;
+ if (upto)
+ {
+ wsrep::gtid upto_gtid(wsrep::id(upto->uuid.data, sizeof(upto->uuid.data)),
+ wsrep::seqno(upto->seqno));
+ ret= Wsrep_server_state::instance().wait_for_gtid(upto_gtid, timeout);
+ }
+ else
+ {
+ ret= Wsrep_server_state::instance().causal_read(timeout).second;
+ }
+ WSREP_DEBUG("wsrep_sync_wait_upto: %d", ret);
+ return ret;
+}
+
void wsrep_keys_free(wsrep_key_arr_t* key_arr)
{
for (size_t i= 0; i < key_arr->keys_len; ++i)
@@ -1061,7 +1086,6 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr)
key_arr->keys_len= 0;
}
-
/*!
* @param db Database string
* @param table Table string
@@ -1073,9 +1097,9 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr)
*/
static bool wsrep_prepare_key_for_isolation(const char* db,
- const char* table,
- wsrep_buf_t* key,
- size_t* key_len)
+ const char* table,
+ wsrep_buf_t* key,
+ size_t* key_len)
{
if (*key_len < 2) return false;
@@ -1087,11 +1111,11 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
case 1:
case 2:
case 3:
+ case 4:
{
*key_len= 0;
if (db)
{
- // sql_print_information("%s.%s", db, table);
key[*key_len].ptr= db;
key[*key_len].len= strlen(db);
++(*key_len);
@@ -1105,26 +1129,23 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
break;
}
default:
+ assert(0);
+ WSREP_ERROR("Unsupported protocol version: %ld", wsrep_protocol_version);
+ unireg_abort(1);
return false;
}
- return true;
-}
+ return true;
+}
static bool wsrep_prepare_key_for_isolation(const char* db,
const char* table,
wsrep_key_arr_t* ka)
{
wsrep_key_t* tmp;
-
- if (!ka->keys)
- tmp= (wsrep_key_t*)my_malloc((ka->keys_len + 1) * sizeof(wsrep_key_t),
- MYF(0));
- else
- tmp= (wsrep_key_t*)my_realloc(ka->keys,
- (ka->keys_len + 1) * sizeof(wsrep_key_t),
- MYF(0));
-
+ tmp= (wsrep_key_t*)my_realloc(ka->keys,
+ (ka->keys_len + 1) * sizeof(wsrep_key_t),
+ MYF(MY_ALLOW_ZERO_PTR));
if (!tmp)
{
WSREP_ERROR("Can't allocate memory for key_array");
@@ -1150,7 +1171,6 @@ static bool wsrep_prepare_key_for_isolation(const char* db,
return true;
}
-
static bool wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
Alter_info* alter_info,
wsrep_key_arr_t* ka)
@@ -1177,7 +1197,6 @@ static bool wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
return true;
}
-
static bool wsrep_prepare_keys_for_isolation(THD* thd,
const char* db,
const char* table,
@@ -1205,16 +1224,19 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
if (!wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info, ka))
goto err;
}
-
return false;
err:
- wsrep_keys_free(ka);
- return true;
+ wsrep_keys_free(ka);
+ return true;
}
+/*
+ * Prepare key list from db/table and table_list
+ *
+ * Return zero in case of success, 1 in case of failure.
+ */
-/* Prepare key list from db/table and table_list */
bool wsrep_prepare_keys_for_isolation(THD* thd,
const char* db,
const char* table,
@@ -1224,7 +1246,6 @@ bool wsrep_prepare_keys_for_isolation(THD* thd,
return wsrep_prepare_keys_for_isolation(thd, db, table, table_list, NULL, ka);
}
-
bool wsrep_prepare_key(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)
@@ -1236,37 +1257,110 @@ bool wsrep_prepare_key(const uchar* cache_key, size_t cache_key_len,
{
case 0:
{
- key[0].ptr = cache_key;
- key[0].len = cache_key_len;
+ key[0].ptr= cache_key;
+ key[0].len= cache_key_len;
- *key_len = 1;
+ *key_len= 1;
break;
}
case 1:
case 2:
case 3:
+ case 4:
{
- key[0].ptr = cache_key;
- key[0].len = strlen( (char*)cache_key );
+ 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[1].ptr= cache_key + strlen( (char*)cache_key ) + 1;
+ key[1].len= strlen( (char*)(key[1].ptr) );
- *key_len = 2;
+ *key_len= 2;
break;
}
default:
return false;
}
- key[*key_len].ptr = row_id;
- key[*key_len].len = row_id_len;
+ key[*key_len].ptr= row_id;
+ key[*key_len].len= row_id_len;
++(*key_len);
return true;
}
+bool wsrep_prepare_key_for_innodb(THD* thd,
+ 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)
+{
+
+ return wsrep_prepare_key(cache_key, cache_key_len, row_id, row_id_len, key, key_len);
+}
+
+wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table,
+ enum wsrep::key::type type)
+{
+ wsrep::key ret(type);
+ DBUG_ASSERT(db);
+ ret.append_key_part(db, strlen(db));
+ if (table) ret.append_key_part(table, strlen(table));
+ return ret;
+}
+wsrep::key_array
+wsrep_prepare_keys_for_alter_add_fk(const char* child_table_db,
+ Alter_info* alter_info)
+
+{
+ wsrep::key_array ret;
+ Key *key;
+ List_iterator<Key> key_iterator(alter_info->key_list);
+ while ((key= key_iterator++))
+ {
+ if (key->type == Key::FOREIGN_KEY)
+ {
+ Foreign_key *fk_key= (Foreign_key *)key;
+ const char *db_name= fk_key->ref_db.str;
+ const char *table_name= fk_key->ref_table.str;
+ if (!db_name)
+ {
+ db_name= child_table_db;
+ }
+ ret.push_back(wsrep_prepare_key_for_toi(db_name, table_name,
+ wsrep::key::exclusive));
+ }
+ }
+ return ret;
+}
+
+wsrep::key_array wsrep_prepare_keys_for_toi(const char* db,
+ const char* table,
+ const TABLE_LIST* table_list,
+ Alter_info* alter_info)
+{
+ wsrep::key_array ret;
+ if (db || table)
+ {
+ ret.push_back(wsrep_prepare_key_for_toi(db, table, wsrep::key::exclusive));
+ }
+ for (const TABLE_LIST* table= table_list; table; table= table->next_global)
+ {
+ ret.push_back(wsrep_prepare_key_for_toi(table->db.str, table->table_name.str,
+ wsrep::key::exclusive));
+ }
+ if (alter_info && (alter_info->flags & ALTER_ADD_FOREIGN_KEY))
+ {
+ wsrep::key_array fk(wsrep_prepare_keys_for_alter_add_fk(table_list->db.str, alter_info));
+ if (!fk.empty())
+ {
+ ret.insert(ret.end(), fk.begin(), fk.end());
+ }
+ }
+ return ret;
+}
/*
* Construct Query_log_Event from thd query and serialize it
* into buffer.
@@ -1277,7 +1371,7 @@ int wsrep_to_buf_helper(
THD* thd, const char *query, uint query_len, uchar** buf, size_t* buf_len)
{
IO_CACHE tmp_io_cache;
- Log_event_writer writer(&tmp_io_cache,0);
+ Log_event_writer writer(&tmp_io_cache, 0);
if (open_cached_file(&tmp_io_cache, mysql_tmpdir, TEMP_PREFIX,
65536, MYF(MY_WME)))
return 1;
@@ -1365,7 +1459,7 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len)
LEX *lex= thd->lex;
SELECT_LEX *select_lex= lex->first_select_lex();
TABLE_LIST *first_table= select_lex->table_list.first;
- TABLE_LIST *views = first_table;
+ TABLE_LIST *views= first_table;
LEX_USER *definer;
String buff;
const LEX_CSTRING command[3]=
@@ -1390,16 +1484,16 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len)
if (definer)
{
- views->definer.user = definer->user;
- views->definer.host = definer->host;
+ views->definer.user= definer->user;
+ views->definer.host= definer->host;
} else {
WSREP_ERROR("Failed to get DEFINER for VIEW.");
return 1;
}
- views->algorithm = lex->create_view->algorithm;
- views->view_suid = lex->create_view->suid;
- views->with_check = lex->create_view->check;
+ views->algorithm = lex->create_view->algorithm;
+ views->view_suid = lex->create_view->suid;
+ views->with_check = lex->create_view->check;
view_store_options(thd, views, &buff);
buff.append(STRING_WITH_LEN("VIEW "));
@@ -1425,12 +1519,8 @@ create_view_query(THD *thd, uchar** buf, size_t* buf_len)
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);
}
@@ -1496,8 +1586,7 @@ static int wsrep_drop_table_query(THD* thd, uchar** buf, size_t* buf_len)
/* Forward declarations. */
-static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len);
-static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
+int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
/*
Decide if statement should run in TOI.
@@ -1577,6 +1666,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
}
}
+#if UNUSED /* 323f269d4099 (Jan Lindström 2018-07-19) */
static const char* wsrep_get_query_or_msg(const THD* thd)
{
switch(thd->lex->sql_command)
@@ -1589,58 +1679,70 @@ static const char* wsrep_get_query_or_msg(const THD* thd)
return "REVOKE";
case SQLCOM_SET_OPTION:
if (thd->lex->definer)
- return "SET PASSWORD";
+ return "SET PASSWORD";
/* fallthrough */
default:
return thd->query();
}
}
+#endif //UNUSED
-/*
- returns:
- 0: statement was replicated as TOI
- 1: TOI replication was skipped
- -1: TOI replication failed
- */
-static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_,
- const TABLE_LIST* table_list,
- Alter_info* alter_info)
+static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
{
- wsrep_status_t ret(WSREP_WARNING);
- uchar* buf(0);
- size_t buf_len(0);
- int buf_err;
- int rc= 0;
+ String log_query;
+ sp_head *sp= thd->lex->sphead;
+ sql_mode_t saved_mode= thd->variables.sql_mode;
+ String retstr(64);
+ LEX_CSTRING returns= empty_clex_str;
+ retstr.set_charset(system_charset_info);
- if (wsrep_can_run_in_toi(thd, db_, table_, table_list) == false)
+ log_query.set_charset(system_charset_info);
+
+ if (sp->m_handler->type() == TYPE_ENUM_FUNCTION)
{
- WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
+ sp_returns_type(thd, retstr, sp);
+ returns= retstr.lex_cstring();
+ }
+ if (sp->m_handler->
+ show_create_sp(thd, &log_query,
+ sp->m_explicit_name ? sp->m_db : null_clex_str,
+ sp->m_name, sp->m_params, returns,
+ sp->m_body, sp->chistics(),
+ thd->lex->definer[0],
+ thd->lex->create_info,
+ saved_mode))
+ {
+ WSREP_WARN("SP create string failed: schema: %s, query: %s",
+ thd->get_db(), thd->query());
return 1;
}
- WSREP_DEBUG("TO BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd),
- thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
+ return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
+}
+static int wsrep_TOI_event_buf(THD* thd, uchar** buf, size_t* buf_len)
+{
+ int err;
switch (thd->lex->sql_command)
{
case SQLCOM_CREATE_VIEW:
- buf_err= create_view_query(thd, &buf, &buf_len);
+ 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);
+ err= wsrep_create_sp(thd, buf, buf_len);
break;
case SQLCOM_CREATE_TRIGGER:
- buf_err= wsrep_create_trigger_query(thd, &buf, &buf_len);
+ err= wsrep_create_trigger_query(thd, buf, buf_len);
break;
case SQLCOM_CREATE_EVENT:
- buf_err= wsrep_create_event_query(thd, &buf, &buf_len);
+ err= wsrep_create_event_query(thd, buf, buf_len);
break;
case SQLCOM_ALTER_EVENT:
- buf_err= wsrep_alter_event_query(thd, &buf, &buf_len);
+ err= wsrep_alter_event_query(thd, buf, buf_len);
break;
case SQLCOM_DROP_TABLE:
- buf_err= wsrep_drop_table_query(thd, &buf, &buf_len);
+ err= wsrep_drop_table_query(thd, buf, buf_len);
break;
case SQLCOM_CREATE_ROLE:
if (sp_process_definer(thd))
@@ -1649,169 +1751,212 @@ static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_,
}
/* fallthrough */
default:
- buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(),
- &buf, &buf_len);
+ 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, alter_info, &key_arr) &&
- key_arr.keys_len > 0 &&
- WSREP_OK == (ret = wsrep->to_execute_start(wsrep, thd->thread_id,
- key_arr.keys, key_arr.keys_len,
- &buff, 1,
- &thd->wsrep_trx_meta)))
- {
- thd->wsrep_exec_mode= TOTAL_ORDER;
- wsrep_to_isolation++;
- wsrep_keys_free(&key_arr);
- WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd),
- thd->wsrep_exec_mode);
- }
- else if (key_arr.keys_len > 0) {
- /* jump to error handler in mysql_execute_command() */
- WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. Check wsrep "
- "connection state and retry the query.",
- ret,
- thd->get_db(),
- (thd->query()) ? thd->query() : "void");
- my_message(ER_LOCK_DEADLOCK, "WSREP replication failed. Check "
- "your wsrep connection state and retry the query.", MYF(0));
- wsrep_keys_free(&key_arr);
- rc= -1;
- }
- else {
- /* non replicated DDL, affecting temporary tables only */
- WSREP_DEBUG("TO isolation skipped for: %d, sql: %s."
- "Only temporary tables affected.",
- ret, (thd->query()) ? thd->query() : "void");
- rc= 1;
+ return err;
+}
+
+static void wsrep_TOI_begin_failed(THD* thd, const wsrep_buf_t* /* const err */)
+{
+ if (wsrep_thd_trx_seqno(thd) > 0)
+ {
+ /* GTID was granted and TO acquired - need to log event and release TO */
+ if (wsrep_emulate_bin_log) wsrep_thd_binlog_trx_reset(thd);
+ if (wsrep_write_dummy_event(thd, "TOI begin failed")) { goto fail; }
+ wsrep::client_state& cs(thd->wsrep_cs());
+ int const ret= cs.leave_toi();
+ if (ret)
+ {
+ WSREP_ERROR("Leaving critical section for failed TOI failed: thd: %lld, "
+ "schema: %s, SQL: %s, rcode: %d wsrep_error: %s",
+ (long long)thd->real_id, thd->db.str,
+ thd->query(), ret, wsrep::to_c_string(cs.current_error()));
+ goto fail;
+ }
}
- if (buf) my_free(buf);
- return rc;
+ return;
+fail:
+ WSREP_ERROR("Failed to release TOI resources. Need to abort.");
+ unireg_abort(1);
}
-static void wsrep_TOI_end(THD *thd) {
- wsrep_status_t ret;
- wsrep_to_isolation--;
- WSREP_DEBUG("TO END: %lld, %d: %s", (long long)wsrep_thd_trx_seqno(thd),
- thd->wsrep_exec_mode, wsrep_get_query_or_msg(thd));
+/*
+ returns:
+ 0: statement was replicated as TOI
+ 1: TOI replication was skipped
+ -1: TOI replication failed
+ */
+static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
+ const TABLE_LIST* table_list,
+ Alter_info* alter_info)
+{
+ DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI);
- wsrep_set_SE_checkpoint(thd->wsrep_trx_meta.gtid.uuid,
- thd->wsrep_trx_meta.gtid.seqno);
- WSREP_DEBUG("TO END: %lld, update seqno",
- (long long)wsrep_thd_trx_seqno(thd));
-
- if (WSREP_OK == (ret = wsrep->to_execute_end(wsrep, thd->thread_id))) {
- WSREP_DEBUG("TO END: %lld", (long long)wsrep_thd_trx_seqno(thd));
+ WSREP_DEBUG("TOI Begin");
+ if (wsrep_can_run_in_toi(thd, db, table, table_list) == false)
+ {
+ WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
+ return 1;
}
- else {
- WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s",
- ret,
- thd->get_db(),
- (thd->query()) ? thd->query() : "void");
+
+ uchar* buf= 0;
+ size_t buf_len(0);
+ int buf_err;
+ int rc;
+
+ buf_err= wsrep_TOI_event_buf(thd, &buf, &buf_len);
+ if (buf_err) {
+ WSREP_ERROR("Failed to create TOI event buf: %d", buf_err);
+ my_message(ER_UNKNOWN_ERROR,
+ "WSREP replication failed to prepare TOI event buffer. "
+ "Check your query.",
+ MYF(0));
+ return -1;
}
-}
+ struct wsrep_buf buff= { buf, buf_len };
-static int wsrep_RSU_begin(THD *thd, const char *db_, const 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() );
+ wsrep::key_array key_array=
+ wsrep_prepare_keys_for_toi(db, table, table_list, alter_info);
- ret = wsrep->desync(wsrep);
- if (ret != WSREP_OK)
+ if (thd->has_read_only_protection())
{
- WSREP_WARN("RSU desync failed %d for schema: %s, query: %s",
- ret, thd->get_db(), thd->query());
- my_error(ER_LOCK_DEADLOCK, MYF(0));
- return(ret);
+ /* non replicated DDL, affecting temporary tables only */
+ WSREP_DEBUG("TO isolation skipped, sql: %s."
+ "Only temporary tables affected.",
+ WSREP_QUERY(thd));
+ if (buf) my_free(buf);
+ return -1;
}
- mysql_mutex_lock(&LOCK_wsrep_replaying);
- wsrep_replaying++;
- mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ thd_proc_info(thd, "acquiring total order isolation");
- if (wsrep_wait_committing_connections_close(5000))
+ wsrep::client_state& cs(thd->wsrep_cs());
+ int ret= cs.enter_toi(key_array,
+ wsrep::const_buffer(buff.ptr, buff.len),
+ wsrep::provider::flag::start_transaction |
+ wsrep::provider::flag::commit);
+
+ if (ret)
{
- /* no can do, bail out from DDL */
- WSREP_WARN("RSU failed due to pending transactions, schema: %s, query %s",
- thd->get_db(), thd->query());
- mysql_mutex_lock(&LOCK_wsrep_replaying);
- wsrep_replaying--;
- mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ DBUG_ASSERT(cs.current_error());
+ WSREP_DEBUG("to_execute_start() failed for %llu: %s, seqno: %lld",
+ thd->thread_id, WSREP_QUERY(thd),
+ (long long)wsrep_thd_trx_seqno(thd));
- ret = wsrep->resync(wsrep);
- if (ret != WSREP_OK)
+ /* jump to error handler in mysql_execute_command() */
+ switch (cs.current_error())
{
- WSREP_WARN("resync failed %d for schema: %s, query: %s",
- ret, thd->get_db(), thd->query());
+ case wsrep::e_size_exceeded_error:
+ WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. "
+ "Maximum size exceeded.",
+ ret,
+ (thd->db.str ? thd->db.str : "(null)"),
+ WSREP_QUERY(thd));
+ my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED);
+ break;
+ default:
+ WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. "
+ "Check wsrep connection state and retry the query.",
+ ret,
+ (thd->db.str ? thd->db.str : "(null)"),
+ WSREP_QUERY(thd));
+ if (!thd->is_error())
+ {
+ my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
+ "your wsrep connection state and retry the query.");
+ }
}
-
- my_error(ER_LOCK_DEADLOCK, MYF(0));
- return(1);
+ rc= -1;
}
-
- wsrep_seqno_t seqno = wsrep->pause(wsrep);
- if (seqno == WSREP_SEQNO_UNDEFINED)
- {
- WSREP_WARN("pause failed %lld for schema: %s, query: %s", (long long)seqno,
- thd->get_db(), thd->query());
- return(1);
+ else {
+ ++wsrep_to_isolation;
+ rc= 0;
}
- 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() );
+ if (buf) my_free(buf);
+ if (rc) wsrep_TOI_begin_failed(thd, NULL);
- mysql_mutex_lock(&LOCK_wsrep_replaying);
- wsrep_replaying--;
- mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ return rc;
+}
- ret = wsrep->resume(wsrep);
- if (ret != WSREP_OK)
+static void wsrep_TOI_end(THD *thd) {
+ int ret;
+ wsrep_to_isolation--;
+ wsrep::client_state& client_state(thd->wsrep_cs());
+ DBUG_ASSERT(wsrep_thd_is_local_toi(thd));
+ WSREP_DEBUG("TO END: %lld: %s", client_state.toi_meta().seqno().get(),
+ WSREP_QUERY(thd));
+
+ if (wsrep_thd_is_local_toi(thd))
{
- WSREP_WARN("resume failed %d for schema: %s, query: %s", ret,
- thd->get_db(), thd->query());
+ wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
+ if (thd->is_error() && !wsrep_must_ignore_error(thd))
+ {
+ wsrep_apply_error err;
+ err.store(thd);
+ client_state.leave_toi();
+ }
+ else
+ {
+ ret= client_state.leave_toi();
+ }
+
+ if (ret == 0)
+ {
+ WSREP_DEBUG("TO END: %lld", client_state.toi_meta().seqno().get());
+ }
+ else
+ {
+ WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s",
+ ret, (thd->db.str ? thd->db.str : "(null)"), WSREP_QUERY(thd));
+ }
}
+}
- ret = wsrep->resync(wsrep);
- if (ret != WSREP_OK)
+static int wsrep_RSU_begin(THD *thd, const char *db_, const char *table_)
+{
+ WSREP_DEBUG("RSU BEGIN: %lld, : %s", wsrep_thd_trx_seqno(thd),
+ WSREP_QUERY(thd));
+ if (thd->wsrep_cs().begin_rsu(5000))
{
- WSREP_WARN("resync failed %d for schema: %s, query: %s", ret,
- thd->get_db(), thd->query());
- return;
+ WSREP_WARN("RSU begin failed");
+ }
+ else
+ {
+ thd->variables.wsrep_on= 0;
}
+ return 0;
+}
- thd->variables.wsrep_on = 1;
+static void wsrep_RSU_end(THD *thd)
+{
+ WSREP_DEBUG("RSU END: %lld : %s", wsrep_thd_trx_seqno(thd),
+ WSREP_QUERY(thd));
+ if (thd->wsrep_cs().end_rsu())
+ {
+ WSREP_WARN("Failed to end RSU, server may need to be restarted");
+ }
+ thd->variables.wsrep_on= 1;
}
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
const TABLE_LIST* table_list,
Alter_info* alter_info)
{
- int ret= 0;
-
/*
No isolation for applier or replaying threads.
*/
- if (thd->wsrep_exec_mode == REPL_RECV)
- return 0;
+ if (!wsrep_thd_is_local(thd)) return 0;
+ int ret= 0;
mysql_mutex_lock(&thd->LOCK_thd_data);
- if (thd->wsrep_conflict_state == MUST_ABORT)
+ if (thd->wsrep_trx().state() == wsrep::transaction::s_must_abort)
{
WSREP_INFO("thread: %lld schema: %s query: %s has been aborted due to multi-master conflict",
(longlong) thd->thread_id, thd->get_db(), thd->query());
@@ -1820,20 +1965,20 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
}
mysql_mutex_unlock(&thd->LOCK_thd_data);
- DBUG_ASSERT(thd->wsrep_exec_mode == LOCAL_STATE);
- DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno == WSREP_SEQNO_UNDEFINED);
+ DBUG_ASSERT(wsrep_thd_is_local(thd));
+ DBUG_ASSERT(thd->wsrep_trx().ws_meta().seqno().is_undefined());
- if (thd->has_read_only_protection())
+ if (thd->global_read_lock.is_acquired())
{
- WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %lld",
- thd->query(), (longlong) thd->thread_id);
+ WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %llu",
+ WSREP_QUERY(thd), thd->thread_id);
return -1;
}
if (wsrep_debug && thd->mdl_context.has_locks())
{
- WSREP_DEBUG("thread holds MDL locks at TI begin: %s %lld",
- thd->query(), (longlong) thd->thread_id);
+ WSREP_DEBUG("thread holds MDL locks at TI begin: %s %llu",
+ WSREP_QUERY(thd), thd->thread_id);
}
/*
@@ -1845,11 +1990,11 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
*/
if (wsrep_auto_increment_control)
{
- thd->variables.auto_increment_offset = 1;
- thd->variables.auto_increment_increment = 1;
+ thd->variables.auto_increment_offset= 1;
+ thd->variables.auto_increment_increment= 1;
}
- if (thd->variables.wsrep_on && thd->wsrep_exec_mode==LOCAL_STATE)
+ if (thd->variables.wsrep_on && wsrep_thd_is_local(thd))
{
switch (thd->variables.wsrep_OSU_method) {
case WSREP_OSU_TOI:
@@ -1865,48 +2010,53 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
break;
}
switch (ret) {
- case 0: thd->wsrep_exec_mode= TOTAL_ORDER; break;
+ case 0: /* wsrep_TOI_begin sould set toi mode */ break;
case 1:
/* TOI replication skipped, treat as success */
- ret = 0;
+ ret= 0;
break;
case -1:
/* TOI replication failed, treat as error */
break;
}
}
+
return ret;
}
void wsrep_to_isolation_end(THD *thd)
{
- if (thd->wsrep_exec_mode == TOTAL_ORDER)
+ DBUG_ASSERT(wsrep_thd_is_local_toi(thd) ||
+ wsrep_thd_is_in_rsu(thd));
+ if (wsrep_thd_is_local_toi(thd))
{
- switch(thd->variables.wsrep_OSU_method)
- {
- case WSREP_OSU_TOI: wsrep_TOI_end(thd); break;
- case WSREP_OSU_RSU: wsrep_RSU_end(thd); break;
- default:
- WSREP_WARN("Unsupported wsrep OSU method at isolation end: %lu",
- thd->variables.wsrep_OSU_method);
- break;
- }
- wsrep_cleanup_transaction(thd);
+ DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI);
+ wsrep_TOI_end(thd);
}
+ else if (wsrep_thd_is_in_rsu(thd))
+ {
+ DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_RSU);
+ wsrep_RSU_end(thd);
+ }
+ else
+ {
+ DBUG_ASSERT(0);
+ }
+ if (wsrep_emulate_bin_log) wsrep_thd_binlog_trx_reset(thd);
}
#define WSREP_MDL_LOG(severity, msg, schema, schema_len, req, gra) \
WSREP_##severity( \
"%s\n" \
"schema: %.*s\n" \
- "request: (%lld \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)\n" \
- "granted: (%lld \tseqno %lld \twsrep (%d, %d, %d) cmd %d %d \t%s)", \
+ "request: (%llu \tseqno %lld \twsrep (%s, %s, %s) cmd %d %d \t%s)\n" \
+ "granted: (%llu \tseqno %lld \twsrep (%s, %s, %s) cmd %d %d \t%s)", \
msg, schema_len, schema, \
- (longlong) req->thread_id, (long long)wsrep_thd_trx_seqno(req), \
- req->wsrep_exec_mode, req->wsrep_query_state, req->wsrep_conflict_state, \
+ req->thread_id, (long long)wsrep_thd_trx_seqno(req), \
+ wsrep_thd_client_mode_str(req), wsrep_thd_client_state_str(req), wsrep_thd_transaction_state_str(req), \
req->get_command(), req->lex->sql_command, req->query(), \
- (longlong) gra->thread_id, (long long)wsrep_thd_trx_seqno(gra), \
- gra->wsrep_exec_mode, gra->wsrep_query_state, gra->wsrep_conflict_state, \
+ gra->thread_id, (long long)wsrep_thd_trx_seqno(gra), \
+ wsrep_thd_client_mode_str(gra), wsrep_thd_client_state_str(gra), wsrep_thd_transaction_state_str(gra), \
gra->get_command(), gra->lex->sql_command, gra->query());
/**
@@ -1919,58 +2069,47 @@ void wsrep_to_isolation_end(THD *thd)
@retval FALSE Lock request cannot be granted
*/
-bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
+void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
MDL_ticket *ticket,
const MDL_key *key)
{
/* Fallback to the non-wsrep behaviour */
- if (!WSREP_ON) return FALSE;
+ if (!WSREP_ON) return;
THD *request_thd= requestor_ctx->get_thd();
THD *granted_thd= ticket->get_ctx()->get_thd();
- bool ret= false;
const char* schema= key->db_name();
int schema_len= key->db_name_length();
mysql_mutex_lock(&request_thd->LOCK_thd_data);
+ if (wsrep_thd_is_toi(request_thd) ||
+ wsrep_thd_is_applying(request_thd)) {
- /*
- We consider granting MDL exceptions only for appliers (BF THD) and ones
- executing under TOI mode.
-
- Rules:
- 1. If granted/owner THD is also an applier (BF THD) or one executing
- under TOI mode, then we grant the requested lock to the requester
- THD.
- @return true
-
- 2. If granted/owner THD is executing a FLUSH command or already has an
- explicit lock, then do not grant the requested lock to the requester
- THD and it has to wait.
- @return false
-
- 3. In all other cases the granted/owner THD is aborted and the requested
- lock is not granted to the requester THD, thus it has to wait.
- @return false
- */
- if (request_thd->wsrep_exec_mode == TOTAL_ORDER ||
- request_thd->wsrep_exec_mode == REPL_RECV)
- {
mysql_mutex_unlock(&request_thd->LOCK_thd_data);
WSREP_MDL_LOG(DEBUG, "MDL conflict ", schema, schema_len,
request_thd, granted_thd);
ticket->wsrep_report(wsrep_debug);
mysql_mutex_lock(&granted_thd->LOCK_thd_data);
- if (granted_thd->wsrep_exec_mode == TOTAL_ORDER ||
- granted_thd->wsrep_exec_mode == REPL_RECV)
+ if (wsrep_thd_is_toi(granted_thd) ||
+ wsrep_thd_is_applying(granted_thd))
{
- WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", schema, schema_len,
- request_thd, granted_thd);
- ticket->wsrep_report(true);
- mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
- ret= true;
+ if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd))
+ {
+ WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
+ schema, schema_len, request_thd, granted_thd);
+ mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
+ }
+ else
+ {
+ WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", schema, schema_len,
+ request_thd, granted_thd);
+ ticket->wsrep_report(true);
+ mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+ unireg_abort(1);
+ }
}
else if (granted_thd->lex->sql_command == SQLCOM_FLUSH ||
granted_thd->mdl_context.has_explicit_locks())
@@ -1978,173 +2117,57 @@ bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
WSREP_DEBUG("BF thread waiting for FLUSH");
ticket->wsrep_report(wsrep_debug);
mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
- ret= false;
+ }
+ else if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE)
+ {
+ WSREP_DEBUG("DROP caused BF abort, conf %s",
+ wsrep_thd_transaction_state_str(granted_thd));
+ ticket->wsrep_report(wsrep_debug);
+ mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+ wsrep_abort_thd((void*)request_thd, (void*)granted_thd, 1);
}
else
{
- /* Print some debug information. */
- if (wsrep_debug)
+ WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", schema, schema_len,
+ request_thd, granted_thd);
+ ticket->wsrep_report(wsrep_debug);
+ if (granted_thd->wsrep_trx().active())
{
- if (request_thd->lex->sql_command == SQLCOM_DROP_TABLE ||
- request_thd->lex->sql_command == SQLCOM_DROP_SEQUENCE)
- {
- WSREP_DEBUG("DROP caused BF abort, conf %d", granted_thd->wsrep_conflict_state);
- }
- else if (granted_thd->wsrep_query_state == QUERY_COMMITTING)
+ mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+ wsrep_abort_thd(request_thd, granted_thd, 1);
+ }
+ else
+ {
+ /*
+ Granted_thd is likely executing with wsrep_on=0. If the requesting
+ thd is BF, BF abort and wait.
+ */
+ mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
+ if (wsrep_thd_is_BF(request_thd, FALSE))
{
- WSREP_DEBUG("MDL granted, but committing thd abort scheduled");
+ ha_abort_transaction(request_thd, granted_thd, TRUE);
}
else
{
- WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", schema, schema_len,
- request_thd, granted_thd);
+ WSREP_MDL_LOG(INFO, "MDL unknown BF-BF conflict", schema, schema_len,
+ request_thd, granted_thd);
+ ticket->wsrep_report(true);
+ unireg_abort(1);
}
- ticket->wsrep_report(true);
}
-
- mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
- wsrep_abort_thd((void *) request_thd, (void *) granted_thd, 1);
- ret= false;
}
}
else
{
mysql_mutex_unlock(&request_thd->LOCK_thd_data);
}
-
- return ret;
-}
-
-
-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(next_thread_id(), true))))
- {
- goto error;
- }
-
- mysql_mutex_lock(&LOCK_thread_count);
-
- if (wsrep_gtid_mode)
- {
- /* Adjust domain_id. */
- thd->variables.gtid_domain_id= wsrep_gtid_domain_id;
- }
-
- thd->real_id=pthread_self(); // Keep purify happy
- thread_created++;
- threads.append(thd);
-
- my_net_init(&thd->net,(st_vio*) 0, thd, MYF(0));
-
- DBUG_PRINT("wsrep",(("creating thread %lld"), (long long)thd->thread_id));
- thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer();
- (void) mysql_mutex_unlock(&LOCK_thread_count);
-
- /* from bootstrap()... */
- thd->bootstrap=1;
- thd->max_client_packet_length= thd->net.max_packet;
- thd->security_ctx->master_access= ~(ulong)0;
-
- /* from handle_one_connection... */
- pthread_detach_this_thread();
-
- mysql_thread_set_psi_id(thd->thread_id);
- thd->thr_create_utime= microsecond_interval_timer();
- if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
- {
- close_connection(thd, ER_OUT_OF_RESOURCES);
- statistic_increment(aborted_connects,&LOCK_status);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
- goto error;
- }
-
-// </5.1.17>
- /*
- handle_one_connection() is normally the only way a thread would
- start and would always be on the very high end of the stack ,
- therefore, the thread stack always starts at the address of the
- first local variable of handle_one_connection, which is thd. We
- need to know the start of the stack so that we could check for
- stack overruns.
- */
- DBUG_PRINT("wsrep", ("handle_one_connection called by thread %lld\n",
- (long long)thd->thread_id));
- /* now that we've called my_thread_init(), it is safe to call DBUG_* */
-
- thd->thread_stack= (char*) &thd;
- if (thd->store_globals())
- {
- close_connection(thd, ER_OUT_OF_RESOURCES);
- statistic_increment(aborted_connects,&LOCK_status);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
- goto error;
- }
-
- thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
- thd->security_ctx->skip_grants();
-
- /* handle_one_connection() again... */
- //thd->version= refresh_version;
- thd->proc_info= 0;
- thd->set_command(COM_SLEEP);
- thd->init_for_queries();
-
- mysql_mutex_lock(&LOCK_thread_count);
- wsrep_running_threads++;
- mysql_cond_broadcast(&COND_thread_count);
- 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
- }
-
- unlink_not_visible_thd(thd);
- delete thd;
- my_thread_end();
- return(NULL);
-
-error:
- WSREP_ERROR("Failed to create/initialize system thread");
-
- /* Abort if its the first applier/rollbacker thread. */
- if (!mysqld_server_initialized)
- unireg_abort(1);
- else
- return NULL;
}
-
/**/
static bool abort_replicated(THD *thd)
{
bool ret_code= false;
- if (thd->wsrep_query_state== QUERY_COMMITTING)
+ if (thd->wsrep_trx().state() == wsrep::transaction::s_committing)
{
WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
@@ -2154,38 +2177,34 @@ static bool abort_replicated(THD *thd)
return ret_code;
}
-
/**/
static inline bool is_client_connection(THD *thd)
{
return (thd->wsrep_client_thread && thd->variables.wsrep_on);
}
-
static inline bool is_replaying_connection(THD *thd)
{
bool ret;
mysql_mutex_lock(&thd->LOCK_thd_data);
- ret= (thd->wsrep_conflict_state == REPLAYING) ? true : false;
+ ret= (thd->wsrep_trx().state() == wsrep::transaction::s_replaying) ? true : false;
mysql_mutex_unlock(&thd->LOCK_thd_data);
return ret;
}
-
static inline bool is_committing_connection(THD *thd)
{
bool ret;
mysql_mutex_lock(&thd->LOCK_thd_data);
- ret= (thd->wsrep_query_state == QUERY_COMMITTING) ? true : false;
+ ret= (thd->wsrep_trx().state() == wsrep::transaction::s_committing) ? true : false;
mysql_mutex_unlock(&thd->LOCK_thd_data);
return ret;
}
-
static bool have_client_connections()
{
THD *tmp;
@@ -2222,7 +2241,6 @@ static void wsrep_close_thread(THD *thd)
}
}
-
static my_bool have_committing_connections()
{
THD *tmp;
@@ -2236,6 +2254,7 @@ static my_bool have_committing_connections()
if (is_committing_connection(tmp))
{
+ mysql_mutex_unlock(&LOCK_thread_count);
return TRUE;
}
}
@@ -2243,7 +2262,6 @@ static my_bool have_committing_connections()
return FALSE;
}
-
int wsrep_wait_committing_connections_close(int wait_time)
{
int sleep_time= 100;
@@ -2261,8 +2279,7 @@ int wsrep_wait_committing_connections_close(int wait_time)
return 0;
}
-
-void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd)
+void wsrep_close_client_connections(my_bool wait_to_end, THD* except_caller_thd)
{
/*
First signal all threads that it's time to die
@@ -2305,12 +2322,7 @@ void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd)
/*
instead of wsrep_close_thread() we do now soft kill by THD::awake
*/
- mysql_mutex_lock(&tmp->LOCK_thd_data);
-
tmp->awake(KILL_CONNECTION);
-
- mysql_mutex_unlock(&tmp->LOCK_thd_data);
-
}
mysql_mutex_unlock(&LOCK_thread_count);
@@ -2360,7 +2372,6 @@ void wsrep_close_applier(THD *thd)
wsrep_close_thread(thd);
}
-
void wsrep_close_threads(THD *thd)
{
THD *tmp;
@@ -2386,10 +2397,12 @@ 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.
+ while (wsrep_running_threads > 2)
+ /*
+ 2 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)
{
@@ -2425,7 +2438,6 @@ void wsrep_wait_appliers_close(THD *thd)
*/
}
-
void wsrep_kill_mysql(THD *thd)
{
if (mysqld_server_started)
@@ -2442,267 +2454,167 @@ void wsrep_kill_mysql(THD *thd)
}
}
-
-static int wsrep_create_sp(THD *thd, uchar** buf, size_t* buf_len)
+void
+wsrep_last_committed_id(wsrep_gtid_t* gtid)
{
- String log_query;
- sp_head *sp = thd->lex->sphead;
- sql_mode_t saved_mode= thd->variables.sql_mode;
- String retstr(64);
- LEX_CSTRING returns= empty_clex_str;
- retstr.set_charset(system_charset_info);
-
- log_query.set_charset(system_charset_info);
-
- if (sp->m_handler->type() == TYPE_ENUM_FUNCTION)
- {
- sp_returns_type(thd, retstr, sp);
- returns= retstr.lex_cstring();
- }
- if (sp->m_handler->
- show_create_sp(thd, &log_query,
- sp->m_explicit_name ? sp->m_db : null_clex_str,
- sp->m_name, sp->m_params, returns,
- sp->m_body, sp->chistics(),
- thd->lex->definer[0],
- thd->lex->create_info,
- saved_mode))
- {
- WSREP_WARN("SP create string failed: schema: %s, query: %s",
- thd->get_db(), thd->query());
- return 1;
- }
-
- return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len);
+ wsrep::gtid ret= Wsrep_server_state::instance().last_committed_gtid();
+ memcpy(gtid->uuid.data, ret.id().data(), sizeof(gtid->uuid.data));
+ gtid->seqno= ret.seqno().get();
}
-
-extern int wsrep_on(THD *thd)
+void
+wsrep_node_uuid(wsrep_uuid_t& uuid)
{
- return (int)(WSREP(thd));
+ uuid= node_uuid;
}
-
-extern "C" bool wsrep_thd_is_wsrep_on(THD *thd)
+int wsrep_must_ignore_error(THD* thd)
{
- return thd->variables.wsrep_on;
-}
+ const int error= thd->get_stmt_da()->sql_errno();
+ const uint flags= sql_command_flags[thd->lex->sql_command];
+ DBUG_ASSERT(error);
+ DBUG_ASSERT((wsrep_thd_is_toi(thd)) ||
+ (wsrep_thd_is_applying(thd) && thd->wsrep_apply_toi));
-bool wsrep_consistency_check(THD *thd)
-{
- return 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;
-}
+ if ((wsrep_ignore_apply_errors & WSREP_IGNORE_ERRORS_ON_DDL))
+ goto ignore_error;
+ if ((flags & CF_WSREP_MAY_IGNORE_ERRORS) &&
+ (wsrep_ignore_apply_errors & WSREP_IGNORE_ERRORS_ON_RECONCILING_DDL))
+ {
+ switch (error)
+ {
+ case ER_DB_DROP_EXISTS:
+ case ER_BAD_TABLE_ERROR:
+ case ER_CANT_DROP_FIELD_OR_KEY:
+ goto ignore_error;
+ }
+ }
-extern "C" void wsrep_thd_set_query_state(
- THD *thd, enum wsrep_query_state state)
-{
- thd->wsrep_query_state= state;
-}
-
-
-void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state)
-{
- if (WSREP(thd)) thd->wsrep_conflict_state= state;
-}
-
-
-enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd)
-{
- return thd->wsrep_exec_mode;
-}
-
-
-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";
-}
-
-
-enum wsrep_query_state wsrep_thd_query_state(THD *thd)
-{
- return thd->wsrep_query_state;
-}
-
-
-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";
-}
-
-
-enum wsrep_conflict_state wsrep_thd_get_conflict_state(THD *thd)
-{
- return thd->wsrep_conflict_state;
-}
-
-
-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";
-}
-
-
-wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd)
-{
- return &thd->wsrep_ws_handle;
-}
-
-
-void wsrep_thd_LOCK(THD *thd)
-{
- mysql_mutex_lock(&thd->LOCK_thd_data);
-}
-
+ return 0;
-void wsrep_thd_UNLOCK(THD *thd)
-{
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ignore_error:
+ WSREP_WARN("Ignoring error '%s' on query. "
+ "Default database: '%s'. Query: '%s', Error_code: %d",
+ thd->get_stmt_da()->message(),
+ print_slave_db_safe(thd->db.str),
+ thd->query(),
+ error);
+ return 1;
}
-
-extern "C" time_t wsrep_thd_query_start(THD *thd)
+int wsrep_ignored_error_code(Log_event* ev, int error)
{
- return thd->query_start();
-}
+ const THD* thd= ev->thd;
+ DBUG_ASSERT(error);
+ DBUG_ASSERT(wsrep_thd_is_applying(thd) &&
+ !wsrep_thd_is_local_toi(thd));
-extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd)
-{
- return thd->wsrep_rand;
-}
-
-longlong wsrep_thd_trx_seqno(THD *thd)
-{
- return (thd) ? thd->wsrep_trx_meta.gtid.seqno : WSREP_SEQNO_UNDEFINED;
-}
+ if ((wsrep_ignore_apply_errors & WSREP_IGNORE_ERRORS_ON_RECONCILING_DML))
+ {
+ const int ev_type= ev->get_type_code();
+ if ((ev_type == DELETE_ROWS_EVENT || ev_type == DELETE_ROWS_EVENT_V1)
+ && error == ER_KEY_NOT_FOUND)
+ goto ignore_error;
+ }
+ return 0;
-extern "C" query_id_t wsrep_thd_query_id(THD *thd)
-{
- return thd->query_id;
+ignore_error:
+ WSREP_WARN("Ignoring error '%s' on %s event. Error_code: %d",
+ thd->get_stmt_da()->message(),
+ ev->get_type_str(),
+ error);
+ return 1;
}
-
-char *wsrep_thd_query(THD *thd)
+bool wsrep_provider_is_SR_capable()
{
- return (thd) ? thd->query() : NULL;
+ return Wsrep_server_state::has_capability(wsrep::provider::capability::streaming);
}
-extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd)
+int wsrep_ordered_commit_if_no_binlog(THD* thd, bool all)
{
- return thd->wsrep_last_query_id;
+ if (((wsrep_thd_is_local(thd) &&
+ (WSREP_EMULATE_BINLOG(thd) || !thd->variables.sql_log_bin)) ||
+ (wsrep_thd_is_applying(thd) && !opt_log_slave_updates))
+ && wsrep_thd_trx_seqno(thd) > 0)
+ {
+ wsrep_apply_error unused;
+ return wsrep_ordered_commit(thd, all, unused);
+ }
+ return 0;
}
-
-extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id)
+wsrep_status_t wsrep_tc_log_commit(THD* thd)
{
- thd->wsrep_last_query_id= id;
-}
-
+ int cookie;
+ my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
-extern "C" void wsrep_thd_awake(THD *thd, my_bool signal)
-{
- if (signal)
+ DBUG_ASSERT(thd->lex->sql_command == SQLCOM_LOAD);
+ if (wsrep_before_commit(thd, true))
{
- thd->awake(KILL_QUERY);
+ WSREP_DEBUG("wsrep_tc_log_commit: wsrep_before_commit failed %llu",
+ thd->thread_id);
+ return WSREP_TRX_FAIL;
}
- else
+ cookie= tc_log->log_and_order(thd, xid, 1, false, true);
+ if (wsrep_after_commit(thd, true))
{
- mysql_mutex_lock(&LOCK_wsrep_replaying);
- mysql_cond_broadcast(&COND_wsrep_replaying);
- mysql_mutex_unlock(&LOCK_wsrep_replaying);
+ WSREP_DEBUG("wsrep_tc_log_commit: wsrep_after_commit failed %llu",
+ thd->thread_id);
+ return WSREP_TRX_FAIL;
+ }
+ if (!cookie)
+ {
+ WSREP_DEBUG("log_and_order has failed %llu %d", thd->thread_id, cookie);
+ return WSREP_TRX_FAIL;
+ }
+ if (tc_log->unlog(cookie, xid))
+ {
+ WSREP_DEBUG("log_and_order has failed %llu %d", thd->thread_id, cookie);
+ return WSREP_TRX_FAIL;
}
-}
-
-
-int wsrep_thd_retry_counter(THD *thd)
-{
- return(thd->wsrep_retry_counter);
-}
-
-
-extern "C" bool wsrep_thd_ignore_table(THD *thd)
-{
- return thd->wsrep_ignore_table;
-}
-
-extern int
-wsrep_trx_order_before(THD *thd1, THD *thd2)
-{
- if (wsrep_thd_trx_seqno(thd1) < wsrep_thd_trx_seqno(thd2)) {
- WSREP_DEBUG("BF conflict, order: %lld %lld\n",
- (long long)wsrep_thd_trx_seqno(thd1),
- (long long)wsrep_thd_trx_seqno(thd2));
- return 1;
+ if (wsrep_after_statement(thd))
+ {
+ return WSREP_TRX_FAIL;
+ }
+ /* Set wsrep transaction id if not set. */
+ if (thd->wsrep_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ if (thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID)
+ {
+ thd->set_wsrep_next_trx_id(thd->query_id);
}
- WSREP_DEBUG("waiting for BF, trx order: %lld %lld\n",
- (long long)wsrep_thd_trx_seqno(thd1),
- (long long)wsrep_thd_trx_seqno(thd2));
- return 0;
+ DBUG_ASSERT(thd->wsrep_next_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ }
+ if (wsrep_start_transaction(thd, thd->wsrep_next_trx_id()))
+ {
+ return WSREP_TRX_FAIL;
+ }
+ DBUG_ASSERT(thd->wsrep_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ return WSREP_OK;
}
-
-int wsrep_trx_is_aborting(THD *thd_ptr)
+int wsrep_thd_retry_counter(const THD *thd)
{
- if (thd_ptr) {
- if ((((THD *)thd_ptr)->wsrep_conflict_state == MUST_ABORT) ||
- (((THD *)thd_ptr)->wsrep_conflict_state == ABORTING)) {
- return 1;
- }
- }
- return 0;
+ return thd->wsrep_retry_counter;
}
-
-void wsrep_copy_query(THD *thd)
+extern bool wsrep_thd_ignore_table(THD *thd)
{
- thd->wsrep_retry_command = thd->get_command();
- thd->wsrep_retry_query_len = thd->query_length();
- if (thd->wsrep_retry_query) {
- my_free(thd->wsrep_retry_query);
- }
- thd->wsrep_retry_query = (char *)my_malloc(
- thd->wsrep_retry_query_len + 1, MYF(0));
- strncpy(thd->wsrep_retry_query, thd->query(), thd->wsrep_retry_query_len);
- thd->wsrep_retry_query[thd->wsrep_retry_query_len] = '\0';
+ return thd->wsrep_ignore_table;
}
-
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;
}
-
bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
TABLE_LIST* src_table,
HA_CREATE_INFO *create_info)
@@ -2753,8 +2665,7 @@ wsrep_error_label:
#endif
}
-
-static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len)
+int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len)
{
LEX *lex= thd->lex;
String stmt_query;
@@ -2809,88 +2720,165 @@ static int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len)
buf, buf_len);
}
-/***** callbacks for wsrep service ************/
-
-my_bool get_wsrep_debug()
+void* start_wsrep_THD(void *arg)
{
- return wsrep_debug;
-}
+ THD *thd;
-my_bool get_wsrep_load_data_splitting()
-{
- return wsrep_load_data_splitting;
-}
+ Wsrep_thd_args* thd_args= (Wsrep_thd_args*) arg;
-long get_wsrep_protocol_version()
-{
- return wsrep_protocol_version;
-}
+ if (my_thread_init() || (!(thd= new THD(next_thread_id(), true))))
+ {
+ goto error;
+ }
-my_bool get_wsrep_drupal_282555_workaround()
-{
- return wsrep_drupal_282555_workaround;
-}
+ mysql_mutex_lock(&LOCK_thread_count);
-my_bool get_wsrep_recovery()
-{
- return wsrep_recovery;
-}
+ if (wsrep_gtid_mode)
+ {
+ /* Adjust domain_id. */
+ thd->variables.gtid_domain_id= wsrep_gtid_domain_id;
+ }
-my_bool get_wsrep_log_conflicts()
-{
- return wsrep_log_conflicts;
-}
+ thd->real_id=pthread_self(); // Keep purify happy
+ thread_created++;
+ threads.append(thd);
-wsrep_t *get_wsrep()
-{
- return wsrep;
-}
+ my_net_init(&thd->net,(st_vio*) 0, thd, MYF(0));
-my_bool get_wsrep_certify_nonPK()
-{
- return wsrep_certify_nonPK;
-}
+ 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);
-void wsrep_lock_rollback()
-{
- mysql_mutex_lock(&LOCK_wsrep_rollback);
-}
+ /* from bootstrap()... */
+ thd->bootstrap=1;
+ thd->max_client_packet_length= thd->net.max_packet;
+ thd->security_ctx->master_access= ~(ulong)0;
-void wsrep_unlock_rollback()
-{
- mysql_cond_signal(&COND_wsrep_rollback);
- mysql_mutex_unlock(&LOCK_wsrep_rollback);
-}
+ /* from handle_one_connection... */
+ pthread_detach_this_thread();
-my_bool wsrep_aborting_thd_contains(THD *thd)
-{
- mysql_mutex_assert_owner(&LOCK_wsrep_rollback);
- wsrep_aborting_thd_t abortees = wsrep_aborting_thd;
- while (abortees)
+ 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))
{
- if (abortees->aborting_thd == thd)
- return true;
- abortees = abortees->next;
+ close_connection(thd, ER_OUT_OF_RESOURCES);
+ statistic_increment(aborted_connects,&LOCK_status);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+ goto error;
}
- return false;
+
+// </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;
+ delete thd_args;
+ goto error;
+ }
+
+ thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
+ thd->security_ctx->skip_grants();
+
+ /* handle_one_connection() again... */
+ thd->proc_info= 0;
+ thd->set_command(COM_SLEEP);
+ thd->init_for_queries();
+ mysql_mutex_lock(&LOCK_thread_count);
+ wsrep_running_threads++;
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ WSREP_DEBUG("wsrep system thread %llu, %p starting",
+ thd->thread_id, thd);
+ thd_args->fun()(thd, thd_args->args());
+
+ WSREP_DEBUG("wsrep system thread: %llu, %p closing",
+ thd->thread_id, thd);
+
+ /* Wsrep may reset globals during thread context switches, store globals
+ before cleanup. */
+ thd->store_globals();
+
+ close_connection(thd, 0);
+
+ delete thd_args;
+
+ 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
+ */
+ }
+
+ unlink_not_visible_thd(thd);
+ delete thd;
+ my_thread_end();
+ return(NULL);
+
+error:
+ WSREP_ERROR("Failed to create/initialize system thread");
+
+ /* Abort if its the first applier/rollbacker thread. */
+ if (!mysqld_server_initialized)
+ unireg_abort(1);
+ else
+ return NULL;
}
-void wsrep_aborting_thd_enqueue(THD *thd)
+enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit)
{
- mysql_mutex_assert_owner(&LOCK_wsrep_rollback);
- 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;
+ switch (unit)
+ {
+ case WSREP_FRAG_BYTES: return wsrep::streaming_context::bytes;
+ case WSREP_FRAG_ROWS: return wsrep::streaming_context::row;
+ case WSREP_FRAG_STATEMENTS: return wsrep::streaming_context::statement;
+ default:
+ DBUG_ASSERT(0);
+ return wsrep::streaming_context::bytes;
+ }
}
-bool wsrep_node_is_donor()
+/***** callbacks for wsrep service ************/
+
+my_bool get_wsrep_recovery()
{
- return (WSREP_ON) ? (wsrep_config_state->get_status() == 2) : false;
+ return wsrep_recovery;
}
-bool wsrep_node_is_synced()
+bool wsrep_consistency_check(THD *thd)
{
- return (WSREP_ON) ? (wsrep_config_state->get_status() == 4) : false;
+ return thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING;
}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index b434c248347..957f1ef3ab1 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -1,4 +1,4 @@
-/* Copyright 2008-2015 Codership Oy <http://www.codership.com>
+/* Copyright 2008-2017 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
@@ -13,24 +13,32 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
-#include <wsrep.h>
-
#ifndef WSREP_MYSQLD_H
#define WSREP_MYSQLD_H
-#include <mysql/plugin.h>
-#include <mysql/service_wsrep.h>
+#include <wsrep.h>
#ifdef WITH_WSREP
+#include <mysql/plugin.h>
+#include "mysql/service_wsrep.h"
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include "log.h"
+#include "mysqld.h"
+
typedef struct st_mysql_show_var SHOW_VAR;
#include <sql_priv.h>
-//#include "rpl_gtid.h"
-#include "../wsrep/wsrep_api.h"
#include "mdl.h"
-#include "mysqld.h"
#include "sql_table.h"
+#include "wsrep/provider.hpp"
+#include "wsrep/streaming_context.hpp"
+#include "wsrep_api.h"
+#include <vector>
+#include "wsrep_server_state.h"
+
#define WSREP_UNDEFINED_TRX_ID ULONGLONG_MAX
class set_var;
@@ -42,20 +50,7 @@ enum wsrep_consistency_check_mode {
CONSISTENCY_CHECK_RUNNING,
};
-struct wsrep_thd_shadow {
- ulonglong options;
- uint server_status;
- enum wsrep_exec_mode wsrep_exec_mode;
- Vio *vio;
- ulong tx_isolation;
- const char *db;
- size_t db_length;
- my_hrtime_t user_time;
- longlong row_count_func;
-};
-
// Global wsrep parameters
-extern wsrep_t* wsrep;
// MySQL wsrep options
extern const char* wsrep_provider;
@@ -69,24 +64,33 @@ extern const char* wsrep_data_home_dir;
extern const char* wsrep_dbug_option;
extern long wsrep_slave_threads;
extern int wsrep_slave_count_change;
+extern MYSQL_PLUGIN_IMPORT my_bool wsrep_debug;
extern my_bool wsrep_convert_LOCK_to_trx;
extern ulong wsrep_retry_autocommit;
extern my_bool wsrep_auto_increment_control;
+extern my_bool wsrep_drupal_282555_workaround;
extern my_bool wsrep_incremental_data_collection;
extern const char* wsrep_start_position;
extern ulong wsrep_max_ws_size;
extern ulong wsrep_max_ws_rows;
extern const char* wsrep_notify_cmd;
-extern long wsrep_max_protocol_version;
+extern my_bool wsrep_certify_nonPK;
+extern long int wsrep_protocol_version;
extern ulong wsrep_forced_binlog_format;
extern my_bool wsrep_desync;
extern ulong wsrep_reject_queries;
+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 ulong wsrep_trx_fragment_unit;
+extern ulong wsrep_SR_store_type;
+extern uint wsrep_ignore_apply_errors;
extern ulong wsrep_running_threads;
extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
@@ -105,15 +109,34 @@ enum enum_wsrep_OSU_method {
};
enum enum_wsrep_sync_wait {
- WSREP_SYNC_WAIT_NONE = 0x0,
+ WSREP_SYNC_WAIT_NONE= 0x0,
// select, begin
- WSREP_SYNC_WAIT_BEFORE_READ = 0x1,
- WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE = 0x2,
- WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE = 0x4,
- WSREP_SYNC_WAIT_BEFORE_SHOW = 0x8,
- WSREP_SYNC_WAIT_MAX = 0xF
+ WSREP_SYNC_WAIT_BEFORE_READ= 0x1,
+ WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE= 0x2,
+ WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE= 0x4,
+ WSREP_SYNC_WAIT_BEFORE_SHOW= 0x8,
+ WSREP_SYNC_WAIT_MAX= 0xF
+};
+
+enum enum_wsrep_ignore_apply_error {
+ WSREP_IGNORE_ERRORS_NONE= 0x0,
+ WSREP_IGNORE_ERRORS_ON_RECONCILING_DDL= 0x1,
+ WSREP_IGNORE_ERRORS_ON_RECONCILING_DML= 0x2,
+ WSREP_IGNORE_ERRORS_ON_DDL= 0x4,
+ WSREP_IGNORE_ERRORS_MAX= 0x7
};
+// Streaming Replication
+#define WSREP_FRAG_BYTES 0
+#define WSREP_FRAG_ROWS 1
+#define WSREP_FRAG_STATEMENTS 2
+
+#define WSREP_SR_STORE_NONE 0
+#define WSREP_SR_STORE_TABLE 1
+
+extern const char *wsrep_fragment_units[];
+extern const char *wsrep_SR_store_types[];
+
// MySQL status variables
extern my_bool wsrep_connected;
extern my_bool wsrep_ready;
@@ -126,9 +149,18 @@ 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;
+extern char* wsrep_provider_capabilities;
+extern char* wsrep_cluster_capabilities;
+
+int wsrep_show_status(THD *thd, SHOW_VAR *var, char *buff);
+int wsrep_show_ready(THD *thd, SHOW_VAR *var, char *buff);
+void wsrep_free_status(THD *thd);
+void wsrep_update_cluster_state_uuid(const char* str);
+
+/* 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_show_status(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope);
int wsrep_init();
void wsrep_deinit(bool free_options);
@@ -144,19 +176,17 @@ bool wsrep_before_SE(); // initialize wsrep before storage
* @param before wsrep_before_SE() value */
void wsrep_init_startup(bool before);
+/* Recover streaming transactions from fragment storage */
+void wsrep_recover_sr_from_storage(THD *);
+
// Other wsrep global variables
extern my_bool wsrep_inited; // whether wsrep is initialized ?
-
-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_trx_to_replay(THD *thd, uint64 trx_id);
-
+extern "C" void wsrep_fire_rollbacker(THD *thd);
extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
extern "C" time_t wsrep_thd_query_start(THD *thd);
-extern "C" query_id_t wsrep_thd_query_id(THD *thd);
+extern void wsrep_close_client_connections(my_bool wait_to_end,
+ THD *except_caller_thd= NULL);
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);
@@ -166,60 +196,87 @@ 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 void wsrep_shutdown_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 enum wsrep::provider::status
+wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout);
+extern void wsrep_last_committed_id (wsrep_gtid_t* gtid);
extern int wsrep_check_opts();
extern void wsrep_prepend_PATH (const char* path);
/* Other global variables */
extern wsrep_seqno_t wsrep_locked_seqno;
-
#define WSREP_ON \
- (global_system_variables.wsrep_on)
-
-#define WSREP_ON_NEW \
((global_system_variables.wsrep_on) && \
wsrep_provider && \
strcmp(wsrep_provider, WSREP_NONE))
-#define WSREP(thd) \
+/* use xxxxxx_NNULL macros when thd pointer is guaranteed to be non-null to
+ * avoid compiler warnings (GCC 6 and later) */
+#define WSREP_NNULL(thd) \
(WSREP_ON && thd->variables.wsrep_on)
+#define WSREP(thd) \
+ (thd && WSREP_NNULL(thd))
+
+#define WSREP_CLIENT_NNULL(thd) \
+ (WSREP_NNULL(thd) && thd->wsrep_client_thread)
+
#define WSREP_CLIENT(thd) \
(WSREP(thd) && thd->wsrep_client_thread)
+#define WSREP_EMULATE_BINLOG_NNULL(thd) \
+ (WSREP_NNULL(thd) && wsrep_emulate_bin_log)
+
#define WSREP_EMULATE_BINLOG(thd) \
(WSREP(thd) && wsrep_emulate_bin_log)
-#define WSREP_FORMAT(my_format) \
- ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) \
- ? wsrep_forced_binlog_format : (ulong)(my_format))
+#define WSREP_BINLOG_FORMAT(my_format) \
+ ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
+ wsrep_forced_binlog_format : my_format)
// prefix all messages with "WSREP"
-void wsrep_log(void (*fun)(const char *, ...), const char *format, ...);
-#define WSREP_LOG(fun, ...) wsrep_log(fun, ## __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, thd_get_thread_id(thd), wsrep_thd_exec_mode_str(thd), \
- wsrep_thd_query_state_str(thd), \
- wsrep_thd_conflict_state_str(thd), (long long)wsrep_thd_trx_seqno(thd), \
- wsrep_thd_query(thd) \
- );
-
-#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \
- if (wsrep_debug || wsrep_log_conflicts) \
- { \
- WSREP_LOG(sql_print_information, "cluster conflict due to %s for threads:",\
- (bf_abort) ? "high priority abort" : "certification failure" \
- ); \
- if (bf_thd != NULL) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
- if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \
+#define WSREP_LOG(fun, ...) \
+ do { \
+ char msg[1024]= {'\0'}; \
+ snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \
+ fun("WSREP: %s", msg); \
+ } while(0)
+
+#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, \
+ thd_get_thread_id(thd), \
+ wsrep_thd_client_mode_str(thd), \
+ wsrep_thd_client_state_str(thd), \
+ wsrep_thd_transaction_state_str(thd), \
+ 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"); \
+ WSREP_LOG(sql_print_information, "context: %s:%d", __FILE__, __LINE__); \
}
#define WSREP_PROVIDER_EXISTS \
@@ -232,15 +289,6 @@ extern void wsrep_ready_wait();
class Ha_trx_info;
struct THD_TRANS;
-void wsrep_register_hton(THD* thd, bool all);
-void wsrep_brute_force_killer(THD *thd);
-int wsrep_hire_brute_force_killer(THD *thd, uint64_t trx_id);
-
-/* 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;
@@ -248,24 +296,26 @@ 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 mysql_mutex_t LOCK_wsrep_SR_pool;
+extern mysql_mutex_t LOCK_wsrep_SR_store;
+extern mysql_mutex_t LOCK_wsrep_thd_pool;
extern mysql_mutex_t LOCK_wsrep_config_state;
-extern wsrep_aborting_thd_t wsrep_aborting_thd;
extern my_bool wsrep_emulate_bin_log;
extern int wsrep_to_isolation;
#ifdef GTID_SUPPORT
extern rpl_sidno wsrep_sidno;
#endif /* GTID_SUPPORT */
extern my_bool wsrep_preordered_opt;
-extern handlerton *wsrep_hton;
#ifdef HAVE_PSI_INTERFACE
+
+extern PSI_cond_key key_COND_wsrep_thd;
+
extern PSI_mutex_key key_LOCK_wsrep_ready;
extern PSI_mutex_key key_COND_wsrep_ready;
extern PSI_mutex_key key_LOCK_wsrep_sst;
@@ -274,12 +324,16 @@ 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;
+extern PSI_mutex_key key_LOCK_wsrep_SR_pool;
+extern PSI_mutex_key key_LOCK_wsrep_SR_store;
+extern PSI_mutex_key key_LOCK_wsrep_thd_pool;
+extern PSI_mutex_key key_LOCK_wsrep_global_seqno;
+extern PSI_mutex_key key_LOCK_wsrep_thd_queue;
+extern PSI_cond_key key_COND_wsrep_thd_queue;
extern PSI_file_key key_file_wsrep_gra_log;
#endif /* HAVE_PSI_INTERFACE */
@@ -287,42 +341,33 @@ struct TABLE_LIST;
class Alter_info;
int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_,
const TABLE_LIST* table_list,
- Alter_info* alter_info = NULL);
+ Alter_info* alter_info= NULL);
+
void wsrep_to_isolation_end(THD *thd);
-void wsrep_cleanup_transaction(THD *thd);
+
+bool wsrep_append_SR_keys(THD *thd);
int wsrep_to_buf_helper(
THD* thd, const char *query, uint query_len, 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);
-extern bool
-wsrep_grant_mdl_exception(MDL_context *requestor_ctx,
- MDL_ticket *ticket,
- const MDL_key *key);
-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_rollback_stmt(THD * thd);
-void thd_binlog_trx_reset(THD * thd);
+bool wsrep_stmt_rollback_is_safe(THD* thd);
-typedef void (*wsrep_thd_processor_fun)(THD *);
-pthread_handler_t start_wsrep_THD(void *arg);
-int wsrep_wait_committing_connections_close(int wait_time);
-extern void wsrep_close_client_connections(my_bool wait_to_end,
- THD *except_caller_thd = NULL);
-void wsrep_close_applier(THD *thd);
-void wsrep_close_applier_threads(int count);
-void wsrep_wait_appliers_close(THD *thd);
-void wsrep_kill_mysql(THD *thd);
-void wsrep_close_threads(THD *thd);
-void wsrep_copy_query(THD *thd);
-bool wsrep_is_show_query(enum enum_sql_command command);
-void wsrep_replay_transaction(THD *thd);
-bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
- TABLE_LIST* src_table,
- HA_CREATE_INFO *create_info);
+void wsrep_init_sidno(const wsrep_uuid_t&);
bool wsrep_node_is_donor();
bool wsrep_node_is_synced();
+void wsrep_init_SR();
+void wsrep_verify_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno);
+int wsrep_replay_from_SR_store(THD*, const wsrep_trx_meta_t&);
+void wsrep_node_uuid(wsrep_uuid_t&);
+
+class Log_event;
+int wsrep_ignored_error_code(Log_event* ev, int error);
+int wsrep_must_ignore_error(THD* thd);
+
+bool wsrep_replicate_GTID(THD* thd);
+
typedef struct wsrep_key_arr
{
wsrep_key_t* keys;
@@ -335,38 +380,125 @@ bool wsrep_prepare_keys_for_isolation(THD* thd,
wsrep_key_arr_t* ka);
void wsrep_keys_free(wsrep_key_arr_t* key_arr);
-#define WSREP_BINLOG_FORMAT(my_format) \
- ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
- wsrep_forced_binlog_format : my_format)
+extern void
+wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
+ MDL_ticket *ticket,
+ const MDL_key *key);
+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_rollback_stmt(THD * thd);
+void thd_binlog_trx_reset(THD * thd);
+
+typedef void (*wsrep_thd_processor_fun)(THD*, void *);
+class Wsrep_thd_args
+{
+ public:
+ Wsrep_thd_args(wsrep_thd_processor_fun fun, void* args)
+ :
+ fun_ (fun),
+ args_(args)
+ { }
+
+ wsrep_thd_processor_fun fun() { return fun_; }
+
+ void* args() { return args_; }
-#else /* WITH_WSREP */
+ private:
+
+ Wsrep_thd_args(const Wsrep_thd_args&);
+ Wsrep_thd_args& operator=(const Wsrep_thd_args&);
+
+ wsrep_thd_processor_fun fun_;
+ void* args_;
+};
+
+void* start_wsrep_THD(void*);
+
+void wsrep_close_threads(THD *thd);
+bool wsrep_is_show_query(enum enum_sql_command command);
+void wsrep_replay_transaction(THD *thd);
+bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
+ TABLE_LIST* src_table,
+ HA_CREATE_INFO *create_info);
+bool wsrep_node_is_donor();
+bool wsrep_node_is_synced();
+
+/**
+ * Check if the wsrep provider (ie the Galera library) is capable of
+ * doing streaming replication.
+ * @return true if SR capable
+ */
+bool wsrep_provider_is_SR_capable();
+
+/**
+ * Mark current commit ordered if binlogging is not enabled.
+ *
+ * The purpose of this function is to leave commit order critical
+ * section if binlog is not enabled.
+ *
+ * The function can be called from inside storage engine during commit.
+ * Binlog options are checked inside the function.
+ *
+ * @return Zero in case of success, non-zero in case of failure.
+ */
+int wsrep_ordered_commit_if_no_binlog(THD*, bool);
+
+/**
+ * Commit the current transaction with the
+ * MySQL "Transaction Coordinator Log" (see `class TC_LOG` in sql/log.h).
+ * Calling this function will generate and assign a new wsrep transaction id
+ * for `thd`.
+ * @return WSREP_OK on success or other WSREP_* error code on failure
+ */
+wsrep_status_t wsrep_tc_log_commit(THD* thd);
+
+/**
+ * Initialize WSREP server instance.
+ *
+ * @return Zero on success, non-zero on error.
+ */
+int wsrep_init_server();
+
+/**
+ * Initialize WSREP globals. This should be done after server initialization
+ * is complete and the server has joined to the cluster.
+ *
+ */
+void wsrep_init_globals();
+
+/**
+ * Deinit and release WSREP resources.
+ */
+void wsrep_deinit_server();
+
+/**
+ * Convert streaming fragment unit (WSREP_FRAG_BYTES, WSREP_FRAG_ROWS...)
+ * to corresponding wsrep-lib fragment_unit
+ */
+enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit);
+
+#else /* !WITH_WSREP */
+
+/* These macros are needed to compile MariaDB without WSREP support
+ * (e.g. embedded) */
#define WSREP(T) (0)
#define WSREP_ON (0)
#define WSREP_EMULATE_BINLOG(thd) (0)
-#define WSREP_CLIENT(thd) (0)
-#define WSREP_FORMAT(my_format) ((ulong)my_format)
+#define WSREP_EMULATE_BINLOG_NNULL(thd) (0)
+#define WSREP_BINLOG_FORMAT(my_format) ((ulong)my_format)
#define WSREP_PROVIDER_EXISTS (0)
#define wsrep_emulate_bin_log (0)
#define wsrep_to_isolation (0)
-#define wsrep_init() (1)
-#define wsrep_prepend_PATH(X)
#define wsrep_before_SE() (0)
#define wsrep_init_startup(X)
-#define wsrep_must_sync_wait(...) (0)
-#define wsrep_sync_wait(...) (0)
-#define wsrep_to_isolation_begin(...) (0)
-#define wsrep_register_hton(...) do { } while(0)
#define wsrep_check_opts() (0)
-#define wsrep_stop_replication(X) do { } while(0)
-#define wsrep_inited (0)
-#define wsrep_deinit(X) do { } while(0)
-#define wsrep_recover() do { } while(0)
-#define wsrep_slave_threads (1)
-#define wsrep_replicate_myisam (0)
#define wsrep_thr_init() do {} while(0)
#define wsrep_thr_deinit() do {} while(0)
-#define wsrep_running_threads (0)
-#define WSREP_BINLOG_FORMAT(my_format) my_format
+#define wsrep_init_globals() do {} while(0)
+#define wsrep_create_appliers(X) do {} while(0)
+
#endif /* WITH_WSREP */
+
#endif /* WSREP_MYSQLD_H */
diff --git a/sql/wsrep_notify.cc b/sql/wsrep_notify.cc
index 92bcc8eda43..ad94aecb6b4 100644
--- a/sql/wsrep_notify.cc
+++ b/sql/wsrep_notify.cc
@@ -18,22 +18,8 @@
#include "wsrep_priv.h"
#include "wsrep_utils.h"
-
-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)
+void wsrep_notify_status(enum wsrep::server_state::state status,
+ const wsrep::view* view)
{
if (!wsrep_notify_cmd || 0 == strlen(wsrep_notify_cmd))
{
@@ -42,51 +28,44 @@ void wsrep_notify_status (wsrep_member_status_t status,
}
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;
+ 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);
- }
+ cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --status %s",
+ to_c_string(status));
- if (0 != view)
+ if (view != NULL)
{
- char uuid_str[40];
-
- wsrep_uuid_print (&view->state_id.uuid, uuid_str, sizeof(uuid_str));
+ std::ostringstream uuid;
+ uuid << view->state_id().id();
cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
- " --uuid %s", uuid_str);
+ " --uuid %s", uuid.str().c_str());
cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
- " --primary %s", view->view >= 0 ? "yes" : "no");
+ " --primary %s", view->view_seqno().get() >= 0 ? "yes" : "no");
cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off,
- " --index %d", view->my_idx);
+ " --index %ld", view->own_index());
- if (view->memb_num)
+ const std::vector<wsrep::view::member>& members(view->members());
+ if (members.size())
{
- 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);
- }
+ cmd_off += snprintf (cmd_ptr + cmd_off, cmd_len - cmd_off, " --members");
+
+ for (unsigned int i= 0; i < members.size(); i++)
+ {
+ std::ostringstream id;
+ id << members[i].id();
+ cmd_off += snprintf(cmd_ptr + cmd_off, cmd_len - cmd_off,
+ "%c%s/%s/%s", i > 0 ? ',' : ' ',
+ id.str().c_str(),
+ members[i].name().c_str(),
+ members[i].incoming().c_str());
+ }
}
}
@@ -100,7 +79,7 @@ void wsrep_notify_status (wsrep_member_status_t status,
wsp::process p(cmd_ptr, "r", NULL);
p.wait();
- int err = p.error();
+ int err= p.error();
if (err)
{
diff --git a/sql/wsrep_plugin.cc b/sql/wsrep_plugin.cc
new file mode 100644
index 00000000000..83618a50637
--- /dev/null
+++ b/sql/wsrep_plugin.cc
@@ -0,0 +1,53 @@
+/* Copyright 2016 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_trans_observer.h"
+#include "wsrep_mysqld.h"
+
+#include <mysql/plugin.h>
+
+static int wsrep_plugin_init(void *p)
+{
+ WSREP_INFO("wsrep_plugin_init()");
+ return 0;
+}
+
+static int wsrep_plugin_deinit(void *p)
+{
+ WSREP_INFO("wsrep_plugin_deinit()");
+ return 0;
+}
+
+struct Mysql_replication wsrep_plugin= {
+ MYSQL_REPLICATION_INTERFACE_VERSION
+};
+
+maria_declare_plugin(wsrep)
+{
+ MYSQL_REPLICATION_PLUGIN,
+ &wsrep_plugin,
+ "wsrep",
+ "Codership Oy",
+ "Wsrep replication plugin",
+ PLUGIN_LICENSE_GPL,
+ wsrep_plugin_init,
+ wsrep_plugin_deinit,
+ 0x0100,
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* Version (string) */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
+}
+maria_declare_plugin_end;
diff --git a/sql/wsrep_priv.h b/sql/wsrep_priv.h
index 222a49cc2ab..68773d27948 100644
--- a/sql/wsrep_priv.h
+++ b/sql/wsrep_priv.h
@@ -19,8 +19,9 @@
#ifndef WSREP_PRIV_H
#define WSREP_PRIV_H
+#include <my_global.h>
#include "wsrep_mysqld.h"
-#include "../wsrep/wsrep_api.h"
+#include "wsrep_schema.h"
#include <log.h>
#include <pthread.h>
@@ -31,25 +32,20 @@ my_bool wsrep_ready_set (my_bool x);
ssize_t wsrep_sst_prepare (void** msg);
wsrep_cb_status wsrep_sst_donate_cb (void* app_ctx,
void* recv_ctx,
- const void* msg, size_t msg_len,
+ const wsrep_buf_t* msg,
const wsrep_gtid_t* state_id,
- const char* state, size_t state_len,
+ const wsrep_buf_t* state,
bool bypass);
extern wsrep_uuid_t local_uuid;
extern wsrep_seqno_t local_seqno;
+extern Wsrep_schema* wsrep_schema;
// a helper function
-bool wsrep_sst_received (wsrep_t* const wsrep,
- const wsrep_uuid_t& uuid,
- const wsrep_seqno_t seqno,
- const void* const state,
- const size_t state_len,
- const bool implicit);
-/*! 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);
+void wsrep_sst_received(THD*, const wsrep_uuid_t&, wsrep_seqno_t,
+ const void*, size_t);
+
+void wsrep_notify_status(enum wsrep::server_state::state status,
+ const wsrep::view* view= 0);
#endif /* WSREP_PRIV_H */
diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc
new file mode 100644
index 00000000000..98f17e41c94
--- /dev/null
+++ b/sql/wsrep_schema.cc
@@ -0,0 +1,1360 @@
+/* Copyright (C) 2015-2017 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 "mariadb.h"
+
+#include "table.h"
+#include "key.h"
+#include "sql_base.h"
+#include "sql_parse.h"
+#include "sql_update.h"
+#include "transaction.h"
+
+#include "mysql/service_wsrep.h"
+#include "wsrep_schema.h"
+#include "wsrep_applier.h"
+#include "wsrep_xid.h"
+#include "wsrep_binlog.h"
+#include "wsrep_high_priority_service.h"
+#include "wsrep_storage_service.h"
+
+#include <string>
+#include <sstream>
+
+#define WSREP_SCHEMA "mysql"
+#define WSREP_STREAMING_TABLE "wsrep_streaming_log"
+#define WSREP_CLUSTER_TABLE "wsrep_cluster"
+#define WSREP_MEMBERS_TABLE "wsrep_cluster_members"
+
+const char* wsrep_sr_table_name_full= WSREP_SCHEMA "/" WSREP_STREAMING_TABLE;
+
+static const std::string wsrep_schema_str= WSREP_SCHEMA;
+static const std::string sr_table_str= WSREP_STREAMING_TABLE;
+static const std::string cluster_table_str= WSREP_CLUSTER_TABLE;
+static const std::string members_table_str= WSREP_MEMBERS_TABLE;
+
+static const std::string create_cluster_table_str=
+ "CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + cluster_table_str +
+ "("
+ "cluster_uuid CHAR(36) PRIMARY KEY,"
+ "view_id BIGINT NOT NULL,"
+ "view_seqno BIGINT NOT NULL,"
+ "protocol_version INT NOT NULL,"
+ "capabilities INT NOT NULL"
+ ") ENGINE=InnoDB";
+
+static const std::string create_members_table_str=
+ "CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + members_table_str +
+ "("
+ "node_uuid CHAR(36) PRIMARY KEY,"
+ "cluster_uuid CHAR(36) NOT NULL,"
+ "node_name CHAR(32) NOT NULL,"
+ "node_incoming_address VARCHAR(256) NOT NULL"
+ ") ENGINE=InnoDB";
+
+#ifdef WSREP_SCHEMA_MEMBERS_HISTORY
+static const std::string cluster_member_history_table_str= "wsrep_cluster_member_history";
+static const std::string create_members_history_table_str=
+ "CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + cluster_member_history_table_str +
+ "("
+ "node_uuid CHAR(36) PRIMARY KEY,"
+ "cluster_uuid CHAR(36) NOT NULL,"
+ "last_view_id BIGINT NOT NULL,"
+ "last_view_seqno BIGINT NOT NULL,"
+ "node_name CHAR(32) NOT NULL,"
+ "node_incoming_address VARCHAR(256) NOT NULL"
+ ") ENGINE=InnoDB";
+#endif /* WSREP_SCHEMA_MEMBERS_HISTORY */
+
+static const std::string create_frag_table_str=
+ "CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + sr_table_str +
+ "("
+ "node_uuid CHAR(36), "
+ "trx_id BIGINT, "
+ "seqno BIGINT, "
+ "flags INT NOT NULL, "
+ "frag LONGBLOB NOT NULL, "
+ "PRIMARY KEY (node_uuid, trx_id, seqno)"
+ ") ENGINE=InnoDB";
+
+static const std::string delete_from_cluster_table=
+ "DELETE FROM " + wsrep_schema_str + "." + cluster_table_str;
+
+static const std::string delete_from_members_table=
+ "DELETE FROM " + wsrep_schema_str + "." + members_table_str;
+
+namespace Wsrep_schema_impl
+{
+
+class binlog_off
+{
+public:
+ binlog_off(THD* thd)
+ : m_thd(thd)
+ , m_option_bits(thd->variables.option_bits)
+ , m_sql_log_bin(thd->variables.sql_log_bin)
+ {
+ thd->variables.option_bits&= ~OPTION_BIN_LOG;
+ thd->variables.sql_log_bin= 0;
+ }
+ ~binlog_off()
+ {
+ m_thd->variables.option_bits= m_option_bits;
+ m_thd->variables.sql_log_bin= m_sql_log_bin;
+ }
+private:
+ THD* m_thd;
+ ulonglong m_option_bits;
+ my_bool m_sql_log_bin;
+};
+
+class wsrep_off
+{
+public:
+ wsrep_off(THD* thd)
+ : m_thd(thd)
+ , m_wsrep_on(thd->variables.wsrep_on)
+ {
+ thd->variables.wsrep_on= 0;
+ }
+ ~wsrep_off()
+ {
+ m_thd->variables.wsrep_on= m_wsrep_on;
+ }
+private:
+ THD* m_thd;
+ my_bool m_wsrep_on;
+};
+
+class thd_context_switch
+{
+public:
+ thd_context_switch(THD *orig_thd, THD *cur_thd)
+ : m_orig_thd(orig_thd)
+ , m_cur_thd(cur_thd)
+ {
+ m_orig_thd->reset_globals();
+ m_cur_thd->store_globals();
+ }
+ ~thd_context_switch()
+ {
+ m_cur_thd->reset_globals();
+ m_orig_thd->store_globals();
+ }
+private:
+ THD *m_orig_thd;
+ THD *m_cur_thd;
+};
+
+static int execute_SQL(THD* thd, const char* sql, uint length) {
+ DBUG_ENTER("Wsrep_schema::execute_SQL()");
+ int err= 0;
+
+ PSI_statement_locker *parent_locker= thd->m_statement_psi;
+ Parser_state parser_state;
+
+ WSREP_DEBUG("SQL: %d %s thd: %lld", length, sql, (long long)thd->thread_id);
+
+ if (parser_state.init(thd, (char*)sql, length) == 0) {
+ thd->reset_for_next_command();
+ lex_start(thd);
+
+ thd->m_statement_psi= NULL;
+
+ thd->set_query((char*)sql, length);
+ thd->set_query_id(next_query_id());
+
+ mysql_parse(thd, (char*)sql, length, & parser_state, FALSE, FALSE);
+
+ if (thd->is_error()) {
+ WSREP_WARN("Wsrep_schema::execute_sql() failed, %d %s\nSQL: %s",
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message(),
+ sql);
+ err= 1;
+ }
+ thd->m_statement_psi= parent_locker;
+ thd->end_statement();
+ thd->reset_query();
+ close_thread_tables(thd);
+ delete_explain_query(thd->lex);
+ }
+ else {
+ WSREP_WARN("SR init failure");
+ }
+ thd->cleanup_after_query();
+ DBUG_RETURN(err);
+}
+
+/*
+ Initialize thd for next "statement"
+ */
+static void init_stmt(THD* thd) {
+ thd->reset_for_next_command();
+}
+
+static void finish_stmt(THD* thd) {
+ trans_commit_stmt(thd);
+ close_thread_tables(thd);
+}
+
+static int open_table(THD* thd,
+ const LEX_CSTRING *schema_name,
+ const LEX_CSTRING *table_name,
+ enum thr_lock_type const lock_type,
+ TABLE** table) {
+ assert(table);
+ *table= NULL;
+
+ DBUG_ENTER("Wsrep_schema::open_table()");
+
+ TABLE_LIST tables;
+ uint flags= (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
+ MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
+ MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_LOCK_IGNORE_TIMEOUT);
+
+ tables.init_one_table(schema_name,
+ table_name,
+ NULL, lock_type);
+
+ if (!open_n_lock_single_table(thd, &tables, tables.lock_type, flags)) {
+ close_thread_tables(thd);
+ my_error(ER_NO_SUCH_TABLE, MYF(0), schema_name->str, table_name->str);
+ DBUG_RETURN(1);
+ }
+
+ *table= tables.table;
+ (*table)->use_all_columns();
+
+ DBUG_RETURN(0);
+}
+
+
+static int open_for_write(THD* thd, const char* table_name, TABLE** table) {
+ LEX_CSTRING schema_str= { wsrep_schema_str.c_str(), wsrep_schema_str.length() };
+ LEX_CSTRING table_str= { table_name, strlen(table_name) };
+ if (Wsrep_schema_impl::open_table(thd, &schema_str, &table_str, TL_WRITE,
+ table)) {
+ WSREP_ERROR("Failed to open table %s.%s for writing",
+ schema_str.str, table_name);
+ return 1;
+ }
+ empty_record(*table);
+ (*table)->use_all_columns();
+ restore_record(*table, s->default_values);
+ return 0;
+}
+
+static void store(TABLE* table, uint field, const Wsrep_id& id) {
+ assert(field < table->s->fields);
+ std::ostringstream os;
+ os << id;
+ table->field[field]->store(os.str().c_str(),
+ os.str().size(),
+ &my_charset_bin);
+}
+
+
+template <typename INTTYPE>
+static void store(TABLE* table, uint field, const INTTYPE val) {
+ assert(field < table->s->fields);
+ table->field[field]->store(val);
+}
+
+template <typename CHARTYPE>
+static void store(TABLE* table, uint field, const CHARTYPE* str, size_t str_len) {
+ assert(field < table->s->fields);
+ table->field[field]->store((const char*)str,
+ str_len,
+ &my_charset_bin);
+}
+
+static void store(TABLE* table, uint field, const std::string& str)
+{
+ store(table, field, str.c_str(), str.size());
+}
+
+static int update_or_insert(TABLE* table) {
+ DBUG_ENTER("Wsrep_schema::update_or_insert()");
+ int ret= 0;
+ char* key;
+ int error;
+
+ /*
+ Verify that the table has primary key defined.
+ */
+ if (table->s->primary_key >= MAX_KEY ||
+ !table->s->keys_in_use.is_set(table->s->primary_key)) {
+ WSREP_ERROR("No primary key for %s.%s",
+ table->s->db.str, table->s->table_name.str);
+ DBUG_RETURN(1);
+ }
+
+ /*
+ Find the record and update or insert a new one if not found.
+ */
+ if (!(key= (char*) my_safe_alloca(table->s->max_unique_length))) {
+ WSREP_ERROR("Error allocating %ud bytes for key",
+ table->s->max_unique_length);
+ DBUG_RETURN(1);
+ }
+
+ key_copy((uchar*) key, table->record[0],
+ table->key_info + table->s->primary_key, 0);
+
+ if ((error= table->file->ha_index_read_idx_map(table->record[1],
+ table->s->primary_key,
+ (uchar*) key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))) {
+ /*
+ Row not found, insert a new one.
+ */
+ if ((error= table->file->ha_write_row(table->record[0]))) {
+ WSREP_ERROR("Error writing into %s.%s: %d",
+ table->s->db.str,
+ table->s->table_name.str,
+ error);
+ ret= 1;
+ }
+ }
+ else if (!records_are_comparable(table) || compare_record(table)) {
+ /*
+ Record has changed
+ */
+ if ((error= table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME) {
+ WSREP_ERROR("Error updating record in %s.%s: %d",
+ table->s->db.str,
+ table->s->table_name.str,
+ error);
+ ret= 1;
+ }
+ }
+
+ my_safe_afree(key, table->s->max_unique_length);
+
+ DBUG_RETURN(ret);
+}
+
+static int insert(TABLE* table) {
+ DBUG_ENTER("Wsrep_schema::insert()");
+ int ret= 0;
+ int error;
+
+ /*
+ Verify that the table has primary key defined.
+ */
+ if (table->s->primary_key >= MAX_KEY ||
+ !table->s->keys_in_use.is_set(table->s->primary_key)) {
+ WSREP_ERROR("No primary key for %s.%s",
+ table->s->db.str, table->s->table_name.str);
+ DBUG_RETURN(1);
+ }
+
+ if ((error= table->file->ha_write_row(table->record[0]))) {
+ WSREP_ERROR("Error writing into %s.%s: %d",
+ table->s->db.str,
+ table->s->table_name.str,
+ error);
+ ret= 1;
+ }
+
+ DBUG_RETURN(ret);
+}
+
+static int delete_row(TABLE* table) {
+ int error;
+ int retry= 3;
+
+ do {
+ error= table->file->ha_delete_row(table->record[0]);
+ retry--;
+ } while (error && retry);
+
+ if (error) {
+ WSREP_ERROR("Error deleting row from %s.%s: %d",
+ table->s->db.str,
+ table->s->table_name.str,
+ error);
+ return 1;
+ }
+ return 0;
+}
+
+static int open_for_read(THD* thd, const char* table_name, TABLE** table) {
+
+ LEX_CSTRING schema_str= { wsrep_schema_str.c_str(), wsrep_schema_str.length() };
+ LEX_CSTRING table_str= { table_name, strlen(table_name) };
+ if (Wsrep_schema_impl::open_table(thd, &schema_str, &table_str, TL_READ,
+ table)) {
+ WSREP_ERROR("Failed to open table %s.%s for reading",
+ schema_str.str, table_name);
+ return 1;
+ }
+ empty_record(*table);
+ (*table)->use_all_columns();
+ restore_record(*table, s->default_values);
+ return 0;
+}
+
+/*
+ Init table for sequential scan.
+
+ @return 0 in case of success, 1 in case of error.
+ */
+static int init_for_scan(TABLE* table) {
+ int error;
+ if ((error= table->file->ha_rnd_init(TRUE))) {
+ WSREP_ERROR("Failed to init table for scan: %d", error);
+ return 1;
+ }
+ return 0;
+}
+/*
+ Scan next record. For return codes see handler::ha_rnd_next()
+
+ @return 0 in case of success, error code in case of error
+ */
+static int next_record(TABLE* table) {
+ int error;
+ if ((error= table->file->ha_rnd_next(table->record[0])) &&
+ error != HA_ERR_END_OF_FILE) {
+ WSREP_ERROR("Failed to read next record: %d", error);
+ }
+ return error;
+}
+
+/*
+ End scan.
+
+ @return 0 in case of success, 1 in case of error.
+ */
+static int end_scan(TABLE* table) {
+ int error;
+ if ((error= table->file->ha_rnd_end())) {
+ WSREP_ERROR("Failed to end scan: %d", error);
+ return 1;
+ }
+ return 0;
+}
+
+static int scan(TABLE* table, uint field, wsrep::id& id)
+{
+ assert(field < table->s->fields);
+ String uuid_str;
+ (void)table->field[field]->val_str(&uuid_str);
+ id= wsrep::id(std::string(uuid_str.c_ptr(), uuid_str.length()));
+ return 0;
+}
+
+template <typename INTTYPE>
+static int scan(TABLE* table, uint field, INTTYPE& val)
+{
+ assert(field < table->s->fields);
+ val= table->field[field]->val_int();
+ return 0;
+}
+
+static int scan(TABLE* table, uint field, char* strbuf, uint strbuf_len)
+{
+ String str;
+ (void)table->field[field]->val_str(&str);
+ strncpy(strbuf, str.c_ptr(), std::min(str.length(), strbuf_len));
+ strbuf[strbuf_len - 1]= '\0';
+ return 0;
+}
+
+/*
+ Scan member
+ TODO: filter members by cluster UUID
+ */
+static int scan_member(TABLE* table,
+ const Wsrep_id& cluster_uuid,
+ std::vector<Wsrep_view::member>& members)
+{
+ Wsrep_id member_id;
+ char member_name[128]= { 0, };
+ char member_incoming[128]= { 0, };
+
+ if (scan(table, 0, member_id) ||
+ scan(table, 2, member_name, sizeof(member_name)) ||
+ scan(table, 3, member_incoming, sizeof(member_incoming))) {
+ return 1;
+ }
+
+ if (members.empty() == false) {
+ assert(members.rbegin()->id() < member_id);
+ }
+
+ try {
+ members.push_back(Wsrep_view::member(member_id,
+ member_name,
+ member_incoming));
+ }
+ catch (...) {
+ WSREP_ERROR("Caught exception while scanning members table");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ Init table for index scan and retrieve first record
+
+ @return 0 in case of success, error code in case of error.
+ */
+static int init_for_index_scan(TABLE* table, const uchar* key,
+ key_part_map map) {
+ int error;
+ if ((error= table->file->ha_index_init(table->s->primary_key, true))) {
+ WSREP_ERROR("Failed to init table for index scan: %d", error);
+ return error;
+ }
+
+ error= table->file->ha_index_read_map(table->record[0],
+ key, map, HA_READ_KEY_EXACT);
+ switch(error) {
+ case 0:
+ case HA_ERR_END_OF_FILE:
+ case HA_ERR_KEY_NOT_FOUND:
+ case HA_ERR_ABORTED_BY_USER:
+ break;
+ case -1:
+ WSREP_DEBUG("init_for_index_scan interrupted");
+ break;
+ default:
+ WSREP_ERROR("init_for_index_scan failed to read first record, error %d", error);
+ }
+ return error;
+}
+
+/*
+ End index scan.
+
+ @return 0 in case of success, 1 in case of error.
+ */
+static int end_index_scan(TABLE* table) {
+ int error;
+ if ((error= table->file->ha_index_end())) {
+ WSREP_ERROR("Failed to end scan: %d", error);
+ return 1;
+ }
+ return 0;
+}
+
+static void make_key(TABLE* table, uchar* key, key_part_map* map, int parts) {
+ uint prefix_length= 0;
+ KEY_PART_INFO* key_part= table->key_info->key_part;
+ for (int i=0; i < parts; i++)
+ prefix_length += key_part[i].store_length;
+ *map= make_prev_keypart_map(parts);
+ key_copy(key, table->record[0], table->key_info, prefix_length);
+}
+} /* namespace Wsrep_schema_impl */
+
+
+Wsrep_schema::Wsrep_schema()
+{
+}
+
+Wsrep_schema::~Wsrep_schema()
+{ }
+
+static void wsrep_init_thd_for_schema(THD *thd)
+{
+ thd->security_ctx->skip_grants();
+ thd->system_thread= SYSTEM_THREAD_GENERIC;
+
+ mysql_mutex_lock(&LOCK_thread_count);
+
+ thd->real_id=pthread_self(); // Keep purify happy
+
+ WSREP_DEBUG("Wsrep_thd_pool: creating system thread: %lld",
+ (long long)thd->thread_id);
+ thd->prior_thr_create_utime= thd->start_utime= thd->thr_create_utime;
+ (void) mysql_mutex_unlock(&LOCK_thread_count);
+
+ /* */
+ thd->variables.wsrep_on = 0;
+ /* No binlogging */
+ thd->variables.sql_log_bin = 0;
+ thd->variables.option_bits &= ~OPTION_BIN_LOG;
+ /* No general log */
+ thd->variables.option_bits |= OPTION_LOG_OFF;
+ /* Read committed isolation to avoid gap locking */
+ thd->variables.tx_isolation= ISO_READ_COMMITTED;
+ thd->store_globals();
+}
+
+int Wsrep_schema::init()
+{
+ DBUG_ENTER("Wsrep_schema::init()");
+ int ret;
+ THD* thd= new THD(next_thread_id());
+ if (!thd) {
+ WSREP_ERROR("Unable to get thd");
+ DBUG_RETURN(1);
+ }
+ thd->thread_stack= (char*)&thd;
+ wsrep_init_thd_for_schema(thd);
+
+ if (Wsrep_schema_impl::execute_SQL(thd, create_cluster_table_str.c_str(),
+ create_cluster_table_str.size()) ||
+ Wsrep_schema_impl::execute_SQL(thd, create_members_table_str.c_str(),
+ create_members_table_str.size()) ||
+#ifdef WSREP_SCHEMA_MEMBERS_HISTORY
+ Wsrep_schema_impl::execute_SQL(thd,
+ create_members_history_table_str.c_str(),
+ create_members_history_table_str.size()) ||
+#endif /* WSREP_SCHEMA_MEMBERS_HISTORY */
+ Wsrep_schema_impl::execute_SQL(thd,
+ create_frag_table_str.c_str(),
+ create_frag_table_str.size())) {
+ ret= 1;
+ }
+ else {
+ ret= 0;
+ }
+
+ delete thd;
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_schema::store_view(THD* thd, const Wsrep_view& view)
+{
+ DBUG_ENTER("Wsrep_schema::store_view()");
+ assert(view.status() == Wsrep_view::primary);
+ int ret= 1;
+ int error;
+ TABLE* cluster_table= 0;
+ TABLE* members_table= 0;
+#ifdef WSREP_SCHEMA_MEMBERS_HISTORY
+ TABLE* members_history_table= 0;
+#endif /* WSREP_SCHEMA_MEMBERS_HISTORY */
+
+ Wsrep_schema_impl::wsrep_off wsrep_off(thd);
+ Wsrep_schema_impl::binlog_off binlog_off(thd);
+
+ /*
+ Clean up cluster table and members table.
+ */
+ if (Wsrep_schema_impl::execute_SQL(thd,
+ delete_from_cluster_table.c_str(),
+ delete_from_cluster_table.size()) ||
+ Wsrep_schema_impl::execute_SQL(thd,
+ delete_from_members_table.c_str(),
+ delete_from_members_table.size())) {
+ goto out;
+ }
+
+ /*
+ Store cluster view info
+ */
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_write(thd, cluster_table_str.c_str(), &cluster_table))
+ {
+ goto out;
+ }
+
+ Wsrep_schema_impl::store(cluster_table, 0, view.state_id().id());
+ Wsrep_schema_impl::store(cluster_table, 1, view.view_seqno().get());
+ Wsrep_schema_impl::store(cluster_table, 2, view.state_id().seqno().get());
+ Wsrep_schema_impl::store(cluster_table, 3, view.protocol_version());
+ Wsrep_schema_impl::store(cluster_table, 4, view.capabilities());
+
+ if ((error= Wsrep_schema_impl::update_or_insert(cluster_table)))
+ {
+ WSREP_ERROR("failed to write to cluster table: %d", error);
+ goto out;
+ }
+
+ Wsrep_schema_impl::finish_stmt(thd);
+
+ /*
+ Store info about current members
+ */
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_write(thd, members_table_str.c_str(),
+ &members_table))
+ {
+ WSREP_ERROR("failed to open wsrep.members table");
+ goto out;
+ }
+
+ for (size_t i= 0; i < view.members().size(); ++i)
+ {
+ Wsrep_schema_impl::store(members_table, 0, view.members()[i].id());
+ Wsrep_schema_impl::store(members_table, 1, view.state_id().id());
+ Wsrep_schema_impl::store(members_table, 2, view.members()[i].name());
+ Wsrep_schema_impl::store(members_table, 3, view.members()[i].incoming());
+ if ((error= Wsrep_schema_impl::update_or_insert(members_table)))
+ {
+ WSREP_ERROR("failed to write wsrep.members table: %d", error);
+ goto out;
+ }
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+
+#ifdef WSREP_SCHEMA_MEMBERS_HISTORY
+ /*
+ Store members history
+ */
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_write(thd, cluster_member_history.c_str(),
+ &members_history_table)) {
+ WSREP_ERROR("failed to open wsrep.members table");
+ goto out;
+ }
+
+ for (size_t i= 0; i < view.members().size(); ++i) {
+ Wsrep_schema_impl::store(members_history_table, 0, view.members()[i].id());
+ Wsrep_schema_impl::store(members_history_table, 1, view.state_id().id());
+ Wsrep_schema_impl::store(members_history_table, 2, view.view_seqno());
+ Wsrep_schema_impl::store(members_history_table, 3, view.state_id().seqno());
+ Wsrep_schema_impl::store(members_history_table, 4,
+ view.members()[i].name());
+ Wsrep_schema_impl::store(members_history_table, 5,
+ view.members()[i].incoming());
+ if ((error= Wsrep_schema_impl::update_or_insert(members_history_table))) {
+ WSREP_ERROR("failed to write wsrep_cluster_member_history table: %d", error);
+ goto out;
+ }
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+#endif /* WSREP_SCHEMA_MEMBERS_HISTORY */
+ ret= 0;
+ out:
+
+ DBUG_RETURN(ret);
+}
+
+Wsrep_view Wsrep_schema::restore_view(THD* thd, const Wsrep_id& own_id) const {
+ DBUG_ENTER("Wsrep_schema::restore_view()");
+
+ int ret= 1;
+ int error;
+
+ TABLE* cluster_table= 0;
+ bool end_cluster_scan= false;
+ TABLE* members_table= 0;
+ bool end_members_scan= false;
+
+ /* variables below need to be initialized in case cluster table is empty */
+ Wsrep_id cluster_uuid;
+ wsrep_seqno_t view_id= -1;
+ wsrep_seqno_t view_seqno= -1;
+ int my_idx= -1;
+ int proto_ver= 0;
+ wsrep_cap_t capabilities= 0;
+ std::vector<Wsrep_view::member> members;
+
+ // we don't want causal waits for reading non-replicated private data
+ int const wsrep_sync_wait_saved= thd->variables.wsrep_sync_wait;
+ thd->variables.wsrep_sync_wait= 0;
+
+ if (trans_begin(thd, MYSQL_START_TRANS_OPT_READ_ONLY)) {
+ WSREP_ERROR("wsrep_schema::restore_view(): Failed to start transaction");
+ goto out;
+ }
+
+ /*
+ Read cluster info from cluster table
+ */
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_read(thd, cluster_table_str.c_str(), &cluster_table) ||
+ Wsrep_schema_impl::init_for_scan(cluster_table)) {
+ goto out;
+ }
+
+ if (((error= Wsrep_schema_impl::next_record(cluster_table)) != 0 ||
+ Wsrep_schema_impl::scan(cluster_table, 0, cluster_uuid) ||
+ Wsrep_schema_impl::scan(cluster_table, 1, view_id) ||
+ Wsrep_schema_impl::scan(cluster_table, 2, view_seqno) ||
+ Wsrep_schema_impl::scan(cluster_table, 3, proto_ver) ||
+ Wsrep_schema_impl::scan(cluster_table, 4, capabilities)) &&
+ error != HA_ERR_END_OF_FILE) {
+ end_cluster_scan= true;
+ goto out;
+ }
+
+ if (Wsrep_schema_impl::end_scan(cluster_table)) {
+ goto out;
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+
+ /*
+ Read members from members table
+ */
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_read(thd, members_table_str.c_str(), &members_table) ||
+ Wsrep_schema_impl::init_for_scan(members_table)) {
+ goto out;
+ }
+ end_members_scan= true;
+
+ while (true) {
+ if ((error= Wsrep_schema_impl::next_record(members_table)) == 0) {
+ if (Wsrep_schema_impl::scan_member(members_table,
+ cluster_uuid,
+ members)) {
+ goto out;
+ }
+ }
+ else if (error == HA_ERR_END_OF_FILE) {
+ break;
+ }
+ else {
+ goto out;
+ }
+ }
+
+ end_members_scan= false;
+ if (Wsrep_schema_impl::end_scan(members_table)) {
+ goto out;
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+
+ if (own_id.is_undefined() == false) {
+ for (uint i= 0; i < members.size(); ++i) {
+ if (members[i].id() == own_id) {
+ my_idx= i;
+ break;
+ }
+ }
+ }
+
+ (void)trans_commit(thd);
+ ret= 0; /* Success*/
+ out:
+
+ if (end_cluster_scan) Wsrep_schema_impl::end_scan(cluster_table);
+ if (end_members_scan) Wsrep_schema_impl::end_scan(members_table);
+
+ if (0 != ret) {
+ trans_rollback_stmt(thd);
+ if (!trans_rollback(thd)) {
+ close_thread_tables(thd);
+ }
+ }
+ thd->mdl_context.release_transactional_locks();
+
+ thd->variables.wsrep_sync_wait= wsrep_sync_wait_saved;
+
+ if (0 == ret) {
+ Wsrep_view ret_view(
+ wsrep::gtid(cluster_uuid, Wsrep_seqno(view_seqno)),
+ Wsrep_seqno(view_id),
+ wsrep::view::primary,
+ capabilities,
+ my_idx,
+ proto_ver,
+ members
+ );
+
+ if (wsrep_debug) {
+ std::ostringstream os;
+ os << "Restored cluster view:\n" << ret_view;
+ WSREP_INFO("%s", os.str().c_str());
+ }
+ DBUG_RETURN(ret_view);
+ }
+ else
+ {
+ WSREP_ERROR("wsrep_schema::restore_view() failed.");
+ Wsrep_view ret_view;
+ DBUG_RETURN(ret_view);
+ }
+}
+
+int Wsrep_schema::append_fragment(THD* thd,
+ const wsrep::id& server_id,
+ wsrep::transaction_id transaction_id,
+ wsrep::seqno seqno,
+ int flags,
+ const wsrep::const_buffer& data)
+{
+ DBUG_ENTER("Wsrep_schema::append_fragment");
+ std::ostringstream os;
+ os << server_id;
+ WSREP_DEBUG("Append fragment(%llu) %s, %llu",
+ thd->thread_id,
+ os.str().c_str(),
+ transaction_id.get());
+ Wsrep_schema_impl::binlog_off binlog_off(thd);
+ Wsrep_schema_impl::init_stmt(thd);
+
+ TABLE* frag_table= 0;
+ if (Wsrep_schema_impl::open_for_write(thd, sr_table_str.c_str(), &frag_table))
+ {
+ trans_rollback_stmt(thd);
+ DBUG_RETURN(1);
+ }
+
+ Wsrep_schema_impl::store(frag_table, 0, server_id);
+ Wsrep_schema_impl::store(frag_table, 1, transaction_id.get());
+ Wsrep_schema_impl::store(frag_table, 2, seqno.get());
+ Wsrep_schema_impl::store(frag_table, 3, flags);
+ Wsrep_schema_impl::store(frag_table, 4, data.data(), data.size());
+
+ int error;
+ if ((error= Wsrep_schema_impl::insert(frag_table))) {
+ WSREP_ERROR("Failed to write to frag table: %d", error);
+ trans_rollback_stmt(thd);
+ DBUG_RETURN(1);
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+ DBUG_RETURN(0);
+}
+
+int Wsrep_schema::update_fragment_meta(THD* thd,
+ const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_schema::update_fragment_meta");
+ std::ostringstream os;
+ os << ws_meta.server_id();
+ WSREP_DEBUG("update_frag_seqno(%llu) %s, %llu, seqno %lld",
+ thd->thread_id,
+ os.str().c_str(),
+ ws_meta.transaction_id().get(),
+ ws_meta.seqno().get());
+ DBUG_ASSERT(ws_meta.seqno().is_undefined() == false);
+
+ Wsrep_schema_impl::binlog_off binlog_off(thd);
+ int error;
+ uchar key[MAX_KEY_LENGTH];
+ key_part_map key_map= 0;
+ TABLE* frag_table= 0;
+
+ Wsrep_schema_impl::init_stmt(thd);
+ if (Wsrep_schema_impl::open_for_write(thd, sr_table_str.c_str(), &frag_table))
+ {
+ DBUG_RETURN(1);
+ }
+
+ /* Find record with the given uuid, trx id, and seqno -1 */
+ Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id());
+ Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get());
+ Wsrep_schema_impl::store(frag_table, 2, -1);
+ Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3);
+
+ if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table,
+ key, key_map)))
+ {
+ if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND)
+ {
+ WSREP_WARN("Record not found in %s.%s: %d",
+ frag_table->s->db.str,
+ frag_table->s->table_name.str,
+ error);
+ }
+ Wsrep_schema_impl::finish_stmt(thd);
+ DBUG_RETURN(1);
+ }
+
+ /* Copy the original record to frag_table->record[1] */
+ store_record(frag_table, record[1]);
+
+ /* Store seqno in frag_table->record[0] and update the row */
+ Wsrep_schema_impl::store(frag_table, 2, ws_meta.seqno().get());
+ if ((error= frag_table->file->ha_update_row(frag_table->record[1],
+ frag_table->record[0]))) {
+ WSREP_ERROR("Error updating record in %s.%s: %d",
+ frag_table->s->db.str,
+ frag_table->s->table_name.str,
+ error);
+ Wsrep_schema_impl::finish_stmt(thd);
+ DBUG_RETURN(1);
+ }
+
+ int ret= Wsrep_schema_impl::end_index_scan(frag_table);
+ Wsrep_schema_impl::finish_stmt(thd);
+ DBUG_RETURN(ret);
+}
+
+static int remove_fragment(THD* thd,
+ TABLE* frag_table,
+ const wsrep::id& server_id,
+ wsrep::transaction_id transaction_id,
+ wsrep::seqno seqno)
+{
+ WSREP_DEBUG("remove_fragment(%llu) trx %llu, seqno %lld",
+ thd->thread_id,
+ transaction_id.get(),
+ seqno.get());
+ int ret= 0;
+ int error;
+ uchar key[MAX_KEY_LENGTH];
+ key_part_map key_map= 0;
+
+ DBUG_ASSERT(server_id.is_undefined() == false);
+ DBUG_ASSERT(transaction_id.is_undefined() == false);
+ DBUG_ASSERT(seqno.is_undefined() == false);
+
+ /*
+ Remove record with the given uuid, trx id, and seqno.
+ Using a complete key here avoids gap locks.
+ */
+ Wsrep_schema_impl::store(frag_table, 0, server_id);
+ Wsrep_schema_impl::store(frag_table, 1, transaction_id.get());
+ Wsrep_schema_impl::store(frag_table, 2, seqno.get());
+ Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3);
+
+ if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table,
+ key,
+ key_map)))
+ {
+ if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND)
+ {
+ WSREP_DEBUG("Record not found in %s.%s:trx %llu, seqno %lld, error %d",
+ frag_table->s->db.str,
+ frag_table->s->table_name.str,
+ transaction_id.get(),
+ seqno.get(),
+ error);
+ }
+ ret= error;
+ }
+ else if (Wsrep_schema_impl::delete_row(frag_table))
+ {
+ ret= 1;
+ }
+
+ Wsrep_schema_impl::end_index_scan(frag_table);
+ return ret;
+}
+
+int Wsrep_schema::remove_fragments(THD* thd,
+ const wsrep::id& server_id,
+ wsrep::transaction_id transaction_id,
+ const std::vector<wsrep::seqno>& fragments)
+{
+ DBUG_ENTER("Wsrep_schema::remove_fragments");
+ int ret= 0;
+
+ WSREP_DEBUG("Removing %zu fragments", fragments.size());
+ Wsrep_schema_impl::wsrep_off wsrep_off(thd);
+ Wsrep_schema_impl::binlog_off binlog_off(thd);
+
+ /*
+ Open SR table for write.
+ Adopted from Rpl_info_table_access::open_table()
+ */
+ uint flags= (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
+ MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
+ MYSQL_OPEN_IGNORE_FLUSH |
+ MYSQL_LOCK_IGNORE_TIMEOUT);
+ Query_tables_list query_tables_list_backup;
+ Open_tables_backup open_tables_backup;
+ thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
+ thd->reset_n_backup_open_tables_state(&open_tables_backup);
+ TABLE_LIST tables;
+ LEX_CSTRING schema_str= { wsrep_schema_str.c_str(), wsrep_schema_str.length() };
+ LEX_CSTRING table_str= { sr_table_str.c_str(), sr_table_str.length() };
+ tables.init_one_table(&schema_str,
+ &table_str, 0, TL_WRITE);
+
+ if (!open_n_lock_single_table(thd, &tables, tables.lock_type, flags))
+ {
+ WSREP_DEBUG("Failed to open SR table for access");
+ ret= 1;
+ }
+ else
+ {
+ tables.table->use_all_columns();
+ for (std::vector<wsrep::seqno>::const_iterator i= fragments.begin();
+ i != fragments.end(); ++i)
+ {
+ if (remove_fragment(thd,
+ tables.table,
+ server_id,
+ transaction_id, *i))
+ {
+ ret= 1;
+ break;
+ }
+ }
+ }
+ close_thread_tables(thd);
+ thd->restore_backup_open_tables_state(&open_tables_backup);
+ thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
+
+ if (thd->wsrep_cs().mode() == wsrep::client_state::m_local &&
+ !thd->in_multi_stmt_transaction_mode())
+ {
+ /*
+ The ugly part: Locally executing autocommit statement is
+ committing and it has removed a fragment from stable storage.
+ Now calling finish_stmt() will call trans_commit_stmt(), which will
+ actually commit the transaction, what we really don't want
+ to do at this point.
+
+ Doing nothing at this point seems to work ok, this block is
+ intentionally no-op and for documentation purposes only.
+ */
+ }
+ else
+ {
+ Wsrep_schema_impl::finish_stmt(thd);
+ }
+
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_schema::replay_transaction(THD* thd,
+ Relay_log_info* rli,
+ const wsrep::ws_meta& ws_meta,
+ const std::vector<wsrep::seqno>& fragments)
+{
+ DBUG_ENTER("Wsrep_schema::replay_transaction");
+ DBUG_ASSERT(!fragments.empty());
+
+ Wsrep_schema_impl::wsrep_off wsrep_off(thd);
+ Wsrep_schema_impl::binlog_off binlog_off(thd);
+
+ int ret= 1;
+ int error;
+ TABLE* frag_table= 0;
+ uchar key[MAX_KEY_LENGTH];
+ key_part_map key_map= 0;
+
+ for (std::vector<wsrep::seqno>::const_iterator i= fragments.begin();
+ i != fragments.end(); ++i)
+ {
+ Wsrep_schema_impl::init_stmt(thd);
+ if ((error= Wsrep_schema_impl::open_for_read(thd, sr_table_str.c_str(), &frag_table)))
+ {
+ WSREP_WARN("Could not open SR table for read: %d", error);
+ Wsrep_schema_impl::finish_stmt(thd);
+ DBUG_RETURN(1);
+ }
+
+ Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id());
+ Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get());
+ Wsrep_schema_impl::store(frag_table, 2, i->get());
+ Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3);
+
+ int error= Wsrep_schema_impl::init_for_index_scan(frag_table,
+ key,
+ key_map);
+ if (error)
+ {
+ WSREP_WARN("Failed to init streaming log table for index scan: %d",
+ error);
+ Wsrep_schema_impl::end_index_scan(frag_table);
+ ret= 1;
+ break;
+ }
+
+ int flags;
+ Wsrep_schema_impl::scan(frag_table, 3, flags);
+ WSREP_DEBUG("replay_fragment(%llu): seqno: %lld flags: %x",
+ ws_meta.transaction_id().get(),
+ i->get(),
+ flags);
+ String buf;
+ frag_table->field[4]->val_str(&buf);
+
+ Wsrep_schema_impl::end_index_scan(frag_table);
+ Wsrep_schema_impl::finish_stmt(thd);
+ ret= wsrep_apply_events(thd, rli, buf.c_ptr_safe(), buf.length());
+ if (ret)
+ {
+ WSREP_WARN("Wsrep_schema::replay_transaction: failed to apply fragments");
+ break;
+ }
+ Wsrep_schema_impl::init_stmt(thd);
+
+ if ((error= Wsrep_schema_impl::open_for_write(thd, sr_table_str.c_str(), &frag_table)))
+ {
+ WSREP_WARN("Could not open SR table for write: %d", error);
+ Wsrep_schema_impl::finish_stmt(thd);
+ DBUG_RETURN(1);
+ }
+ error= Wsrep_schema_impl::init_for_index_scan(frag_table,
+ key,
+ key_map);
+ if (error)
+ {
+ WSREP_WARN("Failed to init streaming log table for index scan: %d",
+ error);
+ Wsrep_schema_impl::end_index_scan(frag_table);
+ ret= 1;
+ break;
+ }
+
+ error= Wsrep_schema_impl::delete_row(frag_table);
+ if (error)
+ {
+ WSREP_WARN("Could not delete row from streaming log table: %d", error);
+ Wsrep_schema_impl::end_index_scan(frag_table);
+ ret= 1;
+ break;
+ }
+ Wsrep_schema_impl::end_index_scan(frag_table);
+ Wsrep_schema_impl::finish_stmt(thd);
+ }
+
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_schema::recover_sr_transactions(THD *orig_thd)
+{
+ DBUG_ENTER("Wsrep_schema::recover_sr_transactions");
+ THD storage_thd(true, true);
+ storage_thd.thread_stack= (orig_thd ? orig_thd->thread_stack :
+ (char*) &storage_thd);
+ TABLE* frag_table= 0;
+ TABLE* cluster_table= 0;
+ Wsrep_storage_service storage_service(&storage_thd);
+ Wsrep_schema_impl::binlog_off binlog_off(&storage_thd);
+ Wsrep_schema_impl::wsrep_off binglog_off(&storage_thd);
+ Wsrep_schema_impl::thd_context_switch thd_context_switch(orig_thd,
+ &storage_thd);
+ Wsrep_server_state& server_state(Wsrep_server_state::instance());
+
+ int ret= 1;
+ int error;
+ wsrep::id cluster_id;
+
+ Wsrep_schema_impl::init_stmt(&storage_thd);
+ storage_thd.wsrep_skip_locking= FALSE;
+ /*
+ Open the table for reading and writing so that fragments without
+ valid seqno can be deleted.
+ */
+ if (Wsrep_schema_impl::open_for_write(&storage_thd,
+ cluster_table_str.c_str(),
+ &cluster_table) ||
+ Wsrep_schema_impl::init_for_scan(cluster_table))
+ {
+ Wsrep_schema_impl::finish_stmt(&storage_thd);
+ DBUG_RETURN(1);
+ }
+
+ if ((error= Wsrep_schema_impl::next_record(cluster_table)))
+ {
+ Wsrep_schema_impl::end_scan(cluster_table);
+ Wsrep_schema_impl::finish_stmt(&storage_thd);
+ trans_commit(&storage_thd);
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ WSREP_INFO("Cluster table is empty, not recovering transactions");
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ WSREP_ERROR("Failed to read cluster table: %d", error);
+ DBUG_RETURN(1);
+ }
+ }
+
+ Wsrep_schema_impl::scan(cluster_table, 0, cluster_id);
+ Wsrep_schema_impl::end_scan(cluster_table);
+ Wsrep_schema_impl::finish_stmt(&storage_thd);
+
+ std::ostringstream os;
+ os << cluster_id;
+ WSREP_INFO("Recovered cluster id %s", os.str().c_str());
+
+ storage_thd.wsrep_skip_locking= TRUE;
+ Wsrep_schema_impl::init_stmt(&storage_thd);
+ if (Wsrep_schema_impl::open_for_read(&storage_thd, sr_table_str.c_str(), &frag_table) ||
+ Wsrep_schema_impl::init_for_scan(frag_table))
+ {
+ WSREP_ERROR("Failed to open SR table for read");
+ goto out;
+ }
+
+ while (true)
+ {
+ if ((error= Wsrep_schema_impl::next_record(frag_table)) == 0)
+ {
+ wsrep::id server_id;
+ Wsrep_schema_impl::scan(frag_table, 0, server_id);
+ wsrep::client_id client_id;
+ unsigned long long transaction_id_ull;
+ Wsrep_schema_impl::scan(frag_table, 1, transaction_id_ull);
+ wsrep::transaction_id transaction_id(transaction_id_ull);
+ long long seqno_ll;
+ Wsrep_schema_impl::scan(frag_table, 2, seqno_ll);
+ wsrep::seqno seqno(seqno_ll);
+
+ /* This is possible if the server crashes between inserting the
+ fragment into table and updating the fragment seqno after
+ certification. */
+ if (seqno.is_undefined())
+ {
+ Wsrep_schema_impl::delete_row(frag_table);
+ continue;
+ }
+
+ wsrep::gtid gtid(cluster_id, seqno);
+ int flags;
+ Wsrep_schema_impl::scan(frag_table, 3, flags);
+ String data_str;
+
+ (void)frag_table->field[4]->val_str(&data_str);
+ wsrep::const_buffer data(data_str.c_ptr(), data_str.length());
+ wsrep::ws_meta ws_meta(gtid,
+ wsrep::stid(server_id,
+ transaction_id,
+ client_id),
+ wsrep::seqno::undefined(),
+ flags);
+
+ wsrep::high_priority_service* applier;
+ if (!(applier= server_state.find_streaming_applier(server_id,
+ transaction_id)))
+ {
+ DBUG_ASSERT(wsrep::starts_transaction(flags));
+ THD* thd= new THD(true, true);
+ thd->thread_stack= (char*)&storage_thd;
+
+ mysql_mutex_lock(&LOCK_thread_count);
+ thd->thread_id= next_thread_id();
+ thd->real_id= pthread_self();
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ applier= new Wsrep_applier_service(thd);
+ server_state.start_streaming_applier(server_id, transaction_id,
+ applier);
+ applier->start_transaction(wsrep::ws_handle(transaction_id, 0),
+ ws_meta);
+ }
+ applier->store_globals();
+ applier->apply_write_set(ws_meta, data);
+ applier->after_apply();
+ storage_service.store_globals();
+ }
+ else if (error == HA_ERR_END_OF_FILE)
+ {
+ ret= 0;
+ break;
+ }
+ else
+ {
+ WSREP_ERROR("SR table scan returned error %d", error);
+ break;
+ }
+ }
+ Wsrep_schema_impl::end_scan(frag_table);
+ Wsrep_schema_impl::finish_stmt(&storage_thd);
+ trans_commit(&storage_thd);
+out:
+ DBUG_RETURN(ret);
+}
diff --git a/sql/wsrep_schema.h b/sql/wsrep_schema.h
new file mode 100644
index 00000000000..fb5eaa8931f
--- /dev/null
+++ b/sql/wsrep_schema.h
@@ -0,0 +1,161 @@
+/* Copyright (C) 2015-2018 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_SCHEMA_H
+#define WSREP_SCHEMA_H
+
+/* wsrep-lib */
+#include "wsrep_types.h"
+
+
+#include "mysqld.h"
+#include "thr_lock.h" /* enum thr_lock_type */
+#include "wsrep_mysqld.h"
+
+#include <string>
+
+/*
+ Forward decls
+*/
+class THD;
+class Relay_log_info;
+struct TABLE;
+struct TABLE_LIST;
+struct st_mysql_lex_string;
+typedef struct st_mysql_lex_string LEX_STRING;
+
+/** Name of the table in `wsrep_schema_str` used for storing streaming
+replication data. In an InnoDB full format, e.g. "database/tablename". */
+extern const char* wsrep_sr_table_name_full;
+
+class Wsrep_schema
+{
+ public:
+
+ Wsrep_schema();
+ ~Wsrep_schema();
+
+ /*
+ Initialize wsrep schema. Storage engines must be running before
+ calling this function.
+ */
+ int init();
+
+ /*
+ Store wsrep view info into wsrep schema.
+ */
+ int store_view(THD*, const Wsrep_view& view);
+
+ /*
+ Restore view info from stable storage.
+ */
+ Wsrep_view restore_view(THD* thd, const Wsrep_id& own_id) const;
+
+ /*
+ Append transaction fragment to fragment storage.
+ Starts a trx using a THD from thd_pool, does not commit.
+ Should be followed by a call to update_frag_seqno(), or
+ release_SR_thd() if wsrep->certify() fails.
+ */
+ THD* append_frag(const wsrep_trx_meta_t&, uint32_t,
+ const unsigned char*, size_t);
+ /**
+ Append transaction fragment to fragment storage.
+ Transaction must have been started for THD before this call.
+ In order to make changes durable, transaction must be committed
+ separately after this call.
+
+ @param thd THD object
+ @param server_id Wsrep server identifier
+ @param transaction_id Transaction identifier
+ @param flags Flags for the fragment
+ @param data Fragment data buffer
+
+ @return Zero in case of success, non-zero on failure.
+ */
+ int append_fragment(THD* thd,
+ const wsrep::id& server_id,
+ wsrep::transaction_id transaction_id,
+ wsrep::seqno seqno,
+ int flags,
+ const wsrep::const_buffer& data);
+ /**
+ Update existing fragment meta data. The fragment must have been
+ inserted before using append_fragment().
+
+ @param thd THD object
+ @param ws_meta Wsrep meta data
+
+ @return Zero in case of success, non-zero on failure.
+ */
+ int update_fragment_meta(THD* thd,
+ const wsrep::ws_meta& ws_meta);
+
+ /**
+ Remove fragments from storage. This method must be called
+ inside active transaction. Fragment removal will be committed
+ once the transaction commits.
+
+ @param thd Pointer to THD object
+ @param server_id Identifier of the running server
+ @param transaction_id Identifier of the current transaction
+ @param fragments Vector of fragment seqnos to be removed
+ */
+ int remove_fragments(THD* thd,
+ const wsrep::id& server_id,
+ wsrep::transaction_id transaction_id,
+ const std::vector<wsrep::seqno>& fragments);
+
+ /**
+ Replay a transaction from stored fragments. The caller must have
+ started a transaction for a thd.
+
+ @param thd Pointer to THD object
+ @param ws_meta Write set meta data for commit fragment.
+ @param fragments Vector of fragments to be replayed
+
+ @return Zero on success, non-zero on failure.
+ */
+ int replay_transaction(THD* thd,
+ Relay_log_info* rli,
+ const wsrep::ws_meta& ws_meta,
+ const std::vector<wsrep::seqno>& fragments);
+
+ /**
+ Recover streaming transactions from SR table.
+ This method should be called after storage enignes are initialized.
+ It will scan SR table and replay found streaming transactions.
+
+ @param orig_thd The THD object of the calling thread.
+
+ @return Zero on success, non-zero on failure.
+ */
+ int recover_sr_transactions(THD* orig_thd);
+
+ /*
+ Close wsrep schema.
+ */
+ void close();
+
+ private:
+ /* Non-copyable */
+ Wsrep_schema(const Wsrep_schema&);
+ Wsrep_schema& operator=(const Wsrep_schema&);
+};
+
+extern Wsrep_schema* wsrep_schema;
+
+#endif /* !WSREP_SCHEMA_H */
diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc
new file mode 100644
index 00000000000..7efff35f2b1
--- /dev/null
+++ b/sql/wsrep_server_service.cc
@@ -0,0 +1,318 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "my_global.h"
+#include "wsrep_server_service.h"
+#include "wsrep_server_state.h"
+#include "wsrep_client_state.h"
+#include "wsrep_client_service.h"
+#include "wsrep_storage_service.h"
+#include "wsrep_high_priority_service.h"
+
+#include "wsrep_sst.h"
+#include "wsrep_xid.h"
+#include "wsrep_mysqld.h"
+#include "wsrep_schema.h"
+#include "wsrep_utils.h"
+
+#include "log.h" /* sql_print_xxx() */
+#include "sql_class.h" /* system variables */
+#include "transaction.h" /* trans_xxx */
+#include "sql_base.h" /* close_thread_tables */
+
+static void init_service_thd(THD* thd, char* thread_stack)
+{
+ thd->thread_stack= thread_stack;
+ thd->real_id= pthread_self();
+ thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer();
+ thd->set_command(COM_SLEEP);
+ thd->reset_for_next_command(true);
+}
+
+wsrep::storage_service* Wsrep_server_service::storage_service(
+ wsrep::client_service& client_service)
+{
+ Wsrep_client_service& cs=
+ static_cast<Wsrep_client_service&>(client_service);
+ THD* thd= new THD(next_thread_id(), true, true);
+ init_service_thd(thd, cs.m_thd->thread_stack);
+ WSREP_DEBUG("Created storage service with thread id %llu",
+ thd->thread_id);
+ return new Wsrep_storage_service(thd);
+}
+
+wsrep::storage_service* Wsrep_server_service::storage_service(
+ wsrep::high_priority_service& high_priority_service)
+{
+ Wsrep_high_priority_service& hps=
+ static_cast<Wsrep_high_priority_service&>(high_priority_service);
+ THD* thd= new THD(next_thread_id(), true, true);
+ init_service_thd(thd, hps.m_thd->thread_stack);
+ WSREP_DEBUG("Created high priority storage service with thread id %llu",
+ thd->thread_id);
+ return new Wsrep_storage_service(thd);
+}
+
+void Wsrep_server_service::release_storage_service(
+ wsrep::storage_service* storage_service)
+{
+ Wsrep_storage_service* ss=
+ static_cast<Wsrep_storage_service*>(storage_service);
+ THD* thd= ss->m_thd;
+ delete ss;
+ delete thd;
+}
+
+wsrep::high_priority_service*
+Wsrep_server_service::streaming_applier_service(
+ wsrep::client_service& orig_client_service)
+{
+ Wsrep_client_service& orig_cs=
+ static_cast<Wsrep_client_service&>(orig_client_service);
+ THD* thd= new THD(next_thread_id(), true, true);
+ init_service_thd(thd, orig_cs.m_thd->thread_stack);
+ WSREP_DEBUG("Created streaming applier service in local context with "
+ "thread id %llu", thd->thread_id);
+ return new Wsrep_applier_service(thd);
+}
+
+wsrep::high_priority_service*
+Wsrep_server_service::streaming_applier_service(
+ wsrep::high_priority_service& orig_high_priority_service)
+{
+ Wsrep_high_priority_service&
+ orig_hps(static_cast<Wsrep_high_priority_service&>(orig_high_priority_service));
+ THD* thd= new THD(next_thread_id(), true, true);
+ init_service_thd(thd, orig_hps.m_thd->thread_stack);
+ WSREP_DEBUG("Created streaming applier service in high priority "
+ "context with thread id %llu", thd->thread_id);
+ return new Wsrep_applier_service(thd);
+}
+
+void Wsrep_server_service::release_high_priority_service(wsrep::high_priority_service* high_priority_service)
+{
+ Wsrep_high_priority_service* hps=
+ static_cast<Wsrep_high_priority_service*>(high_priority_service);
+ THD* thd= hps->m_thd;
+ delete hps;
+ delete thd;
+}
+
+void Wsrep_server_service::background_rollback(wsrep::client_state& client_state)
+{
+ Wsrep_client_state& cs= static_cast<Wsrep_client_state&>(client_state);
+ wsrep_fire_rollbacker(cs.thd());
+}
+
+void Wsrep_server_service::bootstrap()
+{
+ wsrep::log_info()
+ << "Bootstrapping a new cluster, setting initial position to "
+ << wsrep::gtid::undefined();
+ wsrep_set_SE_checkpoint(wsrep::gtid::undefined());
+}
+
+void Wsrep_server_service::log_message(enum wsrep::log::level level,
+ const char* message)
+{
+ switch (level)
+ {
+ case wsrep::log::debug:
+ sql_print_information("debug: %s", message);
+ break;
+ case wsrep::log::info:
+ sql_print_information("%s", message);
+ break;
+ case wsrep::log::warning:
+ sql_print_warning("%s", message);
+ break;
+ case wsrep::log::error:
+ sql_print_error("%s", message);
+ break;
+ }
+}
+
+void Wsrep_server_service::log_view(
+ wsrep::high_priority_service* high_priority_service,
+ const wsrep::view& view)
+{
+ Wsrep_high_priority_service* applier=
+ static_cast<Wsrep_high_priority_service*>(high_priority_service);
+ /* Update global system variables */
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ if (wsrep_auto_increment_control && view.own_index() >= 0)
+ {
+ global_system_variables.auto_increment_offset= view.own_index() + 1;
+ global_system_variables.auto_increment_increment= view.members().size();
+ wsrep_protocol_version= view.protocol_version();
+ }
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+
+ /* Update wsrep status variables */
+ mysql_mutex_lock(&LOCK_status);
+ wsrep_cluster_size= view.members().size();
+ wsrep_local_index= view.own_index();
+ std::ostringstream os;
+ os << view.state_id().id();
+ wsrep_update_cluster_state_uuid(os.str().c_str());
+ mysql_mutex_unlock(&LOCK_status);
+ wsrep_config_state->set(view);
+
+ if (view.status() == wsrep::view::primary)
+ {
+ if (applier)
+ {
+ Wsrep_id id;
+ Wsrep_view prev_view= wsrep_schema->restore_view(applier->m_thd, id);
+ if (prev_view.state_id().id() != view.state_id().id())
+ {
+ WSREP_DEBUG("New cluster UUID was generated, resetting position info");
+ wsrep_set_SE_checkpoint(wsrep::gtid::undefined());
+ }
+
+ if (wsrep_debug)
+ {
+ std::ostringstream os;
+ os << "Storing cluster view:\n" << view;
+ WSREP_INFO("%s", os.str().c_str());
+ DBUG_ASSERT(prev_view.state_id().id() != view.state_id().id() ||
+ view.state_id().seqno() > prev_view.state_id().seqno());
+ }
+
+ if (trans_begin(applier->m_thd, MYSQL_START_TRANS_OPT_READ_WRITE))
+ {
+ WSREP_WARN("Failed to start transaction for store view");
+ }
+ else
+ {
+ if (wsrep_schema->store_view(applier->m_thd, view))
+ {
+ WSREP_WARN("Failed to store view");
+ trans_rollback_stmt(applier->m_thd);
+ if (!trans_rollback(applier->m_thd))
+ {
+ close_thread_tables(applier->m_thd);
+ }
+ }
+ else
+ {
+ if (trans_commit(applier->m_thd))
+ {
+ WSREP_WARN("Failed to commit transaction for store view");
+ }
+ }
+ applier->m_thd->mdl_context.release_transactional_locks();
+ }
+
+ wsrep_set_SE_checkpoint(view.state_id());
+ DBUG_ASSERT(wsrep_get_SE_checkpoint().id() == view.state_id().id());
+ }
+ else
+ {
+ WSREP_DEBUG("No applier in Wsrep_server_service::log_view(), "
+ "skipping write to wsrep_schema");
+ }
+ }
+}
+
+void Wsrep_server_service::recover_streaming_appliers(wsrep::client_service& cs)
+{
+ Wsrep_client_service& client_service= static_cast<Wsrep_client_service&>(cs);
+ wsrep_recover_sr_from_storage(client_service.m_thd);
+}
+
+void Wsrep_server_service::recover_streaming_appliers(
+ wsrep::high_priority_service& hs)
+{
+ Wsrep_high_priority_service& high_priority_service=
+ static_cast<Wsrep_high_priority_service&>(hs);
+ wsrep_recover_sr_from_storage(high_priority_service.m_thd);
+}
+
+wsrep::view Wsrep_server_service::get_view(wsrep::client_service& c,
+ const wsrep::id& own_id)
+{
+ Wsrep_client_service& cs(static_cast<Wsrep_client_service&>(c));
+ wsrep::view v(wsrep_schema->restore_view(cs.m_thd, own_id));
+ return v;
+}
+
+wsrep::gtid Wsrep_server_service::get_position(wsrep::client_service&)
+{
+ return wsrep_get_SE_checkpoint();
+}
+
+void Wsrep_server_service::log_state_change(
+ enum Wsrep_server_state::state prev_state,
+ enum Wsrep_server_state::state current_state)
+{
+ WSREP_INFO("Server status change %s -> %s",
+ wsrep::to_c_string(prev_state),
+ wsrep::to_c_string(current_state));
+ mysql_mutex_lock(&LOCK_status);
+ switch (current_state)
+ {
+ case Wsrep_server_state::s_synced:
+ wsrep_ready= TRUE;
+ WSREP_INFO("Synchronized with group, ready for connections");
+ /* fall through */
+ case Wsrep_server_state::s_joined:
+ case Wsrep_server_state::s_donor:
+ wsrep_cluster_status= "Primary";
+ break;
+ case Wsrep_server_state::s_connected:
+ wsrep_cluster_status= "non-Primary";
+ wsrep_ready= FALSE;
+ wsrep_connected= TRUE;
+ break;
+ case Wsrep_server_state::s_disconnected:
+ wsrep_ready= FALSE;
+ wsrep_connected= FALSE;
+ wsrep_cluster_status= "Disconnected";
+ break;
+ default:
+ wsrep_ready= FALSE;
+ wsrep_cluster_status= "non-Primary";
+ break;
+ }
+ mysql_mutex_unlock(&LOCK_status);
+ wsrep_config_state->set(current_state);
+}
+
+bool Wsrep_server_service::sst_before_init() const
+{
+ return wsrep_before_SE();
+}
+
+std::string Wsrep_server_service::sst_request()
+{
+ return wsrep_sst_prepare();
+}
+
+int Wsrep_server_service::start_sst(const std::string& sst_request,
+ const wsrep::gtid& gtid,
+ bool bypass)
+{
+ return wsrep_sst_donate(sst_request, gtid, bypass);
+}
+
+int Wsrep_server_service::wait_committing_transactions(int timeout)
+{
+ return wsrep_wait_committing_connections_close(timeout);
+}
+
+void Wsrep_server_service::debug_sync(const char*)
+{
+}
diff --git a/sql/wsrep_server_service.h b/sql/wsrep_server_service.h
new file mode 100644
index 00000000000..b8f1f009cde
--- /dev/null
+++ b/sql/wsrep_server_service.h
@@ -0,0 +1,81 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_SERVER_SERVICE_H
+#define WSREP_SERVER_SERVICE_H
+
+/* wsrep-lib */
+#include "wsrep/server_service.hpp"
+#include "wsrep/exception.hpp" // not_impemented_error(), remove when finished
+#include "wsrep/storage_service.hpp"
+
+class Wsrep_server_state;
+
+
+/* wsrep::server_service interface implementation */
+class Wsrep_server_service : public wsrep::server_service
+{
+public:
+ Wsrep_server_service(Wsrep_server_state& server_state)
+ : m_server_state(server_state)
+ { }
+
+ wsrep::storage_service* storage_service(wsrep::client_service&);
+
+ wsrep::storage_service* storage_service(wsrep::high_priority_service&);
+
+ void release_storage_service(wsrep::storage_service*);
+
+ wsrep::high_priority_service*
+ streaming_applier_service(wsrep::client_service&);
+
+ wsrep::high_priority_service*
+ streaming_applier_service(wsrep::high_priority_service&);
+
+ void release_high_priority_service(wsrep::high_priority_service*);
+
+ void background_rollback(wsrep::client_state&);
+
+ void bootstrap();
+ void log_message(enum wsrep::log::level, const char*);
+
+ void log_dummy_write_set(wsrep::client_state&, const wsrep::ws_meta&)
+ { throw wsrep::not_implemented_error(); }
+
+ void log_view(wsrep::high_priority_service*, const wsrep::view&);
+
+ void recover_streaming_appliers(wsrep::client_service&);
+ void recover_streaming_appliers(wsrep::high_priority_service&);
+ wsrep::view get_view(wsrep::client_service&, const wsrep::id& own_id);
+
+ wsrep::gtid get_position(wsrep::client_service&);
+
+ void log_state_change(enum wsrep::server_state::state,
+ enum wsrep::server_state::state);
+
+ bool sst_before_init() const;
+
+ std::string sst_request();
+ int start_sst(const std::string&, const wsrep::gtid&, bool);
+
+ int wait_committing_transactions(int);
+
+ void debug_sync(const char*);
+private:
+ Wsrep_server_state& m_server_state;
+};
+
+
+#endif /* WSREP_SERVER_SERVICE */
diff --git a/sql/wsrep_server_state.cc b/sql/wsrep_server_state.cc
new file mode 100644
index 00000000000..4571201b07d
--- /dev/null
+++ b/sql/wsrep_server_state.cc
@@ -0,0 +1,82 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "my_global.h"
+#include "wsrep_api.h"
+#include "wsrep_server_state.h"
+
+mysql_mutex_t LOCK_wsrep_server_state;
+mysql_cond_t COND_wsrep_server_state;
+
+#ifdef HAVE_PSI_INTERFACE
+PSI_mutex_key key_LOCK_wsrep_server_state;
+PSI_cond_key key_COND_wsrep_server_state;
+#endif
+
+Wsrep_server_state::Wsrep_server_state(const std::string& name,
+ const std::string& incoming_address,
+ const std::string& address,
+ const std::string& working_dir,
+ const wsrep::gtid& initial_position,
+ int max_protocol_version)
+ : wsrep::server_state(m_mutex,
+ m_cond,
+ m_service,
+ name,
+ incoming_address,
+ address,
+ working_dir,
+ initial_position,
+ max_protocol_version,
+ wsrep::server_state::rm_sync)
+ , m_mutex(LOCK_wsrep_server_state)
+ , m_cond(COND_wsrep_server_state)
+ , m_service(*this)
+{
+
+}
+
+void Wsrep_server_state::init_once(const std::string& name,
+ const std::string& incoming_address,
+ const std::string& address,
+ const std::string& working_dir,
+ const wsrep::gtid& initial_position,
+ int max_protocol_version)
+{
+ if (m_instance == 0)
+ {
+ mysql_mutex_init(key_LOCK_wsrep_server_state, &LOCK_wsrep_server_state,
+ MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_server_state, &COND_wsrep_server_state, 0);
+ m_instance = new Wsrep_server_state(name,
+ incoming_address,
+ address,
+ working_dir,
+ initial_position,
+ max_protocol_version);
+ }
+}
+
+void Wsrep_server_state::destroy()
+{
+
+ if (m_instance)
+ {
+ delete m_instance;
+ m_instance= 0;
+ mysql_mutex_destroy(&LOCK_wsrep_server_state);
+ mysql_cond_destroy(&COND_wsrep_server_state);
+ }
+}
diff --git a/sql/wsrep_server_state.h b/sql/wsrep_server_state.h
new file mode 100644
index 00000000000..d0946498d56
--- /dev/null
+++ b/sql/wsrep_server_state.h
@@ -0,0 +1,66 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_SERVER_STATE_H
+#define WSREP_SERVER_STATE_H
+
+/* wsrep-lib */
+#include "wsrep/server_state.hpp"
+#include "wsrep/provider.hpp"
+
+/* implementation */
+#include "wsrep_server_service.h"
+#include "wsrep_mutex.h"
+#include "wsrep_condition_variable.h"
+
+class Wsrep_server_state : public wsrep::server_state
+{
+public:
+ static void init_once(const std::string& name,
+ const std::string& incoming_address,
+ const std::string& address,
+ const std::string& working_dir,
+ const wsrep::gtid& initial_position,
+ int max_protocol_version);
+ static void destroy();
+ static Wsrep_server_state& instance()
+ {
+ return *m_instance;
+ }
+
+ static wsrep::provider& get_provider()
+ {
+ return instance().provider();
+ }
+
+ static bool has_capability(int capability)
+ {
+ return (get_provider().capabilities() & capability);
+ }
+private:
+ Wsrep_server_state(const std::string& name,
+ const std::string& incoming_address,
+ const std::string& address,
+ const std::string& working_dir,
+ const wsrep::gtid& initial_position,
+ int max_protocol_version);
+ Wsrep_mutex m_mutex;
+ Wsrep_condition_variable m_cond;
+ Wsrep_server_service m_service;
+
+ static Wsrep_server_state* m_instance;
+};
+
+#endif // WSREP_SERVER_STATE_H
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 0a2424fa069..4e3a7072629 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -1,4 +1,4 @@
-/* Copyright 2008-2015 Codership Oy <http://www.codership.com>
+/* Copyright 2008-2017 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
@@ -35,16 +35,16 @@
static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 +
sizeof(WSREP_SST_OPT_CONF) +
sizeof(WSREP_SST_OPT_CONF_SUFFIX) +
- sizeof(WSREP_SST_OPT_CONF_EXTRA)] = {0};
+ sizeof(WSREP_SST_OPT_CONF_EXTRA)]= {0};
-const char* wsrep_sst_method = WSREP_SST_DEFAULT;
-const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO;
-const char* wsrep_sst_donor = "";
-const char* wsrep_sst_auth = NULL;
+const char* wsrep_sst_method = WSREP_SST_DEFAULT;
+const char* wsrep_sst_receive_address= WSREP_SST_ADDRESS_AUTO;
+const char* wsrep_sst_donor = "";
+const 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;
+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)
{
@@ -65,7 +65,7 @@ bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type)
return 0;
}
-static const char* data_home_dir = NULL;
+static const char* data_home_dir= NULL;
void wsrep_set_data_home_dir(const char *data_dir)
{
@@ -139,7 +139,7 @@ static bool sst_auth_real_set (const char* value)
{
// set sst_auth_real
if (sst_auth_real) { my_free((void *) sst_auth_real); }
- sst_auth_real = v;
+ sst_auth_real= v;
// mask wsrep_sst_auth
if (strlen(sst_auth_real))
@@ -180,6 +180,7 @@ bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type)
return 0;
}
+
bool wsrep_before_SE()
{
return (wsrep_provider != NULL
@@ -188,111 +189,29 @@ bool wsrep_before_SE()
&& strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP));
}
-static bool sst_complete = false;
-static bool sst_needed = false;
-
-#define WSREP_EXTEND_TIMEOUT_INTERVAL 30
-#define WSREP_TIMEDWAIT_SECONDS 10
-
-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 ()
-{
- double total_wtime = 0;
-
- if (mysql_mutex_lock (&LOCK_wsrep_sst))
- abort();
-
- WSREP_INFO("Waiting for SST to complete.");
-
- while (!sst_complete)
- {
- struct timespec wtime;
- set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS);
- time_t start_time = time(NULL);
- mysql_cond_timedwait (&COND_wsrep_sst, &LOCK_wsrep_sst, &wtime);
- time_t end_time = time(NULL);
-
- if (!sst_complete)
- {
- total_wtime += difftime(end_time, start_time);
- WSREP_DEBUG("Waiting for SST to complete. current seqno: %" PRId64 " waited %f secs.", local_seqno, total_wtime);
- service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
- "WSREP state transfer ongoing, current seqno: %ld waited %f secs", local_seqno, total_wtime);
- }
- }
-
- 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)
+static void wsrep_sst_complete (THD* thd,
+ int const rcode)
{
- 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);
+ Wsrep_client_service client_service(thd, thd->wsrep_cs());
+ Wsrep_server_state::instance().sst_received(client_service, rcode);
}
-/*
+ /*
If wsrep provider is loaded, inform that the new state snapshot
has been received. Also update the local checkpoint.
- @param wsrep [IN] wsrep handle
+ @param thd [IN]
@param uuid [IN] Initial state UUID
@param seqno [IN] Initial state sequence number
@param state [IN] Always NULL, also ignored by wsrep provider (?)
@param state_len [IN] Always 0, also ignored by wsrep provider (?)
- @param implicit [IN] Whether invoked implicitly due to SST
- (true) or explicitly because if change
- in wsrep_start_position by user (false).
- @return false Success
- true Error
-
*/
-bool wsrep_sst_received (wsrep_t* const wsrep,
- const wsrep_uuid_t& uuid,
- const wsrep_seqno_t seqno,
- const void* const state,
- const size_t state_len,
- const bool implicit)
+void wsrep_sst_received (THD* thd,
+ const wsrep_uuid_t& uuid,
+ wsrep_seqno_t const seqno,
+ const void* const state,
+ size_t const state_len)
{
/*
To keep track of whether the local uuid:seqno should be updated. Also, note
@@ -300,81 +219,40 @@ bool wsrep_sst_received (wsrep_t* const wsrep,
OK from wsrep provider. By doing so, the values remain consistent across
the server & wsrep provider.
*/
- bool do_update= false;
-
- // Get the locally stored uuid:seqno.
- if (wsrep_get_SE_checkpoint(local_uuid, local_seqno))
- {
- return true;
- }
-
- if (memcmp(&local_uuid, &uuid, sizeof(wsrep_uuid_t)) ||
- local_seqno < seqno || seqno < 0)
- {
- do_update= true;
- }
- else if (local_seqno > seqno)
- {
- WSREP_WARN("SST position can't be set in past. Requested: %lld, Current: "
- " %lld.", (long long)seqno, (long long)local_seqno);
/*
- If we are here because of SET command, simply return true (error) instead of
- aborting.
+ TODO: Handle backwards compatibility. WSREP API v25 does not have
+ wsrep schema.
*/
- if (implicit)
- {
- WSREP_WARN("Can't continue.");
- unireg_abort(1);
- }
- else
- {
- return true;
+ /*
+ Logical SST methods (mysqldump etc) don't update InnoDB sys header.
+ Reset the SE checkpoint before recovering view in order to avoid
+ sanity check failure.
+ */
+ wsrep::gtid const sst_gtid(wsrep::id(uuid.data, sizeof(uuid.data)),
+ wsrep::seqno(seqno));
+
+ if (!wsrep_before_SE()) {
+ wsrep_set_SE_checkpoint(wsrep::gtid::undefined());
+ wsrep_set_SE_checkpoint(sst_gtid);
}
- }
+ wsrep_verify_SE_checkpoint(uuid, seqno);
-#ifdef GTID_SUPPORT
- wsrep_init_sidno(uuid);
-#endif /* GTID_SUPPORT */
-
- if (wsrep)
- {
- int const rcode(seqno < 0 ? seqno : 0);
- wsrep_gtid_t const state_id= {uuid,
- (rcode ? WSREP_SEQNO_UNDEFINED : seqno)};
-
- wsrep_status_t ret= wsrep->sst_received(wsrep, &state_id, state,
- state_len, rcode);
-
- if (ret != WSREP_OK)
- {
- return true;
+ /*
+ Both wsrep_init_SR() and wsrep_recover_view() may use
+ wsrep thread pool. Restore original thd context before returning.
+ */
+ if (thd) {
+ thd->store_globals();
+ }
+ else {
+ my_pthread_setspecific_ptr(THR_THD, NULL);
}
- }
- // Now is the good time to update the local state and checkpoint.
- if (do_update)
- {
- if (wsrep_set_SE_checkpoint(uuid, seqno))
+ if (WSREP_ON)
{
- return true;
+ int const rcode(seqno < 0 ? seqno : 0);
+ wsrep_sst_complete(thd,rcode);
}
-
- local_uuid= uuid;
- local_seqno= seqno;
- }
-
- return false;
-}
-
-// Let applier threads to continue
-bool wsrep_sst_continue ()
-{
- if (sst_needed)
- {
- WSREP_INFO("Signalling provider to continue.");
- return wsrep_sst_received (wsrep, local_uuid, local_seqno, NULL, 0, true);
- }
- return false;
}
struct sst_thread_arg
@@ -404,11 +282,11 @@ struct sst_thread_arg
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);
+ int offt= wsrep_uuid_scan (str, strlen(str), uuid);
errno= 0; /* Reset the errno */
if (offt > 0 && strlen(str) > (unsigned int)offt && ':' == str[offt])
{
- *seqno = strtoll (str + offt + 1, NULL, 10);
+ *seqno= strtoll (str + offt + 1, NULL, 10);
if (*seqno != LLONG_MAX || errno != ERANGE)
{
return 0;
@@ -416,7 +294,7 @@ static int sst_scan_uuid_seqno (const char* str,
}
WSREP_ERROR("Failed to parse uuid:seqno pair: '%s'", str);
- return EINVAL;
+ return -EINVAL;
}
// get rid of trailing \n
@@ -426,8 +304,8 @@ static char* my_fgets (char* buf, size_t buf_len, FILE* stream)
if (ret)
{
- size_t len = strlen(ret);
- if (len > 0 && ret[len - 1] == '\n') ret[len - 1] = '\0';
+ size_t len= strlen(ret);
+ if (len > 0 && ret[len - 1] == '\n') ret[len - 1]= '\0';
}
return ret;
@@ -482,9 +360,10 @@ static void* sst_joiner_thread (void* a)
int err= 1;
{
- const char magic[] = "ready";
- const size_t magic_len = sizeof(magic) - 1;
- const size_t out_len = 512;
+ THD* thd;
+ 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);
@@ -501,29 +380,31 @@ static void* sst_joiner_thread (void* a)
WSREP_ERROR("Failed to read '%s <addr>' from: %s\n\tRead: '%s'",
magic, arg->cmd, tmp);
proc.wait();
- if (proc.error()) err = proc.error();
+ if (proc.error()) err= proc.error();
}
else
{
- err = 0;
+ err= 0;
}
}
else
{
- err = proc.error();
+ 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
+ /*
+ 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->ret_str= strdup (out + magic_len + 1);
+ if (!arg->ret_str) err= ENOMEM;
}
- arg->err = -err;
+ arg->err= -err;
mysql_cond_signal (&arg->cond);
mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
@@ -531,11 +412,11 @@ static void* sst_joiner_thread (void* a)
* initializer thread to ensure single thread of
* shutdown. */
- wsrep_uuid_t ret_uuid = WSREP_UUID_UNDEFINED;
- wsrep_seqno_t ret_seqno = WSREP_SEQNO_UNDEFINED;
+ 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());
+ char* tmp= my_fgets (out, out_len, proc.pipe());
proc.wait();
err= EINVAL;
@@ -544,7 +425,7 @@ static void* sst_joiner_thread (void* a)
{
WSREP_ERROR("Failed to read uuid:seqno and wsrep_gtid_domain_id from "
"joiner script.");
- if (proc.error()) err = proc.error();
+ if (proc.error()) err= proc.error();
}
else
{
@@ -552,7 +433,14 @@ static void* sst_joiner_thread (void* a)
const char *pos= strchr(out, ' ');
if (!pos) {
- // There is no wsrep_gtid_domain_id (some older version SST script?).
+
+ if (wsrep_gtid_mode)
+ {
+ // There is no wsrep_gtid_domain_id (some older version SST script?).
+ WSREP_WARN("Did not find domain ID from SST script output '%s'. "
+ "Domain ID must be set manually to keep binlog consistent",
+ out);
+ }
err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno);
} else {
@@ -588,14 +476,59 @@ static void* sst_joiner_thread (void* a)
err:
+ wsrep::gtid ret_gtid;
+
if (err)
{
- ret_uuid= WSREP_UUID_UNDEFINED;
- ret_seqno= -err;
+ ret_gtid= wsrep::gtid::undefined();
+ }
+ else
+ {
+ ret_gtid= wsrep::gtid(wsrep::id(ret_uuid.data, sizeof(ret_uuid.data)),
+ wsrep::seqno(ret_seqno));
}
- // Tell initializer thread that SST is complete
- wsrep_sst_complete (&ret_uuid, ret_seqno, true);
+ /*
+ Tell initializer thread that SST is complete
+ For that initialize a THD
+ */
+ if (my_thread_init())
+ {
+ WSREP_ERROR("my_thread_init() failed, can't signal end of SST. "
+ "Aborting.");
+ unireg_abort(1);
+ }
+
+ thd= new THD(next_thread_id());
+
+ if (!thd)
+ {
+ WSREP_ERROR("Failed to allocate THD to restore view from local state, "
+ "can't signal end of SST. Aborting.");
+ unireg_abort(1);
+ }
+
+ thd->thread_stack= (char*) &thd;
+ thd->security_ctx->skip_grants();
+ thd->system_thread= SYSTEM_THREAD_GENERIC;
+ thd->real_id= pthread_self();
+
+ thd->store_globals();
+
+ /* */
+ thd->variables.wsrep_on = 0;
+ /* No binlogging */
+ thd->variables.sql_log_bin = 0;
+ thd->variables.option_bits &= ~OPTION_BIN_LOG;
+ /* No general log */
+ thd->variables.option_bits |= OPTION_LOG_OFF;
+ /* Read committed isolation to avoid gap locking */
+ thd->variables.tx_isolation= ISO_READ_COMMITTED;
+
+ wsrep_sst_complete (thd, -err);
+
+ delete thd;
+ my_thread_end();
}
return NULL;
@@ -694,7 +627,7 @@ static ssize_t sst_prepare_other (const char* method,
" %s "
WSREP_SST_OPT_PARENT " '%d'"
" %s '%s'"
- " %s '%s'",
+ " %s '%s'",
method, addr_in, mysql_real_data_home,
wsrep_defaults_file,
(int)getpid(), binlog_opt, binlog_opt_val,
@@ -734,7 +667,7 @@ static ssize_t sst_prepare_other (const char* method,
pthread_t tmp;
sst_thread_arg arg(cmd_str(), env());
mysql_mutex_lock (&arg.lock);
- ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg);
+ ret= pthread_create (&tmp, NULL, sst_joiner_thread, &arg);
if (ret)
{
WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)",
@@ -746,11 +679,11 @@ static ssize_t sst_prepare_other (const char* method,
*addr_out= arg.ret_str;
if (!arg.err)
- ret = strlen(*addr_out);
+ ret= strlen(*addr_out);
else
{
assert (arg.err < 0);
- ret = arg.err;
+ ret= arg.err;
}
pthread_detach (tmp);
@@ -764,12 +697,12 @@ extern uint mysqld_port;
static ssize_t sst_prepare_mysqldump (const char* addr_in,
const char** addr_out)
{
- ssize_t ret = strlen (addr_in);
+ ssize_t ret= strlen (addr_in);
if (!strrchr(addr_in, ':'))
{
- ssize_t s = ret + 7;
- char* tmp = (char*) malloc (s);
+ ssize_t s= ret + 7;
+ char* tmp= (char*) malloc (s);
if (tmp)
{
@@ -780,7 +713,7 @@ static ssize_t sst_prepare_mysqldump (const char* addr_in,
*addr_out= tmp;
return ret;
}
- if (ret > 0) /* buffer too short */ ret = -EMSGSIZE;
+ if (ret > 0) /* buffer too short */ ret= -EMSGSIZE;
free (tmp);
}
else {
@@ -797,32 +730,22 @@ static ssize_t sst_prepare_mysqldump (const char* addr_in,
return ret;
}
-static bool SE_initialized = false;
-
-ssize_t wsrep_sst_prepare (void** msg)
+std::string wsrep_sst_prepare()
{
+ const ssize_t ip_max= 256;
+ char ip_buf[ip_max];
const char* addr_in= NULL;
const char* addr_out= NULL;
const char* method;
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;
+ return WSREP_STATE_TRANSFER_TRIVIAL;
}
/*
Figure out SST receive address. Common for all SST methods.
*/
- char ip_buf[256];
- const ssize_t ip_max= sizeof(ip_buf);
-
// Attempt 1: wsrep_sst_receive_address
if (wsrep_sst_receive_address &&
strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO))
@@ -839,7 +762,7 @@ ssize_t wsrep_sst_prepare (void** msg)
{
WSREP_ERROR("Could not parse wsrep_node_address : %s",
wsrep_node_address);
- unireg_abort(1);
+ throw wsrep::runtime_error("Failed to prepare for SST. Unrecoverable");
}
memcpy(ip_buf, addr.get_address(), addr.get_address_len());
addr_in= ip_buf;
@@ -857,7 +780,7 @@ ssize_t wsrep_sst_prepare (void** msg)
{
WSREP_ERROR("Failed to guess address to accept state transfer. "
"wsrep_sst_receive_address must be set manually.");
- unireg_abort(1);
+ throw wsrep::runtime_error("Could not prepare state transfer request");
}
}
@@ -866,12 +789,16 @@ ssize_t wsrep_sst_prepare (void** msg)
if (!strcmp(method, WSREP_SST_MYSQLDUMP))
{
addr_len= sst_prepare_mysqldump (addr_in, &addr_out);
- if (addr_len < 0) unireg_abort(1);
+ if (addr_len < 0)
+ {
+ throw wsrep::runtime_error("Could not prepare mysqldimp address");
+ }
}
else
{
/*! A heuristic workaround until we learn how to stop and start engines */
- if (SE_initialized)
+ if (Wsrep_server_state::instance().is_initialized() &&
+ Wsrep_server_state::instance().state() == Wsrep_server_state::s_joiner)
{
if (!strcmp(method, WSREP_SST_XTRABACKUP) ||
!strcmp(method, WSREP_SST_XTRABACKUPV2))
@@ -890,8 +817,7 @@ ssize_t wsrep_sst_prepare (void** msg)
"if other means of state transfer are unavailable. "
"In that case you will need to restart the server.",
method);
- *msg = 0;
- return 0;
+ return "";
}
addr_len = sst_prepare_other (method, sst_auth_real,
@@ -900,37 +826,28 @@ ssize_t wsrep_sst_prepare (void** msg)
{
WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.",
method);
- unireg_abort(1);
+ throw wsrep::runtime_error("Failed to prepare for SST. Unrecoverable");
}
}
- size_t const method_len(strlen(method));
- size_t const msg_len (method_len + addr_len + 2 /* + auth_len + 1*/);
+ std::string ret;
+ ret += method;
+ ret.push_back('\0');
+ ret += addr_out;
- *msg = malloc (msg_len);
- if (NULL != *msg) {
- char* const method_ptr(reinterpret_cast<char*>(*msg));
- strcpy (method_ptr, 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);
- }
+ const char* method_ptr(ret.data());
+ const char* addr_ptr(ret.data() + strlen(method_ptr) + 1);
+ WSREP_INFO ("Prepared SST request: %s|%s", method_ptr, addr_ptr);
if (addr_out != addr_in) /* malloc'ed */ free ((char*)addr_out);
- return msg_len;
+ return ret;
}
// helper method for donors
static int sst_run_shell (const char* cmd_str, char** env, int max_tries)
{
- int ret = 0;
+ int ret= 0;
for (int tries=1; tries <= max_tries; tries++)
{
@@ -941,7 +858,7 @@ static int sst_run_shell (const char* cmd_str, char** env, int max_tries)
proc.wait();
}
- if ((ret = proc.error()))
+ if ((ret= proc.error()))
{
WSREP_ERROR("Try %d/%d: '%s' failed: %d (%s)",
tries, max_tries, proc.cmd(), ret, strerror(ret));
@@ -959,15 +876,12 @@ static int sst_run_shell (const char* cmd_str, char** env, int max_tries)
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);
+ 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,
+ const wsrep::gtid& gtid,
bool bypass,
char** env) // carries auth info
{
@@ -990,23 +904,31 @@ static int sst_donate_mysqldump (const char* addr,
return -ENOMEM;
}
+ /*
+ we enable new client connections so that mysqldump donation can connect in,
+ but we reject local connections from modifyingcdata during SST, to keep
+ data intact
+ */
if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
make_wsrep_defaults_file();
+ std::ostringstream uuid_oss;
+ uuid_oss << gtid.id();
int ret= snprintf (cmd_str(), cmd_len,
"wsrep_sst_mysqldump "
WSREP_SST_OPT_ADDR " '%s' "
- WSREP_SST_OPT_PORT " '%d' "
+ WSREP_SST_OPT_PORT " '%u' "
WSREP_SST_OPT_LPORT " '%u' "
WSREP_SST_OPT_SOCKET " '%s' "
" %s "
WSREP_SST_OPT_GTID " '%s:%lld' "
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
"%s",
- addr, port, mysqld_port, mysqld_unix_port,
- wsrep_defaults_file, uuid_str,
- (long long)seqno, wsrep_gtid_domain_id,
+ addr, port, mysqld_port, mysqld_unix_port,
+ wsrep_defaults_file,
+ uuid_oss.str().c_str(), gtid.seqno().get(),
+ wsrep_gtid_domain_id,
bypass ? " " WSREP_SST_OPT_BYPASS : "");
if (ret < 0 || ret >= cmd_len)
@@ -1019,16 +941,17 @@ static int sst_donate_mysqldump (const char* addr,
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);
+ wsrep::gtid sst_sent_gtid(ret == 0 ?
+ gtid :
+ wsrep::gtid(gtid.id(),
+ wsrep::seqno::undefined()));
+ Wsrep_server_state::instance().sst_sent(sst_sent_gtid, ret);
return ret;
}
wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
-
/*
Create a file under data directory.
*/
@@ -1077,7 +1000,6 @@ static int sst_create_file(const char *name, const char *content)
return err;
}
-
static int run_sql_command(THD *thd, const char *query)
{
thd->set_query((char *)query, strlen(query));
@@ -1123,9 +1045,9 @@ static int sst_flush_tables(THD* thd)
{
/* 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;
+ thd->variables.character_set_client= &my_charset_latin1;
WSREP_WARN("For SST temporally setting character set to : %s",
- my_charset_latin1.csname);
+ my_charset_latin1.csname);
}
if (run_sql_command(thd, "FLUSH TABLES WITH READ LOCK"))
@@ -1146,7 +1068,7 @@ static int sst_flush_tables(THD* thd)
}
}
- thd->variables.character_set_client = current_charset;
+ thd->variables.character_set_client= current_charset;
if (err)
{
@@ -1164,7 +1086,6 @@ static int sst_flush_tables(THD* thd)
else
{
WSREP_INFO("Tables flushed.");
-
/*
Tables have been flushed. Create a file with cluster state ID and
wsrep_gtid_domain_id.
@@ -1173,6 +1094,41 @@ static int sst_flush_tables(THD* thd)
snprintf(content, sizeof(content), "%s:%lld %d\n", wsrep_cluster_state_uuid,
(long long)wsrep_locked_seqno, wsrep_gtid_domain_id);
err= sst_create_file(flush_success, content);
+
+ const char base_name[]= "tables_flushed";
+ ssize_t const full_len= strlen(mysql_real_data_home) + strlen(base_name)+2;
+ char *real_name= (char*) malloc(full_len);
+ sprintf(real_name, "%s/%s", mysql_real_data_home, base_name);
+ char *tmp_name= (char*) malloc(full_len + 4);
+ sprintf(tmp_name, "%s.tmp", real_name);
+
+ FILE* file= fopen(tmp_name, "w+");
+ if (0 == file)
+ {
+ err= errno;
+ WSREP_ERROR("Failed to open '%s': %d (%s)", tmp_name, err,strerror(err));
+ }
+ else
+ {
+ Wsrep_server_state& server_state= Wsrep_server_state::instance();
+ std::ostringstream uuid_oss;
+
+ uuid_oss << server_state.current_view().state_id().id();
+
+ fprintf(file, "%s:%lld %u\n",
+ uuid_oss.str().c_str(), server_state.pause_seqno().get(),
+ wsrep_gtid_domain_id);
+ fsync(fileno(file));
+ fclose(file);
+ if (rename(tmp_name, real_name) == -1)
+ {
+ err= errno;
+ WSREP_ERROR("Failed to rename '%s' to '%s': %d (%s)",
+ tmp_name, real_name, err,strerror(err));
+ }
+ }
+ free(real_name);
+ free(tmp_name);
}
return err;
@@ -1181,19 +1137,19 @@ static int sst_flush_tables(THD* thd)
static void sst_disallow_writes (THD* thd, bool yes)
{
- char query_str[64] = { 0, };
- ssize_t const query_max = sizeof(query_str) - 1;
+ 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;
+ 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;
+ thd->variables.character_set_client= &my_charset_latin1;
WSREP_WARN("For SST temporally setting character set to : %s",
- my_charset_latin1.csname);
+ my_charset_latin1.csname);
}
snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d",
@@ -1203,7 +1159,7 @@ static void sst_disallow_writes (THD* thd, bool yes)
{
WSREP_ERROR("Failed to disallow InnoDB writes");
}
- thd->variables.character_set_client = current_charset;
+ thd->variables.character_set_client= current_charset;
}
static void* sst_donor_thread (void* a)
@@ -1226,11 +1182,11 @@ static void* sst_donor_thread (void* a)
// operate with wsrep_ready == OFF
wsp::process proc(arg->cmd, "r", arg->env);
- err= proc.error();
+ err= -proc.error();
/* Inform server about SST script startup and release TO isolation */
mysql_mutex_lock (&arg->lock);
- arg->err = -err;
+ arg->err= -err;
mysql_cond_signal (&arg->cond);
mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
@@ -1289,6 +1245,7 @@ wait_signal:
else
{
WSREP_WARN("Received unknown signal: '%s'", out);
+ proc.wait();
}
}
else
@@ -1296,7 +1253,7 @@ wait_signal:
WSREP_ERROR("Failed to read from: %s", proc.cmd());
proc.wait();
}
- if (!err && proc.error()) err= proc.error();
+ if (!err && proc.error()) err= -proc.error();
}
else
{
@@ -1315,24 +1272,20 @@ wait_signal:
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);
+ wsrep::gtid gtid(wsrep::id(ret_uuid.data, sizeof(ret_uuid.data)),
+ wsrep::seqno(err ? wsrep::seqno::undefined() :
+ wsrep::seqno(ret_seqno)));
+ Wsrep_server_state::instance().sst_sent(gtid, 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
+static int sst_donate_other (const char* method,
+ const char* addr,
+ const wsrep::gtid& gtid,
+ bool bypass,
+ char** env) // carries auth info
{
int const cmd_len= 4096;
wsp::string cmd_str(cmd_len);
@@ -1357,6 +1310,8 @@ static int sst_donate_other (const char* method,
make_wsrep_defaults_file();
+ std::ostringstream uuid_oss;
+ uuid_oss << gtid.id();
ret= snprintf (cmd_str(), cmd_len,
"wsrep_sst_%s "
WSREP_SST_OPT_ROLE " 'donor' "
@@ -1371,7 +1326,7 @@ static int sst_donate_other (const char* method,
method, addr, mysqld_unix_port, mysql_real_data_home,
wsrep_defaults_file,
binlog_opt, binlog_opt_val,
- uuid, (long long) seqno, wsrep_gtid_domain_id,
+ uuid_oss.str().c_str(), gtid.seqno().get(), wsrep_gtid_domain_id,
bypass ? " " WSREP_SST_OPT_BYPASS : "");
my_free(binlog_opt_val);
@@ -1386,7 +1341,7 @@ static int sst_donate_other (const char* method,
pthread_t tmp;
sst_thread_arg arg(cmd_str(), env);
mysql_mutex_lock (&arg.lock);
- ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg);
+ ret= pthread_create (&tmp, NULL, sst_donor_thread, &arg);
if (ret)
{
WSREP_ERROR("sst_donate_other(): pthread_create() failed: %d (%s)",
@@ -1399,23 +1354,18 @@ static int sst_donate_other (const char* method,
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)
+int wsrep_sst_donate(const std::string& msg,
+ const wsrep::gtid& current_gtid,
+ const bool bypass)
{
/* This will be reset when sync callback is called.
* Should we set wsrep_ready to FALSE here too? */
- wsrep_config_state->set(WSREP_MEMBER_DONOR);
+ wsrep_config_state->set(wsrep::server_state::s_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));
+ const char* method= msg.data();
+ size_t method_len= strlen (method);
+ const char* data= method + method_len + 1;
wsp::env env(NULL);
if (env.error())
@@ -1443,54 +1393,13 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
if (!strcmp (WSREP_SST_MYSQLDUMP, method))
{
- ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str,
- current_gtid->seqno, bypass, env());
+ ret= sst_donate_mysqldump(data, current_gtid, bypass, env());
}
else
{
- ret = sst_donate_other(method, data, uuid_str,
- current_gtid->seqno, bypass, env());
+ ret= sst_donate_other(method, data, current_gtid, 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()
-{
- double total_wtime=0;
-
- while (SE_initialized == false)
- {
- struct timespec wtime;
- set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS);
- time_t start_time = time(NULL);
- mysql_cond_timedwait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init, &wtime);
- time_t end_time = time(NULL);
-
- if (!SE_initialized)
- {
- total_wtime += difftime(end_time, start_time);
- WSREP_DEBUG("Waiting for SST to complete. current seqno: %" PRId64 " waited %f secs.", local_seqno, total_wtime);
- service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
- "WSREP state transfer ongoing, current seqno: %ld waited %f secs", local_seqno, total_wtime);
- }
- }
-
- 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;
+ return (ret >= 0 ? 0 : 1);
}
+
diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h
index 29724a00797..46059a7f436 100644
--- a/sql/wsrep_sst.h
+++ b/sql/wsrep_sst.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Codership Oy <info@codership.com>
+/* Copyright (C) 2013-2018 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
@@ -13,14 +13,14 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
-#include <my_config.h>
-
#ifndef WSREP_SST_H
#define WSREP_SST_H
-#ifdef WITH_WSREP
+#include <my_config.h>
-#include <mysql.h> // my_bool
+#include "wsrep/gtid.hpp"
+#include <my_global.h>
+#include <string>
#define WSREP_SST_OPT_ROLE "--role"
#define WSREP_SST_OPT_ADDR "--address"
@@ -77,11 +77,29 @@ 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 */
+/**
+ Return a string containing the state transfer request string.
+ Note that the string may contain a '\0' in the middle.
+*/
+std::string wsrep_sst_prepare();
+
+/**
+ Donate a SST.
+
+ @param request SST request string received from the joiner. Note that
+ the string may contain a '\0' in the middle.
+ @param gtid Current position of the donor
+ @param bypass If true, full SST is not needed. Joiner needs to be
+ notified that it can continue starting from gtid.
+ */
+int wsrep_sst_donate(const std::string& request,
+ const wsrep::gtid& gtid,
+ bool bypass);
+
#else
#define wsrep_SE_initialized() do { } while(0)
#define wsrep_SE_init_grab() do { } while(0)
#define wsrep_SE_init_done() do { } while(0)
#define wsrep_sst_continue() (0)
-#endif /* WITH_WSREP */
#endif /* WSREP_SST_H */
diff --git a/sql/wsrep_storage_service.cc b/sql/wsrep_storage_service.cc
new file mode 100644
index 00000000000..5a15f22ab57
--- /dev/null
+++ b/sql/wsrep_storage_service.cc
@@ -0,0 +1,238 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include "my_global.h"
+#include "wsrep_storage_service.h"
+#include "wsrep_trans_observer.h" /* wsrep_open() */
+#include "wsrep_schema.h"
+#include "wsrep_binlog.h"
+
+#include "sql_class.h"
+#include "mysqld.h" /* next_query_id() */
+#include "slave.h" /* opt_log_slave_updates() */
+#include "transaction.h" /* trans_commit(), trans_rollback() */
+
+/*
+ Temporarily enable wsrep on thd
+ */
+class Wsrep_on
+{
+public:
+ Wsrep_on(THD* thd)
+ : m_thd(thd)
+ , m_wsrep_on(thd->variables.wsrep_on)
+ {
+ thd->variables.wsrep_on= TRUE;
+ }
+ ~Wsrep_on()
+ {
+ m_thd->variables.wsrep_on= m_wsrep_on;
+ }
+private:
+ THD* m_thd;
+ my_bool m_wsrep_on;
+};
+
+Wsrep_storage_service::Wsrep_storage_service(THD* thd)
+ : wsrep::storage_service()
+ , wsrep::high_priority_context(thd->wsrep_cs())
+ , m_thd(thd)
+{
+ thd->security_ctx->skip_grants();
+ thd->system_thread= SYSTEM_THREAD_SLAVE_SQL;
+
+ /* No binlogging */
+
+ /* No general log */
+ thd->variables.option_bits |= OPTION_LOG_OFF;
+
+ /* Read committed isolation to avoid gap locking */
+ thd->variables.tx_isolation = ISO_READ_COMMITTED;
+
+ /* Keep wsrep on to enter commit ordering hooks */
+ thd->variables.wsrep_on= 1;
+ thd->wsrep_skip_locking= true;
+
+ wsrep_open(thd);
+ wsrep_before_command(thd);
+}
+
+Wsrep_storage_service::~Wsrep_storage_service()
+{
+ wsrep_after_command_ignore_result(m_thd);
+ wsrep_close(m_thd);
+ m_thd->wsrep_skip_locking= false;
+}
+
+int Wsrep_storage_service::start_transaction(const wsrep::ws_handle& ws_handle)
+{
+ DBUG_ENTER("Wsrep_storage_service::start_transaction");
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_PRINT("info", ("Wsrep_storage_service::start_transcation(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ m_thd->set_wsrep_next_trx_id(ws_handle.transaction_id().get());
+ DBUG_RETURN(m_thd->wsrep_cs().start_transaction(
+ wsrep::transaction_id(m_thd->wsrep_next_trx_id())) ||
+ trans_begin(m_thd, MYSQL_START_TRANS_OPT_READ_WRITE));
+}
+
+void Wsrep_storage_service::adopt_transaction(const wsrep::transaction& transaction)
+{
+ DBUG_ENTER("Wsrep_Storage_server::adopt_transaction");
+ DBUG_ASSERT(m_thd == current_thd);
+ m_thd->wsrep_cs().adopt_transaction(transaction);
+ trans_begin(m_thd, MYSQL_START_TRANS_OPT_READ_WRITE);
+ DBUG_VOID_RETURN;
+}
+
+int Wsrep_storage_service::append_fragment(const wsrep::id& server_id,
+ wsrep::transaction_id transaction_id,
+ int flags,
+ const wsrep::const_buffer& data)
+{
+ DBUG_ENTER("Wsrep_storage_service::append_fragment");
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_PRINT("info", ("Wsrep_storage_service::append_fragment(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ int ret= wsrep_schema->append_fragment(m_thd,
+ server_id,
+ transaction_id,
+ wsrep::seqno(-1),
+ flags,
+ data);
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_storage_service::update_fragment_meta(const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_storage_service::update_fragment_meta");
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_PRINT("info", ("Wsrep_storage_service::update_fragment_meta(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ int ret= wsrep_schema->update_fragment_meta(m_thd, ws_meta);
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_storage_service::remove_fragments()
+{
+ DBUG_ENTER("Wsrep_storage_service::remove_fragments");
+ DBUG_ASSERT(m_thd == current_thd);
+
+ int ret= wsrep_schema->remove_fragments(m_thd,
+ m_thd->wsrep_trx().server_id(),
+ m_thd->wsrep_trx().id(),
+ m_thd->wsrep_sr().fragments());
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_storage_service::commit(const wsrep::ws_handle& ws_handle,
+ const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_storage_service::commit");
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_PRINT("info", ("Wsrep_storage_service::commit(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ WSREP_DEBUG("Storage service commit: %llu, %lld",
+ ws_meta.transaction_id().get(), ws_meta.seqno().get());
+ int ret= 0;
+ const bool do_binlog_commit= (opt_log_slave_updates && wsrep_gtid_mode);
+ const bool is_ordered= !ws_meta.seqno().is_undefined();
+ /*
+ Write skip event into binlog if gtid_mode is on. This is to
+ maintain gtid continuity.
+ */
+ if (do_binlog_commit && is_ordered)
+ {
+ ret= wsrep_write_skip_event(m_thd);
+ }
+
+ if (!ret && is_ordered)
+ {
+ ret= m_thd->wsrep_cs().prepare_for_ordering(ws_handle,
+ ws_meta, true);
+ }
+
+ if (!ret)
+ {
+ if (!do_binlog_commit && is_ordered)
+ {
+ ret= wsrep_before_commit(m_thd, true);
+ }
+ ret= ret || trans_commit(m_thd);
+ if (!do_binlog_commit && is_ordered)
+ {
+ if (opt_log_slave_updates)
+ {
+ ret= ret || wsrep_ordered_commit(m_thd, true, wsrep_apply_error());
+ }
+ ret= ret || wsrep_after_commit(m_thd, true);
+ }
+ }
+
+ if (!is_ordered)
+ {
+ /* Wsrep commit was not ordered so it does not go through commit time
+ hooks and remains active. Roll it back to make cleanup happen
+ in after_applying() call. */
+ m_thd->wsrep_cs().before_rollback();
+ m_thd->wsrep_cs().after_rollback();
+ }
+ else if (ret)
+ {
+ /* Commit failed, this probably means that the parent SR transaction
+ was BF aborted. Roll back out of order, the parent
+ transaction will release commit order after it has rolled back. */
+ m_thd->wsrep_cs().prepare_for_ordering(wsrep::ws_handle(),
+ wsrep::ws_meta(),
+ false);
+ trans_rollback(m_thd);
+ }
+ m_thd->wsrep_cs().after_applying();
+ m_thd->mdl_context.release_transactional_locks();
+ DBUG_RETURN(ret);
+}
+
+int Wsrep_storage_service::rollback(const wsrep::ws_handle& ws_handle,
+ const wsrep::ws_meta& ws_meta)
+{
+ DBUG_ENTER("Wsrep_storage_service::rollback");
+ DBUG_ASSERT(m_thd == current_thd);
+ DBUG_PRINT("info", ("Wsrep_storage_service::rollback(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ int ret= (m_thd->wsrep_cs().prepare_for_ordering(
+ ws_handle, ws_meta, false) ||
+ trans_rollback(m_thd));
+ m_thd->wsrep_cs().after_applying();
+ m_thd->mdl_context.release_transactional_locks();
+ DBUG_RETURN(ret);
+}
+
+void Wsrep_storage_service::store_globals()
+{
+ DBUG_ENTER("Wsrep_storage_service::store_globals");
+ DBUG_PRINT("info", ("Wsrep_storage_service::store_globals(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ m_thd->store_globals();
+ DBUG_VOID_RETURN;
+}
+
+void Wsrep_storage_service::reset_globals()
+{
+ DBUG_ENTER("Wsrep_storage_service::reset_globals");
+ DBUG_PRINT("info", ("Wsrep_storage_service::reset_globals(%llu, %p)",
+ m_thd->thread_id, m_thd));
+ m_thd->reset_globals();
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/wsrep_storage_service.h b/sql/wsrep_storage_service.h
new file mode 100644
index 00000000000..6208300930f
--- /dev/null
+++ b/sql/wsrep_storage_service.h
@@ -0,0 +1,48 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef WSREP_STORAGE_SERVICE_H
+#define WSREP_STORAGE_SERVICE_H
+
+#include "wsrep/storage_service.hpp"
+#include "wsrep/client_state.hpp"
+
+class THD;
+class Wsrep_server_service;
+class Wsrep_storage_service :
+ public wsrep::storage_service,
+ public wsrep::high_priority_context
+{
+public:
+ Wsrep_storage_service(THD*);
+ ~Wsrep_storage_service();
+ int start_transaction(const wsrep::ws_handle&);
+ void adopt_transaction(const wsrep::transaction&);
+ int append_fragment(const wsrep::id&,
+ wsrep::transaction_id,
+ int flags,
+ const wsrep::const_buffer&);
+ int update_fragment_meta(const wsrep::ws_meta&);
+ int remove_fragments();
+ int commit(const wsrep::ws_handle&, const wsrep::ws_meta&);
+ int rollback(const wsrep::ws_handle&, const wsrep::ws_meta&);
+ void store_globals();
+ void reset_globals();
+private:
+ friend class Wsrep_server_service;
+ THD* m_thd;
+};
+
+#endif /* WSREP_STORAGE_SERVICE_H */
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index ce6d9688cb3..4f9915fa05f 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -15,412 +15,82 @@
#include "mariadb.h"
#include "wsrep_thd.h"
+#include "wsrep_trans_observer.h"
+#include "wsrep_high_priority_service.h"
+#include "wsrep_storage_service.h"
#include "transaction.h"
#include "rpl_rli.h"
#include "log_event.h"
#include "sql_parse.h"
-//#include "global_threads.h" // LOCK_thread_count, etc.
#include "sql_base.h" // close_thread_tables()
#include "mysqld.h" // start_wsrep_THD();
-
-#include "slave.h" // opt_log_slave_updates
-#include "rpl_filter.h"
+#include "wsrep_applier.h" // start_wsrep_THD();
+#include "mysql/service_wsrep.h"
+#include "debug_sync.h"
+#include "slave.h"
#include "rpl_rli.h"
#include "rpl_mi.h"
-#if (__LP64__)
-static volatile int64 wsrep_bf_aborts_counter(0);
-#define WSREP_ATOMIC_LOAD_LONG my_atomic_load64
-#define WSREP_ATOMIC_ADD_LONG my_atomic_add64
-#else
-static volatile int32 wsrep_bf_aborts_counter(0);
-#define WSREP_ATOMIC_LOAD_LONG my_atomic_load32
-#define WSREP_ATOMIC_ADD_LONG my_atomic_add32
-#endif
+static Wsrep_thd_queue* wsrep_rollback_queue= 0;
+static Wsrep_thd_queue* wsrep_post_rollback_queue= 0;
+static Atomic_counter<uint64_t> wsrep_bf_aborts_counter;
+
int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope)
{
- wsrep_local_bf_aborts = WSREP_ATOMIC_LOAD_LONG(&wsrep_bf_aborts_counter);
- var->type = SHOW_LONGLONG;
- var->value = (char*)&wsrep_local_bf_aborts;
+ wsrep_local_bf_aborts= wsrep_bf_aborts_counter;
+ var->type= SHOW_LONGLONG;
+ var->value= (char*)&wsrep_local_bf_aborts;
return 0;
}
-/* must have (&thd->LOCK_thd_data) */
-void wsrep_client_rollback(THD *thd)
-{
- WSREP_DEBUG("client rollback due to BF abort for (%lld), query: %s",
- (longlong) thd->thread_id, thd->query());
-
- WSREP_ATOMIC_ADD_LONG(&wsrep_bf_aborts_counter, 1);
-
- thd->wsrep_conflict_state= ABORTING;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- trans_rollback(thd);
-
- if (thd->locked_tables_mode && thd->lock)
- {
- WSREP_DEBUG("unlocking tables for BF abort (%lld)",
- (longlong) 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 (%lld)",
- (longlong) 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 (%lld)",
- (longlong) thd->thread_id);
- thd->clear_binlog_table_maps();
- }
- mysql_mutex_lock(&thd->LOCK_thd_data);
- thd->wsrep_conflict_state= ABORTED;
-}
-
-#define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1
-#define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2
-
-static rpl_group_info* wsrep_relay_group_init(const char* log_fname)
-{
- Relay_log_info* rli= new Relay_log_info(false);
-
- if (!rli->relay_log.description_event_for_exec)
- {
- rli->relay_log.description_event_for_exec=
- new Format_description_log_event(4);
- }
-
- static LEX_CSTRING connection_name= { STRING_WITH_LEN("wsrep") };
-
- /*
- Master_info's constructor initializes rpl_filter by either an already
- constructed Rpl_filter object from global 'rpl_filters' list if the
- specified connection name is same, or it constructs a new Rpl_filter
- object and adds it to rpl_filters. This object is later destructed by
- Mater_info's destructor by looking it up based on connection name in
- rpl_filters list.
-
- However, since all Master_info objects created here would share same
- connection name ("wsrep"), destruction of any of the existing Master_info
- objects (in wsrep_return_from_bf_mode()) would free rpl_filter referenced
- by any/all existing Master_info objects.
-
- In order to avoid that, we have added a check in Master_info's destructor
- to not free the "wsrep" rpl_filter. It will eventually be freed by
- free_all_rpl_filters() when server terminates.
- */
- rli->mi = new Master_info(&connection_name, false);
-
- struct rpl_group_info *rgi= new rpl_group_info(rli);
- rgi->thd= rli->sql_driver_thd= current_thd;
-
- if ((rgi->deferred_events_collecting= rli->mi->rpl_filter->is_on()))
- {
- rgi->deferred_events= new Deferred_log_events(rli);
- }
-
- return rgi;
-}
-
-static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
+static void wsrep_replication_process(THD *thd,
+ void* arg __attribute__((unused)))
{
- shadow->options = thd->variables.option_bits;
- shadow->server_status = thd->server_status;
- shadow->wsrep_exec_mode = thd->wsrep_exec_mode;
- shadow->vio = thd->net.vio;
-
- // Disable general logging on applier threads
- thd->variables.option_bits |= OPTION_LOG_OFF;
- // Enable binlogging if opt_log_slave_updates is set
- if (opt_log_slave_updates)
- thd->variables.option_bits|= OPTION_BIN_LOG;
- else
- thd->variables.option_bits&= ~(OPTION_BIN_LOG);
+ DBUG_ENTER("wsrep_replication_process");
- if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init("wsrep_relay");
+ Wsrep_applier_service applier_service(thd);
/* thd->system_thread_info.rpl_sql_info isn't initialized. */
thd->system_thread_info.rpl_sql_info=
new rpl_sql_thread_info(thd->wsrep_rgi->rli->mi->rpl_filter);
- thd->wsrep_exec_mode= REPL_RECV;
- thd->net.vio= 0;
- thd->clear_error();
-
- shadow->tx_isolation = thd->variables.tx_isolation;
- thd->variables.tx_isolation = ISO_READ_COMMITTED;
- thd->tx_isolation = ISO_READ_COMMITTED;
-
- shadow->db = thd->db.str;
- shadow->db_length = thd->db.length;
- shadow->user_time = thd->user_time;
- shadow->row_count_func= thd->get_row_count_func();
- thd->reset_db(&null_clex_str);
-}
+ WSREP_INFO("Starting applier thread %llu", thd->thread_id);
+ enum wsrep::provider::status
+ ret= Wsrep_server_state::get_provider().run_applier(&applier_service);
-static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow)
-{
- LEX_CSTRING db= {shadow->db, shadow->db_length };
- 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(&db);
+ WSREP_INFO("Applier thread exiting %d", ret);
+ mysql_mutex_lock(&LOCK_thread_count);
+ wsrep_close_applier(thd);
+ mysql_cond_broadcast(&COND_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
delete thd->system_thread_info.rpl_sql_info;
delete thd->wsrep_rgi->rli->mi;
delete thd->wsrep_rgi->rli;
-
+
thd->wsrep_rgi->cleanup_after_session();
delete thd->wsrep_rgi;
- thd->wsrep_rgi = NULL;
- thd->set_row_count_func(shadow->row_count_func);
-}
-
-void wsrep_replay_transaction(THD *thd)
-{
- DBUG_ENTER("wsrep_replay_transaction");
- /* checking if BF trx must be replayed */
- if (thd->wsrep_conflict_state== MUST_REPLAY) {
- DBUG_ASSERT(wsrep_thd_trx_seqno(thd));
- if (thd->wsrep_exec_mode!= REPL_RECV) {
- if (thd->get_stmt_da()->is_sent())
- {
- WSREP_ERROR("replay issue, thd has reported status already");
- }
-
-
- /*
- PS reprepare observer should have been removed already.
- open_table() will fail if we have dangling observer here.
- */
- DBUG_ASSERT(thd->m_reprepare_observer == NULL);
-
- struct da_shadow
- {
- enum Diagnostics_area::enum_diagnostics_status status;
- ulonglong affected_rows;
- ulonglong last_insert_id;
- char message[MYSQL_ERRMSG_SIZE];
- };
- struct da_shadow da_status;
- da_status.status= thd->get_stmt_da()->status();
- if (da_status.status == Diagnostics_area::DA_OK)
- {
- da_status.affected_rows= thd->get_stmt_da()->affected_rows();
- da_status.last_insert_id= thd->get_stmt_da()->last_insert_id();
- strmake(da_status.message,
- thd->get_stmt_da()->message(),
- sizeof(da_status.message)-1);
- }
-
- thd->get_stmt_da()->reset_diagnostics_area();
-
- thd->wsrep_conflict_state= REPLAYING;
- mysql_mutex_unlock(&thd->LOCK_thd_data);
+ thd->wsrep_rgi= NULL;
- thd->reset_for_next_command();
- thd->reset_killed();
- close_thread_tables(thd);
- if (thd->locked_tables_mode && thd->lock)
- {
- WSREP_DEBUG("releasing table lock for replaying (%lld)",
- (longlong) thd->thread_id);
- thd->locked_tables_list.unlock_locked_tables(thd);
- thd->variables.option_bits&= ~(OPTION_TABLE_LOCK);
- }
- thd->mdl_context.release_transactional_locks();
- /*
- Replaying will call MYSQL_START_STATEMENT when handling
- BEGIN Query_log_event so end statement must be called before
- replaying.
- */
- MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
- thd->m_statement_psi= NULL;
- thd->m_digest= NULL;
- thd_proc_info(thd, "WSREP replaying trx");
- WSREP_DEBUG("replay trx: %s %lld",
- thd->query() ? thd->query() : "void",
- (long long)wsrep_thd_trx_seqno(thd));
- struct wsrep_thd_shadow shadow;
- wsrep_prepare_bf_thd(thd, &shadow);
-
- /* From trans_begin() */
- thd->variables.option_bits|= OPTION_BEGIN;
- thd->server_status|= SERVER_STATUS_IN_TRANS;
-
- int rcode = wsrep->replay_trx(wsrep,
- &thd->wsrep_ws_handle,
- (void *)thd);
-
- wsrep_return_from_bf_mode(thd, &shadow);
- if (thd->wsrep_conflict_state!= REPLAYING)
- WSREP_WARN("lost replaying mode: %d", thd->wsrep_conflict_state );
-
- mysql_mutex_lock(&thd->LOCK_thd_data);
-
- 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: %lld %lld",
- (longlong) thd->thread_id, (longlong) thd->real_id);
- if (thd->get_stmt_da()->is_sent())
- {
- WSREP_WARN("replay ok, thd has reported status");
- }
- else if (thd->get_stmt_da()->is_set())
- {
- if (thd->get_stmt_da()->status() != Diagnostics_area::DA_OK &&
- thd->get_stmt_da()->status() != Diagnostics_area::DA_OK_BULK)
- {
- WSREP_WARN("replay ok, thd has error status %d",
- thd->get_stmt_da()->status());
- }
- }
- else
- {
- if (da_status.status == Diagnostics_area::DA_OK)
- {
- my_ok(thd,
- da_status.affected_rows,
- da_status.last_insert_id,
- da_status.message);
- }
- else
- {
- my_ok(thd);
- }
- }
- break;
- case WSREP_TRX_FAIL:
- if (thd->get_stmt_da()->is_sent())
- {
- WSREP_ERROR("replay failed, thd has reported status");
- }
- else
- {
- WSREP_DEBUG("replay failed, rolling back");
- }
- thd->wsrep_conflict_state= ABORTED;
- wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle);
- break;
- default:
- WSREP_ERROR("trx_replay failed for: %d, schema: %s, query: %s",
- rcode, thd->get_db(),
- thd->query() ? thd->query() : "void");
- /* we're now in inconsistent state, must abort */
-
- /* http://bazaar.launchpad.net/~codership/codership-mysql/5.6/revision/3962#sql/wsrep_thd.cc */
- mysql_mutex_unlock(&thd->LOCK_thd_data);
-
- unireg_abort(1);
- break;
- }
-
- wsrep_cleanup_transaction(thd);
-
- mysql_mutex_lock(&LOCK_wsrep_replaying);
- wsrep_replaying--;
- WSREP_DEBUG("replaying decreased: %d, thd: %lld",
- wsrep_replaying, (longlong) thd->thread_id);
- mysql_cond_broadcast(&COND_wsrep_replaying);
- mysql_mutex_unlock(&LOCK_wsrep_replaying);
- }
- }
- DBUG_VOID_RETURN;
-}
-
-static void wsrep_replication_process(THD *thd)
-{
- int rcode;
- DBUG_ENTER("wsrep_replication_process");
-
- struct wsrep_thd_shadow shadow;
- wsrep_prepare_bf_thd(thd, &shadow);
-
- /* From trans_begin() */
- thd->variables.option_bits|= OPTION_BEGIN;
- thd->server_status|= SERVER_STATUS_IN_TRANS;
-
- rcode = wsrep->recv(wsrep, (void *)thd);
- DBUG_PRINT("wsrep",("wsrep_repl returned: %d", rcode));
-
- WSREP_INFO("applier thread exiting (code:%d)", rcode);
-
- switch (rcode) {
- case WSREP_OK:
- case WSREP_NOT_IMPLEMENTED:
- case WSREP_CONN_FAIL:
- /* provider does not support slave operations / disconnected from group,
- * just close applier thread */
- break;
- case WSREP_NODE_FAIL:
- /* data inconsistency => SST is needed */
- /* Note: we cannot just blindly restart replication here,
- * SST might require server restart if storage engines must be
- * initialized after SST */
- WSREP_ERROR("node consistency compromised, aborting");
- wsrep_kill_mysql(thd);
- break;
- case WSREP_WARNING:
- case WSREP_TRX_FAIL:
- case WSREP_TRX_MISSING:
- /* these suggests a bug in provider code */
- WSREP_WARN("bad return from recv() call: %d", rcode);
- /* Shut down this node. */
- /* fall through */
- case WSREP_FATAL:
- /* Cluster connectivity is lost.
- *
- * If applier was killed on purpose (KILL_CONNECTION), we
- * avoid mysql shutdown. This is because the killer will then handle
- * shutdown processing (or replication restarting)
- */
- if (thd->killed != KILL_CONNECTION)
- {
- wsrep_kill_mysql(thd);
- }
- break;
- }
-
- mysql_mutex_lock(&LOCK_thread_count);
- wsrep_close_applier(thd);
- mysql_cond_broadcast(&COND_thread_count);
- mysql_mutex_unlock(&LOCK_thread_count);
if(thd->has_thd_temporary_tables())
{
WSREP_WARN("Applier %lld has temporary tables at exit.",
thd->thread_id);
}
- wsrep_return_from_bf_mode(thd, &shadow);
DBUG_VOID_RETURN;
}
-static bool create_wsrep_THD(wsrep_thd_processor_fun processor)
+static bool create_wsrep_THD(Wsrep_thd_args* args)
{
ulong old_wsrep_running_threads= wsrep_running_threads;
pthread_t unused;
mysql_mutex_lock(&LOCK_thread_count);
+
bool res= pthread_create(&unused, &connection_attrib, start_wsrep_THD,
- (void*)processor);
+ args);
/*
if starting a thread on server startup, wait until the this thread's THD
is fully initialized (otherwise a THD initialization code might
@@ -435,244 +105,291 @@ static bool create_wsrep_THD(wsrep_thd_processor_fun processor)
void wsrep_create_appliers(long threads)
{
- if (!wsrep_connected)
+ /* Dont' start slave threads if wsrep-provider or wsrep-cluster-address
+ is not set.
+ */
+ if (!WSREP_PROVIDER_EXISTS)
+ {
+ return;
+ }
+
+ if (!wsrep_cluster_address || wsrep_cluster_address[0]== 0)
{
- /* 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;
- while (wsrep_threads++ < threads) {
- if (create_wsrep_THD(wsrep_replication_process))
+
+ while (wsrep_threads++ < threads)
+ {
+ Wsrep_thd_args* args(new Wsrep_thd_args(wsrep_replication_process, 0));
+ if (create_wsrep_THD(args))
+ {
WSREP_WARN("Can't create thread to manage wsrep replication");
+ }
}
}
-static void wsrep_rollback_process(THD *thd)
+static void wsrep_rollback_process(THD *rollbacker,
+ void *arg __attribute__((unused)))
{
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;
+ THD* thd= NULL;
+ DBUG_ASSERT(!wsrep_rollback_queue);
+ wsrep_rollback_queue= new Wsrep_thd_queue(rollbacker);
- mysql_cond_wait(&COND_wsrep_rollback,&LOCK_wsrep_rollback);
+ thd_proc_info(rollbacker, "wsrep aborter idle");
+ while ((thd= wsrep_rollback_queue->pop_front()) != NULL)
+ {
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ wsrep::client_state& cs(thd->wsrep_cs());
+ const wsrep::transaction& tx(cs.transaction());
+ if (tx.state() == wsrep::transaction::s_aborted)
+ {
+ WSREP_DEBUG("rollbacker thd already aborted: %llu state: %d",
+ (long long)thd->real_id,
+ tx.state());
- WSREP_DEBUG("WSREP rollback thread wakes for signal");
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ continue;
+ }
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
- 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);
+ thd_proc_info(rollbacker, "wsrep aborter active");
- /* check for false alarms */
- if (!wsrep_aborting_thd)
+ wsrep::transaction_id transaction_id(thd->wsrep_trx().id());
+ if (thd->wsrep_trx().is_streaming() &&
+ thd->wsrep_trx().bf_aborted_in_total_order())
{
- 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_thd_data);
- if (aborting->wsrep_conflict_state== ABORTED)
+ thd->store_globals();
+ thd->wsrep_cs().store_globals();
+ if (thd->wsrep_cs().mode() == wsrep::client_state::m_high_priority)
{
- WSREP_DEBUG("WSREP, thd already aborted: %llu state: %d",
- (long long)aborting->real_id,
- aborting->wsrep_conflict_state);
-
- mysql_mutex_unlock(&aborting->LOCK_thd_data);
- mysql_mutex_lock(&LOCK_wsrep_rollback);
- continue;
+ DBUG_ASSERT(thd->wsrep_applier_service);
+ thd->wsrep_applier_service->rollback(wsrep::ws_handle(),
+ wsrep::ws_meta());
+ thd->wsrep_applier_service->after_apply();
+ /* Will free THD */
+ Wsrep_server_state::instance().server_service().
+ release_high_priority_service(thd->wsrep_applier_service);
}
- aborting->wsrep_conflict_state= ABORTING;
-
- mysql_mutex_unlock(&aborting->LOCK_thd_data);
-
- set_current_thd(aborting);
- aborting->store_globals();
-
- mysql_mutex_lock(&aborting->LOCK_thd_data);
- wsrep_client_rollback(aborting);
- WSREP_DEBUG("WSREP rollbacker aborted thd: (%lld %lld)",
- (longlong) aborting->thread_id,
- (longlong) aborting->real_id);
- mysql_mutex_unlock(&aborting->LOCK_thd_data);
-
- set_current_thd(thd);
+ else
+ {
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ /* prepare THD for rollback processing */
+ thd->reset_for_next_command(true);
+ thd->lex->sql_command= SQLCOM_ROLLBACK;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ /* Perform a client rollback, restore globals and signal
+ the victim only when all the resources have been
+ released */
+ thd->wsrep_cs().client_service().bf_rollback();
+ thd->reset_globals();
+ thd->wsrep_cs().sync_rollback_complete();
+ }
+ }
+ else if (wsrep_thd_is_applying(thd))
+ {
+ WSREP_DEBUG("rollbacker aborting SR thd: (%lld %llu)",
+ thd->thread_id, (long long)thd->real_id);
+ DBUG_ASSERT(thd->wsrep_cs().mode() == Wsrep_client_state::m_high_priority);
+ /* Must be streaming and must have been removed from the
+ server state streaming appliers map. */
+ DBUG_ASSERT(thd->wsrep_trx().is_streaming());
+ DBUG_ASSERT(!Wsrep_server_state::instance().find_streaming_applier(
+ thd->wsrep_trx().server_id(),
+ thd->wsrep_trx().id()));
+ DBUG_ASSERT(thd->wsrep_applier_service);
+
+ /* Fragment removal should happen before rollback to make
+ the transaction non-observable in SR table after the rollback
+ completes. For correctness the order does not matter here,
+ but currently it is mandated by checks in some MTR tests. */
+ Wsrep_storage_service* storage_service=
+ static_cast<Wsrep_storage_service*>(
+ Wsrep_server_state::instance().server_service().storage_service(
+ *thd->wsrep_applier_service));
+ storage_service->store_globals();
+ storage_service->adopt_transaction(thd->wsrep_trx());
+ storage_service->remove_fragments();
+ storage_service->commit(wsrep::ws_handle(transaction_id, 0),
+ wsrep::ws_meta());
+ Wsrep_server_state::instance().server_service().release_storage_service(storage_service);
thd->store_globals();
+ thd->wsrep_cs().store_globals();
+ thd->wsrep_applier_service->rollback(wsrep::ws_handle(),
+ wsrep::ws_meta());
+ thd->wsrep_applier_service->after_apply();
+ /* Will free THD */
+ Wsrep_server_state::instance().server_service()
+ .release_high_priority_service(thd->wsrep_applier_service);
- mysql_mutex_lock(&LOCK_wsrep_rollback);
}
+ else
+ {
+ if (thd->wsrep_trx().is_streaming())
+ {
+ Wsrep_storage_service* storage_service=
+ static_cast<Wsrep_storage_service*>(
+ Wsrep_server_state::instance().server_service().
+ storage_service(thd->wsrep_cs().client_service()));
+
+ storage_service->store_globals();
+ storage_service->adopt_transaction(thd->wsrep_trx());
+ storage_service->remove_fragments();
+ storage_service->commit(wsrep::ws_handle(transaction_id, 0),
+ wsrep::ws_meta());
+ Wsrep_server_state::instance().server_service().
+ release_storage_service(storage_service);
+ }
+ thd->store_globals();
+ thd->wsrep_cs().store_globals();
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ /* prepare THD for rollback processing */
+ thd->reset_for_next_command();
+ thd->lex->sql_command= SQLCOM_ROLLBACK;
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
+ /* Perform a client rollback, restore globals and signal
+ the victim only when all the resources have been
+ released */
+ thd->wsrep_cs().client_service().bf_rollback();
+ thd->reset_globals();
+ thd->wsrep_cs().sync_rollback_complete();
+ WSREP_DEBUG("rollbacker aborted thd: (%llu %llu)",
+ thd->thread_id, (long long)thd->real_id);
+ }
+
+ thd_proc_info(rollbacker, "wsrep aborter idle");
}
+
+ delete wsrep_rollback_queue;
+ wsrep_rollback_queue= NULL;
- mysql_mutex_unlock(&LOCK_wsrep_rollback);
sql_print_information("WSREP: rollbacker thread exiting");
+ DBUG_ASSERT(rollbacker->killed != NOT_KILLED);
DBUG_PRINT("wsrep",("wsrep rollbacker thread exiting"));
DBUG_VOID_RETURN;
}
-void wsrep_create_rollbacker()
+static void wsrep_post_rollback_process(THD *post_rollbacker,
+ void *arg __attribute__((unused)))
{
- if (wsrep_provider && strcasecmp(wsrep_provider, "none"))
- {
- /* create rollbacker */
- if (create_wsrep_THD(wsrep_rollback_process))
- WSREP_WARN("Can't create thread to manage wsrep rollback");
- }
-}
+ DBUG_ENTER("wsrep_post_rollback_process");
+ THD* thd= NULL;
-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;
- }
-}
+ DBUG_ASSERT(!wsrep_post_rollback_queue);
+ wsrep_post_rollback_queue= new Wsrep_thd_queue(post_rollbacker);
-enum wsrep_conflict_state wsrep_thd_conflict_state(THD *thd, my_bool sync)
-{
- enum wsrep_conflict_state state = NO_CONFLICT;
- if (thd)
+ while ((thd= wsrep_post_rollback_queue->pop_front()) != NULL)
{
- if (sync) mysql_mutex_lock(&thd->LOCK_thd_data);
-
- state = thd->wsrep_conflict_state;
- if (sync) mysql_mutex_unlock(&thd->LOCK_thd_data);
+ thd->store_globals();
+ wsrep::client_state& cs(thd->wsrep_cs());
+ mysql_mutex_lock(&thd->LOCK_thd_data);
+ DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_aborting);
+ WSREP_DEBUG("post rollbacker calling post rollback for thd %llu, conf %s",
+ thd->thread_id, wsrep_thd_transaction_state_str(thd));
+
+ cs.after_rollback();
+ DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_aborted);
+ mysql_mutex_unlock(&thd->LOCK_thd_data);
}
- return state;
-}
-my_bool wsrep_thd_is_wsrep(THD *thd)
-{
- my_bool status = FALSE;
- if (thd)
- {
- status = (WSREP(thd) && WSREP_PROVIDER_EXISTS);
- }
- return status;
+ delete wsrep_post_rollback_queue;
+ wsrep_post_rollback_queue= NULL;
+
+ DBUG_ASSERT(post_rollbacker->killed != NOT_KILLED);
+ DBUG_PRINT("wsrep",("wsrep post rollbacker thread exiting"));
+ DBUG_VOID_RETURN;
}
-my_bool wsrep_thd_is_BF(THD *thd, my_bool sync)
+void wsrep_create_rollbacker()
{
- my_bool status = FALSE;
- if (thd)
+ if (wsrep_provider && strcasecmp(wsrep_provider, "none"))
{
- // THD can be BF only if provider exists
- if (wsrep_thd_is_wsrep(thd))
- {
- if (sync)
- mysql_mutex_lock(&thd->LOCK_thd_data);
+ Wsrep_thd_args* args= new Wsrep_thd_args(wsrep_rollback_process, 0);
- status = ((thd->wsrep_exec_mode == REPL_RECV) ||
- (thd->wsrep_exec_mode == TOTAL_ORDER));
- if (sync)
- mysql_mutex_unlock(&thd->LOCK_thd_data);
- }
- }
- return status;
-}
+ /* create rollbacker */
+ if (create_wsrep_THD(args))
+ WSREP_WARN("Can't create thread to manage wsrep rollback");
-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_thd_data);
-
- 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_thd_data);
- }
- return status;
+ /* create post_rollbacker */
+ args= new Wsrep_thd_args(wsrep_post_rollback_process, 0);
+ if (create_wsrep_THD(args))
+ WSREP_WARN("Can't create thread to manage wsrep post rollback");
+ }
}
-extern "C"
-my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync)
+/*
+ Start async rollback process
+
+ Asserts thd->LOCK_thd_data ownership
+ */
+void wsrep_fire_rollbacker(THD *thd)
{
- bool status = FALSE;
- if (thd_ptr)
+ DBUG_ASSERT(thd->wsrep_trx().state() == wsrep::transaction::s_aborting);
+ DBUG_PRINT("wsrep",("enqueuing trx abort for %llu", thd->thread_id));
+ WSREP_DEBUG("enqueuing trx abort for (%llu)", thd->thread_id);
+ if (wsrep_rollback_queue->push_back(thd))
{
- THD* thd = (THD*)thd_ptr;
- if (sync) mysql_mutex_lock(&thd->LOCK_thd_data);
-
- status = (thd->wsrep_exec_mode == LOCAL_STATE);
- if (sync) mysql_mutex_unlock(&thd->LOCK_thd_data);
+ WSREP_WARN("duplicate thd %llu for rollbacker",
+ thd->thread_id);
}
- return status;
}
+
int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal)
{
- THD *victim_thd = (THD *) victim_thd_ptr;
- THD *bf_thd = (THD *) bf_thd_ptr;
DBUG_ENTER("wsrep_abort_thd");
-
+ THD *victim_thd= (THD *) victim_thd_ptr;
+ THD *bf_thd= (THD *) bf_thd_ptr;
+ mysql_mutex_lock(&victim_thd->LOCK_thd_data);
if ( (WSREP(bf_thd) ||
( (WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) &&
- bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) &&
- victim_thd)
+ wsrep_thd_is_toi(bf_thd)) ) &&
+ victim_thd &&
+ !wsrep_thd_is_aborting(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_abort_transaction(bf_thd, victim_thd, signal);
+ WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ?
+ (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id);
+ mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
+ ha_abort_transaction(bf_thd, victim_thd, signal);
+ mysql_mutex_lock(&victim_thd->LOCK_thd_data);
}
else
{
WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd);
}
-
+ mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
DBUG_RETURN(1);
}
-extern "C"
-int wsrep_thd_in_locking_session(void *thd_ptr)
+bool wsrep_bf_abort(const THD* bf_thd, THD* victim_thd)
{
- if (thd_ptr && ((THD *)thd_ptr)->in_lock_tables) {
- return 1;
+ WSREP_LOG_THD((THD*)bf_thd, "BF aborter before");
+ WSREP_LOG_THD(victim_thd, "victim before");
+ wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno());
+
+ if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
+ {
+ WSREP_DEBUG("wsrep_bf_abort, BF abort for non active transaction");
+ wsrep_start_transaction(victim_thd, victim_thd->wsrep_next_trx_id());
}
- return 0;
-}
-bool wsrep_thd_has_explicit_locks(THD *thd)
-{
- assert(thd);
- return thd->mdl_context.has_explicit_locks();
+ bool ret;
+ if (wsrep_thd_is_toi(bf_thd))
+ {
+ ret= victim_thd->wsrep_cs().total_order_bf_abort(bf_seqno);
+ }
+ else
+ {
+ ret= victim_thd->wsrep_cs().bf_abort(bf_seqno);
+ }
+ if (ret)
+ {
+ wsrep_bf_aborts_counter++;
+ }
+ return ret;
}
+
diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h
index 5900668f3fb..3114e02e1b8 100644
--- a/sql/wsrep_thd.h
+++ b/sql/wsrep_thd.h
@@ -13,42 +13,220 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
-#include <my_config.h>
-
#ifndef WSREP_THD_H
#define WSREP_THD_H
-#ifdef WITH_WSREP
+#include <my_config.h>
+#include "mysql/service_wsrep.h"
+#include "wsrep/client_state.hpp"
#include "sql_class.h"
+#include "wsrep_utils.h"
+#include <deque>
+class Wsrep_thd_queue
+{
+public:
+ Wsrep_thd_queue(THD* t) : thd(t)
+ {
+ mysql_mutex_init(key_LOCK_wsrep_thd_queue,
+ &LOCK_wsrep_thd_queue,
+ MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_wsrep_thd_queue, &COND_wsrep_thd_queue, NULL);
+ }
+ ~Wsrep_thd_queue()
+ {
+ mysql_mutex_destroy(&LOCK_wsrep_thd_queue);
+ mysql_cond_destroy(&COND_wsrep_thd_queue);
+ }
+ bool push_back(THD* thd)
+ {
+ DBUG_ASSERT(thd);
+ wsp::auto_lock lock(&LOCK_wsrep_thd_queue);
+ std::deque<THD*>::iterator it = queue.begin();
+ while (it != queue.end())
+ {
+ if (*it == thd)
+ {
+ return true;
+ }
+ it++;
+ }
+ queue.push_back(thd);
+ mysql_cond_signal(&COND_wsrep_thd_queue);
+ return false;
+ }
+ THD* pop_front()
+ {
+ wsp::auto_lock lock(&LOCK_wsrep_thd_queue);
+ while (queue.empty())
+ {
+ if (thd->killed != NOT_KILLED)
+ return NULL;
+
+ thd->mysys_var->current_mutex= &LOCK_wsrep_thd_queue;
+ thd->mysys_var->current_cond= &COND_wsrep_thd_queue;
+
+ mysql_cond_wait(&COND_wsrep_thd_queue, &LOCK_wsrep_thd_queue);
+
+ thd->mysys_var->current_mutex= 0;
+ thd->mysys_var->current_cond= 0;
+ }
+ THD* ret= queue.front();
+ queue.pop_front();
+ return ret;
+ }
+private:
+ THD* thd;
+ std::deque<THD*> queue;
+ mysql_mutex_t LOCK_wsrep_thd_queue;
+ mysql_cond_t COND_wsrep_thd_queue;
+};
+
+void wsrep_prepare_bf_thd(THD*, struct wsrep_thd_shadow*);
+void wsrep_return_from_bf_mode(THD*, struct wsrep_thd_shadow*);
int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope);
-void wsrep_client_rollback(THD *thd);
+void wsrep_client_rollback(THD *thd, bool rollbacker = false);
void wsrep_replay_transaction(THD *thd);
void wsrep_create_appliers(long threads);
void wsrep_create_rollbacker();
+bool wsrep_bf_abort(const THD*, THD*);
int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
my_bool signal);
-
-/*
- PA = Parallel Applying (on the slave side)
-*/
extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
-extern my_bool wsrep_thd_is_BF(THD *thd, my_bool sync);
-extern my_bool wsrep_thd_is_wsrep(void *thd_ptr);
+THD* wsrep_start_SR_THD(char *thread_stack);
+void wsrep_end_SR_THD(THD* thd);
+
+/**
+ Helper functions to override error status
+
+ In many contexts it is desirable to mask the original error status
+ set for THD or it is necessary to change OK status to error.
+ This function implements the common logic for the most
+ of the cases.
+
+ Rules:
+ * If the diagnostics are has OK or EOF status, override it unconditionally
+ * If the error is either ER_ERROR_DURING_COMMIT or ER_LOCK_DEADLOCK
+ it is usually the correct error status to be returned to client,
+ so don't override those by default
+ */
+
+static inline void wsrep_override_error(THD *thd, uint error)
+{
+ DBUG_ASSERT(error != ER_ERROR_DURING_COMMIT);
+ Diagnostics_area *da= thd->get_stmt_da();
+ if (da->is_ok() ||
+ da->is_eof() ||
+ !da->is_set() ||
+ (da->is_error() &&
+ da->sql_errno() != error &&
+ da->sql_errno() != ER_ERROR_DURING_COMMIT &&
+ da->sql_errno() != ER_LOCK_DEADLOCK))
+ {
+ da->reset_diagnostics_area();
+ my_error(error, MYF(0));
+ }
+}
+
+/**
+ Override error with additional wsrep status.
+ */
+static inline void wsrep_override_error(THD *thd, uint error,
+ enum wsrep::provider::status status)
+{
+ Diagnostics_area *da= thd->get_stmt_da();
+ if (da->is_ok() ||
+ !da->is_set() ||
+ (da->is_error() &&
+ da->sql_errno() != error &&
+ da->sql_errno() != ER_ERROR_DURING_COMMIT &&
+ da->sql_errno() != ER_LOCK_DEADLOCK))
+ {
+ da->reset_diagnostics_area();
+ my_error(error, MYF(0), status);
+ }
+}
+
+static inline void wsrep_override_error(THD* thd,
+ wsrep::client_error ce,
+ enum wsrep::provider::status status)
+{
+ DBUG_ASSERT(ce != wsrep::e_success);
+ switch (ce)
+ {
+ case wsrep::e_error_during_commit:
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status);
+ break;
+ case wsrep::e_deadlock_error:
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ break;
+ case wsrep::e_interrupted_error:
+ wsrep_override_error(thd, ER_QUERY_INTERRUPTED);
+ break;
+ case wsrep::e_size_exceeded_error:
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status);
+ break;
+ case wsrep::e_append_fragment_error:
+ /* TODO: Figure out better error number */
+ wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status);
+ break;
+ case wsrep::e_not_supported_error:
+ wsrep_override_error(thd, ER_NOT_SUPPORTED_YET);
+ break;
+ case wsrep::e_timeout_error:
+ wsrep_override_error(thd, ER_LOCK_WAIT_TIMEOUT);
+ break;
+ default:
+ wsrep_override_error(thd, ER_UNKNOWN_ERROR);
+ break;
+ }
+}
-enum wsrep_conflict_state wsrep_thd_conflict_state(void *thd_ptr, my_bool sync);
-extern "C" my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync);
-extern "C" my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync);
-extern "C" int wsrep_thd_in_locking_session(void *thd_ptr);
+/**
+ Helper function to log THD wsrep context.
-#else /* WITH_WSREP */
+ @param thd Pointer to THD
+ @param message Optional message
+ @param function Function where the call was made from
+ */
+static inline void wsrep_log_thd(THD *thd,
+ const char *message,
+ const char *function)
+{
+ WSREP_DEBUG("%s %s\n"
+ " thd: %llu thd_ptr: %p client_mode: %s client_state: %s trx_state: %s\n"
+ " next_trx_id: %lld trx_id: %lld seqno: %lld\n"
+ " is_streaming: %d fragments: %zu\n"
+ " sql_errno: %u message: %s\n"
+#define WSREP_THD_LOG_QUERIES
+#ifdef WSREP_THD_LOG_QUERIES
+ " command: %d query: %.72s"
+#endif /* WSREP_OBSERVER_LOG_QUERIES */
+ ,
+ function,
+ message ? message : "",
+ thd->thread_id,
+ thd,
+ wsrep_thd_client_mode_str(thd),
+ wsrep_thd_client_state_str(thd),
+ wsrep_thd_transaction_state_str(thd),
+ (long long)thd->wsrep_next_trx_id(),
+ (long long)thd->wsrep_trx_id(),
+ (long long)wsrep_thd_trx_seqno(thd),
+ thd->wsrep_trx().is_streaming(),
+ thd->wsrep_sr().fragments().size(),
+ (thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0),
+ (thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->message() : "")
+#ifdef WSREP_THD_LOG_QUERIES
+ , thd->lex->sql_command,
+ WSREP_QUERY(thd)
+#endif /* WSREP_OBSERVER_LOG_QUERIES */
+ );
+}
-#define wsrep_thd_is_BF(T, S) (0)
-#define wsrep_abort_thd(X,Y,Z) do { } while(0)
-#define wsrep_create_appliers(T) do { } while(0)
+#define WSREP_LOG_THD(thd_, message_) wsrep_log_thd(thd_, message_, __FUNCTION__)
-#endif
#endif /* WSREP_THD_H */
diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h
new file mode 100644
index 00000000000..a3acc9e78fb
--- /dev/null
+++ b/sql/wsrep_trans_observer.h
@@ -0,0 +1,423 @@
+/* Copyright 2016 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_TRANS_OBSERVER_H
+#define WSREP_TRANS_OBSERVER_H
+
+#include "my_global.h"
+#include "mysql/service_wsrep.h"
+#include "wsrep_applier.h" /* wsrep_apply_error */
+#include "wsrep_xid.h"
+#include "wsrep_thd.h"
+
+#include "my_dbug.h"
+
+class THD;
+
+/*
+ Return true if THD has active wsrep transaction.
+ */
+static inline bool wsrep_is_active(THD* thd)
+{
+ return (thd->wsrep_cs().state() != wsrep::client_state::s_none &&
+ thd->wsrep_cs().transaction().active());
+}
+
+/*
+ Return true if THD is either committing a transaction or statement
+ is autocommit.
+ */
+static inline bool wsrep_is_real(THD* thd, bool all)
+{
+ return (all || thd->transaction.all.ha_list == 0);
+}
+
+/*
+ Check if a transaction has generated changes.
+ */
+static inline bool wsrep_has_changes(THD* thd, my_bool all)
+{
+ return (thd->wsrep_trx().is_empty() == false);
+}
+
+/*
+ Check if an active transaction has been BF aborted.
+ */
+static inline bool wsrep_is_bf_aborted(THD* thd)
+{
+ return (thd->wsrep_trx().active() && thd->wsrep_trx().bf_aborted());
+}
+
+static inline int wsrep_check_pk(THD* thd)
+{
+ if (!wsrep_certify_nonPK)
+ {
+ for (TABLE* table= thd->open_tables; table != NULL; table= table->next)
+ {
+ if (table->key_info == NULL || table->s->primary_key == MAX_KEY)
+ {
+ WSREP_DEBUG("No primary key found for table %s.%s",
+ table->s->db.str, table->s->table_name.str);
+ wsrep_override_error(thd, ER_LOCK_DEADLOCK);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline bool wsrep_streaming_enabled(THD* thd)
+{
+ return (thd->wsrep_sr().fragment_size() > 0);
+}
+
+
+static inline int wsrep_start_transaction(THD* thd, wsrep_trx_id_t trx_id)
+{
+ return (thd->wsrep_cs().state() != wsrep::client_state::s_none ?
+ thd->wsrep_cs().start_transaction(wsrep::transaction_id(trx_id)) :
+ 0);
+}
+
+/**/
+static inline int wsrep_start_trx_if_not_started(THD* thd)
+{
+ int ret= 0;
+ DBUG_ASSERT(thd->wsrep_next_trx_id() != WSREP_UNDEFINED_TRX_ID);
+ DBUG_ASSERT(thd->wsrep_cs().mode() == Wsrep_client_state::m_local);
+ if (thd->wsrep_trx().active() == false)
+ {
+ ret= wsrep_start_transaction(thd, thd->wsrep_next_trx_id());
+ }
+ return ret;
+}
+
+/*
+ Called after each row operation.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_after_row(THD* thd, bool)
+{
+ if (thd->wsrep_cs().state() != wsrep::client_state::s_none &&
+ wsrep_thd_is_local(thd))
+ {
+ if (wsrep_check_pk(thd))
+ {
+ return 1;
+ }
+ else if (wsrep_streaming_enabled(thd))
+ {
+ return thd->wsrep_cs().after_row();
+ }
+ }
+ return 0;
+}
+
+/*
+ Helper method to determine whether commit time hooks
+ should be run for the transaction.
+ */
+static inline bool wsrep_run_commit_hook(THD* thd, bool all)
+{
+ return (wsrep_is_real(thd, all) && wsrep_is_active(thd) &&
+ (wsrep_thd_is_applying(thd) || wsrep_has_changes(thd, all)));
+}
+
+/*
+ Called before the transaction is prepared.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_before_prepare(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_before_prepare");
+ WSREP_DEBUG("wsrep_before_prepare: %d", wsrep_is_real(thd, all));
+ int ret= 0;
+ if (wsrep_run_commit_hook(thd, all))
+ {
+ if ((ret= thd->wsrep_cs().before_prepare()) == 0)
+ {
+ DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined());
+ wsrep_xid_init(&thd->wsrep_xid,
+ thd->wsrep_trx().ws_meta().gtid());
+ }
+ }
+ DBUG_RETURN(ret);
+}
+
+/*
+ Called after the transaction has been prepared.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_after_prepare(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_after_prepare");
+ WSREP_DEBUG("wsrep_after_prepare: %d", wsrep_is_real(thd, all));
+ int ret= (wsrep_run_commit_hook(thd, all) ?
+ thd->wsrep_cs().after_prepare() : 0);
+ DBUG_ASSERT(ret == 0 || thd->wsrep_cs().current_error() ||
+ thd->wsrep_cs().transaction().state() == wsrep::transaction::s_must_replay);
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Called before the transaction is committed.
+
+ This function must be called from both client and
+ applier contexts before commit.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_before_commit(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_before_commit");
+ WSREP_DEBUG("wsrep_before_commit: %d, %lld",
+ wsrep_is_real(thd, all),
+ (long long)wsrep_thd_trx_seqno(thd));
+ int ret= 0;
+ if (wsrep_run_commit_hook(thd, all))
+ {
+ if ((ret= thd->wsrep_cs().before_commit()) == 0)
+ {
+ DBUG_ASSERT(!thd->wsrep_trx().ws_meta().gtid().is_undefined());
+ wsrep_xid_init(&thd->wsrep_xid,
+ thd->wsrep_trx().ws_meta().gtid());
+ }
+ }
+ DBUG_RETURN(ret);
+}
+
+/*
+ Called after the transaction has been ordered for commit.
+
+ This function must be called from both client and
+ applier contexts after the commit has been ordered.
+
+ @param thd Pointer to THD
+ @param all
+ @param err Error buffer in case of applying error
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_ordered_commit(THD* thd,
+ bool all,
+ const wsrep_apply_error&)
+{
+ DBUG_ENTER("wsrep_ordered_commit");
+ WSREP_DEBUG("wsrep_ordered_commit: %d", wsrep_is_real(thd, all));
+ DBUG_RETURN(wsrep_run_commit_hook(thd, all) ?
+ thd->wsrep_cs().ordered_commit() : 0);
+}
+
+/*
+ Called after the transaction has been committed.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_after_commit(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_after_commit");
+ WSREP_DEBUG("wsrep_after_commit: %d, %d, %lld, %d",
+ wsrep_is_real(thd, all),
+ wsrep_is_active(thd),
+ (long long)wsrep_thd_trx_seqno(thd),
+ wsrep_has_changes(thd, all));
+ if (wsrep_run_commit_hook(thd, all))
+ {
+ DBUG_RETURN((wsrep_ordered_commit_if_no_binlog(thd, all) ||
+ (thd->wsrep_xid.null(),
+ thd->wsrep_cs().after_commit())));
+ }
+ DBUG_RETURN(0);
+}
+
+/*
+ Called before the transaction is rolled back.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_before_rollback(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_before_rollback");
+ int ret= 0;
+ if (wsrep_is_active(thd))
+ {
+ if (!all && thd->in_active_multi_stmt_transaction() &&
+ thd->wsrep_trx().is_streaming() &&
+ !wsrep_stmt_rollback_is_safe(thd))
+ {
+ /* Non-safe statement rollback during SR multi statement
+ transasction. Self abort the transaction, the actual rollback
+ and error handling will be done in after statement phase. */
+ wsrep_thd_self_abort(thd);
+ ret= 0;
+ }
+ else if (wsrep_is_real(thd, all) &&
+ thd->wsrep_trx().state() != wsrep::transaction::s_aborted)
+ {
+ /* Real transaction rolling back and wsrep abort not completed
+ yet */
+ /* Reset XID so that it does not trigger writing serialization
+ history in InnoDB. This needs to be avoided because rollback
+ may happen out of order and replay may follow. */
+ thd->wsrep_xid.null();
+ ret= thd->wsrep_cs().before_rollback();
+ }
+ }
+ DBUG_RETURN(ret);
+}
+
+/*
+ Called after the transaction has been rolled back.
+
+ Return zero on succes, non-zero on failure.
+ */
+static inline int wsrep_after_rollback(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_after_rollback");
+ DBUG_RETURN((wsrep_is_real(thd, all) && wsrep_is_active(thd) &&
+ thd->wsrep_cs().transaction().state() !=
+ wsrep::transaction::s_aborted) ?
+ thd->wsrep_cs().after_rollback() : 0);
+}
+
+static inline int wsrep_before_statement(THD* thd)
+{
+ return (thd->wsrep_cs().state() != wsrep::client_state::s_none ?
+ thd->wsrep_cs().before_statement() : 0);
+}
+
+static inline
+int wsrep_after_statement(THD* thd)
+{
+ DBUG_ENTER("wsrep_after_statement");
+ DBUG_RETURN(thd->wsrep_cs().state() != wsrep::client_state::s_none ?
+ thd->wsrep_cs().after_statement() : 0);
+}
+
+static inline void wsrep_after_apply(THD* thd)
+{
+ DBUG_ASSERT(wsrep_thd_is_applying(thd));
+ WSREP_DEBUG("wsrep_after_apply %lld", thd->thread_id);
+ thd->wsrep_cs().after_applying();
+}
+
+static inline void wsrep_open(THD* thd)
+{
+ DBUG_ENTER("wsrep_open");
+ if (wsrep_on(thd))
+ {
+ thd->wsrep_cs().open(wsrep::client_id(thd->thread_id));
+ thd->wsrep_cs().debug_log_level(wsrep_debug);
+ if (!thd->wsrep_applier && thd->variables.wsrep_trx_fragment_size)
+ {
+ thd->wsrep_cs().enable_streaming(
+ wsrep_fragment_unit(thd->variables.wsrep_trx_fragment_unit),
+ size_t(thd->variables.wsrep_trx_fragment_size));
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+static inline void wsrep_close(THD* thd)
+{
+ DBUG_ENTER("wsrep_close");
+ if (thd->wsrep_cs().state() != wsrep::client_state::s_none)
+ {
+ thd->wsrep_cs().close();
+ }
+ DBUG_VOID_RETURN;
+}
+
+static inline int wsrep_before_command(THD* thd)
+{
+ return (thd->wsrep_cs().state() != wsrep::client_state::s_none ?
+ thd->wsrep_cs().before_command() : 0);
+}
+/*
+ Called after each command.
+
+ Return zero on success, non-zero on failure.
+*/
+static inline void wsrep_after_command_before_result(THD* thd)
+{
+ if (thd->wsrep_cs().state() != wsrep::client_state::s_none)
+ {
+ thd->wsrep_cs().after_command_before_result();
+ }
+}
+
+static inline void wsrep_after_command_after_result(THD* thd)
+{
+ if (thd->wsrep_cs().state() != wsrep::client_state::s_none)
+ {
+ thd->wsrep_cs().after_command_after_result();
+ }
+}
+
+static inline void wsrep_after_command_ignore_result(THD* thd)
+{
+ wsrep_after_command_before_result(thd);
+ DBUG_ASSERT(!thd->wsrep_cs().current_error());
+ wsrep_after_command_after_result(thd);
+}
+
+static inline enum wsrep::client_error wsrep_current_error(THD* thd)
+{
+ return thd->wsrep_cs().current_error();
+}
+
+static inline enum wsrep::provider::status
+wsrep_current_error_status(THD* thd)
+{
+ return thd->wsrep_cs().current_error_status();
+}
+
+
+/*
+ Commit an empty transaction.
+
+ If the transaction is real and the wsrep transaction is still active,
+ the transaction did not generate any rows or keys and is committed
+ as empty. Here the wsrep transaction is rolled back and after statement
+ step is performed to leave the wsrep transaction in the state as it
+ never existed.
+*/
+static inline void wsrep_commit_empty(THD* thd, bool all)
+{
+ DBUG_ENTER("wsrep_commit_empty");
+ WSREP_DEBUG("wsrep_commit_empty(%llu)", thd->thread_id);
+ if (wsrep_is_real(thd, all) &&
+ wsrep_thd_is_local(thd) &&
+ thd->wsrep_trx().active() &&
+ thd->wsrep_trx().state() != wsrep::transaction::s_committed)
+ {
+ bool have_error= wsrep_current_error(thd);
+ int ret= wsrep_before_rollback(thd, all) ||
+ wsrep_after_rollback(thd, all) ||
+ wsrep_after_statement(thd);
+ DBUG_ASSERT(have_error || !wsrep_current_error(thd));
+ if (ret)
+ {
+ WSREP_DEBUG("wsrep_commit_empty failed: %d", wsrep_current_error(thd));
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+#endif /* WSREP_TRANS_OBSERVER */
diff --git a/sql/wsrep_types.h b/sql/wsrep_types.h
new file mode 100644
index 00000000000..9da00e305a7
--- /dev/null
+++ b/sql/wsrep_types.h
@@ -0,0 +1,29 @@
+/* Copyright 2018 Codership Oy <info@codership.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/*
+ Wsrep typedefs to better conform to coding style.
+ */
+#ifndef WSREP_TYPES_H
+#define WSREP_TYPES_H
+
+#include "wsrep/seqno.hpp"
+#include "wsrep/view.hpp"
+
+typedef wsrep::id Wsrep_id;
+typedef wsrep::seqno Wsrep_seqno;
+typedef wsrep::view Wsrep_view;
+
+#endif /* WSREP_TYPES_H */
diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc
index 3c341e222b3..8db0f7be99a 100644
--- a/sql/wsrep_utils.cc
+++ b/sql/wsrep_utils.cc
@@ -21,6 +21,8 @@
#endif
#include "mariadb.h"
+#include "my_global.h"
+#include "wsrep_api.h"
#include "wsrep_utils.h"
#include "wsrep_mysqld.h"
@@ -47,7 +49,7 @@ static wsp::string wsrep_PATH;
void
wsrep_prepend_PATH (const char* path)
{
- int count = 0;
+ int count= 0;
while (environ[count])
{
@@ -72,7 +74,7 @@ wsrep_prepend_PATH (const char* path)
old_path + strlen("PATH="));
wsrep_PATH.set (new_path);
- environ[count] = new_path;
+ environ[count]= new_path;
}
else
{
@@ -93,28 +95,28 @@ namespace wsp
bool
env::ctor_common(char** e)
{
- env_ = static_cast<char**>(malloc((len_ + 1) * sizeof(char*)));
+ 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]);
+ env_[i]= strdup(e[i]);
if (!env_[i])
{
- errno_ = errno;
+ errno_= errno;
WSREP_ERROR("Failed to allocate env. var: %s", e[i]);
return true;
}
}
- env_[len_] = NULL;
+ env_[len_]= NULL;
return false;
}
else
{
- errno_ = errno;
+ errno_= errno;
WSREP_ERROR("Failed to allocate env. var vector of length: %zu", len_);
return true;
}
@@ -128,15 +130,15 @@ env::dtor()
/* 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;
+ env_= NULL;
}
- len_ = 0;
+ len_= 0;
}
env::env(char** e)
: len_(0), env_(NULL), errno_(0)
{
- if (!e) { e = environ; }
+ if (!e) { e= environ; }
/* count the size of the vector */
while (e[len_]) { ++len_; }
@@ -154,21 +156,21 @@ env::~env() { dtor(); }
int
env::append(const char* val)
{
- char** tmp = static_cast<char**>(realloc(env_, (len_ + 2)*sizeof(char*)));
+ char** tmp= static_cast<char**>(realloc(env_, (len_ + 2)*sizeof(char*)));
if (tmp)
{
- env_ = tmp;
- env_[len_] = strdup(val);
+ env_= tmp;
+ env_[len_]= strdup(val);
if (env_[len_])
{
++len_;
- env_[len_] = NULL;
+ env_[len_]= NULL;
}
- else errno_ = errno;
+ else errno_= errno;
}
- else errno_ = errno;
+ else errno_= errno;
return errno_;
}
@@ -189,7 +191,7 @@ process::process (const char* cmd, const char* type, char** env)
if (0 == str_)
{
WSREP_ERROR ("Can't allocate command line of size: %zu", strlen(cmd));
- err_ = ENOMEM;
+ err_= ENOMEM;
return;
}
@@ -205,12 +207,12 @@ process::process (const char* cmd, const char* type, char** env)
return;
}
- if (NULL == env) { env = environ; } // default to global environment
+ if (NULL == env) { env= environ; } // default to global environment
- int pipe_fds[2] = { -1, };
+ int pipe_fds[2]= { -1, };
if (::pipe(pipe_fds))
{
- err_ = errno;
+ err_= errno;
WSREP_ERROR ("pipe() failed: %d (%s)", err_, strerror(err_));
return;
}
@@ -220,16 +222,16 @@ process::process (const char* cmd, const char* type, char** env)
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 };
+ char* const pargv[4]= { strdup("sh"), strdup("-c"), strdup(str_), NULL };
if (!(pargv[0] && pargv[1] && pargv[2]))
{
- err_ = ENOMEM;
+ err_= ENOMEM;
WSREP_ERROR ("Failed to allocate pargv[] array.");
goto cleanup_pipe;
}
posix_spawnattr_t attr;
- err_ = posix_spawnattr_init (&attr);
+ err_= posix_spawnattr_init (&attr);
if (err_)
{
WSREP_ERROR ("posix_spawnattr_init() failed: %d (%s)",
@@ -239,7 +241,7 @@ process::process (const char* cmd, const char* type, char** env)
/* make sure that no signlas are masked in child process */
sigset_t sigmask_empty; sigemptyset(&sigmask_empty);
- err_ = posix_spawnattr_setsigmask(&attr, &sigmask_empty);
+ err_= posix_spawnattr_setsigmask(&attr, &sigmask_empty);
if (err_)
{
WSREP_ERROR ("posix_spawnattr_setsigmask() failed: %d (%s)",
@@ -255,7 +257,7 @@ process::process (const char* cmd, const char* type, char** env)
sigaddset(&default_signals, SIGPIPE);
sigaddset(&default_signals, SIGTERM);
sigaddset(&default_signals, SIGCHLD);
- err_ = posix_spawnattr_setsigdefault(&attr, &default_signals);
+ err_= posix_spawnattr_setsigdefault(&attr, &default_signals);
if (err_)
{
WSREP_ERROR ("posix_spawnattr_setsigdefault() failed: %d (%s)",
@@ -263,7 +265,7 @@ process::process (const char* cmd, const char* type, char** env)
goto cleanup_attr;
}
- err_ = posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF |
+ err_= posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF |
POSIX_SPAWN_SETSIGMASK |
POSIX_SPAWN_USEVFORK);
if (err_)
@@ -274,7 +276,7 @@ process::process (const char* cmd, const char* type, char** env)
}
posix_spawn_file_actions_t fact;
- err_ = posix_spawn_file_actions_init (&fact);
+ err_= posix_spawn_file_actions_init (&fact);
if (err_)
{
WSREP_ERROR ("posix_spawn_file_actions_init() failed: %d (%s)",
@@ -283,7 +285,7 @@ process::process (const char* cmd, const char* type, char** env)
}
// close child's stdout|stdin depending on what we returning
- err_ = posix_spawn_file_actions_addclose (&fact, close_fd);
+ err_= posix_spawn_file_actions_addclose (&fact, close_fd);
if (err_)
{
WSREP_ERROR ("posix_spawn_file_actions_addclose() failed: %d (%s)",
@@ -292,7 +294,7 @@ process::process (const char* cmd, const char* type, char** env)
}
// substitute our pipe descriptor in place of the closed one
- err_ = posix_spawn_file_actions_adddup2 (&fact,
+ err_= posix_spawn_file_actions_adddup2 (&fact,
pipe_fds[child_end], close_fd);
if (err_)
{
@@ -301,30 +303,30 @@ process::process (const char* cmd, const char* type, char** env)
goto cleanup_fact;
}
- err_ = posix_spawnp (&pid_, pargv[0], &fact, &attr, pargv, env);
+ 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
+ pid_= 0; // just to make sure it was not messed up in the call
goto cleanup_fact;
}
- io_ = fdopen (pipe_fds[parent_end], type);
+ io_= fdopen (pipe_fds[parent_end], type);
if (io_)
{
- pipe_fds[parent_end] = -1; // skip close on cleanup
+ pipe_fds[parent_end]= -1; // skip close on cleanup
}
else
{
- err_ = errno;
+ 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);
+ err= posix_spawn_file_actions_destroy (&fact);
if (err)
{
WSREP_ERROR ("posix_spawn_file_actions_destroy() failed: %d (%s)\n",
@@ -332,7 +334,7 @@ cleanup_fact:
}
cleanup_attr:
- err = posix_spawnattr_destroy (&attr);
+ err= posix_spawnattr_destroy (&attr);
if (err)
{
WSREP_ERROR ("posix_spawnattr_destroy() failed: %d (%s)",
@@ -360,7 +362,7 @@ process::~process ()
if (fclose (io_) == -1)
{
- err_ = errno;
+ err_= errno;
WSREP_ERROR("fclose() failed: %d (%s)", err_, strerror(err_));
}
}
@@ -376,34 +378,34 @@ process::wait ()
int status;
if (-1 == waitpid(pid_, &status, 0))
{
- err_ = errno; assert (err_);
+ 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);
+ err_= WEXITSTATUS (status);
}
else { // command didn't complete with exit()
WSREP_ERROR("Process was aborted.");
- err_ = errno ? errno : ECHILD;
+ 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 */
+ 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;
+ pid_= 0;
if (io_) fclose (io_);
- io_ = NULL;
+ io_= NULL;
}
}
else {
@@ -421,7 +423,7 @@ thd::thd (my_bool won) : init(), ptr(new THD(0))
ptr->thread_stack= (char*) &ptr;
ptr->store_globals();
ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog
- ptr->variables.wsrep_on = won;
+ ptr->variables.wsrep_on= won;
ptr->security_ctx->master_access= ~(ulong)0;
lex_start(ptr);
}
@@ -441,7 +443,7 @@ thd::~thd ()
/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */
unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6)
{
- unsigned int ret = INADDR_NONE;
+ unsigned int ret= INADDR_NONE;
struct addrinfo *res, hints;
memset (&hints, 0, sizeof(hints));
@@ -451,7 +453,7 @@ unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6)
*is_ipv6= false;
- int gai_ret = getaddrinfo(addr, NULL, &hints, &res);
+ int gai_ret= getaddrinfo(addr, NULL, &hints, &res);
if (0 == gai_ret)
{
if (AF_INET == res->ai_family) /* IPv4 */
@@ -488,7 +490,9 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len)
size_t ret= 0;
// Attempt 1: Try to get the IP from bind-address.
- if (my_bind_addr_str && my_bind_addr_str[0] != '\0')
+ // Skip if empty or bind-address=*
+ if (my_bind_addr_str && my_bind_addr_str[0] != '\0' &&
+ strcmp(my_bind_addr_str, "*") != 0)
{
bool unused;
unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str, &unused);
@@ -539,7 +543,7 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len)
if (getifaddrs(&ifaddr) == 0)
{
- for (ifa= ifaddr; ifa != NULL; ifa = ifa->ifa_next)
+ for (ifa= ifaddr; ifa != NULL; ifa= ifa->ifa_next)
{
if (!ifa->ifa_addr)
continue;
diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
index 277cea9dc31..147da8e7c52 100644
--- a/sql/wsrep_utils.h
+++ b/sql/wsrep_utils.h
@@ -21,6 +21,27 @@
unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6);
size_t wsrep_guess_ip (char* buf, size_t buf_len);
+namespace wsp {
+class node_status
+{
+public:
+ node_status() : status(wsrep::server_state::s_disconnected) {}
+ void set(enum wsrep::server_state::state new_status,
+ const wsrep::view* view= 0)
+ {
+ if (status != new_status || 0 != view)
+ {
+ wsrep_notify_status(new_status, view);
+ status= new_status;
+ }
+ }
+ enum wsrep::server_state::state get() const { return status; }
+private:
+ enum wsrep::server_state::state status;
+};
+} /* namespace wsp */
+
+extern wsp::node_status local_status;
/* returns the length of the host part of the address string */
size_t wsrep_host_len(const char* addr, size_t addr_len);
@@ -173,52 +194,37 @@ private:
class Config_state
{
public:
- Config_state() : view_(), status_(WSREP_MEMBER_UNDEFINED)
+ Config_state() : view_(), status_(wsrep::server_state::s_disconnected)
{}
- void set(wsrep_member_status_t status, const wsrep_view_info_t* view)
+ void set(const wsrep::view& view)
{
- wsrep_notify_status(status, view);
+ wsrep_notify_status(status_, &view);
lock();
-
- status_= status;
- view_= *view;
- member_info_.clear();
-
- wsrep_member_info_t memb;
- for(int i= 0; i < view->memb_num; i ++)
- {
- memb= view->members[i];
- member_info_.append_val(memb);
- }
-
+ view_= view;
unlock();
}
- void set(wsrep_member_status_t status)
+ void set(enum wsrep::server_state::state status)
{
- wsrep_notify_status(status, 0);
+ wsrep_notify_status(status);
+
lock();
status_= status;
unlock();
}
- wsrep_view_info_t get_view_info() const
+ const wsrep::view& get_view_info() const
{
return view_;
}
- wsrep_member_status_t get_status() const
+ enum wsrep::server_state::state get_status() const
{
return status_;
}
- Dynamic_array<wsrep_member_info_t> * get_member_info()
- {
- return &member_info_;
- }
-
int lock()
{
return mysql_mutex_lock(&LOCK_wsrep_config_state);
@@ -230,9 +236,8 @@ public:
}
private:
- wsrep_view_info_t view_;
- wsrep_member_status_t status_;
- Dynamic_array<wsrep_member_info_t> member_info_;
+ wsrep::view view_;
+ enum wsrep::server_state::state status_;
};
} /* namespace wsp */
@@ -308,12 +313,23 @@ 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; }
+ void set(char* str) { if (string_) free (string_); string_= str; }
~string() { set (0); }
private:
char* string_;
};
+/* scope level lock */
+class auto_lock
+{
+public:
+ auto_lock(mysql_mutex_t* m) : m_(m) { mysql_mutex_lock(m_); }
+ ~auto_lock() { mysql_mutex_unlock(m_); }
+private:
+ mysql_mutex_t& operator =(mysql_mutex_t&);
+ mysql_mutex_t* const m_;
+};
+
#ifdef REMOVED
class lock
{
@@ -323,7 +339,7 @@ public:
lock (pthread_mutex_t* mtx) : mtx_(mtx)
{
- int err = pthread_mutex_lock (mtx_);
+ int err= pthread_mutex_lock (mtx_);
if (err)
{
@@ -334,7 +350,7 @@ public:
virtual ~lock ()
{
- int err = pthread_mutex_unlock (mtx_);
+ int err= pthread_mutex_unlock (mtx_);
if (err)
{
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 1471ad91a96..8a0968639c2 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -28,8 +28,6 @@
ulong wsrep_reject_queries;
-static long wsrep_prev_slave_threads = wsrep_slave_threads;
-
int wsrep_init_vars()
{
wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME));
@@ -53,7 +51,7 @@ 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;
+ thd->variables.wsrep_on= global_system_variables.wsrep_on;
}
return false;
@@ -68,8 +66,8 @@ bool wsrep_on_check(sys_var *self, THD* thd, set_var* var)
if (new_wsrep_on && innodb_hton_ptr && innodb_lock_schedule_algorithm != 0) {
my_message(ER_WRONG_ARGUMENTS, " WSREP (galera) can't be enabled "
- "if innodb_lock_schedule_algorithm=VATS. Please configure"
- " innodb_lock_schedule_algorithm=FCFS and restart.", MYF(0));
+ "if innodb_lock_schedule_algorithm=VATS. Please configure"
+ " innodb_lock_schedule_algorithm=FCFS and restart.", MYF(0));
return true;
}
return false;
@@ -77,10 +75,6 @@ bool wsrep_on_check(sys_var *self, THD* thd, set_var* var)
bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type)
{
- // global setting should not affect session setting.
- // if (var_type == OPT_GLOBAL) {
- // thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads;
- // }
if (thd->variables.wsrep_causal_reads) {
thd->variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ;
} else {
@@ -99,15 +93,11 @@ bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type)
bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type)
{
- // global setting should not affect session setting.
- // if (var_type == OPT_GLOBAL) {
- // thd->variables.wsrep_sync_wait = global_system_variables.wsrep_sync_wait;
- // }
- thd->variables.wsrep_causal_reads = thd->variables.wsrep_sync_wait &
+ thd->variables.wsrep_causal_reads= thd->variables.wsrep_sync_wait &
WSREP_SYNC_WAIT_BEFORE_READ;
// update global settings too
- global_system_variables.wsrep_causal_reads = global_system_variables.wsrep_sync_wait &
+ global_system_variables.wsrep_causal_reads= global_system_variables.wsrep_sync_wait &
WSREP_SYNC_WAIT_BEFORE_READ;
return false;
@@ -129,7 +119,7 @@ bool wsrep_start_position_verify (const char* start_str)
ssize_t uuid_len;
// Check whether it has minimum acceptable length.
- start_len = strlen (start_str);
+ start_len= strlen (start_str);
if (start_len < 34)
return true;
@@ -137,7 +127,7 @@ bool wsrep_start_position_verify (const char* start_str)
Parse the input to check whether UUID length is acceptable
and seqno has been provided.
*/
- uuid_len = wsrep_uuid_scan (start_str, start_len, &uuid);
+ uuid_len= wsrep_uuid_scan (start_str, start_len, &uuid);
if (uuid_len < 0 || (start_len - uuid_len) < 2)
return true;
@@ -157,19 +147,18 @@ bool wsrep_start_position_verify (const char* start_str)
static
-bool wsrep_set_local_position(const char* const value, size_t length,
- bool const sst)
+bool wsrep_set_local_position(THD* thd, const char* const value,
+ size_t length, bool const sst)
{
wsrep_uuid_t uuid;
- size_t const uuid_len = wsrep_uuid_scan(value, length, &uuid);
- wsrep_seqno_t const seqno = strtoll(value + uuid_len + 1, NULL, 10);
+ size_t const uuid_len= wsrep_uuid_scan(value, length, &uuid);
+ wsrep_seqno_t const seqno= strtoll(value + uuid_len + 1, NULL, 10);
if (sst) {
- return wsrep_sst_received (wsrep, uuid, seqno, NULL, 0, false);
+ wsrep_sst_received (thd, uuid, seqno, NULL, 0);
} else {
- // initialization
- local_uuid = uuid;
- local_seqno = seqno;
+ local_uuid= uuid;
+ local_seqno= seqno;
}
return false;
}
@@ -194,7 +183,7 @@ bool wsrep_start_position_check (sys_var *self, THD* thd, set_var* var)
As part of further verification, we try to update the value and catch
errors (if any).
*/
- if (wsrep_set_local_position(var->save_result.string_value.str,
+ if (wsrep_set_local_position(thd, var->save_result.string_value.str,
var->save_result.string_value.length,
true))
{
@@ -226,7 +215,7 @@ bool wsrep_start_position_init (const char* val)
return true;
}
- if (wsrep_set_local_position (val, strlen(val), false))
+ if (wsrep_set_local_position (NULL, val, strlen(val), false))
{
WSREP_ERROR("Failed to set initial wsep_start_position: %s", val);
return true;
@@ -263,25 +252,23 @@ end:
static bool refresh_provider_options()
{
- DBUG_ASSERT(wsrep);
-
WSREP_DEBUG("refresh_provider_options: %s",
(wsrep_provider_options) ? wsrep_provider_options : "null");
- char* opts= wsrep->options_get(wsrep);
- if (opts)
+
+ try
{
- wsrep_provider_options_init(opts);
+ std::string opts= Wsrep_server_state::instance().provider().options();
+ wsrep_provider_options_init(opts.c_str());
get_provider_option_value(wsrep_provider_options,
(char*)"repl.max_ws_size",
&wsrep_max_ws_size);
- free(opts);
+ return false;
}
- else
+ catch (...)
{
WSREP_ERROR("Failed to get provider options");
return true;
}
- return false;
}
static int wsrep_provider_verify (const char* provider_str)
@@ -332,8 +319,6 @@ 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);
@@ -346,7 +331,12 @@ bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type)
*/
mysql_mutex_unlock(&LOCK_global_system_variables);
wsrep_stop_replication(thd);
- mysql_mutex_lock(&LOCK_global_system_variables);
+
+ /* provider status variables are allocated in provider library
+ and need to freed here, otherwise a dangling reference to
+ wsrep_status_vars would remain in THD
+ */
+ wsrep_free_status(thd);
if (wsrep_inited == 1)
wsrep_deinit(false);
@@ -357,17 +347,17 @@ bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type)
if (wsrep_init())
{
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp, my_error, "wsrep_init failed");
- rcode = true;
+ 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);
+ if (!rcode)
+ refresh_provider_options();
- thd->variables.wsrep_on= wsrep_on_saved;
-
- refresh_provider_options();
+ mysql_mutex_lock(&LOCK_global_system_variables);
return rcode;
}
@@ -385,12 +375,12 @@ void wsrep_provider_init (const char* value)
}
if (wsrep_provider) my_free((void *)wsrep_provider);
- wsrep_provider = my_strdup(value, MYF(0));
+ wsrep_provider= my_strdup(value, MYF(0));
}
bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var)
{
- if (wsrep == NULL)
+ if (!WSREP_ON)
{
my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0));
return true;
@@ -400,9 +390,9 @@ bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var)
bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type)
{
- DBUG_ASSERT(wsrep);
- wsrep_status_t ret= wsrep->options_set(wsrep, wsrep_provider_options);
- if (ret != WSREP_OK)
+ enum wsrep::provider::status ret=
+ Wsrep_server_state::instance().provider().options(wsrep_provider_options);
+ if (ret)
{
WSREP_ERROR("Set options returned %d", ret);
refresh_provider_options();
@@ -415,7 +405,7 @@ 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;
+ wsrep_provider_options= (value) ? my_strdup(value, MYF(0)) : NULL;
}
bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type)
@@ -469,18 +459,12 @@ bool wsrep_cluster_address_check (sys_var *self, THD* thd, set_var* var)
bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type)
{
- bool wsrep_on_saved;
-
- /* Do not proceed if wsrep provider is not loaded. */
- if (!wsrep)
+ if (!Wsrep_server_state::instance().is_provider_loaded())
{
- WSREP_INFO("wsrep provider is not loaded, can't re(start) replication.");
+ WSREP_INFO("WSREP (galera) provider is not loaded, can't re(start) replication.");
return false;
}
- 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.
@@ -491,13 +475,6 @@ bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type)
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())
{
@@ -505,7 +482,13 @@ bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type)
wsrep_create_appliers(wsrep_slave_threads);
}
- thd->variables.wsrep_on= wsrep_on_saved;
+ /* locking order to be enforced is:
+ 1. LOCK_global_system_variables
+ 2. LOCK_wsrep_slave_threads
+ */
+ mysql_mutex_unlock(&LOCK_wsrep_slave_threads);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ mysql_mutex_lock(&LOCK_wsrep_slave_threads);
return false;
}
@@ -590,15 +573,14 @@ 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;
+ wsrep_node_address= (value) ? my_strdup(value, MYF(0)) : NULL;
}
static void wsrep_slave_count_change_update ()
{
- wsrep_slave_count_change = (wsrep_slave_threads - wsrep_prev_slave_threads);
+ wsrep_slave_count_change= (wsrep_slave_threads - wsrep_running_threads + 2);
WSREP_DEBUG("Change on slave threads: New %lu old %lu difference %d",
- wsrep_slave_threads, wsrep_prev_slave_threads, wsrep_slave_count_change);
- wsrep_prev_slave_threads = wsrep_slave_threads;
+ wsrep_slave_threads, wsrep_running_threads, wsrep_slave_count_change);
}
bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type)
@@ -607,14 +589,14 @@ 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;
+ wsrep_slave_count_change= 0;
}
return false;
}
bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
{
- if (wsrep == NULL)
+ if (!WSREP_ON)
{
my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0));
return true;
@@ -639,17 +621,17 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
}
return false;
}
- wsrep_status_t ret(WSREP_WARNING);
+ int ret= 1;
if (new_wsrep_desync) {
- ret = wsrep->desync (wsrep);
- if (ret != WSREP_OK) {
- WSREP_WARN ("SET desync failed %d for schema: %s, query: %s",
- ret, thd->get_db(), thd->query());
+ ret= Wsrep_server_state::instance().provider().desync();
+ if (ret) {
+ WSREP_WARN ("SET desync failed %d for schema: %s, query: %s", ret,
+ thd->db.str, WSREP_QUERY(thd));
my_error (ER_CANNOT_USER, MYF(0), "'desync'", thd->query());
return true;
}
} else {
- ret = wsrep->resync (wsrep);
+ ret= Wsrep_server_state::instance().provider().resync();
if (ret != WSREP_OK) {
WSREP_WARN ("SET resync failed %d for schema: %s, query: %s", ret,
thd->get_db(), thd->query());
@@ -662,13 +644,70 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var)
bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type)
{
- DBUG_ASSERT(wsrep);
+ return false;
+}
+
+bool wsrep_trx_fragment_size_check (sys_var *self, THD* thd, set_var* var)
+{
+ if (var->value == NULL) {
+ return false;
+ }
+
+ const ulong new_trx_fragment_size= var->value->val_uint();
+
+ if (!WSREP(thd) && new_trx_fragment_size > 0) {
+ push_warning (thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_VAR,
+ "Cannot set 'wsrep_trx_fragment_size' to a value other than "
+ "0 because wsrep is switched off.");
+ return true;
+ }
+
+ if (new_trx_fragment_size > 0 && !wsrep_provider_is_SR_capable()) {
+ push_warning (thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_VALUE_FOR_VAR,
+ "Cannot set 'wsrep_trx_fragment_size' to a value other than "
+ "0 because the wsrep_provider does not support streaming "
+ "replication.");
+ return true;
+ }
+
+ return false;
+}
+
+bool wsrep_trx_fragment_size_update(sys_var* self, THD *thd, enum_var_type)
+{
+ WSREP_DEBUG("wsrep_trx_fragment_size_update: %llu",
+ thd->variables.wsrep_trx_fragment_size);
+ if (thd->variables.wsrep_trx_fragment_size)
+ {
+ return thd->wsrep_cs().enable_streaming(
+ wsrep_fragment_unit(thd->variables.wsrep_trx_fragment_unit),
+ size_t(thd->variables.wsrep_trx_fragment_size));
+ }
+ else
+ {
+ thd->wsrep_cs().disable_streaming();
+ return false;
+ }
+}
+
+bool wsrep_trx_fragment_unit_update(sys_var* self, THD *thd, enum_var_type)
+{
+ WSREP_DEBUG("wsrep_trx_fragment_unit_update: %lu",
+ thd->variables.wsrep_trx_fragment_unit);
+ if (thd->variables.wsrep_trx_fragment_size)
+ {
+ return thd->wsrep_cs().enable_streaming(
+ wsrep_fragment_unit(thd->variables.wsrep_trx_fragment_unit),
+ size_t(thd->variables.wsrep_trx_fragment_size));
+ }
return false;
}
bool wsrep_max_ws_size_check(sys_var *self, THD* thd, set_var* var)
{
- if (wsrep == NULL)
+ if (!WSREP_ON)
{
my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0));
return true;
@@ -676,36 +715,35 @@ bool wsrep_max_ws_size_check(sys_var *self, THD* thd, set_var* var)
return false;
}
-bool wsrep_max_ws_size_update (sys_var *self, THD *thd, enum_var_type)
+bool wsrep_max_ws_size_update(sys_var *self, THD *thd, enum_var_type)
{
- DBUG_ASSERT(wsrep);
-
char max_ws_size_opt[128];
my_snprintf(max_ws_size_opt, sizeof(max_ws_size_opt),
- "repl.max_ws_size=%lu", wsrep_max_ws_size);
- wsrep_status_t ret= wsrep->options_set(wsrep, max_ws_size_opt);
- if (ret != WSREP_OK)
+ "repl.max_ws_size=%d", wsrep_max_ws_size);
+ enum wsrep::provider::status ret= Wsrep_server_state::instance().provider().options(max_ws_size_opt);
+ if (ret)
{
WSREP_ERROR("Set options returned %d", ret);
- refresh_provider_options();
return true;
}
return refresh_provider_options();
}
+#if UNUSED /* eaec266eb16c (Sergei Golubchik 2014-09-28) */
static SHOW_VAR wsrep_status_vars[]=
{
{"connected", (char*) &wsrep_connected, SHOW_BOOL},
- {"ready", (char*) &wsrep_ready, SHOW_BOOL},
+ {"ready", (char*) &wsrep_show_ready, SHOW_FUNC},
{"cluster_state_uuid",(char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR},
{"cluster_conf_id", (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG},
{"cluster_status", (char*) &wsrep_cluster_status, SHOW_CHAR_PTR},
{"cluster_size", (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH},
{"local_index", (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH},
- {"local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC},
+ {"local_bf_aborts", (char*) &wsrep_show_bf_aborts, SHOW_FUNC},
{"provider_name", (char*) &wsrep_provider_name, SHOW_CHAR_PTR},
{"provider_version", (char*) &wsrep_provider_version, SHOW_CHAR_PTR},
{"provider_vendor", (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR},
+ {"wsrep_provider_capabilities", (char*) &wsrep_provider_capabilities, SHOW_CHAR_PTR},
{"thread_count", (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH}
};
@@ -713,49 +751,90 @@ static int show_var_cmp(const void *var1, const void *var2)
{
return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
}
+#endif /* UNUSED */
+/*
+ * Status variables stuff below
+ */
+static inline void
+wsrep_assign_to_mysql (SHOW_VAR* mysql, wsrep_stats_var* wsrep_var)
+{
+ mysql->name= wsrep_var->name;
+ switch (wsrep_var->type) {
+ case WSREP_VAR_INT64:
+ mysql->value= (char*) &wsrep_var->value._int64;
+ mysql->type= SHOW_LONGLONG;
+ break;
+ case WSREP_VAR_STRING:
+ mysql->value= (char*) &wsrep_var->value._string;
+ mysql->type= SHOW_CHAR_PTR;
+ break;
+ case WSREP_VAR_DOUBLE:
+ mysql->value= (char*) &wsrep_var->value._double;
+ mysql->type= SHOW_DOUBLE;
+ break;
+ }
+}
-int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope)
+#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)
{
- uint i, maxi= SHOW_VAR_FUNC_BUFF_SIZE / sizeof(*var) - 1;
- SHOW_VAR *v= (SHOW_VAR *)buff;
+ int wsrep_status_len, i;
- var->type= SHOW_ARRAY;
- var->value= buff;
+ thd->wsrep_status_vars= Wsrep_server_state::instance().status();
- for (i=0; i < array_elements(wsrep_status_vars); i++)
- *v++= wsrep_status_vars[i];
+ wsrep_status_len= thd->wsrep_status_vars.size();
- DBUG_ASSERT(i < maxi);
+#if DYNAMIC
+ if (wsrep_status_len != mysql_status_len) {
+ void* tmp= realloc (mysql_status_vars,
+ (wsrep_status_len + 1) * sizeof(SHOW_VAR));
+ if (!tmp) {
- if (wsrep != NULL)
- {
- wsrep_stats_var* stats= wsrep->stats_get(wsrep);
- for (wsrep_stats_var *sv= stats;
- i < maxi && sv && sv->name; i++,
- sv++, v++)
- {
- v->name = thd->strdup(sv->name);
- switch (sv->type) {
- case WSREP_VAR_INT64:
- v->value = (char*)thd->memdup(&sv->value._integer64, sizeof(longlong));
- v->type = SHOW_LONGLONG;
- break;
- case WSREP_VAR_STRING:
- v->value = thd->strdup(sv->value._string);
- v->type = SHOW_CHAR;
- break;
- case WSREP_VAR_DOUBLE:
- v->value = (char*)thd->memdup(&sv->value._double, sizeof(double));
- v->type = SHOW_DOUBLE;
- break;
- }
+ sql_print_error ("Out of memory for wsrep status variables."
+ "Number of variables: %d", wsrep_status_len);
+ return;
}
- wsrep->stats_free(wsrep, stats);
+
+ 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++)
+ {
+ mysql_status_vars[i].name= (char*)thd->wsrep_status_vars[i].name().c_str();
+ mysql_status_vars[i].value= (char*)thd->wsrep_status_vars[i].value().c_str();
+ mysql_status_vars[i].type= SHOW_CHAR;
}
- my_qsort(buff, i, sizeof(*v), show_var_cmp);
+ 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;
+}
- v->name= 0; // terminator
+int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff)
+{
+ if (WSREP_ON)
+ {
+ export_wsrep_status_to_mysql(thd);
+ var->type= SHOW_ARRAY;
+ var->value= (char *) &mysql_status_vars;
+ }
return 0;
}
+
+void wsrep_free_status (THD* thd)
+{
+ thd->wsrep_status_vars.clear();
+}
diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h
index 7d3ff50f1d2..b732fb48b38 100644
--- a/sql/wsrep_var.h
+++ b/sql/wsrep_var.h
@@ -13,11 +13,11 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
-#include <my_config.h>
-
#ifndef WSREP_VAR_H
#define WSREP_VAR_H
+#include <my_config.h>
+
#ifdef WITH_WSREP
#define WSREP_CLUSTER_NAME "my_wsrep_cluster"
@@ -90,13 +90,18 @@ extern bool wsrep_slave_threads_update UPDATE_ARGS;
extern bool wsrep_desync_check CHECK_ARGS;
extern bool wsrep_desync_update UPDATE_ARGS;
+extern bool wsrep_trx_fragment_size_check CHECK_ARGS;
+extern bool wsrep_trx_fragment_size_update UPDATE_ARGS;
+
+extern bool wsrep_trx_fragment_unit_update UPDATE_ARGS;
+
extern bool wsrep_max_ws_size_check CHECK_ARGS;
extern bool wsrep_max_ws_size_update UPDATE_ARGS;
+
extern bool wsrep_reject_queries_update UPDATE_ARGS;
#else /* WITH_WSREP */
-#define WSREP_NONE
#define wsrep_provider_init(X)
#define wsrep_init_vars() (0)
#define wsrep_start_position_init(X)
diff --git a/sql/wsrep_xid.cc b/sql/wsrep_xid.cc
index 2834100568a..a1c454d9d65 100644
--- a/sql/wsrep_xid.cc
+++ b/sql/wsrep_xid.cc
@@ -21,6 +21,9 @@
#include "sql_class.h"
#include "wsrep_mysqld.h" // for logging macros
+#include <mysql/service_wsrep.h>
+
+#include <algorithm> /* std::sort() */
/*
* WSREPXid
*/
@@ -34,20 +37,22 @@
#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)
+void wsrep_xid_init(XID* xid, const wsrep::gtid& wsgtid)
{
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);
- xid->data[WSREP_XID_VERSION_OFFSET] = WSREP_XID_VERSION_2;
- memcpy(xid->data + WSREP_XID_UUID_OFFSET, &uuid, sizeof(wsrep_uuid_t));
- int8store(xid->data + WSREP_XID_SEQNO_OFFSET,seqno);
+ xid->data[WSREP_XID_VERSION_OFFSET]= WSREP_XID_VERSION_2;
+ memcpy(xid->data + WSREP_XID_UUID_OFFSET, wsgtid.id().data(),sizeof(wsrep::id));
+ int8store(xid->data + WSREP_XID_SEQNO_OFFSET, wsgtid.seqno().get());
}
-int wsrep_is_wsrep_xid(const XID* xid)
+extern "C"
+int wsrep_is_wsrep_xid(const void* xid_ptr)
{
+ const XID* xid= static_cast<const XID*>(xid_ptr);
return (xid->formatID == 1 &&
xid->gtrid_length == WSREP_XID_GTRID_LEN &&
xid->bqual_length == 0 &&
@@ -56,33 +61,36 @@ int wsrep_is_wsrep_xid(const XID* xid)
xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_2));
}
-const wsrep_uuid_t* wsrep_xid_uuid(const XID& xid)
+const unsigned char* wsrep_xid_uuid(const xid_t* xid)
{
- if (wsrep_is_wsrep_xid(&xid))
- return reinterpret_cast<const wsrep_uuid_t*>(xid.data
- + WSREP_XID_UUID_OFFSET);
+ DBUG_ASSERT(xid);
+ static wsrep::id const undefined;
+ if (wsrep_is_wsrep_xid(xid))
+ return reinterpret_cast<const unsigned char*>
+ (xid->data + WSREP_XID_UUID_OFFSET);
else
- return &WSREP_UUID_UNDEFINED;
+ return static_cast<const unsigned char*>(wsrep::id::undefined().data());
}
-const unsigned char* wsrep_xid_uuid(const xid_t* xid)
+const wsrep::id& wsrep_xid_uuid(const XID& xid)
{
- DBUG_ASSERT(xid);
- return wsrep_xid_uuid(*xid)->data;
+ compile_time_assert(sizeof(wsrep::id) == sizeof(wsrep_uuid_t));
+ return *reinterpret_cast<const wsrep::id*>(wsrep_xid_uuid(&xid));
}
-wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
+long long wsrep_xid_seqno(const xid_t* xid)
{
- wsrep_seqno_t ret= WSREP_SEQNO_UNDEFINED;
- if (wsrep_is_wsrep_xid(&xid))
+ DBUG_ASSERT(xid);
+ long long ret= wsrep::seqno::undefined().get();
+ if (wsrep_is_wsrep_xid(xid))
{
- switch (xid.data[WSREP_XID_VERSION_OFFSET])
+ switch (xid->data[WSREP_XID_VERSION_OFFSET])
{
case WSREP_XID_VERSION_1:
- memcpy(&ret, xid.data + WSREP_XID_SEQNO_OFFSET, sizeof ret);
+ memcpy(&ret, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof ret);
break;
case WSREP_XID_VERSION_2:
- ret= sint8korr(xid.data + WSREP_XID_SEQNO_OFFSET);
+ ret= sint8korr(xid->data + WSREP_XID_SEQNO_OFFSET);
break;
default:
break;
@@ -91,10 +99,9 @@ wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
return ret;
}
-long long wsrep_xid_seqno(const xid_t* xid)
+wsrep::seqno wsrep_xid_seqno(const XID& xid)
{
- DBUG_ASSERT(xid);
- return wsrep_xid_seqno(*xid);
+ return wsrep::seqno(wsrep_xid_seqno(&xid));
}
static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
@@ -104,11 +111,11 @@ static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
if (hton->set_checkpoint)
{
- const wsrep_uuid_t* uuid(wsrep_xid_uuid(*xid));
- char uuid_str[40] = {0, };
- wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
+ const unsigned char* uuid= wsrep_xid_uuid(xid);
+ char uuid_str[40]= {0, };
+ wsrep_uuid_print((const wsrep_uuid_t*)uuid, uuid_str, sizeof(uuid_str));
WSREP_DEBUG("Set WSREPXid for InnoDB: %s:%lld",
- uuid_str, (long long)wsrep_xid_seqno(*xid));
+ uuid_str, (long long)wsrep_xid_seqno(xid));
hton->set_checkpoint(hton, xid);
}
return FALSE;
@@ -120,10 +127,10 @@ bool wsrep_set_SE_checkpoint(XID& xid)
&xid);
}
-bool wsrep_set_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
+bool wsrep_set_SE_checkpoint(const wsrep::gtid& wsgtid)
{
XID xid;
- wsrep_xid_init(&xid, uuid, seqno);
+ wsrep_xid_init(&xid, wsgtid);
return wsrep_set_SE_checkpoint(xid);
}
@@ -135,11 +142,12 @@ static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
if (hton->get_checkpoint)
{
hton->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_uuid_t uuid;
+ memcpy(&uuid, wsrep_xid_uuid(xid), sizeof(uuid));
+ 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));
+ uuid_str, (long long)wsrep_xid_seqno(xid));
}
return FALSE;
}
@@ -150,32 +158,58 @@ bool wsrep_get_SE_checkpoint(XID& xid)
&xid);
}
-bool wsrep_get_SE_checkpoint(wsrep_uuid_t& uuid, wsrep_seqno_t& seqno)
+wsrep::gtid wsrep_get_SE_checkpoint()
{
- uuid= WSREP_UUID_UNDEFINED;
- seqno= WSREP_SEQNO_UNDEFINED;
-
XID xid;
xid.null();
if (wsrep_get_SE_checkpoint(xid))
{
- return true;
+ return wsrep::gtid();
}
if (xid.is_null())
{
- return false;
+ return wsrep::gtid();
}
if (!wsrep_is_wsrep_xid(&xid))
{
WSREP_WARN("Read non-wsrep XID from storage engines.");
- return false;
+ return wsrep::gtid();
}
- uuid= *wsrep_xid_uuid(xid);
- seqno= wsrep_xid_seqno(xid);
+ return wsrep::gtid(wsrep_xid_uuid(xid),wsrep_xid_seqno(xid));
+}
+
+/*
+ Sort order for XIDs. Wsrep XIDs are sorted according to
+ seqno in ascending order. Non-wsrep XIDs are considered
+ equal among themselves and greater than with respect
+ to wsrep XIDs.
+ */
+struct Wsrep_xid_cmp
+{
+ bool operator()(const XID& left, const XID& right) const
+ {
+ const bool left_is_wsrep= wsrep_is_wsrep_xid(&left);
+ const bool right_is_wsrep= wsrep_is_wsrep_xid(&right);
+ if (left_is_wsrep && right_is_wsrep)
+ {
+ return (wsrep_xid_seqno(&left) < wsrep_xid_seqno(&right));
+ }
+ else if (left_is_wsrep)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+};
- return false;
+void wsrep_sort_xid_array(XID *array, int len)
+{
+ std::sort(array, array + len, Wsrep_xid_cmp());
}
diff --git a/sql/wsrep_xid.h b/sql/wsrep_xid.h
index 5b33a904de1..e41f6fba420 100644
--- a/sql/wsrep_xid.h
+++ b/sql/wsrep_xid.h
@@ -20,17 +20,19 @@
#ifdef WITH_WSREP
-#include "../wsrep/wsrep_api.h"
+#include "wsrep/gtid.hpp"
#include "handler.h" // XID typedef
-void wsrep_xid_init(xid_t*, const wsrep_uuid_t&, wsrep_seqno_t);
-const wsrep_uuid_t* wsrep_xid_uuid(const XID&);
-wsrep_seqno_t wsrep_xid_seqno(const XID&);
+void wsrep_xid_init(xid_t*, const wsrep::gtid&);
+const wsrep::id& wsrep_xid_uuid(const XID&);
+wsrep::seqno wsrep_xid_seqno(const XID&);
+wsrep::gtid wsrep_get_SE_checkpoint();
+bool wsrep_set_SE_checkpoint(const wsrep::gtid& gtid);
//void wsrep_get_SE_checkpoint(XID&); /* uncomment if needed */
-bool wsrep_get_SE_checkpoint(wsrep_uuid_t&, wsrep_seqno_t&);
//void wsrep_set_SE_checkpoint(XID&); /* uncomment if needed */
-bool wsrep_set_SE_checkpoint(const wsrep_uuid_t&, wsrep_seqno_t);
+
+void wsrep_sort_xid_array(XID *array, int len);
#endif /* WITH_WSREP */
#endif /* WSREP_UTILS_H */
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index c8e7236dc93..2747a6fa338 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -822,7 +822,7 @@ DECLARE_THREAD(buf_dump_thread)(void*)
if (srv_buffer_pool_load_at_startup) {
#ifdef WITH_WSREP
- if (!wsrep_recovery) {
+ if (!get_wsrep_recovery()) {
#endif /* WITH_WSREP */
buf_load();
#ifdef WITH_WSREP
@@ -856,7 +856,7 @@ DECLARE_THREAD(buf_dump_thread)(void*)
"Dumping of buffer pool not started"
" as load was incomplete");
#ifdef WITH_WSREP
- } else if (wsrep_recovery) {
+ } else if (get_wsrep_recovery()) {
#endif /* WITH_WSREP */
} else {
buf_dump(FALSE/* do complete dump at shutdown */);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 2690ff9f736..186c3ee3154 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -131,6 +131,9 @@ void close_thread_tables(THD* thd);
#define tdc_size 400
#endif
+#include <mysql/plugin.h>
+#include <mysql/service_wsrep.h>
+
#include "ha_innodb.h"
#include "i_s.h"
#include "sync0sync.h"
@@ -138,9 +141,6 @@ void close_thread_tables(THD* thd);
#include <string>
#include <sstream>
-#include <mysql/plugin.h>
-#include <mysql/service_wsrep.h>
-
#ifdef WITH_WSREP
#include "dict0priv.h"
#include <mysql/service_md5.h>
@@ -148,21 +148,6 @@ void close_thread_tables(THD* thd);
extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
-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 TC_LOG* tc_log;
-extern void wsrep_cleanup_transaction(THD *thd);
-static int
-wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
- my_bool signal);
-static void
-wsrep_fake_trx_id(handlerton* hton, THD *thd);
-static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
-static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
#endif /* WITH_WSREP */
/** to force correct commit order in binlog */
@@ -1843,8 +1828,13 @@ thd_to_trx_id(
{
return(thd_to_trx(thd)->id);
}
-#endif /* WITH_WSREP */
+static int
+wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
+ my_bool signal);
+static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
+static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
+#endif /* WITH_WSREP */
/********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used
@@ -4161,13 +4151,12 @@ static int innodb_init(void* p)
innobase_hton->show_status = innobase_show_status;
innobase_hton->flags =
HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS
- | HTON_NATIVE_SYS_VERSIONING;
+ | HTON_NATIVE_SYS_VERSIONING | HTON_WSREP_REPLICATION;
#ifdef WITH_WSREP
innobase_hton->abort_transaction=wsrep_abort_transaction;
innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint;
innobase_hton->get_checkpoint=innobase_wsrep_get_checkpoint;
- innobase_hton->fake_trx_id=wsrep_fake_trx_id;
#endif /* WITH_WSREP */
innobase_hton->tablefile_extensions = ha_innobase_exts;
@@ -4502,6 +4491,14 @@ innobase_commit_ordered_2(
trx->flush_log_later = true;
}
+#ifdef WITH_WSREP
+ /* If the transaction is not run in 2pc, we must assign wsrep
+ XID here in order to get it written in rollback segment. */
+ if (wsrep_on(thd)) {
+ thd_get_xid(thd, (MYSQL_XID*)trx->xid);
+ }
+#endif /* WITH_WSREP */
+
innobase_commit_low(trx);
if (!read_only) {
@@ -4704,6 +4701,15 @@ innobase_rollback(
dberr_t error;
+#ifdef WITH_WSREP
+ /* If trx was assigned wsrep XID in prepare phase and the
+ trx is being rolled back due to BF abort, clear XID in order
+ to avoid writing it to rollback segment out of order. The XID
+ will be reassigned when the transaction is replayed. */
+ if (wsrep_is_wsrep_xid(trx->xid)) {
+ trx->xid->null();
+ }
+#endif /* WITH_WSREP */
if (rollback_trx
|| !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
@@ -5109,7 +5115,7 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
{
DBUG_ENTER("innobase_kill_query");
#ifdef WITH_WSREP
- if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) {
+ if (wsrep_on(thd) && wsrep_thd_is_aborting(thd)) {
/* if victim has been signaled by BF thread and/or aborting
is already progressing, following query aborting is not necessary
any more.
@@ -8107,9 +8113,9 @@ ha_innobase::write_row(
wsrep_thd_query(m_user_thd) :
(char *)"void");
error= DB_SUCCESS;
- wsrep_thd_set_conflict_state(
- m_user_thd, MUST_ABORT);
- innobase_srv_conc_exit_innodb(m_prebuilt);
+ wsrep_thd_self_abort(m_user_thd);
+ innobase_srv_conc_exit_innodb(
+ m_prebuilt);
/* jump straight to func exit over
* later wsrep hooks */
goto func_exit;
@@ -8179,10 +8185,14 @@ report_error:
#ifdef WITH_WSREP
if (!error_result
&& wsrep_on(m_user_thd)
- && wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE
+ && wsrep_thd_is_local(m_user_thd)
&& !wsrep_consistency_check(m_user_thd)
- && !wsrep_thd_ignore_table(m_user_thd)) {
- if (wsrep_append_keys(m_user_thd, false, record, NULL)) {
+ && (thd_sql_command(m_user_thd) != SQLCOM_CREATE_TABLE)
+ && (thd_sql_command(m_user_thd) != SQLCOM_LOAD ||
+ thd_binlog_format(m_user_thd) == BINLOG_FORMAT_ROW)) {
+ if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE,
+ record,
+ NULL)) {
DBUG_PRINT("wsrep", ("row key failed"));
error_result = HA_ERR_INTERNAL_ERROR;
goto wsrep_error;
@@ -8868,13 +8878,17 @@ func_exit:
innobase_active_small();
#ifdef WITH_WSREP
- if (error == DB_SUCCESS &&
- wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
- wsrep_on(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd)) {
+ if (error == DB_SUCCESS
+ && wsrep_on(m_user_thd)
+ && wsrep_thd_is_local(m_user_thd)) {
+
DBUG_PRINT("wsrep", ("update row key"));
- if (wsrep_append_keys(m_user_thd, false, old_row, new_row)) {
+ if (wsrep_append_keys(m_user_thd,
+ wsrep_protocol_version >= 4
+ ? WSREP_SERVICE_KEY_UPDATE
+ : WSREP_SERVICE_KEY_EXCLUSIVE,
+ old_row, new_row)){
WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED");
DBUG_PRINT("wsrep", ("row key failed"));
err = HA_ERR_INTERNAL_ERROR;
@@ -8934,11 +8948,14 @@ ha_innobase::delete_row(
innobase_active_small();
#ifdef WITH_WSREP
- if (error == DB_SUCCESS &&
- wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
- wsrep_on(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd)) {
- if (wsrep_append_keys(m_user_thd, false, record, NULL)) {
+ if (error == DB_SUCCESS
+ && wsrep_on(m_user_thd)
+ && wsrep_thd_is_local(m_user_thd)
+ && !wsrep_thd_ignore_table(m_user_thd)) {
+
+ if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE,
+ record,
+ NULL)) {
DBUG_PRINT("wsrep", ("delete fail"));
error = (dberr_t) HA_ERR_INTERNAL_ERROR;
goto wsrep_error;
@@ -10121,6 +10138,22 @@ wsrep_dict_foreign_find_index(
ibool check_charsets,
ulint check_null);
+inline
+const char*
+wsrep_key_type_to_str(Wsrep_service_key_type type)
+{
+ switch (type) {
+ case WSREP_SERVICE_KEY_SHARED:
+ return "shared";
+ case WSREP_SERVICE_KEY_REFERENCE:
+ return "reference";
+ case WSREP_SERVICE_KEY_UPDATE:
+ return "update";
+ case WSREP_SERVICE_KEY_EXCLUSIVE:
+ return "exclusive";
+ };
+ return "unknown";
+}
extern dberr_t
wsrep_append_foreign_key(
@@ -10130,17 +10163,17 @@ wsrep_append_foreign_key(
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 */
+ Wsrep_service_key_type key_type) /*!< in: access type of this key
+ (shared, exclusive, reference...) */
{
ut_a(trx);
THD* thd = (THD*)trx->mysql_thd;
ulint rcode = DB_SUCCESS;
char cache_key[513] = {'\0'};
int cache_key_len=0;
- bool const copy = true;
if (!wsrep_on(trx->mysql_thd) ||
- wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
+ wsrep_thd_is_local(trx->mysql_thd) == false) {
return DB_SUCCESS;
}
@@ -10230,8 +10263,8 @@ wsrep_append_foreign_key(
if (rcode != DB_SUCCESS) {
WSREP_ERROR(
"FK key set failed: " ULINTPF
- " (" ULINTPF " " ULINTPF "), index: %s %s, %s",
- rcode, referenced, shared,
+ " (" ULINTPF "%s), index: %s %s, %s",
+ rcode, referenced, wsrep_key_type_to_str(key_type),
(index) ? index->name() : "void index",
(index && index->table) ? index->table->name.m_name :
"void table",
@@ -10250,7 +10283,7 @@ wsrep_append_foreign_key(
#ifdef WSREP_DEBUG_PRINT
ulint j;
fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
- cache_key, (shared) ? "shared" : "exclusive", len+1);
+ cache_key, wsrep_key_type_to_str(key_type), len+1);
for (j=0; j<len+1; j++) {
fprintf(stderr, " %hhX, ", key[j]);
}
@@ -10269,7 +10302,8 @@ wsrep_append_foreign_key(
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
- if (!wsrep_prepare_key(
+ if (!wsrep_prepare_key_for_innodb(
+ thd,
(const uchar*)cache_key,
cache_key_len + 1,
(const uchar*)key, len+1,
@@ -10280,17 +10314,7 @@ wsrep_append_foreign_key(
wsrep_thd_query(thd) : "void");
return DB_ERROR;
}
-
- wsrep_t *wsrep= get_wsrep();
-
- rcode = (int)wsrep->append_key(
- wsrep,
- wsrep_ws_handle(thd, trx),
- &wkey,
- 1,
- shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
- copy);
-
+ rcode = wsrep_thd_append_key(thd, &wkey, 1, key_type);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: " ULINTPF, rcode));
WSREP_ERROR("Appending cascaded fk row key failed: %s, "
@@ -10311,16 +10335,19 @@ wsrep_append_key(
TABLE_SHARE *table_share,
const char* key,
uint16_t key_len,
- bool shared
+ Wsrep_service_key_type key_type /*!< in: access type of this key
+ (shared, exclusive, semi...) */
)
{
DBUG_ENTER("wsrep_append_key");
- bool const copy = true;
+ DBUG_PRINT("enter",
+ ("thd: %lu trx: %lld", thd_get_thread_id(thd),
+ (long long)trx->id));
#ifdef WSREP_DEBUG_PRINT
- fprintf(stderr, "%s conn %ld, trx %llu, keylen %d, table %s\n Query: %s ",
- (shared) ? "Shared" : "Exclusive",
- thd_get_thread_id(thd), (long long)trx->id, key_len,
- table_share->table_name.str, wsrep_thd_query(thd));
+ fprintf(stderr, "%s conn %lu, trx " TRX_ID_FMT ", keylen %d, key %s.%s\n",
+ wsrep_key_type_to_str(key_type),
+ thd_get_thread_id(thd), trx->id, key_len,
+ table_share->table_name.str, key);
for (int i=0; i<key_len; i++) {
fprintf(stderr, "%hhX, ", key[i]);
}
@@ -10329,7 +10356,8 @@ wsrep_append_key(
wsrep_buf_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
- if (!wsrep_prepare_key(
+ if (!wsrep_prepare_key_for_innodb(
+ thd,
(const uchar*)table_share->table_cache_key.str,
table_share->table_cache_key.length,
(const uchar*)key, key_len,
@@ -10341,15 +10369,7 @@ wsrep_append_key(
DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
}
- wsrep_t *wsrep= get_wsrep();
-
- int rcode = (int)wsrep->append_key(
- wsrep,
- wsrep_ws_handle(thd, trx),
- &wkey,
- 1,
- shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE,
- copy);
+ int rcode = wsrep_thd_append_key(thd, &wkey, 1, key_type);
if (rcode) {
DBUG_PRINT("wsrep", ("row key failed: %d", rcode));
WSREP_WARN("Appending row key failed: %s, %d",
@@ -10390,16 +10410,30 @@ int
ha_innobase::wsrep_append_keys(
/*===========================*/
THD *thd,
- bool shared,
+ Wsrep_service_key_type key_type, /*!< in: access type of this row
+ operation:
+ (shared, exclusive, reference...) */
const uchar* record0, /* in: row in MySQL format */
const uchar* record1) /* in: row in MySQL format */
{
+ /* Sanity check: newly inserted records should always be passed with
+ EXCLUSIVE key type, all the rest are expected to carry a pre-image
+ */
+ ut_a(record1 != NULL || key_type == WSREP_SERVICE_KEY_EXCLUSIVE);
+
int rcode;
DBUG_ENTER("wsrep_append_keys");
bool key_appended = false;
trx_t *trx = thd_to_trx(thd);
+#ifdef WSREP_DEBUG_PRINT
+ fprintf(stderr, "%s conn %lu, trx " TRX_ID_FMT ", table %s\nSQL: %s\n",
+ wsrep_key_type_to_str(key_type),
+ thd_get_thread_id(thd), trx->id,
+ table_share->table_name.str, wsrep_thd_query(thd));
+#endif
+
if (table_share && table_share->tmp_table != NO_TMP_TABLE) {
WSREP_DEBUG("skipping tmp table DML: THD: %lu tmp: %d SQL: %s",
thd_get_thread_id(thd),
@@ -10422,7 +10456,7 @@ ha_innobase::wsrep_append_keys(
if (!is_null) {
rcode = wsrep_append_key(
thd, trx, table_share, keyval,
- len, shared);
+ len, key_type);
if (rcode) {
DBUG_RETURN(rcode);
@@ -10440,68 +10474,91 @@ ha_innobase::wsrep_append_keys(
KEY* key_info = table->key_info + i;
if (key_info->flags & HA_NOSAME) {
hasPK = true;
+ break;
}
}
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;
+ /* keyval[] shall contain an ordinal number at byte 0
+ and the actual key data shall be written at byte 1.
+ Hence the total data length is the key length + 1 */
+ char keyval0[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
+ char keyval1[WSREP_MAX_SUPPORTED_KEY_LENGTH+1] = {'\0'};
keyval0[0] = (char)i;
keyval1[0] = (char)i;
+ char* key0 = &keyval0[1];
+ char* key1 = &keyval1[1];
if (!tab) {
WSREP_WARN("MariaDB-InnoDB key mismatch %s %s",
table->s->table_name.str,
key_info->name.str);
}
- /* !hasPK == table with no PK, must append all non-unique keys */
+ /* !hasPK == table with no PK,
+ must append all non-unique keys */
if (!hasPK || key_info->flags & HA_NOSAME ||
((tab &&
referenced_by_foreign_key2(tab, idx)) ||
(!tab && referenced_by_foreign_key()))) {
- len = wsrep_store_key_val_for_row(
+ ibool is_null0;
+ uint len0 = wsrep_store_key_val_for_row(
thd, table, i, key0,
WSREP_MAX_SUPPORTED_KEY_LENGTH,
- record0, &is_null);
- if (!is_null) {
- rcode = wsrep_append_key(
- thd, trx, table_share,
- 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));
- }
+ record0, &is_null0);
if (record1) {
- len = wsrep_store_key_val_for_row(
+ ibool is_null1;
+ uint len1 = wsrep_store_key_val_for_row(
thd, table, i, key1,
WSREP_MAX_SUPPORTED_KEY_LENGTH,
- record1, &is_null);
+ record1, &is_null1);
+
+ if (is_null0 != is_null1 ||
+ len0 != len1 ||
+ memcmp(key0, key1, len0)) {
+ /* This key has chaged. If it
+ is unique, this is an exclusive
+ operation -> upgrade key type */
+ if (key_info->flags & HA_NOSAME) {
+ key_type = WSREP_SERVICE_KEY_EXCLUSIVE;
+ }
- if (!is_null && memcmp(key0, key1, len)) {
- rcode = wsrep_append_key(
+ if (!is_null1) {
+ rcode = wsrep_append_key(
thd, trx, table_share,
- keyval1, len+1, shared);
- if (rcode) DBUG_RETURN(rcode);
+ keyval1,
+ /* for len1+1 see keyval1
+ initialization comment */
+ len1+1, key_type);
+ if (rcode)
+ DBUG_RETURN(rcode);
+ }
}
}
+
+ if (!is_null0) {
+ rcode = wsrep_append_key(
+ thd, trx, table_share,
+ /* for len0+1 see keyval0
+ initialization comment */
+ keyval0, len0+1, key_type);
+ if (rcode)
+ DBUG_RETURN(rcode);
+
+ if (key_info->flags & HA_NOSAME ||
+ key_type == WSREP_SERVICE_KEY_SHARED||
+ key_type == WSREP_SERVICE_KEY_REFERENCE)
+ key_appended = true;
+ } else {
+ WSREP_DEBUG("NULL key skipped: %s",
+ wsrep_thd_query(thd));
+ }
}
}
}
@@ -10515,7 +10572,7 @@ ha_innobase::wsrep_append_keys(
if ((rcode = wsrep_append_key(thd, trx, table_share,
(const char*) digest, 16,
- shared))) {
+ key_type))) {
DBUG_RETURN(rcode);
}
@@ -10524,7 +10581,7 @@ ha_innobase::wsrep_append_keys(
digest, record1, table, m_prebuilt);
if ((rcode = wsrep_append_key(thd, trx, table_share,
(const char*) digest,
- 16, shared))) {
+ 16, key_type))) {
DBUG_RETURN(rcode);
}
}
@@ -15405,8 +15462,7 @@ ha_innobase::external_lock(
if (!skip) {
#ifdef WITH_WSREP
- if (!wsrep_on(thd) || wsrep_thd_exec_mode(thd) == LOCAL_STATE)
- {
+ if (!wsrep_on(thd) || wsrep_thd_is_local(m_user_thd)) {
#endif /* WITH_WSREP */
my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0),
" InnoDB is limited to row-logging when"
@@ -16920,6 +16976,14 @@ innobase_rollback_by_xid(
}
if (trx_t* trx = trx_get_trx_by_xid(xid)) {
+#ifdef WITH_WSREP
+ /* If a wsrep transaction is being rolled back during
+ the recovery, we must clear the xid in order to avoid
+ writing serialisation history for rolled back transaction. */
+ if (wsrep_is_wsrep_xid(trx->xid)) {
+ trx->xid->null();
+ }
+#endif /* WITH_WSREP */
int ret = innobase_rollback_trx(trx);
trx_deregister_from_2pc(trx);
ut_ad(!trx->will_lock);
@@ -18520,123 +18584,32 @@ wsrep_innobase_kill_one_trx(
bf_trx ? bf_trx->id : 0);
DBUG_RETURN(1);
}
-
WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
-
+ wsrep_thd_LOCK(thd);
WSREP_DEBUG("BF kill (" ULINTPF ", seqno: " INT64PF
"), victim: (%lu) trx: " TRX_ID_FMT,
signal, bf_seqno,
thd_get_thread_id(thd),
victim_trx->id);
- WSREP_DEBUG("Aborting query: %s conf %d trx: %" PRId64,
+ WSREP_DEBUG("Aborting query: %s conf %s trx: %lld",
(thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void",
- wsrep_thd_conflict_state(thd, FALSE),
- wsrep_thd_ws_handle(thd)->trx_id);
-
- wsrep_thd_LOCK(thd);
- DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
- {
- const char act[]=
- "now "
- "wait_for signal.wsrep_after_BF_victim_lock";
- DBUG_ASSERT(!debug_sync_set_action(bf_thd,
- STRING_WITH_LEN(act)));
- };);
-
-
- if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
- WSREP_DEBUG("kill trx EXITING for " TRX_ID_FMT,
- victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- DBUG_RETURN(0);
- }
-
- if (wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
- WSREP_DEBUG("withdraw for BF trx: " TRX_ID_FMT ", state: %d",
- victim_trx->id,
- wsrep_thd_get_conflict_state(thd));
- }
-
- switch (wsrep_thd_get_conflict_state(thd)) {
- case NO_CONFLICT:
- wsrep_thd_set_conflict_state(thd, MUST_ABORT);
- break;
- case MUST_ABORT:
- WSREP_DEBUG("victim " TRX_ID_FMT " in MUST ABORT state",
- victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- DBUG_RETURN(0);
- break;
- case ABORTED:
- case ABORTING: // fall through
- default:
- WSREP_DEBUG("victim " TRX_ID_FMT " in state %d",
- victim_trx->id, wsrep_thd_get_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",
- thd_get_thread_id(thd));
- WSREP_DEBUG("kill trx QUERY_COMMITTING for " TRX_ID_FMT,
- victim_trx->id);
-
- if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- wsrep_abort_slave_trx(bf_seqno,
- wsrep_thd_trx_seqno(thd));
- } else {
- wsrep_t *wsrep= get_wsrep();
- rcode = wsrep->abort_pre_commit(
- wsrep, bf_seqno,
- (wsrep_trx_id_t)wsrep_thd_ws_handle(thd)->trx_id
- );
-
- switch (rcode) {
- case WSREP_WARNING:
- WSREP_DEBUG("cancel commit warning: "
- TRX_ID_FMT,
- victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- DBUG_RETURN(1);
- break;
- case WSREP_OK:
- break;
- default:
- WSREP_ERROR(
- "cancel commit bad exit: %d "
- TRX_ID_FMT,
- rcode, victim_trx->id);
- /* unable to interrupt, must abort */
- /* note: kill_mysql() will block, if we cannot.
- * kill the lock holder first.
- */
- abort();
- break;
- }
- }
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- break;
- case QUERY_EXEC:
- /* it is possible that victim trx is itself waiting for some
- * other lock. We need to cancel this waiting
- */
- WSREP_DEBUG("kill trx QUERY_EXEC for " TRX_ID_FMT,
- victim_trx->id);
-
- victim_trx->lock.was_chosen_as_deadlock_victim= TRUE;
-
+ wsrep_thd_transaction_state_str(thd),
+ wsrep_thd_transaction_id(thd));
+
+ /*
+ * we mark with was_chosen_as_deadlock_victim transaction,
+ * which is already marked as BF victim
+ * lock_sys is held until this vicitm has aborted
+ */
+ victim_trx->lock.was_chosen_as_wsrep_victim = TRUE;
+
+ wsrep_thd_UNLOCK(thd);
+ if (wsrep_thd_bf_abort(bf_thd, thd, signal))
+ {
if (victim_trx->lock.wait_lock) {
- WSREP_DEBUG("victim has wait flag: %ld",
- thd_get_thread_id(thd));
+ WSREP_DEBUG("victim has wait flag: %lu",
+ thd_get_thread_id(thd));
lock_t* wait_lock = victim_trx->lock.wait_lock;
if (wait_lock) {
@@ -18644,67 +18617,7 @@ wsrep_innobase_kill_one_trx(
victim_trx->lock.was_chosen_as_deadlock_victim= TRUE;
lock_cancel_waiting_and_release(wait_lock);
}
-
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
- } else {
- /* abort currently executing query */
- DBUG_PRINT("wsrep",("sending KILL_QUERY to: %lu",
- thd_get_thread_id(thd)));
- WSREP_DEBUG("kill query for: %ld",
- thd_get_thread_id(thd));
- /* Note that innobase_kill_query will take lock_mutex
- and trx_mutex */
- wsrep_thd_UNLOCK(thd);
- wsrep_thd_awake(thd, signal);
-
- /* for BF thd, we need to prevent him from committing */
- if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- wsrep_abort_slave_trx(bf_seqno,
- wsrep_thd_trx_seqno(thd));
- }
- }
- break;
- case QUERY_IDLE:
- {
- WSREP_DEBUG("kill IDLE for " TRX_ID_FMT, 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);
-
- wsrep_lock_rollback();
-
- if (wsrep_aborting_thd_contains(thd)) {
- WSREP_WARN("duplicate thd aborter %lu",
- (ulong) thd_get_thread_id(thd));
- } else {
- wsrep_aborting_thd_enqueue(thd);
- DBUG_PRINT("wsrep",("enqueuing trx abort for %lu",
- thd_get_thread_id(thd)));
- WSREP_DEBUG("enqueuing trx abort for (%lu)",
- thd_get_thread_id(thd));
- }
-
- DBUG_PRINT("wsrep",("signalling wsrep rollbacker"));
- WSREP_DEBUG("signaling aborter");
- wsrep_unlock_rollback();
- wsrep_thd_UNLOCK(thd);
-
- break;
- }
- default:
- WSREP_WARN("bad wsrep query state: %d",
- wsrep_thd_query_state(thd));
- wsrep_thd_UNLOCK(thd);
- break;
}
DBUG_RETURN(0);
@@ -18724,26 +18637,22 @@ wsrep_abort_transaction(
trx_t* victim_trx = thd_to_trx(victim_thd);
trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
- WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %d",
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
wsrep_thd_query(bf_thd),
wsrep_thd_query(victim_thd),
- wsrep_thd_conflict_state(victim_thd, FALSE));
+ wsrep_thd_transaction_state_str(victim_thd));
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
- int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
- victim_trx, signal);
- lock_mutex_exit();
+ int rcode= wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
+ victim_trx, signal);
trx_mutex_exit(victim_trx);
+ lock_mutex_exit();
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {
- WSREP_DEBUG("victim does not have transaction");
- wsrep_thd_LOCK(victim_thd);
- wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT);
- wsrep_thd_UNLOCK(victim_thd);
- wsrep_thd_awake(victim_thd, signal);
+ wsrep_thd_bf_abort(bf_thd, victim_thd, signal);
}
DBUG_RETURN(-1);
@@ -18779,15 +18688,6 @@ innobase_wsrep_get_checkpoint(
trx_rseg_read_wsrep_checkpoint(*xid);
return 0;
}
-
-static void wsrep_fake_trx_id(handlerton *, THD *thd)
-{
- trx_id_t trx_id = trx_sys.get_new_trx_id();
- WSREP_DEBUG("innodb fake trx id: " TRX_ID_FMT " thd: %s",
- trx_id, wsrep_thd_query(thd));
- wsrep_ws_handle_for_trx(wsrep_thd_ws_handle(thd), trx_id);
-}
-
#endif /* WITH_WSREP */
/* plugin options */
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 6f0c5b535fb..71212785df4 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -16,6 +16,10 @@ this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
+#ifdef WITH_WSREP
+#include "wsrep_api.h"
+#include <mysql/service_wsrep.h>
+#endif /* WITH_WSREP */
/* The InnoDB handler: the interface between MySQL and InnoDB. */
@@ -444,8 +448,11 @@ protected:
dict_index_t* innobase_get_index(uint keynr);
#ifdef WITH_WSREP
- int wsrep_append_keys(THD *thd, bool shared,
- const uchar* record0, const uchar* record1);
+ int wsrep_append_keys(
+ THD *thd,
+ Wsrep_service_key_type key_type,
+ const uchar* record0,
+ const uchar* record1);
#endif
/** Builds a 'template' to the prebuilt struct.
@@ -571,23 +578,7 @@ thd_get_work_part_info(
struct trx_t;
#ifdef WITH_WSREP
#include <mysql/service_wsrep.h>
-//extern "C" int wsrep_trx_order_before(void *thd1, void *thd2);
-
-extern "C" bool wsrep_thd_is_wsrep_on(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_trx_to_replay(THD *thd, uint64 trx_id);
-
-extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
-extern "C" time_t wsrep_thd_query_start(THD *thd);
-extern "C" query_id_t wsrep_thd_query_id(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);
-#endif
+#endif /* WITH_WSREP */
extern const struct _ft_vft ft_vft_result;
@@ -621,10 +612,6 @@ innobase_index_name_is_reserved(
be created. */
MY_ATTRIBUTE((nonnull(1), warn_unused_result));
-#ifdef WITH_WSREP
-//extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
-#endif
-
/** Parse hint for table and its indexes, and update the information
in dictionary.
@param[in] thd Connection thread
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 34d61100a9b..8bf64c28441 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -577,6 +577,11 @@ struct trx_lock_t {
lock_sys.mutex. Otherwise, this may
only be modified by the thread that is
serving the running transaction. */
+#ifdef WITH_WSREP
+ bool was_chosen_as_wsrep_victim;
+ /*!< high priority wsrep thread has
+ marked this trx to abort */
+#endif /* WITH_WSREP */
/** Pre-allocated record locks */
struct {
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 7fc986bdbca..493f73cc148 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -762,9 +762,7 @@ lock_rec_has_to_wait(
<< wsrep_thd_query(lock2->trx->mysql_thd);
}
- if (wsrep_trx_order_before(trx->mysql_thd,
- lock2->trx->mysql_thd)
- && (type_mode & LOCK_MODE_MASK) == LOCK_X
+ if ((type_mode & LOCK_MODE_MASK) == LOCK_X
&& (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) {
if (for_locking || wsrep_debug) {
/* exclusive lock conflicts are not
@@ -774,12 +772,11 @@ lock_rec_has_to_wait(
<< type_mode
<< " supremum: " << lock_is_on_supremum
<< "conflicts states: my "
- << wsrep_thd_conflict_state(
- trx->mysql_thd, FALSE)
+ << wsrep_thd_transaction_state_str(
+ trx->mysql_thd)
<< " locked "
- << wsrep_thd_conflict_state(
- lock2->trx->mysql_thd,
- FALSE);
+ << wsrep_thd_transaction_state_str(
+ lock2->trx->mysql_thd);
lock_rec_print(stderr, lock2);
ib::info() << " SQL1: "
<< wsrep_thd_query(trx->mysql_thd)
@@ -1098,11 +1095,14 @@ wsrep_kill_victim(
return;
}
- my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE);
+ if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
+ return;
+ }
+
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(
+ if ((!bf_other) ||
+ (wsrep_thd_order_before(
trx->mysql_thd, lock->trx->mysql_thd))) {
if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
@@ -1113,11 +1113,7 @@ wsrep_kill_victim(
is in the queue*/
} else if (lock->trx != trx) {
if (wsrep_log_conflicts) {
- if (bf_this) {
- ib::info() << "*** Priority TRANSACTION:";
- } else {
- ib::info() << "*** Victim TRANSACTION:";
- }
+ ib::info() << "*** Priority TRANSACTION:";
trx_print_latched(stderr, trx, 3000);
@@ -1426,7 +1422,7 @@ lock_rec_create_low(
lock_t *prev = NULL;
while (hash && wsrep_thd_is_BF(hash->trx->mysql_thd, TRUE)
- && wsrep_trx_order_before(hash->trx->mysql_thd,
+ && wsrep_thd_order_before(hash->trx->mysql_thd,
trx->mysql_thd)) {
prev = hash;
hash = (lock_t *)hash->hash;
@@ -1840,15 +1836,15 @@ lock_rec_add_to_queue(
ib::info() << "WSREP BF lock conflict for my lock:\n BF:" <<
((wsrep_thd_is_BF(trx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " <<
- wsrep_thd_exec_mode(trx->mysql_thd) << " conflict: " <<
- wsrep_thd_conflict_state(trx->mysql_thd, false) << " seqno: " <<
+ wsrep_thd_client_state_str(trx->mysql_thd) << " conflict: " <<
+ wsrep_thd_transaction_state_str(trx->mysql_thd) << " seqno: " <<
wsrep_thd_trx_seqno(trx->mysql_thd) << " SQL: " <<
wsrep_thd_query(trx->mysql_thd);
trx_t* otrx = other_lock->trx;
ib::info() << "WSREP other lock:\n BF:" <<
((wsrep_thd_is_BF(otrx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " <<
- wsrep_thd_exec_mode(otrx->mysql_thd) << " conflict: " <<
- wsrep_thd_conflict_state(otrx->mysql_thd, false) << " seqno: " <<
+ wsrep_thd_client_state_str(otrx->mysql_thd) << " conflict: " <<
+ wsrep_thd_transaction_state_str(otrx->mysql_thd) << " seqno: " <<
wsrep_thd_trx_seqno(otrx->mysql_thd) << " SQL: " <<
wsrep_thd_query(otrx->mysql_thd);
}
@@ -4949,8 +4945,8 @@ lock_rec_queue_validate(
if (!lock_get_wait(other_lock) ) {
ib::info() << "WSREP impl BF lock conflict for my impl lock:\n BF:" <<
((wsrep_thd_is_BF(impl_trx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " <<
- wsrep_thd_exec_mode(impl_trx->mysql_thd) << " conflict: " <<
- wsrep_thd_conflict_state(impl_trx->mysql_thd, false) << " seqno: " <<
+ wsrep_thd_client_state_str(impl_trx->mysql_thd) << " conflict: " <<
+ wsrep_thd_transaction_state_str(impl_trx->mysql_thd) << " seqno: " <<
wsrep_thd_trx_seqno(impl_trx->mysql_thd) << " SQL: " <<
wsrep_thd_query(impl_trx->mysql_thd);
@@ -4958,8 +4954,8 @@ lock_rec_queue_validate(
ib::info() << "WSREP other lock:\n BF:" <<
((wsrep_thd_is_BF(otrx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " <<
- wsrep_thd_exec_mode(otrx->mysql_thd) << " conflict: " <<
- wsrep_thd_conflict_state(otrx->mysql_thd, false) << " seqno: " <<
+ wsrep_thd_client_state_str(otrx->mysql_thd) << " conflict: " <<
+ wsrep_thd_transaction_state_str(otrx->mysql_thd) << " seqno: " <<
wsrep_thd_trx_seqno(otrx->mysql_thd) << " SQL: " <<
wsrep_thd_query(otrx->mysql_thd);
}
@@ -6395,6 +6391,12 @@ lock_trx_handle_wait(
/*=================*/
trx_t* trx) /*!< in/out: trx lock state */
{
+#ifdef WITH_WSREP
+ /* We already own mutexes */
+ if (trx->lock.was_chosen_as_wsrep_victim) {
+ return lock_trx_handle_wait_low(trx);
+ }
+#endif /* WITH_WSREP */
lock_mutex_enter();
trx_mutex_enter(trx);
dberr_t err = lock_trx_handle_wait_low(trx);
@@ -6992,6 +6994,9 @@ DeadlockChecker::trx_rollback()
trx_t* trx = m_wait_lock->trx;
print("*** WE ROLL BACK TRANSACTION (1)\n");
+#ifdef WITH_WSREP
+ wsrep_handle_SR_rollback(m_start->mysql_thd, trx->mysql_thd);
+#endif
trx_mutex_enter(trx);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index e2ac60c1103..ed72f6d482b 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -44,6 +44,9 @@ Created 4/20/1996 Heikki Tuuri
#include "buf0lru.h"
#include "fts0fts.h"
#include "fts0types.h"
+#ifdef WITH_WSREP
+#include "wsrep_mysqld.h"
+#endif /* WITH_WSREP */
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
@@ -1043,7 +1046,7 @@ dberr_t wsrep_append_foreign_key(trx_t *trx,
const rec_t* clust_rec,
dict_index_t* clust_index,
ibool referenced,
- ibool shared);
+ Wsrep_service_key_type key_type);
#endif /* WITH_WSREP */
/*********************************************************************//**
@@ -1430,7 +1433,7 @@ row_ins_foreign_check_on_constraint(
#ifdef WITH_WSREP
err = wsrep_append_foreign_key(trx, foreign, clust_rec, clust_index,
- FALSE, FALSE);
+ FALSE, WSREP_SERVICE_KEY_EXCLUSIVE);
if (err != DB_SUCCESS) {
fprintf(stderr,
"WSREP: foreign key append failed: %d\n", err);
@@ -1811,7 +1814,10 @@ row_ins_check_foreign_constraint(
rec,
check_index,
check_ref,
- (upd_node) ? TRUE : FALSE);
+ (upd_node != NULL
+ && wsrep_protocol_version < 4)
+ ? WSREP_SERVICE_KEY_SHARED
+ : WSREP_SERVICE_KEY_REFERENCE);
#endif /* WITH_WSREP */
goto end_scan;
} else if (foreign->type != 0) {
@@ -3228,9 +3234,27 @@ row_ins_clust_index_entry(
n_uniq = dict_index_is_unique(index) ? index->n_uniq : 0;
+#ifdef WITH_WSREP
+ const bool skip_locking
+ = wsrep_thd_skip_locking(thr_get_trx(thr)->mysql_thd);
+ ulint flags = index->table->no_rollback() ? BTR_NO_ROLLBACK
+ : (index->table->is_temporary() || skip_locking)
+ ? BTR_NO_LOCKING_FLAG : 0;
+#ifdef UNIV_DEBUG
+ if (skip_locking && strcmp(wsrep_get_sr_table_name(),
+ index->table->name.m_name)) {
+ WSREP_ERROR("Record locking is disabled in this thread, "
+ "but the table being modified is not "
+ "`%s`: `%s`.", wsrep_get_sr_table_name(),
+ index->table->name.m_name);
+ ut_error;
+ }
+#endif /* UNIV_DEBUG */
+#else
ulint flags = index->table->no_rollback() ? BTR_NO_ROLLBACK
: index->table->is_temporary()
? BTR_NO_LOCKING_FLAG : 0;
+#endif /* WITH_WSREP */
const ulint orig_n_fields = entry->n_fields;
/* Try first optimistic descent to the B-tree */
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 658785a5c03..8d7824bfc56 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -54,6 +54,9 @@ Created 12/19/1997 Heikki Tuuri
#include "buf0lru.h"
#include "srv0srv.h"
#include "srv0mon.h"
+#ifdef WITH_WSREP
+#include "mysql/service_wsrep.h" /* For wsrep_thd_skip_locking */
+#endif
/* Maximum number of rows to prefetch; MySQL interface has another parameter */
#define SEL_MAX_N_PREFETCH 16
@@ -4442,6 +4445,13 @@ row_search_mvcc(
set_also_gap_locks = FALSE;
}
+#ifdef WITH_WSREP
+ else if (wsrep_thd_skip_locking(trx->mysql_thd)) {
+ ut_ad(!strcmp(wsrep_get_sr_table_name(),
+ prebuilt->table->name.m_name));
+ set_also_gap_locks = FALSE;
+ }
+#endif /* WITH_WSREP */
/* Note that if the search mode was GE or G, then the cursor
naturally moves upward (in fetch next) in alphabetical order,
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 591ae238c43..a60210c77c8 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -2458,7 +2458,7 @@ row_upd_sec_index_entry(
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::warn() << "WSREP: sec index FK check fail for deadlock"
<< " index " << index->name
<< " table " << index->table->name;
@@ -2773,7 +2773,7 @@ check_fk:
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::warn() << "WSREP: sec index FK check fail for deadlock"
<< " index " << index->name
<< " table " << index->table->name;
@@ -3002,7 +3002,7 @@ row_upd_del_mark_clust_rec(
err = DB_SUCCESS;
break;
case DB_DEADLOCK:
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::warn() << "WSREP: sec index FK check fail for deadlock"
<< " index " << index->name
<< " table " << index->table->name;
diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc
index 6beeee58fae..b2b464e31fa 100644
--- a/storage/innobase/srv/srv0conc.cc
+++ b/storage/innobase/srv/srv0conc.cc
@@ -119,8 +119,8 @@ srv_conc_enter_innodb_with_atomics(
ulint sleep_in_us;
#ifdef WITH_WSREP
if (wsrep_on(trx->mysql_thd) &&
- wsrep_trx_is_aborting(trx->mysql_thd)) {
- if (wsrep_debug) {
+ wsrep_thd_is_aborting(trx->mysql_thd)) {
+ if (wsrep_get_debug()) {
ib::info() <<
"srv_conc_enter due to MUST_ABORT";
}
@@ -308,14 +308,14 @@ wsrep_srv_conc_cancel_wait(
srv_conc_enter_innodb_with_atomics(). No need to cancel here,
thr will wake up after os_sleep and let to enter innodb
*/
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::info() << "WSREP: conc slot cancel, no atomics";
}
#else
// JAN: TODO: MySQL 5.7
//os_fast_mutex_lock(&srv_conc_mutex);
if (trx->wsrep_event) {
- if (wsrep_debug) {
+ if (wsrep_get_debug()) {
ib::info() << "WSREP: conc slot cancel";
}
os_event_set(trx->wsrep_event);
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 890bd969670..3b5461aae25 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -76,10 +76,6 @@ Created 10/8/1995 Heikki Tuuri
#include <my_service_manager.h>
-#ifdef WITH_WSREP
-extern int wsrep_debug;
-extern int wsrep_trx_is_aborting(void *thd_ptr);
-#endif
/* The following is the maximum allowed duration of a lock wait. */
UNIV_INTERN ulong srv_fatal_semaphore_wait_threshold = DEFAULT_SRV_FATAL_SEMAPHORE_TIMEOUT;
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 54b0e75fd80..e15afcf9cd7 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -2328,7 +2328,7 @@ files_checked:
Create the dump/load thread only when not running with
--wsrep-recover.
*/
- if (!wsrep_recovery) {
+ if (!get_wsrep_recovery()) {
#endif /* WITH_WSREP */
/* Create the buffer pool dump/load thread */
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index 4b0684d1735..22b72a14304 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -178,6 +178,11 @@ trx_rollback_to_savepoint(
partial rollback requested, or NULL for
complete rollback */
{
+#ifdef WITH_WSREP
+ if (savept == NULL && wsrep_on(trx->mysql_thd)) {
+ wsrep_handle_SR_rollback(NULL, trx->mysql_thd);
+ }
+#endif /* WITH_WSREP */
ut_ad(!trx_mutex_own(trx));
trx_start_if_not_started_xa(trx, true);
@@ -446,12 +451,8 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
-
#ifdef WITH_WSREP
- if (wsrep_on(trx->mysql_thd) &&
- trx->lock.was_chosen_as_deadlock_victim) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
+ trx->lock.was_chosen_as_wsrep_victim = FALSE;
#endif
return(err);
}
diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc
index f0793140277..239df440c2b 100644
--- a/storage/innobase/trx/trx0rseg.cc
+++ b/storage/innobase/trx/trx0rseg.cc
@@ -43,6 +43,33 @@ static long long wsrep_seqno = -1;
/** The latest known WSREP XID UUID */
static unsigned char wsrep_uuid[16];
+/** Write the WSREP XID information into rollback segment header.
+@param[in,out] rseg_header rollback segment header
+@param[in] xid WSREP XID
+@param[in,out] mtr mini transaction */
+static void
+trx_rseg_write_wsrep_checkpoint(
+ trx_rsegf_t* rseg_header,
+ const XID* xid,
+ mtr_t* mtr)
+{
+ mlog_write_ulint(TRX_RSEG_WSREP_XID_FORMAT + rseg_header,
+ uint32_t(xid->formatID),
+ MLOG_4BYTES, mtr);
+
+ mlog_write_ulint(TRX_RSEG_WSREP_XID_GTRID_LEN + rseg_header,
+ uint32_t(xid->gtrid_length),
+ MLOG_4BYTES, mtr);
+
+ mlog_write_ulint(TRX_RSEG_WSREP_XID_BQUAL_LEN + rseg_header,
+ uint32_t(xid->bqual_length),
+ MLOG_4BYTES, mtr);
+
+ mlog_write_string(TRX_RSEG_WSREP_XID_DATA + rseg_header,
+ reinterpret_cast<const byte*>(xid->data),
+ XIDDATASIZE, mtr);
+}
+
/** Update the WSREP XID information in rollback segment header.
@param[in,out] rseg_header rollback segment header
@param[in] xid WSREP XID
@@ -60,29 +87,15 @@ trx_rseg_update_wsrep_checkpoint(
long long xid_seqno = wsrep_xid_seqno(xid);
const byte* xid_uuid = wsrep_xid_uuid(xid);
- if (!memcmp(xid_uuid, wsrep_uuid, sizeof wsrep_uuid)) {
+ if (xid_seqno != -1
+ && !memcmp(xid_uuid, wsrep_uuid, sizeof wsrep_uuid)) {
ut_ad(xid_seqno > wsrep_seqno);
} else {
memcpy(wsrep_uuid, xid_uuid, sizeof wsrep_uuid);
}
wsrep_seqno = xid_seqno;
#endif /* UNIV_DEBUG */
-
- mlog_write_ulint(TRX_RSEG_WSREP_XID_FORMAT + rseg_header,
- uint32_t(xid->formatID),
- MLOG_4BYTES, mtr);
-
- mlog_write_ulint(TRX_RSEG_WSREP_XID_GTRID_LEN + rseg_header,
- uint32_t(xid->gtrid_length),
- MLOG_4BYTES, mtr);
-
- mlog_write_ulint(TRX_RSEG_WSREP_XID_BQUAL_LEN + rseg_header,
- uint32_t(xid->bqual_length),
- MLOG_4BYTES, mtr);
-
- mlog_write_string(TRX_RSEG_WSREP_XID_DATA + rseg_header,
- reinterpret_cast<const byte*>(xid->data),
- XIDDATASIZE, mtr);
+ trx_rseg_write_wsrep_checkpoint(rseg_header, xid, mtr);
}
/** Update WSREP checkpoint XID in first rollback segment header
@@ -97,6 +110,13 @@ void trx_rseg_update_wsrep_checkpoint(const XID* xid)
mtr_t mtr;
mtr.start();
+ const byte* xid_uuid = wsrep_xid_uuid(xid);
+ /* We must make check against wsrep_uuid here, the
+ trx_rseg_update_wsrep_checkpoint() writes over wsrep_uuid with
+ xid contents in debug mode and the memcmp() will never give nonzero
+ result. */
+ const bool must_clear_rsegs = memcmp(wsrep_uuid, xid_uuid,
+ sizeof wsrep_uuid);
const trx_rseg_t* rseg = trx_sys.rseg_array[0];
trx_rsegf_t* rseg_header = trx_rsegf_get(rseg->space, rseg->page_no,
@@ -107,10 +127,11 @@ void trx_rseg_update_wsrep_checkpoint(const XID* xid)
trx_rseg_update_wsrep_checkpoint(rseg_header, xid, &mtr);
- const byte* xid_uuid = wsrep_xid_uuid(xid);
- if (memcmp(wsrep_uuid, xid_uuid, sizeof wsrep_uuid)) {
+ if (must_clear_rsegs) {
+ XID null_xid;
+ memset(&null_xid, 0, sizeof null_xid);
+ null_xid.null();
memcpy(wsrep_uuid, xid_uuid, sizeof wsrep_uuid);
-
/* Because the UUID part of the WSREP XID differed
from current_xid_uuid, the WSREP group UUID was
changed, and we must reset the XID in all rollback
@@ -118,10 +139,12 @@ void trx_rseg_update_wsrep_checkpoint(const XID* xid)
for (ulint rseg_id = 1; rseg_id < TRX_SYS_N_RSEGS; ++rseg_id) {
if (const trx_rseg_t* rseg =
trx_sys.rseg_array[rseg_id]) {
- trx_rseg_update_wsrep_checkpoint(
+ trx_rseg_write_wsrep_checkpoint(
trx_rsegf_get(rseg->space,
- rseg->page_no, &mtr),
- xid, &mtr);
+ rseg->page_no,
+ &mtr),
+ &null_xid,
+ &mtr);
}
}
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 333c7fe90eb..7be760c6221 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -1441,11 +1441,8 @@ trx_commit_in_memory(
trx_mutex_enter(trx);
trx->dict_operation = TRX_DICT_OP_NONE;
-
#ifdef WITH_WSREP
- if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
- trx->lock.was_chosen_as_deadlock_victim = FALSE;
- }
+ trx->lock.was_chosen_as_wsrep_victim = FALSE;
#endif
DBUG_LOG("trx", "Commit in memory: " << trx);
@@ -2155,7 +2152,7 @@ static my_bool trx_get_trx_by_xid_callback(rw_trx_hash_element_t *element,
transaction needs a valid trx->xid for
invoking trx_sys_update_wsrep_checkpoint(). */
if (!wsrep_is_wsrep_xid(trx->xid))
-#endif
+#endif /* WITH_WSREP */
/* Invalidate the XID, so that subsequent calls will not find it. */
trx->xid->null();
arg->trx= trx;
diff --git a/support-files/compiler_warnings.supp b/support-files/compiler_warnings.supp
index 4d9ca1c815b..3f7a79556f9 100644
--- a/support-files/compiler_warnings.supp
+++ b/support-files/compiler_warnings.supp
@@ -204,7 +204,6 @@
.*/ctype-simple\.c : .*unary minus operator applied to unsigned type, result still unsigned.*
.*/sql/sys_vars\.cc : invalid access to non-static data member
.*/string3\.h : memset used with constant zero length parameter
-.*/sql/wsrep_hton\.cc : NULL used in arithmetic : 500-600
.* : missing-declarations.*is valid
#
diff --git a/wsrep-lib b/wsrep-lib
new file mode 160000
+Subproject 8e4777114b92f4d86000d69603c66ec49ca41b9
diff --git a/wsrep/CMakeLists.txt b/wsrep/CMakeLists.txt
deleted file mode 100644
index ff2bdec4def..00000000000
--- a/wsrep/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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
-
-SET(WSREP_SOURCES wsrep_gtid.c wsrep_uuid.c wsrep_loader.c wsrep_dummy.c)
-
-IF(NOT WITH_INNOBASE_STORAGE_ENGINE)
- MESSAGE(WARNING "WSRep is enabled, but innodb is not. This configuration is not supported")
-ENDIF()
-
-ADD_CONVENIENCE_LIBRARY(wsrep ${WSREP_SOURCES})
-DTRACE_INSTRUMENT(wsrep)
-
-#ADD_EXECUTABLE(listener wsrep_listener.c ${WSREP_SOURCES})
-#TARGET_LINK_LIBRARIES(listener ${LIBDL})
diff --git a/wsrep/wsrep_api.h b/wsrep/wsrep_api.h
deleted file mode 100644
index 1d6bc059d3d..00000000000
--- a/wsrep/wsrep_api.h
+++ /dev/null
@@ -1,1117 +0,0 @@
-/* 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 <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 _integer64;
- 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
deleted file mode 100644
index e48dcff39a1..00000000000
--- a/wsrep/wsrep_dummy.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-/*! @file Dummy wsrep API implementation. */
-
-#include "wsrep_api.h"
-
-#include <errno.h>
-#include <string.h>
-
-/*! Dummy backend context. */
-typedef struct wsrep_dummy
-{
- wsrep_log_cb_t log_fn;
- char* options;
-} wsrep_dummy_t;
-
-/* Get pointer to wsrep_dummy context from wsrep_t pointer */
-#define WSREP_DUMMY(_p) ((wsrep_dummy_t *) (_p)->ctx)
-
-/* Trace function usage a-la DBUG */
-#define WSREP_DBUG_ENTER(_w) do { \
- if (WSREP_DUMMY(_w)) { \
- if (WSREP_DUMMY(_w)->log_fn) \
- WSREP_DUMMY(_w)->log_fn(WSREP_LOG_DEBUG, __FUNCTION__); \
- } \
- } while (0)
-
-
-static void dummy_free(wsrep_t *w)
-{
- WSREP_DBUG_ENTER(w);
- if (WSREP_DUMMY(w)->options) {
- free(WSREP_DUMMY(w)->options);
- WSREP_DUMMY(w)->options = NULL;
- }
- free(w->ctx);
- w->ctx = NULL;
-}
-
-static wsrep_status_t dummy_init (wsrep_t* w,
- const struct wsrep_init_args* args)
-{
- WSREP_DUMMY(w)->log_fn = args->logger_cb;
- WSREP_DBUG_ENTER(w);
- if (args->options) {
- WSREP_DUMMY(w)->options = strdup(args->options);
- }
- return WSREP_OK;
-}
-
-static uint64_t dummy_capabilities (wsrep_t* w __attribute__((unused)))
-{
- return 0;
-}
-
-static wsrep_status_t dummy_options_set(
- wsrep_t* w,
- const char* conf)
-{
- WSREP_DBUG_ENTER(w);
- if (WSREP_DUMMY(w)->options) {
- free(WSREP_DUMMY(w)->options);
- WSREP_DUMMY(w)->options = NULL;
- }
- if (conf) {
- WSREP_DUMMY(w)->options = strdup(conf);
- }
- return WSREP_OK;
-}
-
-static char* dummy_options_get (wsrep_t* w)
-{
- char *options;
-
- WSREP_DBUG_ENTER(w);
- options= WSREP_DUMMY(w)->options;
-
- if (options)
- options= strdup(WSREP_DUMMY(w)->options);
-
- return options;
-}
-
-static wsrep_status_t dummy_connect(
- wsrep_t* w,
- const char* name __attribute__((unused)),
- const char* url __attribute__((unused)),
- const char* donor __attribute__((unused)),
- wsrep_bool_t bootstrap __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_disconnect(wsrep_t* w)
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_recv(wsrep_t* w,
- void* recv_ctx __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_pre_commit(
- wsrep_t* w,
- const wsrep_conn_id_t conn_id __attribute__((unused)),
- wsrep_ws_handle_t* ws_handle __attribute__((unused)),
- uint32_t flags __attribute__((unused)),
- wsrep_trx_meta_t* meta __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_post_commit(
- wsrep_t* w,
- wsrep_ws_handle_t* ws_handle __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_post_rollback(
- wsrep_t* w,
- wsrep_ws_handle_t* ws_handle __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_replay_trx(
- wsrep_t* w,
- wsrep_ws_handle_t* ws_handle __attribute__((unused)),
- void* trx_ctx __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_abort_pre_commit(
- wsrep_t* w,
- const wsrep_seqno_t bf_seqno __attribute__((unused)),
- const wsrep_trx_id_t trx_id __attribute__((unused)))
-{
- WSREP_DBUG_ENTER(w);
- return WSREP_OK;
-}
-
-static wsrep_status_t dummy_append_key(
- wsrep_t* w,
- wsrep_ws_handle_t* ws_handle __attribute__((unused)),
- const wsrep_key_t* key __attribute__((unused)),
- const size_t key_num __attribute__((unused)),
- const wsrep_key_type_t key_type __attribute__((unused)),
- const wsrep_bool_t 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 wsrep_bool_t 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)),
- wsrep_bool_t 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 wsrep_bool_t 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 0;
-}
-
-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
deleted file mode 100644
index 45148785c25..00000000000
--- a/wsrep/wsrep_gtid.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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
deleted file mode 100644
index 1321538742f..00000000000
--- a/wsrep/wsrep_loader.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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[1025];
- msg[sizeof(msg)-1] = 0;
-
- if (NULL != log_cb)
- logger = log_cb;
-
- if (!(spec && hptr))
- return EINVAL;
-
- snprintf (msg, sizeof(msg)-1,
- "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)-1, "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)-1, "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)-1,
- "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)-1,
- "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
deleted file mode 100644
index 54ae4ab5ed5..00000000000
--- a/wsrep/wsrep_uuid.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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;
- }
-}