mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
BUG#46129 Failing mixed stm (with trans and non-trans tables) causes wrong seq in
binlog The fix for BUG 43929 introduced a regression issue. In a nutshell, when a statement that changes a non-transactional table fails, it is written to the binary log with the error code appended. Unfortunately, after BUG 43929, this failure was flushing the transactional chace causing mismatch between execution and logging histories. To fix this issue, we avoid flushing the transactional cache when a commit or rollback is not issued.
This commit is contained in:
@ -33,12 +33,10 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
|
||||
show binlog events from <binlog_start>;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'magenta 2' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # ROLLBACK
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'yellow 2' WHERE i = 3
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'magenta 2' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (5 + (2 * 10),"brown")
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
|
||||
master-bin.000001 # Query # # ROLLBACK
|
||||
@ -56,12 +54,10 @@ COMMIT;
|
||||
show binlog events from <binlog_start>;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 2' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # ROLLBACK
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'gray 2' WHERE i = 3
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 2' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (6 + (2 * 10),"brown")
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
@ -79,12 +75,10 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
|
||||
show binlog events from <binlog_start>;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'magenta 1' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # ROLLBACK
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'yellow 1' WHERE i = 3
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'magenta 1' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (5 + (1 * 10),"brown")
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
|
||||
master-bin.000001 # Query # # ROLLBACK
|
||||
@ -100,17 +94,13 @@ COMMIT;
|
||||
show binlog events from <binlog_start>;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 1' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # ROLLBACK
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'gray 1' WHERE i = 3
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
master-bin.000001 # Query # # BEGIN
|
||||
master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 1' WHERE f = 'red'
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (6 + (1 * 10),"brown")
|
||||
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
|
||||
master-bin.000001 # Xid # # COMMIT /* XID */
|
||||
source include/diff_master_slave.inc;
|
||||
source include/diff_master_slave.inc;
|
||||
########################################################################
|
||||
# Cleanup
|
||||
########################################################################
|
||||
|
@ -125,13 +125,14 @@ while ($type)
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
|
||||
connection master;
|
||||
let $diff_statement= SELECT * FROM t order by i;
|
||||
source include/diff_master_slave.inc;
|
||||
# Re-enable this after fixing BUG#46130
|
||||
#connection master;
|
||||
#let $diff_statement= SELECT * FROM t order by i;
|
||||
#source include/diff_master_slave.inc;
|
||||
|
||||
connection master;
|
||||
let $diff_statement= SELECT * FROM n order by d, f;
|
||||
source include/diff_master_slave.inc;
|
||||
#connection master;
|
||||
#let $diff_statement= SELECT * FROM n order by d, f;
|
||||
#source include/diff_master_slave.inc;
|
||||
|
||||
--echo ########################################################################
|
||||
--echo # Cleanup
|
||||
|
50
sql/log.cc
50
sql/log.cc
@ -1564,25 +1564,15 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
|
||||
YESNO(all),
|
||||
YESNO(thd->transaction.all.modified_non_trans_table),
|
||||
YESNO(thd->transaction.stmt.modified_non_trans_table)));
|
||||
if ((all && thd->transaction.all.modified_non_trans_table) ||
|
||||
(!all && thd->transaction.stmt.modified_non_trans_table &&
|
||||
!mysql_bin_log.check_write_error(thd)) ||
|
||||
((thd->options & OPTION_KEEP_LOG) &&
|
||||
!mysql_bin_log.check_write_error(thd)))
|
||||
if (mysql_bin_log.check_write_error(thd))
|
||||
{
|
||||
/*
|
||||
We write the transaction cache with a rollback last if we have
|
||||
modified any non-transactional table. We do this even if we are
|
||||
committing a single statement that has modified a
|
||||
non-transactional table since it can have modified a
|
||||
transactional table in that statement as well, which needs to be
|
||||
rolled back on the slave.
|
||||
"all == true" means that a "rollback statement" triggered the error and
|
||||
this function was called. However, this must not happen as a rollback
|
||||
is written directly to the binary log. And in auto-commit mode, a single
|
||||
statement that is rolled back has the flag all == false.
|
||||
*/
|
||||
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0);
|
||||
error= binlog_end_trans(thd, trx_data, &qev, all);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(!all);
|
||||
/*
|
||||
We reach this point if either only transactional tables were modified or
|
||||
the effect of a statement that did not get into the binlog needs to be
|
||||
@ -1592,13 +1582,39 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
|
||||
on the master did not get into the binlog and slaves will be inconsistent.
|
||||
On the other hand, if a statement is transactional, we just safely roll it
|
||||
back.
|
||||
*/
|
||||
*/
|
||||
if ((thd->transaction.stmt.modified_non_trans_table ||
|
||||
(thd->options & OPTION_KEEP_LOG)) &&
|
||||
mysql_bin_log.check_write_error(thd))
|
||||
trx_data->set_incident();
|
||||
error= binlog_end_trans(thd, trx_data, 0, all);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
We flush the cache with a rollback, wrapped in a beging/rollback if:
|
||||
. aborting a transcation that modified a non-transactional table or;
|
||||
. aborting a statement that modified both transactional and
|
||||
non-transctional tables but which is not in the boundaries of any
|
||||
transaction;
|
||||
. the OPTION_KEEP_LOG is activate.
|
||||
*/
|
||||
if ((all && thd->transaction.all.modified_non_trans_table) ||
|
||||
(!all && thd->transaction.stmt.modified_non_trans_table &&
|
||||
!(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) ||
|
||||
((thd->options & OPTION_KEEP_LOG)))
|
||||
{
|
||||
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0);
|
||||
error= binlog_end_trans(thd, trx_data, &qev, all);
|
||||
}
|
||||
/*
|
||||
Otherwise, we simply truncate the cache as there is no change on
|
||||
non-transactional tables as follows.
|
||||
*/
|
||||
else if ((all && !thd->transaction.all.modified_non_trans_table) ||
|
||||
(!all && !thd->transaction.stmt.modified_non_trans_table))
|
||||
error= binlog_end_trans(thd, trx_data, 0, all);
|
||||
}
|
||||
if (!all)
|
||||
trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt rollback
|
||||
DBUG_RETURN(error);
|
||||
|
Reference in New Issue
Block a user