Description:
After executing the statement 'xa parpare', the prepare state may be lost if the database is crashed. The reason for this problem is that the statement xa prepare does not ensure that the innodb log is written to disk。
How to repeat:
I wrote a test case that reproduced the problem with a high probability.
----------- Code adjustments required for test cases.
diff --git a/sql/xa.cc b/sql/xa.cc
index 353640efe26..9874b6a0cbb 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -1135,6 +1135,7 @@ bool Sql_cmd_xa_prepare::trans_xa_prepare(THD *thd) {
}
}
+ DBUG_EXECUTE_IF("simulate_crash_after_xa_prepare", DBUG_SUICIDE(););
return thd->is_error() || !xid_state->has_state(XID_STATE::XA_PREPARED);
}
--------test cases: binlog_gtid.bug_xa_prepare_lost.test
--source include/force_restart.inc
--source include/not_valgrind.inc
--source include/have_binlog_format_row.inc
--source include/have_debug.inc
call mtr.add_suppression("Found 1 prepared XA transactions");
# For reseting mysql.gtid_executed table
RESET MASTER;
--let $master_uuid= `SELECT @@GLOBAL.SERVER_UUID`
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
FLUSH LOGS;
XA START '1';
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
XA END '1';
SET @@GLOBAL.DEBUG= '+d, simulate_crash_after_xa_prepare';
--error 2013
XA PREPARE '1';
--enable_reconnect
--echo # Restart the master server
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--source include/wait_until_connected_again.inc
--disable_reconnect
XA ROLLBACK '1';
DROP TABLE t1;
--------------- Execute the test case
==============================================================================
TEST NAME RESULT TIME (ms) COMMENT
------------------------------------------------------------------------------
[ 33%] binlog_gtid.bug_xa_prepare_lost 'mix' [ skipped ] Doesn't support --binlog-format = 'mixed'
[ 66%] binlog_gtid.bug_xa_prepare_lost 'row' [ fail ]
Test ended at 2020-02-21 15:35:10
CURRENT_TEST: binlog_gtid.bug_xa_prepare_lost
mysqltest: At line 30: Query 'XA ROLLBACK '1'' failed.
ERROR 1397 (XAE04): XAER_NOTA: Unknown XID
The result from queries just before the failure was:
call mtr.add_suppression("Found 1 prepared XA transactions");
RESET MASTER;
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
FLUSH LOGS;
XA START '1';
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
XA END '1';
SET @@GLOBAL.DEBUG= '+d, simulate_crash_after_xa_prepare';
XA PREPARE '1';
ERROR HY000: Lost connection to MySQL server during query
# Restart the master server
safe_process[18390]: Child process: 18391, exit: 1
Suggested fix:
The cause of the problem function Sql_cmd_xa_prepare::trans_xa_prepare does not ensure that the innodb log for xa prepare is written to disk.