diff options
author | Andrei Elkin <aelkin@mysql.com> | 2009-03-26 10:25:06 +0200 |
---|---|---|
committer | Andrei Elkin <aelkin@mysql.com> | 2009-03-26 10:25:06 +0200 |
commit | 21cc7d5a2582f5baa61c936beab72015027cfdc0 (patch) | |
tree | 00d71846a756dc8f5f2eb2fce38b14c532c26894 /mysql-test/suite | |
parent | 583390388916e21b9008fdc3871df9f1304bf8c2 (diff) | |
download | mariadb-git-21cc7d5a2582f5baa61c936beab72015027cfdc0.tar.gz |
Bug#38205 Row-based Replication (RBR) causes inconsistencies: HA_ERR_FOUND_DUP
Bug#319 if while a non-transactional slave is replicating a transaction possible problem
It is impossible to roll back a mixed engines transaction when one of the engine is
non-transaction. In replication that fact is crucial because the slave can not safely
re-apply a transction that was interrupted with STOP SLAVE.
Fixed with making STOP SLAVE not be effective immediately in the case the current
group of replication events has modified a non-transaction table. In order for slave to leave
either the group needs finishing or the user issues KILL QUERY|CONNECTION slave_thread_id.
mysql-test/suite/bugs/r/rpl_bug38205.result:
bug#38205 non-deterministic part of tests results.
mysql-test/suite/bugs/t/rpl_bug38205.test:
bug#38205 non-deterministic part of tests.
mysql-test/suite/rpl/r/rpl_start_stop_slave.result:
bug#38205 deterministic part of tests results.
mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt:
increasing `innodb_lock_wait_timeout' to make the test pass on slow env w/o
timeout expired issue.
mysql-test/suite/rpl/t/rpl_start_stop_slave.test:
bug#38205 deterministic part of tests.
sql/log_event.cc:
Augmenting row-based events applying with the notion of
thd->transaction.{all,stmt}.modified_non_trans_table.
The pair is set and reset according to its specification
for the mixed transaction processing.
Particualry, once `modified_non_trans_table' is set in the row-events
processing loop, it will remain till the commit of the transaction.
sql/slave.cc:
Consulting `thd->transaction.all.modified_non_trans_table' to decide
whether to terminate by the sql thread or to continue even though
the sql thread might have been STOP-ed (rli->abort_slave).
Diffstat (limited to 'mysql-test/suite')
-rw-r--r-- | mysql-test/suite/bugs/r/rpl_bug38205.result | 56 | ||||
-rw-r--r-- | mysql-test/suite/bugs/t/rpl_bug38205.test | 165 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_start_stop_slave.result | 28 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt | 1 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_start_stop_slave.test | 87 |
5 files changed, 336 insertions, 1 deletions
diff --git a/mysql-test/suite/bugs/r/rpl_bug38205.result b/mysql-test/suite/bugs/r/rpl_bug38205.result new file mode 100644 index 00000000000..195c0ca1135 --- /dev/null +++ b/mysql-test/suite/bugs/r/rpl_bug38205.result @@ -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 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; diff --git a/mysql-test/suite/bugs/t/rpl_bug38205.test b/mysql-test/suite/bugs/t/rpl_bug38205.test new file mode 100644 index 00000000000..f754d7481c7 --- /dev/null +++ b/mysql-test/suite/bugs/t/rpl_bug38205.test @@ -0,0 +1,165 @@ +# +# Bug #38205 Row-based Replication (RBR) causes inconsistencies: HA_ERR_FOUND_DUPP_KEY +# +# 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 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; diff --git a/mysql-test/suite/rpl/r/rpl_start_stop_slave.result b/mysql-test/suite/rpl/r/rpl_start_stop_slave.result index 04ece812f35..130b65c704c 100644 --- a/mysql-test/suite/rpl/r/rpl_start_stop_slave.result +++ b/mysql-test/suite/rpl/r/rpl_start_stop_slave.result @@ -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 running: No *** +*** the prove: the stopped slave has finished the current transaction *** +five +5 +zero +0 +one +1 +start slave; +drop table t1i, t2m; diff --git a/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt b/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt new file mode 100644 index 00000000000..00ea161cd6e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave-slave.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=60 diff --git a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test index dbf0775c978..529ed7acb32 100644 --- a/mysql-test/suite/rpl/t/rpl_start_stop_slave.test +++ b/mysql-test/suite/rpl/t/rpl_start_stop_slave.test @@ -1,4 +1,5 @@ source include/master-slave.inc; +source include/have_innodb.inc; # # Bug#6148 () @@ -35,4 +36,88 @@ save_master_pos; connection slave; sync_with_master; -# End of 4.1 tests + +# +# Bug #38205 Row-based Replication (RBR) causes inconsistencies... +# +# 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 running: $sql_status *** + + +connection master; +let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1); + +connection slave; +source include/wait_for_slave_sql_to_stop.inc; + +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 + +start slave; + +# clean-up +connection master; +drop table t1i, t2m; + +sync_slave_with_master; + +# End of tests |