summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSachin Kumar <sachin.setiya@mariadb.com>2021-05-14 08:11:13 +0100
committerSachin Kumar <sachin.setiya@mariadb.com>2021-06-07 11:14:42 +0100
commit55c8b426fa8e841b8807f4fecc961e61765d138a (patch)
tree1eef092a0affbe624fabea97d9953943458523b7
parent8d40039fb5a574fc1fd09b1cd7ef3161c9045f08 (diff)
downloadmariadb-git-tmp_sachin.tar.gz
Roll Forward recovery for binlog teststmp_sachin
-rw-r--r--mysql-test/suite/rpl/include/binlog_commit_crash_crud.inc34
-rw-r--r--mysql-test/suite/rpl/r/rpl_binlog_commit_crash_safe.result39
-rw-r--r--mysql-test/suite/rpl/r/rpl_xa_commit_crash_safe_innodb_sync.result50
-rw-r--r--mysql-test/suite/rpl/r/rpl_xa_event_apply_failure_sync.result60
-rw-r--r--mysql-test/suite/rpl/r/rpl_xa_prepare_commit_prepare_sync.result48
-rw-r--r--mysql-test/suite/rpl/r/rpl_xa_prepare_crash_safe_sync.result62
-rw-r--r--mysql-test/suite/rpl/r/rpl_xa_rollback_commit_crash_safe_sync.result47
-rw-r--r--mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.test42
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.test98
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.test119
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.test95
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.test117
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.opt1
-rw-r--r--mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.test97
-rw-r--r--sql/log.cc3
-rw-r--r--storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.inc40
-rw-r--r--storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.opt1
-rw-r--r--storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.test49
23 files changed, 1007 insertions, 0 deletions
diff --git a/mysql-test/suite/rpl/include/binlog_commit_crash_crud.inc b/mysql-test/suite/rpl/include/binlog_commit_crash_crud.inc
new file mode 100644
index 00000000000..d9545a79f0a
--- /dev/null
+++ b/mysql-test/suite/rpl/include/binlog_commit_crash_crud.inc
@@ -0,0 +1,34 @@
+#
+# Execute a transaction and crash the server after binlog commit.
+#
+# @@input $exec_query The query which needs to be executed.
+
+--connection master
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+--error 2013 # CR_SERVER_LOST
+--eval $exec_query
+
+--source include/wait_until_disconnected.inc
+
+# Server restart
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
diff --git a/mysql-test/suite/rpl/r/rpl_binlog_commit_crash_safe.result b/mysql-test/suite/rpl/r/rpl_binlog_commit_crash_safe.result
new file mode 100644
index 00000000000..766169caee3
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_binlog_commit_crash_safe.result
@@ -0,0 +1,39 @@
+include/master-slave.inc
+[connection master]
+connection master;
+CREATE TABLE t ( f INT) ENGINE=INNODB;
+INSERT INTO t values(1);
+connection slave;
+connection master;
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+INSERT INTO t values(10);
+ERROR HY000: Lost connection to MySQL server during query
+connection default;
+connection server_1;
+connection master;
+connection master;
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+update t set f= 2 where f= 1;
+ERROR HY000: Lost connection to MySQL server during query
+connection default;
+connection server_1;
+connection master;
+connection master;
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+delete from t where f= 2;
+ERROR HY000: Lost connection to MySQL server during query
+connection default;
+connection server_1;
+connection master;
+connection master;
+SELECT * FROM t;
+f
+10
+connection slave;
+SELECT * FROM t;
+f
+10
+connection master;
+DROP TABLE t;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_commit_crash_safe_innodb_sync.result b/mysql-test/suite/rpl/r/rpl_xa_commit_crash_safe_innodb_sync.result
new file mode 100644
index 00000000000..ce7d257690a
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_commit_crash_safe_innodb_sync.result
@@ -0,0 +1,50 @@
+include/master-slave.inc
+[connection master]
+connect master2,localhost,root,,;
+connection master;
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+connection slave;
+include/stop_slave.inc
+connection master1;
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+XA PREPARE 'xa2';
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+XA COMMIT 'xa2';
+ERROR HY000: Lost connection to MySQL server during query
+connection master1;
+connection master;
+connection default;
+connection server_1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+SELECT * FROM t;
+f
+20
+40
+XA RECOVER;
+formatID gtrid_length bqual_length data
+XA COMMIT 'xa2';
+ERROR XAE04: XAER_NOTA: Unknown XID
+SELECT * FROM t;
+f
+20
+40
+connection slave;
+SELECT * FROM t;
+f
+20
+40
+connection master;
+DROP TABLE t;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_event_apply_failure_sync.result b/mysql-test/suite/rpl/r/rpl_xa_event_apply_failure_sync.result
new file mode 100644
index 00000000000..dc9930b77b1
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_event_apply_failure_sync.result
@@ -0,0 +1,60 @@
+include/master-slave.inc
+[connection master]
+connect master2,localhost,root,,;
+connection master;
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CALL mtr.add_suppression("Failed to execute binlog query event");
+CALL mtr.add_suppression("Recovery: Error .Out of memory..");
+CALL mtr.add_suppression("Crash recovery failed.");
+CALL mtr.add_suppression("Can.t init tc log");
+CALL mtr.add_suppression("Aborting");
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+connection slave;
+include/stop_slave.inc
+connection master1;
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+XA PREPARE 'xa2';
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+XA COMMIT 'xa2';
+ERROR HY000: Lost connection to MySQL server during query
+connection master1;
+connection master;
+connection default;
+connection default;
+connection master;
+*** must be no 'xa2' commit seen, as it's still prepared:
+SELECT * FROM t;
+f
+20
+XA RECOVER;
+formatID gtrid_length bqual_length data
+1 3 0 xa2
+SET GLOBAL DEBUG_DBUG="";
+SET SQL_LOG_BIN=0;
+XA COMMIT 'xa2';
+SET SQL_LOG_BIN=1;
+connection server_1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+SELECT * FROM t;
+f
+20
+40
+connection slave;
+SELECT * FROM t;
+f
+20
+40
+connection master;
+DROP TABLE t;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_prepare_commit_prepare_sync.result b/mysql-test/suite/rpl/r/rpl_xa_prepare_commit_prepare_sync.result
new file mode 100644
index 00000000000..9ba24716639
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_prepare_commit_prepare_sync.result
@@ -0,0 +1,48 @@
+include/master-slave.inc
+[connection master]
+connect master2,localhost,root,,;
+connection master;
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+connection slave;
+include/stop_slave.inc
+connection master1;
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_prepare";
+XA PREPARE 'xa2';
+ERROR HY000: Lost connection to MySQL server during query
+connection master1;
+connection master;
+connection default;
+connection server_1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+SELECT * FROM t;
+f
+20
+XA RECOVER;
+formatID gtrid_length bqual_length data
+1 3 0 xa2
+XA COMMIT 'xa2';
+SELECT * FROM t;
+f
+20
+40
+connection slave;
+SELECT * FROM t;
+f
+20
+40
+connection master;
+DROP TABLE t;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_prepare_crash_safe_sync.result b/mysql-test/suite/rpl/r/rpl_xa_prepare_crash_safe_sync.result
new file mode 100644
index 00000000000..99baf59a3c1
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_prepare_crash_safe_sync.result
@@ -0,0 +1,62 @@
+include/master-slave.inc
+[connection master]
+connect master2,localhost,root,,;
+connection master;
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CALL mtr.add_suppression("Found 2 prepared XA transactions");
+CALL mtr.add_suppression("Found 3 prepared XA transactions");
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+connection slave;
+include/stop_slave.inc
+connection master1;
+use test;
+xa start 'xa2';
+insert into t values (30);
+xa end 'xa2';
+SET DEBUG_SYNC="simulate_hang_after_binlog_prepare SIGNAL reached WAIT_FOR go";
+xa prepare 'xa2';
+connection master2;
+XA START 'xa3';
+INSERT INTO t VALUES (40);
+XA END 'xa3';
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_prepare";
+XA PREPARE 'xa3';
+ERROR HY000: Lost connection to MySQL server during query
+connection master1;
+ERROR HY000: Lost connection to MySQL server during query
+connection master;
+connection default;
+connection server_1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+SELECT * FROM t;
+f
+XA RECOVER;
+formatID gtrid_length bqual_length data
+1 3 0 xa3
+1 3 0 xa1
+1 3 0 xa2
+XA COMMIT 'xa1';
+XA COMMIT 'xa2';
+XA COMMIT 'xa3';
+SELECT * FROM t;
+f
+20
+30
+40
+connection slave;
+SELECT * FROM t;
+f
+20
+30
+40
+connection master;
+DROP TABLE t;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_xa_rollback_commit_crash_safe_sync.result b/mysql-test/suite/rpl/r/rpl_xa_rollback_commit_crash_safe_sync.result
new file mode 100644
index 00000000000..dc26c224ea9
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_xa_rollback_commit_crash_safe_sync.result
@@ -0,0 +1,47 @@
+include/master-slave.inc
+[connection master]
+connect master2,localhost,root,,;
+connection master;
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+connection slave;
+include/stop_slave.inc
+connection master1;
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+XA PREPARE 'xa2';
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+XA ROLLBACK 'xa2';
+ERROR HY000: Lost connection to MySQL server during query
+connection master1;
+connection master;
+connection default;
+connection server_1;
+connection master;
+connection slave;
+include/start_slave.inc
+connection master;
+SELECT * FROM t;
+f
+20
+XA RECOVER;
+formatID gtrid_length bqual_length data
+XA ROLLBACK 'xa2';
+ERROR XAE04: XAER_NOTA: Unknown XID
+SELECT * FROM t;
+f
+20
+connection slave;
+SELECT * FROM t;
+f
+20
+connection master;
+DROP TABLE t;
+connection slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.opt b/mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.test b/mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.test
new file mode 100644
index 00000000000..714ae16859d
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_binlog_commit_crash_safe.test
@@ -0,0 +1,42 @@
+# ==== Purpose ====
+#
+# Test verifies that Binlog Commits statements are crash safe.
+#
+# ==== Implementation ====
+# Create a innodb insert/update/delete and crash the server after binlog
+# commit. Roll forward recovery should work.
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+--connection master
+
+CREATE TABLE t ( f INT) ENGINE=INNODB;
+INSERT INTO t values(1);
+--sync_slave_with_master
+
+
+##Insert Block
+--let $exec_query= INSERT INTO t values(10)
+--source include/binlog_commit_crash_crud.inc
+
+
+##Update Block
+--let $exec_query= update t set f= 2 where f= 1
+--source include/binlog_commit_crash_crud.inc
+
+
+##Delete Block
+--let $exec_query= delete from t where f= 2
+--source include/binlog_commit_crash_crud.inc
+
+--connection master
+SELECT * FROM t;
+--sync_slave_with_master
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.opt b/mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.test b/mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.test
new file mode 100644
index 00000000000..e972e3f09de
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_commit_crash_safe_innodb_sync.test
@@ -0,0 +1,98 @@
+# ==== Purpose ====
+#
+# Test verifies that XA COMMIT statements are crash safe.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Generate 2 explicit XA transactions. 'xa1' and 'xa2'.
+# 'xa1' will be prepared and committed.
+# 1 - For 'xa2' let the XA COMMIT be done in binary log and crash the
+# server so that it is not committed in engine.
+# 2 - Restart the server. The recovery code should successfully recover
+# 'xa2'. The COMMIT should be executed during recovery.
+# 3 - Check the data in table. Both rows should be present in table.
+# 4 - Trying to commit 'xa2' should report unknown 'XA' error as COMMIT is
+# already complete during recovery.
+#
+# ==== References ====
+#
+# MDEV-21469: Implement crash-safe logging of the user XA
+
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/have_debug.inc
+
+connect (master2,localhost,root,,);
+--connection master
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+--sync_slave_with_master
+--source include/stop_slave.inc
+
+--connection master1
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+XA PREPARE 'xa2';
+
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+--error 2013 # CR_SERVER_LOST
+XA COMMIT 'xa2';
+--source include/wait_until_disconnected.inc
+
+--connection master1
+--source include/wait_until_disconnected.inc
+
+--connection master
+--source include/wait_until_disconnected.inc
+
+#
+# Server restart
+#
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection slave
+--source include/start_slave.inc
+--sync_with_master
+
+--connection master
+SELECT * FROM t;
+XA RECOVER;
+--error 1397 # ER_XAER_NOTA
+XA COMMIT 'xa2';
+SELECT * FROM t;
+--sync_slave_with_master
+
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.opt b/mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.test b/mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.test
new file mode 100644
index 00000000000..14cebbd9b13
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_event_apply_failure_sync.test
@@ -0,0 +1,119 @@
+# ==== Purpose ====
+#
+# Test verifies that if for some reason an event cannot be applied during
+# recovery, appropriate error is reported.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Generate 2 explicit XA transactions. 'xa1' and 'xa2'.
+# 'xa1' will be prepared and committed.
+# 1 - For 'xa2' let the XA COMMIT be done in binary log and crash the
+# server so that it is not committed in engine.
+# 2 - Restart the server. Using debug simulation point make XA COMMIT 'xa2'
+# execution to fail. The server will resume anyway
+# to leave the error in the errlog (see "Recovery: Error..").
+# 3 - Work around the simulated failure with Commit once again
+# from a connection that turns OFF binlogging.
+# Slave must catch up with the master.
+#
+# ==== References ====
+#
+# MDEV-21469: Implement crash-safe logging of the user XA
+
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/have_debug.inc
+
+connect (master2,localhost,root,,);
+--connection master
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CALL mtr.add_suppression("Failed to execute binlog query event");
+CALL mtr.add_suppression("Recovery: Error .Out of memory..");
+CALL mtr.add_suppression("Crash recovery failed.");
+CALL mtr.add_suppression("Can.t init tc log");
+CALL mtr.add_suppression("Aborting");
+
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+--sync_slave_with_master
+--source include/stop_slave.inc
+
+--connection master1
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+XA PREPARE 'xa2';
+
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+--error 2013 # CR_SERVER_LOST
+XA COMMIT 'xa2';
+--source include/wait_until_disconnected.inc
+
+--connection master1
+--source include/wait_until_disconnected.inc
+
+--connection master
+--source include/wait_until_disconnected.inc
+
+#
+# Server restart
+#
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart: --debug-dbug=d,trans_xa_commit_fail
+EOF
+
+connection default;
+--source include/wait_until_disconnected.inc
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--echo *** must be no 'xa2' commit seen, as it's still prepared:
+SELECT * FROM t;
+XA RECOVER;
+
+# Commit it manually now to work around the extra binlog record
+# by turning binlogging OFF by the connection.
+
+SET GLOBAL DEBUG_DBUG="";
+SET SQL_LOG_BIN=0;
+--error 0
+XA COMMIT 'xa2';
+SET SQL_LOG_BIN=1;
+
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--source include/wait_until_connected_again.inc
+
+--connection slave
+--source include/start_slave.inc
+--sync_with_master
+
+--connection master
+SELECT * FROM t;
+
+--sync_slave_with_master
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.opt b/mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.test b/mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.test
new file mode 100644
index 00000000000..7b987c7f29b
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_prepare_commit_prepare_sync.test
@@ -0,0 +1,95 @@
+# ==== Purpose ====
+#
+# Test verifies that XA PREPARE transactions are crash safe.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Generate 2 explicit XA transactions. 'xa1' and 'xa2'.
+# 'xa1' will be prepared and committed.
+# 1 - For 'xa2' let the XA PREPARE be done in binary log and crash the
+# server so that it is not prepared in engine.
+# 2 - Restart the server. The recovery code should successfully recover
+# 'xa2'.
+# 3 - When server is up, execute XA RECOVER and verify that 'xa2' is
+# present.
+# 4 - Commit the XA transaction and verify its correctness.
+#
+# ==== References ====
+#
+# MDEV-21469: Implement crash-safe logging of the user XA
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/have_debug.inc
+
+connect (master2,localhost,root,,);
+--connection master
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+--sync_slave_with_master
+--source include/stop_slave.inc
+
+--connection master1
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_prepare";
+--error 2013 # CR_SERVER_LOST
+XA PREPARE 'xa2';
+--source include/wait_until_disconnected.inc
+
+--connection master1
+--source include/wait_until_disconnected.inc
+
+--connection master
+--source include/wait_until_disconnected.inc
+
+#
+# Server restart
+#
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection slave
+--source include/start_slave.inc
+--sync_with_master
+
+--connection master
+SELECT * FROM t;
+XA RECOVER;
+XA COMMIT 'xa2';
+SELECT * FROM t;
+--sync_slave_with_master
+
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.opt b/mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.test b/mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.test
new file mode 100644
index 00000000000..9d2c5cce528
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_prepare_crash_safe_sync.test
@@ -0,0 +1,117 @@
+# ==== Purpose ====
+#
+# Test verifies that XA PREPARE transactions are crash safe.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Generate 3 explicit XA transactions. 'xa1', 'xa2' and 'xa3'.
+# Using debug simulation hold the execution of second XA PREPARE
+# statement after the XA PREPARE is written to the binary log.
+# With this the prepare will not be done in engine.
+# 1 - For 'xa3' allow the PREPARE statement to be written to binary log and
+# simulate server crash.
+# 2 - Restart the server. The recovery code should successfully recover
+# 'xa2' and 'xa3'.
+# 3 - When server is up, execute XA RECOVER and verify that 'xa2' and 'xa3'
+# are present along with 'xa1'.
+# 4 - Commit all the XA transactions and verify their correctness.
+#
+# ==== References ====
+#
+# MDEV-21469: Implement crash-safe logging of the user XA
+
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/have_debug.inc
+
+connect (master2,localhost,root,,);
+--connection master
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+CALL mtr.add_suppression("Found 2 prepared XA transactions");
+CALL mtr.add_suppression("Found 3 prepared XA transactions");
+
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+--sync_slave_with_master
+--source include/stop_slave.inc
+
+--connection master1
+use test;
+xa start 'xa2';
+insert into t values (30);
+xa end 'xa2';
+SET DEBUG_SYNC="simulate_hang_after_binlog_prepare SIGNAL reached WAIT_FOR go";
+send xa prepare 'xa2';
+
+--connection master2
+let $wait_condition=
+ SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
+ WHERE STATE like "debug sync point: simulate_hang_after_binlog_prepare%";
+--source include/wait_condition.inc
+
+XA START 'xa3';
+INSERT INTO t VALUES (40);
+XA END 'xa3';
+
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_prepare";
+--error 2013 # CR_SERVER_LOST
+XA PREPARE 'xa3';
+--source include/wait_until_disconnected.inc
+
+--connection master1
+--error 2013
+--reap
+--source include/wait_until_disconnected.inc
+
+--connection master
+--source include/wait_until_disconnected.inc
+
+#
+# Server restart
+#
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+
+--connection slave
+--source include/start_slave.inc
+--sync_with_master
+
+--connection master
+SELECT * FROM t;
+XA RECOVER;
+XA COMMIT 'xa1';
+XA COMMIT 'xa2';
+XA COMMIT 'xa3';
+SELECT * FROM t;
+--sync_slave_with_master
+
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.opt b/mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.test b/mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.test
new file mode 100644
index 00000000000..1d19f96116e
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_xa_rollback_commit_crash_safe_sync.test
@@ -0,0 +1,97 @@
+# ==== Purpose ====
+#
+# Test verifies that XA COMMIT statements are crash safe.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Generate 2 explicit XA transactions. 'xa1' and 'xa2'.
+# 'xa1' will be prepared and committed.
+# 1 - For 'xa2' let the XA ROLLBACK be done in binary log and crash the
+# server so that it is not committed in engine.
+# 2 - Restart the server. The recovery code should successfully recover
+# 'xa2'. The ROLLBACK should be executed during recovery.
+# 3 - Check the data in table. Only one row should be present in table.
+# 4 - Trying to rollback 'xa2' should report unknown 'XA' error as rollback
+# is already complete during recovery.
+#
+# ==== References ====
+#
+# MDEV-21469: Implement crash-safe logging of the user XA
+
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/have_debug.inc
+
+connect (master2,localhost,root,,);
+--connection master
+CALL mtr.add_suppression("Found 1 prepared XA transactions");
+
+CREATE TABLE t ( f INT ) ENGINE=INNODB;
+XA START 'xa1';
+INSERT INTO t VALUES (20);
+XA END 'xa1';
+XA PREPARE 'xa1';
+XA COMMIT 'xa1';
+--sync_slave_with_master
+--source include/stop_slave.inc
+
+--connection master1
+XA START 'xa2';
+INSERT INTO t VALUES (40);
+XA END 'xa2';
+XA PREPARE 'xa2';
+
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+--error 2013 # CR_SERVER_LOST
+XA ROLLBACK 'xa2';
+--source include/wait_until_disconnected.inc
+
+--connection master1
+--source include/wait_until_disconnected.inc
+
+--connection master
+--source include/wait_until_disconnected.inc
+
+#
+# Server restart
+#
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection slave
+--source include/start_slave.inc
+--sync_with_master
+
+--connection master
+SELECT * FROM t;
+XA RECOVER;
+--error 1397 # ER_XAER_NOTA
+XA ROLLBACK 'xa2';
+SELECT * FROM t;
+--sync_slave_with_master
+
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
diff --git a/sql/log.cc b/sql/log.cc
index ec038e42586..fc025b43fa6 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2203,6 +2203,9 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
*/
cache_mngr->reset(false, true);
THD_STAGE_INFO(thd, org_stage);
+ //todo
+ DBUG_EXECUTE_IF("simulate_crash_after_binlog_commit_or_rollback",
+ DBUG_SUICIDE(););
DBUG_RETURN(error);
}
diff --git a/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.inc b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.inc
new file mode 100644
index 00000000000..f27f1b64213
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.inc
@@ -0,0 +1,40 @@
+#
+# Execute given queries and crash(and restart) the server after binary log
+# commit
+# @@input $exec_query_1
+# @@input $exec_query_2
+
+--connection master
+set autocommit= 0;
+--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+wait
+EOF
+
+start transaction;
+ --eval $exec_query_1
+ --eval $exec_query_2
+SET GLOBAL DEBUG_DBUG="d,simulate_crash_after_binlog_commit_or_rollback";
+--error 2013 # CR_SERVER_LOST
+commit;
+
+--source include/wait_until_disconnected.inc
+
+# Server restart
+--append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+restart
+EOF
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# rpl_end.inc needs to use the connection server_1
+connection server_1;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--connection master
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+set autocommit= 1;
+SET GLOBAL DEBUG_DBUG="reset";
diff --git a/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.opt b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.opt
new file mode 100644
index 00000000000..8547d377417
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.opt
@@ -0,0 +1 @@
+--sync_binlog=1 --innodb_flush_log_at_trx_commit=1
diff --git a/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.test b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.test
new file mode 100644
index 00000000000..caa3a7ddf90
--- /dev/null
+++ b/storage/rocksdb/mysql-test/rocksdb_rpl/t/rpl_rocksdb_binlog_recover.test
@@ -0,0 +1,49 @@
+# ==== Purpose ====
+#
+# Test verifies that MultiEngine COMMITS statements are crash safe(crash after
+# Binlog sync).
+#
+# ==== Implementation ====
+# Create a innodb and insert/update/delete and crash the server after binlog
+# commit. Roll forward recovery should work.
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+--connection master
+
+CREATE TABLE t1 ( f INT) ENGINE=INNODB;
+CREATE TABLE t2 ( f INT) ENGINE=INNODB;
+INSERT INTO t1 values(1);
+INSERT INTO t2 values(1);
+--sync_slave_with_master
+
+
+##Insert Block
+--let $exec_query_1= INSERT INTO t1 values(10)
+--let $exec_query_2= INSERT INTO t2 values(10)
+--source rpl_rocksdb_binlog_recover.inc
+
+
+##Update Block
+--let $exec_query_1= update t1 set f= 2 where f= 1
+--let $exec_query_2= update t2 set f= 2 where f= 1
+--source rpl_rocksdb_binlog_recover.inc
+
+
+##Delete Block
+--let $exec_query_1= delete from t1 where f= 2
+--let $exec_query_2= delete from t2 where f= 2
+--source rpl_rocksdb_binlog_recover.inc
+
+--connection master
+SELECT * FROM t;
+--sync_slave_with_master
+SELECT * FROM t;
+
+--connection master
+DROP TABLE t;
+--sync_slave_with_master
+--source include/rpl_end.inc
+