Skip to content

Commit 1e60fcd

Browse files
committed
Bug#32416819 ASSERTION "UT_LIST_GET_LEN.TRX_SYS->MYSQL_TRX_LIST. ==
0" ON SHUTDOWN Background: ----------- If the pseudo_replica_mode is enabled and an internal binlog command is run, the current thread is treated as an applier thread. If an XA START query is issued at this stage, the applier thread will detach the native transaction thread from all handlertons and store the backup in hton->slot's ha_ptr_backup via rpl_detach_engine_ha_data. The detached transaction is returned back during a commit or rollback via rpl_reattach_engine_ha_data. Issue: ------ If a shutdown is issued in the same session which is marked as an applier, immediately after an XA START, then the call to reattach via rpl_reattach_engine_ha_data is missed. The shutdown is handled in ha_rollback_low. Since no statements were run after the XA START, ha_list is empty, skipping over the checks to reattach the engine data. As the shutdown progresses, innodb asserts that the trx_sys->mysql_trx_list (list of trx_t's created for mysql) is not empty during trx_sys_close(). A similar issue is seen in ha_commit_low. If ha_list is empty, thd->rpl_reattach_engine_ha_data will be skipped. If a new XA START is issued at this stage, then an assert is hit stating that ha_engine_data is already detached Fix: ---- Ensure that the checks to reattach engine ha data happens even if ha_list is empty in both ha_commit_low and ha_rollback_low Change-Id: I13cbd289314437175e5813edc44978f027d97798
1 parent 2990f09 commit 1e60fcd

File tree

4 files changed

+678
-41
lines changed

4 files changed

+678
-41
lines changed

Diff for: mysql-test/include/xa_applier_shutdown.inc

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# This test checks the behavior of applier thread when shutdown is issued at
2+
# various stages of the XA transaction. The session thread is marked as an
3+
# applier thread by setting the pseudo_replica_mode and executing BINLOG''
4+
# query.
5+
#
6+
# References:
7+
# Bug#32416819: ASSERTION "UT_LIST_GET_LEN.TRX_SYS->MYSQL_TRX_LIST. == 0" ON
8+
# SHUTDOWN
9+
#
10+
# The include file lists the scenarios to be checked before running shutdown.
11+
# Enable the following flags to check different scenarios:
12+
# $create_table: Create the table for the test and drop it at the end
13+
# $insert_table: Insert 3 rows into the table containing single int col
14+
# $need_xa_end: Includes the XA END statement
15+
# $need_xa_commit_one: Includes the XA COMMIT..ONE PHASE statement followed by
16+
# the previous set of statements
17+
# $need_xa_prepare: Includes the XA PREPARE statement
18+
# $need_xa_commit: Includes the XA COMMIT statement
19+
# $need_xa_rollback: Includes the XA ROLLBACK statement
20+
# $restart_connection: If set, create new connection and restart the server
21+
# using the new connection
22+
# If unset, restart the server on the connection that
23+
# executes the transaction
24+
#
25+
# Note:
26+
# During shutdown, Innodb closes trx_sys. At this stage, it is expected that all
27+
# the trx_t's created for mysql is freed (mysql_trx_list - list of trx_t created
28+
# for mysql is empty). Whenever a `USE <database>` command is issued, Innodb
29+
# will create a trx_t (associated with the corresponding session THD) and adds
30+
# it to mysql_trx_list
31+
#
32+
# During replication, if the replication applier sees an 'XA START', it will
33+
# call detach_native_trx on all handlertons. In Innodb, this function will store
34+
# a backup of the above trx_t in ha_data, and replace it will nullptr
35+
#
36+
# In an ideal scenario, the applier will be able to finish the XA transaction,
37+
# and during the commit, ha_commit_low will restore the backup from ha_data
38+
# using reattach_native_trx. In case the applier is not able to finish the XA
39+
# transaction, then ha_rollback_low will reattach_native_trx
40+
#
41+
# In the bug scenario, this was happening only when ha_list was non-empty.
42+
# Hence, if shutdown is issued at this point, then the trx_t will never be
43+
# returned from ha_data causing the assertion in Innodb
44+
#
45+
# The current connection can simulate a replication applier by issuing:
46+
# SET @@SESSION.pseudo_replica_mode=1;
47+
# BINLOG '0';
48+
#
49+
# The BINLOG statement will initialize thd->rli_fake, even though the statement
50+
# fails. The thd->rli_fake will simulate the replication applier. '0' is used
51+
# for better readability
52+
53+
if ($create_table) {
54+
CREATE TABLE t1 (c1 INT);
55+
INSERT INTO t1 VALUES (10);
56+
}
57+
58+
SET @@SESSION.pseudo_replica_mode=1;
59+
--error ER_BASE64_DECODE_ERROR
60+
BINLOG '0';
61+
62+
XA START 'test0';
63+
64+
if ($insert_table) {
65+
INSERT INTO t1 VALUES (1);
66+
INSERT INTO t1 VALUES (2);
67+
INSERT INTO t1 VALUES (3);
68+
}
69+
70+
if ($need_xa_end) {
71+
XA END 'test0';
72+
}
73+
74+
if ($need_xa_commit_one) {
75+
XA COMMIT 'test0' ONE PHASE;
76+
77+
XA START 'test0';
78+
if ($insert_table) {
79+
INSERT INTO t1 VALUES (4);
80+
INSERT INTO t1 VALUES (5);
81+
INSERT INTO t1 VALUES (6);
82+
}
83+
84+
if ($need_xa_end) {
85+
XA END 'test0';
86+
}
87+
}
88+
89+
if ($need_xa_prepare) {
90+
XA PREPARE 'test0';
91+
}
92+
93+
XA RECOVER;
94+
95+
if ($restart_connection) {
96+
# When restarting from a different connection, default connection must be
97+
# handled separately. In this case, the default connection simply waits until
98+
# it can reconnect after the server starts.
99+
100+
--connection default
101+
--disable_reconnect
102+
103+
--connect ($restart_connection, localhost, root,,)
104+
--connection $restart_connection
105+
--source include/restart_mysqld.inc
106+
--disconnect $restart_connection
107+
108+
--connection default
109+
--enable_reconnect
110+
--source include/wait_until_connected_again.inc
111+
}
112+
113+
if (!$restart_connection) {
114+
# The `connection default` is used to indicate that restart is issued in the
115+
# current connection
116+
117+
--connection default
118+
--source include/restart_mysqld.inc
119+
--connection default
120+
}
121+
122+
XA RECOVER;
123+
124+
if ($need_xa_rollback) {
125+
XA ROLLBACK 'test0';
126+
}
127+
128+
if ($need_xa_commit) {
129+
XA COMMIT 'test0';
130+
}
131+
132+
if ($create_table) {
133+
SELECT * FROM t1 ORDER BY c1;
134+
DROP TABLE t1;
135+
}

0 commit comments

Comments
 (0)