#At file:///home/andrei/MySQL/BZR/MERGE/6.0-bt/ based on revid:chad@stripped
3220 Andrei Elkin 2009-04-21 [merge]
merging bug#37313fixes from 5.1-bt to 6.0-bt
added:
mysql-test/suite/bugs/r/rpl_bug38205.result
mysql-test/suite/bugs/t/rpl_bug38205.test
mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt
modified:
mysql-test/suite/rpl/r/rpl_start_stop_slave.result
mysql-test/suite/rpl/t/rpl_start_stop_slave.test
sql/log_event.cc
sql/slave.cc
=== added file 'mysql-test/suite/bugs/r/rpl_bug38205.result'
--- a/mysql-test/suite/bugs/r/rpl_bug38205.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/bugs/r/rpl_bug38205.result 2009-04-09 13:05:41 +0000
@@ -0,0 +1,56 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+create table t1i(n int primary key) engine=innodb;
+create table t2m(n int primary key) engine=myisam;
+begin;
+insert into t1i values (1);
+insert into t1i values (2);
+insert into t1i values (3);
+commit;
+begin;
+insert into t1i values (5);
+begin;
+insert into t1i values (4);
+insert into t2m values (1);
+update t1i set n = 5 where n = 4;
+commit;
+zero
+0
+*** kill sql thread ***
+rollback;
+*** sql thread is *not* running: No ***
+*** the prove: the killed slave has not finished the current transaction ***
+three
+3
+one
+1
+zero
+0
+delete from t2m;
+start slave sql_thread;
+delete from t1i;
+delete from t2m;
+begin;
+insert into t1i values (5);
+begin;
+insert into t1i values (4);
+update t1i set n = 5 where n = 4;
+commit;
+zero
+0
+stop slave sql_thread;
+rollback;
+*** sql thread is *not* running: No ***
+*** the prove: the stopped slave has rolled back the current transaction ***
+zero
+0
+zero
+0
+one
+1
+start slave sql_thread;
+drop table t1i, t2m;
=== added file 'mysql-test/suite/bugs/t/rpl_bug38205.test'
--- a/mysql-test/suite/bugs/t/rpl_bug38205.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/bugs/t/rpl_bug38205.test 2009-04-09 13:05:41 +0000
@@ -0,0 +1,166 @@
+#
+# Bug #38205 Row-based Replication (RBR) causes inconsistencies: HA_ERR_FOUND_DUPP_KEY
+# Bug#319 if while a non-transactional slave is replicating a transaction possible problem
+#
+# Verifying the fact that STOP SLAVE in the middle of a group execution waits
+# for the end of the group before the slave sql thread will stop.
+# The patch refines STOP SLAVE to not interrupt a transaction or other type of
+# the replication events group (the part I).
+# Killing the sql thread continues to provide a "hard" stop (the part II).
+#
+# Non-deterministic tests
+#
+
+source include/master-slave.inc;
+source include/have_innodb.inc;
+
+
+#
+# Part II, killed sql slave leaves instantly
+#
+
+# A. multi-statement transaction as the replication group
+
+connection master;
+
+create table t1i(n int primary key) engine=innodb;
+create table t2m(n int primary key) engine=myisam;
+
+sync_slave_with_master;
+
+connection master;
+
+begin;
+insert into t1i values (1);
+insert into t1i values (2);
+insert into t1i values (3);
+commit;
+
+sync_slave_with_master;
+
+#
+# todo: first challenge is to find out the SQL thread id
+# the following is not fully reliable
+#
+
+let $id=`SELECT id from information_schema.processlist where user like 'system user' and state like '%Has read all relay log%' or user like 'system user' and state like '%Reading event from the relay log%'`;
+connection slave;
+begin;
+insert into t1i values (5);
+
+connection master;
+let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+begin;
+insert into t1i values (4);
+insert into t2m values (1); # non-ta update
+update t1i set n = 5 where n = 4; # to block at. can't be played with killed
+commit;
+let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+connection slave;
+# slave sql thread must be locked out by the conn `slave' explicit lock
+let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+--disable_query_log
+eval select $pos0_master - $pos0_slave as zero;
+--enable_query_log
+
+connection slave1;
+
+let $count= 1;
+let $table= t2m;
+source include/wait_until_rows_count.inc;
+#
+# todo: may fail as said above
+#
+--echo *** kill sql thread ***
+--disable_query_log
+eval kill connection $id;
+--enable_query_log
+
+connection slave;
+rollback; # release the sql thread
+
+connection slave1;
+
+source include/wait_for_slave_sql_to_stop.inc;
+let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
+--echo *** sql thread is *not* running: $sql_status ***
+let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+
+connection slave;
+--echo *** the prove: the killed slave has not finished the current transaction ***
+
+--disable_query_log
+select count(*) as three from t1i;
+eval select $pos1_master > $pos1_slave as one;
+eval select $pos1_slave - $pos0_slave as zero;
+--enable_query_log
+
+delete from t2m; # remove the row to be able to replay
+start slave sql_thread;
+
+#
+# Part I: B The homogenous transaction remains interuptable in between
+#
+
+connection master;
+delete from t1i;
+delete from t2m;
+
+sync_slave_with_master;
+begin;
+insert into t1i values (5);
+
+connection master;
+let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+begin;
+insert into t1i values (4);
+update t1i set n = 5 where n = 4; # to block at. not to be played
+commit;
+let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+
+connection slave1;
+# slave sql can't advance as must be locked by the conn `slave' trans
+let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+--disable_query_log
+eval select $pos0_master - $pos0_slave as zero;
+--enable_query_log
+
+#
+# the replicated trans is blocked by the slave's local.
+# However, it's not easy to catch the exact moment when it happens.
+# The test issues sleep which makes the test either non-deterministic or
+# wasting too much time.
+#
+--sleep 3
+
+send stop slave sql_thread;
+
+connection slave;
+rollback; # release the sql thread
+
+connection slave1;
+reap;
+source include/wait_for_slave_sql_to_stop.inc;
+let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
+--echo *** sql thread is *not* running: $sql_status ***
+
+let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+
+--echo *** the prove: the stopped slave has rolled back the current transaction ***
+
+--disable_query_log
+select count(*) as zero from t1i;
+eval select $pos0_master - $pos0_slave as zero;
+eval select $pos1_master > $pos0_slave as one;
+--enable_query_log
+
+start slave sql_thread;
+
+# clean-up
+
+connection master;
+drop table t1i, t2m;
+
+sync_slave_with_master;
=== modified file 'mysql-test/suite/rpl/r/rpl_start_stop_slave.result'
--- a/mysql-test/suite/rpl/r/rpl_start_stop_slave.result 2007-12-06 15:27:10 +0000
+++ b/mysql-test/suite/rpl/r/rpl_start_stop_slave.result 2009-04-09 13:05:41 +0000
@@ -10,3 +10,31 @@ start slave;
stop slave io_thread;
start slave io_thread;
drop table t1;
+create table t1i(n int primary key) engine=innodb;
+create table t2m(n int primary key) engine=myisam;
+begin;
+insert into t1i values (1);
+insert into t1i values (2);
+insert into t1i values (3);
+commit;
+begin;
+insert into t1i values (5);
+begin;
+insert into t1i values (4);
+insert into t2m values (1);
+insert into t1i values (5);
+commit;
+zero
+0
+stop slave;
+rollback;
+*** sql thread is *not* running: No ***
+*** the prove: the stopped slave has finished the current transaction ***
+five
+5
+zero
+0
+one
+1
+include/start_slave.inc
+drop table t1i, t2m;
=== added file 'mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt 2009-03-26 08:25:06 +0000
@@ -0,0 +1 @@
+--innodb_lock_wait_timeout=60
=== modified file 'mysql-test/suite/rpl/t/rpl_start_stop_slave.test'
--- a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test 2008-12-12 13:06:40 +0000
+++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test 2009-04-21 09:48:03 +0000
@@ -1,4 +1,5 @@
source include/master-slave.inc;
+source include/have_innodb.inc;
#
# Bug#6148 ()
@@ -33,4 +34,88 @@ connection master;
drop table t1;
sync_slave_with_master;
-# End of 4.1 tests
+
+#
+# Bug#38205 Row-based Replication (RBR) causes inconsistencies...
+# Bug#319 if while a non-transactional slave is replicating a transaction...
+#
+# Verifying that STOP SLAVE does not interrupt excution of a group
+# execution of events if the group can not roll back.
+# Killing the sql thread continues to provide a "hard" stop (the
+# part II, moved to the bugs suite as it's hard to make it
+# deterministic with KILL).
+#
+
+#
+# Part I. The being stopped sql thread finishes first the current group of
+# events if the group contains an event on a non-transaction table.
+
+connection master;
+create table t1i(n int primary key) engine=innodb;
+create table t2m(n int primary key) engine=myisam;
+begin;
+insert into t1i values (1);
+insert into t1i values (2);
+insert into t1i values (3);
+commit;
+
+sync_slave_with_master;
+connection slave;
+begin;
+insert into t1i values (5);
+
+connection master;
+let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+begin;
+insert into t1i values (4);
+insert into t2m values (1); # non-ta update to process
+insert into t1i values (5); # to block at. to be played with stopped
+commit;
+
+connection slave;
+# slave sql thread must be locked out by the conn `slave' explicit lock
+let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+--disable_query_log
+eval select $pos0_master - $pos0_slave as zero;
+--enable_query_log
+
+connection slave1;
+let $count= 1;
+let $table= t2m;
+source include/wait_until_rows_count.inc;
+send stop slave;
+
+connection slave;
+rollback; # release the sql thread
+
+connection slave1;
+reap;
+source include/wait_for_slave_to_stop.inc;
+let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
+--echo *** sql thread is *not* running: $sql_status ***
+
+
+connection master;
+let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+connection slave;
+
+let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+
+--echo *** the prove: the stopped slave has finished the current transaction ***
+
+--disable_query_log
+select count(*) as five from t1i;
+eval select $pos1_master - $pos1_slave as zero;
+eval select $pos1_slave > $pos0_slave as one;
+--enable_query_log
+
+source include/start_slave.inc;
+
+# clean-up
+connection master;
+drop table t1i, t2m;
+
+sync_slave_with_master;
+
+# End of tests
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2009-04-13 09:59:22 +0000
+++ b/sql/log_event.cc 2009-04-21 09:48:03 +0000
@@ -7230,7 +7230,12 @@ int Rows_log_event::do_apply_event(Relay
*/
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
-
+ /*
+ The current statement is just about to begin and
+ has not yet modified anything. Note, all.modified is reset
+ by mysql_reset_thd_for_next_command.
+ */
+ thd->transaction.stmt.modified_non_trans_table= FALSE;
/*
Check if the slave is set to use SBR. If so, it should switch
to using RBR until the end of the "statement", i.e., next
@@ -7339,6 +7344,7 @@ int Rows_log_event::do_apply_event(Relay
if (table)
{
+ bool transactional_table= table->file->has_transactions();
/*
table == NULL means that this table should not be replicated
(this was set up by Table_map_log_event::do_apply_event()
@@ -7470,6 +7476,9 @@ int Rows_log_event::do_apply_event(Relay
m_curr_row= m_curr_row_end;
+ if (error == 0 && !transactional_table)
+ thd->transaction.all.modified_non_trans_table=
+ thd->transaction.stmt.modified_non_trans_table= TRUE;
} // row processing loop
DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
=== modified file 'sql/slave.cc'
--- a/sql/slave.cc 2009-04-14 14:23:07 +0000
+++ b/sql/slave.cc 2009-04-21 09:48:03 +0000
@@ -754,6 +754,9 @@ static bool sql_slave_killed(THD* thd, R
DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
if (abort_loop || thd->killed || rli->abort_slave)
{
+ if (rli->abort_slave && rli->is_in_group() &&
+ thd->transaction.all.modified_non_trans_table)
+ DBUG_RETURN(0);
/*
If we are in an unsafe situation (stopping could corrupt replication),
we give one minute to the slave SQL thread of grace before really
Thread |
---|
• bzr commit into mysql-6.0-bugteam branch (aelkin:3220) Bug#37313 | Andrei Elkin | 21 Apr |