Skip to content

Commit addca34

Browse files
author
Andrei Elkin
committed
Bug #25755137 MASTER IS GENERATING INCOMPLETE TRX ON BINARY LOG (MISSING COMMIT)
The failure is about missed COMMIT Query-log-event which was caused on the master side by not sufficient cleanup after a failing atomic DDL. Before sensing the error, the DDL has been binlog-cached. Yet at both the following statement and session level rollback ```binlog_trx_cache_data::flags.with_xid``` left unreset though it should have been. More to the session level the flag is effectively made defined on the STATEMENT one by WL9175. It was supposed that its reset is unavoidable when the SESSION scope ends with either rollback or commit. That stays for the commit. For the rollback the binlog caches have a cleanup procedure for statement rollback (restore_prev_position) and a cleanup procedure for transaction rollback (reset), where reset() is only called when the cache is empty. But they cache got emptied from the only statement by the statement level rollback. Therefore, reset() is missed in this case so the flag remains up. Fixed with unflaging ```binlog_trx_cache_data::flags.with_xid``` at the statement rollback in binlog hton in one step with the cache rollback for the statement. If the raised flag survives to the session commit its statement scope value is "upgraded" to the session level to serve its original session level semantics.
1 parent 1de63e1 commit addca34

File tree

4 files changed

+94
-2
lines changed

4 files changed

+94
-2
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE t1 (a int);
2+
CREATE TABLE t2 (a int);
3+
CREATE VIEW v_12 AS SELECT t1.a AS a, t2.a AS b FROM t1,t2;
4+
CREATE TEMPORARY TABLE tmp (a INT) ENGINE=innodb;
5+
ALTER TABLE t2 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
6+
DROP TABLE t1,t2;
7+
SET DEBUG_SYNC= 'now SIGNAL continue';
8+
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
9+
include/save_binlog_position.inc
10+
DELETE FROM tmp;
11+
include/assert_binlog_events.inc
12+
DROP VIEW v_12;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# ==== Purpose ====
2+
#
3+
# Prove a group of events is logged correctly including
4+
# a terminal Query-log-event(COMMIT), despite a failing atomic DDL
5+
# in front of the group generating query.
6+
#
7+
#
8+
# ==== References ====
9+
# BUG25755137 MASTER IS GENERATING INCOMPLETE TRX ON BINARY LOG (MISSING COMMIT)
10+
#
11+
--source include/have_debug_sync.inc
12+
--source include/have_log_bin.inc
13+
--source include/have_binlog_format_statement.inc
14+
15+
# In order to construct the deadlock error two tables and a view
16+
# based on them are required.
17+
CREATE TABLE t1 (a int);
18+
CREATE TABLE t2 (a int);
19+
CREATE VIEW v_12 AS SELECT t1.a AS a, t2.a AS b FROM t1,t2;
20+
21+
# The Commit-free group generator.
22+
CREATE TEMPORARY TABLE tmp (a INT) ENGINE=innodb;
23+
24+
--connection default
25+
--send ALTER TABLE t2 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1
26+
27+
# Deadlock's 2nd participant
28+
--connect (con1, localhost, root,,)
29+
DROP TABLE t1,t2;
30+
SET DEBUG_SYNC= 'now SIGNAL continue';
31+
32+
--connection default
33+
--error ER_LOCK_DEADLOCK
34+
--reap
35+
36+
#
37+
# the group generator
38+
#
39+
--source include/save_binlog_position.inc
40+
DELETE FROM tmp;
41+
42+
#
43+
# Proof:
44+
# the whole group of BEGIN; DELETE...; COMMIT must be present
45+
#
46+
--let $gtid_event= Gtid
47+
--let $gtid_mode_on= `SELECT @@GLOBAL.GTID_MODE = 'ON'`
48+
if (!$gtid_mode_on)
49+
{
50+
--let $gtid_event= Anonymous_Gtid
51+
}
52+
53+
--let $dont_print_pattern= 1
54+
--let $event_sequence= $gtid_event # !Begin # !Q(DELETE.*) # !Commit
55+
--source include/assert_binlog_events.inc
56+
--let $dont_print_pattern= 0
57+
58+
59+
# Cleanup:
60+
61+
DROP VIEW v_12;
62+

sql/binlog.cc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,16 @@ class binlog_cache_data
633633
bool finalized:1;
634634

635635
/*
636-
This indicates that the cache contain an XID event.
637-
*/
636+
This indicates that either the cache contain an XID event, or it's
637+
an atomic DDL Query-log-event. In the latter case the flag is set up
638+
on the statement level, namely when the Query-log-event is cached
639+
at time the DDL transaction is not committing.
640+
The flag therefore gets reset when the cache is cleaned due to
641+
the statement rollback, e.g in case of a DDL post-caching execution
642+
error.
643+
Any statement scope flag among other things must consider its
644+
reset policy when the statement is rolled back.
645+
*/
638646
bool with_xid:1;
639647
} flags;
640648

@@ -779,6 +787,11 @@ class binlog_trx_cache_data : public binlog_cache_data
779787
DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong) before_stmt_pos));
780788
binlog_cache_data::truncate(before_stmt_pos);
781789
before_stmt_pos= MY_OFF_T_UNDEF;
790+
/*
791+
Binlog statement rollback clears with_xid now as the atomic DDL statement
792+
marker which can be set as early as at event creation and caching.
793+
*/
794+
flags.with_xid= false;
782795
DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong) before_stmt_pos));
783796
DBUG_VOID_RETURN;
784797
}
@@ -1707,6 +1720,9 @@ binlog_trx_cache_data::truncate(THD *thd, bool all)
17071720
/*
17081721
If rolling back an entire transaction or a single statement not
17091722
inside a transaction, we reset the transaction cache.
1723+
Even though formally the atomic DDL statement may not end multi-statement
1724+
transaction the cache needs full resetting as there must
1725+
be no other data in it but belonging to the DDL.
17101726
*/
17111727
if (ending_trans(thd, all))
17121728
{

sql/sql_table.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10309,6 +10309,8 @@ static bool mysql_inplace_alter_table(THD *thd,
1030910309
goto cleanup2;
1031010310
}
1031110311

10312+
DEBUG_SYNC(thd, "action_after_write_bin_log");
10313+
1031210314
if (db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)
1031310315
{
1031410316
/*

0 commit comments

Comments
 (0)