Skip to content

Commit

Permalink
MDEV-22757 Assertion !binlog || exist_hton_without_prepare' failed in…
Browse files Browse the repository at this point in the history
… MYSQL_BIN_LOG::unlog_xa_prepare

The assert fired falsely having not captured two more not apparent
possiblities in its condition.

They are masked out hton error out of REPLACE execution (so at later xa-prepare
that engine is still present as read-write) and a prepare-capable engine
which also may not be an actual participant in the xa transation. That
engine, such as SEQUENCE, though does create its own event block.
  • Loading branch information
andrelkin committed Apr 19, 2021
1 parent 0620ccf commit 675c22c
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 22 deletions.
79 changes: 79 additions & 0 deletions mysql-test/suite/binlog/r/binlog_empty_xa_prepared.result
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,82 @@ master-bin.000001 # Query # # XA END X'33',X'',1
master-bin.000001 # XA_prepare # # XA PREPARE X'33',X'',1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # XA ROLLBACK X'33',X'',1
RESET MASTER;
CREATE TABLE t1 (a INT) ENGINE=MyISAM;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
INSERT INTO t2 VALUES (1),(2);
XA START '1';
REPLACE INTO t1 SELECT * FROM t1;
REPLACE INTO t2 SELECT * FROM t2;
XA END '1';
XA PREPARE '1';
XA ROLLBACK '1';
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
DROP TABLE t1, t2;
# Proof of correct logging incl empty XA-PREPARE
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) ENGINE=MyISAM
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1),(2)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; INSERT INTO t2 VALUES (1),(2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Annotate_rows # # REPLACE INTO t1 SELECT * FROM t1
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # XA START X'31',X'',1 GTID #-#-#
master-bin.000001 # Query # # XA END X'31',X'',1
master-bin.000001 # XA_prepare # # XA PREPARE X'31',X'',1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # XA ROLLBACK X'31',X'',1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2` /* generated by server */
RESET MASTER;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
CREATE SEQUENCE s ENGINE=InnoDB;
XA START '2';
SELECT NEXT VALUE FOR s;
NEXT VALUE FOR s
1
REPLACE INTO t1 SELECT * FROM t1;
XA END '2';
XA PREPARE '2';
XA ROLLBACK '2';
DROP SEQUENCE s;
DROP TABLE t1;
# Proof of correct logging incl empty XA-PREPARE
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Annotate_rows # # INSERT INTO t1 VALUES (1)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE SEQUENCE s ENGINE=InnoDB
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Annotate_rows # # SELECT NEXT VALUE FOR s
master-bin.000001 # Table_map # # table_id: # (test.s)
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # XA START X'32',X'',1 GTID #-#-#
master-bin.000001 # Query # # XA END X'32',X'',1
master-bin.000001 # XA_prepare # # XA PREPARE X'32',X'',1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # XA ROLLBACK X'32',X'',1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP SEQUENCE `s` /* generated by server */
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
47 changes: 47 additions & 0 deletions mysql-test/suite/binlog/t/binlog_empty_xa_prepared.test
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,50 @@ XA ROLLBACK '3';

--echo # Proof of correct logging incl empty XA-PREPARE
--source include/show_binlog_events.inc

# The test verifies execution and binary logging of user XA that produce empty
# XA-PREPARE group of events.
#
# MDEV-22757 Assertion `!binlog || exist_hton_without_prepare'
# in MYSQL_BIN_LOG::unlog_xa_prepare

RESET MASTER;
CREATE TABLE t1 (a INT) ENGINE=MyISAM;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
INSERT INTO t2 VALUES (1),(2);

XA START '1';
REPLACE INTO t1 SELECT * FROM t1;
REPLACE INTO t2 SELECT * FROM t2;
XA END '1';
XA PREPARE '1';

# Cleanup
XA ROLLBACK '1';
DROP TABLE t1, t2;

--echo # Proof of correct logging incl empty XA-PREPARE
--source include/show_binlog_events.inc


# MDEV-22430 Assertion ... in MYSQL_BIN_LOG::unlog_xa_prepare

RESET MASTER;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1);
CREATE SEQUENCE s ENGINE=InnoDB;

XA START '2';
SELECT NEXT VALUE FOR s;
REPLACE INTO t1 SELECT * FROM t1;
XA END '2';
XA PREPARE '2';

# Cleanup
XA ROLLBACK '2';
DROP SEQUENCE s;
DROP TABLE t1;

--echo # Proof of correct logging incl empty XA-PREPARE
--source include/show_binlog_events.inc
29 changes: 7 additions & 22 deletions sql/log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10218,28 +10218,13 @@ int TC_LOG_BINLOG::unlog_xa_prepare(THD *thd, bool all)
uint rw_count= ha_count_rw_all(thd, &ha_info);
bool rc= false;

#ifndef DBUG_OFF
if (rw_count > 1)
{
/*
There must be no binlog_hton used in a transaction consisting of more
than 1 engine, *when* (at this point) this transaction has not been
binlogged. The one exception is if there is an engine without a
prepare method, as in this case the engine doesn't support XA and
we have to ignore this check.
*/
bool binlog= false, exist_hton_without_prepare= false;
for (ha_info= thd->transaction->all.ha_list; ha_info;
ha_info= ha_info->next())
{
if (ha_info->ht() == binlog_hton)
binlog= true;
if (!ha_info->ht()->prepare)
exist_hton_without_prepare= true;
}
DBUG_ASSERT(!binlog || exist_hton_without_prepare);
}
#endif
/*
This transaction has not been binlogged as indicated by need_unlog.
Such exceptional cases include transactions with no effect to engines,
e.g REPLACE that does not change the dat but still the Engine
transaction branch claims to be rw, and few more.
In all such cases an empty XA-prepare group of events is bin-logged.
*/
if (rw_count > 0)
{
/* an empty XA-prepare event group is logged */
Expand Down

0 comments on commit 675c22c

Please sign in to comment.