Commit f16fe16d authored by Alfranio Correia's avatar Alfranio Correia

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.
parent 760efb51
...@@ -33,12 +33,10 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back ...@@ -33,12 +33,10 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from <binlog_start>; show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN 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 # Query # # use `test`; UPDATE t SET f = 'yellow 2' WHERE i = 3
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN 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 t VALUES (5 + (2 * 10),"brown")
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown") master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
master-bin.000001 # Query # # ROLLBACK master-bin.000001 # Query # # ROLLBACK
...@@ -56,12 +54,10 @@ COMMIT; ...@@ -56,12 +54,10 @@ COMMIT;
show binlog events from <binlog_start>; show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN 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 # Query # # use `test`; UPDATE t SET f = 'gray 2' WHERE i = 3
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN 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 t VALUES (6 + (2 * 10),"brown")
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown") master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
...@@ -79,12 +75,10 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back ...@@ -79,12 +75,10 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from <binlog_start>; show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN 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 # Query # # use `test`; UPDATE t SET f = 'yellow 1' WHERE i = 3
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN 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 t VALUES (5 + (1 * 10),"brown")
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown") master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
master-bin.000001 # Query # # ROLLBACK master-bin.000001 # Query # # ROLLBACK
...@@ -100,17 +94,13 @@ COMMIT; ...@@ -100,17 +94,13 @@ COMMIT;
show binlog events from <binlog_start>; show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN 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 # Query # # use `test`; UPDATE t SET f = 'gray 1' WHERE i = 3
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN 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 t VALUES (6 + (1 * 10),"brown")
master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown") master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
source include/diff_master_slave.inc;
source include/diff_master_slave.inc;
######################################################################## ########################################################################
# Cleanup # Cleanup
######################################################################## ########################################################################
......
...@@ -125,13 +125,14 @@ while ($type) ...@@ -125,13 +125,14 @@ while ($type)
connection master; connection master;
sync_slave_with_master; sync_slave_with_master;
connection master; # Re-enable this after fixing BUG#46130
let $diff_statement= SELECT * FROM t order by i; #connection master;
source include/diff_master_slave.inc; #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; #connection master;
source include/diff_master_slave.inc; #let $diff_statement= SELECT * FROM n order by d, f;
#source include/diff_master_slave.inc;
--echo ######################################################################## --echo ########################################################################
--echo # Cleanup --echo # Cleanup
......
...@@ -1564,25 +1564,15 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) ...@@ -1564,25 +1564,15 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
YESNO(all), YESNO(all),
YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table))); YESNO(thd->transaction.stmt.modified_non_trans_table)));
if ((all && thd->transaction.all.modified_non_trans_table) || if (mysql_bin_log.check_write_error(thd))
(!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)))
{ {
/* /*
We write the transaction cache with a rollback last if we have "all == true" means that a "rollback statement" triggered the error and
modified any non-transactional table. We do this even if we are this function was called. However, this must not happen as a rollback
committing a single statement that has modified a is written directly to the binary log. And in auto-commit mode, a single
non-transactional table since it can have modified a statement that is rolled back has the flag all == false.
transactional table in that statement as well, which needs to be
rolled back on the slave.
*/ */
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0); DBUG_ASSERT(!all);
error= binlog_end_trans(thd, trx_data, &qev, all);
}
else
{
/* /*
We reach this point if either only transactional tables were modified or 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 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) ...@@ -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 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 On the other hand, if a statement is transactional, we just safely roll it
back. back.
*/ */
if ((thd->transaction.stmt.modified_non_trans_table || if ((thd->transaction.stmt.modified_non_trans_table ||
(thd->options & OPTION_KEEP_LOG)) && (thd->options & OPTION_KEEP_LOG)) &&
mysql_bin_log.check_write_error(thd)) mysql_bin_log.check_write_error(thd))
trx_data->set_incident(); trx_data->set_incident();
error= binlog_end_trans(thd, trx_data, 0, all); 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) if (!all)
trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt rollback trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt rollback
DBUG_RETURN(error); DBUG_RETURN(error);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment