diff options
author | unknown <mats@kindahl-laptop.dnsalias.net> | 2007-10-26 19:18:02 +0200 |
---|---|---|
committer | unknown <mats@kindahl-laptop.dnsalias.net> | 2007-10-26 19:18:02 +0200 |
commit | 2d380a832d60670ec687fa33c25befeec13b99e0 (patch) | |
tree | 09bd943ec95b86158ac1396acaaa1e55fb707152 | |
parent | 18436d48d7a1ca263e790adfb59f9cae1ea9535b (diff) | |
parent | f01321fd090b5e22898e571ccae9a2be9574d297 (diff) | |
download | mariadb-git-2d380a832d60670ec687fa33c25befeec13b99e0.tar.gz |
Merge kindahl-laptop.dnsalias.net:/home/bkroot/mysql-5.0-rpl
into kindahl-laptop.dnsalias.net:/home/bk/b12691-mysql-5.0-rpl
sql/slave.cc:
Auto merged
-rw-r--r-- | mysql-test/r/rpl_slave_skip.result | 144 | ||||
-rw-r--r-- | mysql-test/t/rpl_slave_skip-slave.opt | 1 | ||||
-rw-r--r-- | mysql-test/t/rpl_slave_skip.test | 203 | ||||
-rw-r--r-- | sql/slave.cc | 56 |
4 files changed, 401 insertions, 3 deletions
diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result new file mode 100644 index 00000000000..a59ac3eb884 --- /dev/null +++ b/mysql-test/r/rpl_slave_skip.result @@ -0,0 +1,144 @@ +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; +**** On Master **** +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; +==== Skipping normal transactions ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master,slave +5 master,slave +6 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +4 master,slave +5 master,slave +6 master,slave +**** On Master **** +DELETE FROM t1; +==== Skipping two normal transactions ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (4, 'master'); +INSERT INTO t1 VALUES (5, 'master'); +INSERT INTO t1 VALUES (6, 'master'); +COMMIT; +BEGIN; +INSERT INTO t1 VALUES (7, 'master,slave'); +INSERT INTO t1 VALUES (8, 'master,slave'); +INSERT INTO t1 VALUES (9, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master +5 master +6 master +7 master,slave +8 master,slave +9 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +7 master,slave +8 master,slave +9 master,slave +**** On Master **** +DELETE FROM t1; +==== Skipping without autocommit ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +SET AUTOCOMMIT=0; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; +SELECT * FROM t1 ORDER BY a; +a b +1 master +2 master +3 master +4 master,slave +5 master,slave +6 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +4 master,slave +5 master,slave +6 master,slave +==== Rollback of transaction with non-transactional change ==== +**** On Master **** +DELETE FROM t1; +SET AUTOCOMMIT=1; +**** On Slave **** +STOP SLAVE; +**** On Master **** +BEGIN; +INSERT INTO t1 VALUES (1, ''); +INSERT INTO t2 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, ''); +ROLLBACK; +BEGIN; +INSERT INTO t1 VALUES (4, ''); +INSERT INTO t2 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, ''); +ROLLBACK; +SELECT * FROM t1 ORDER BY a; +a b +SELECT * FROM t2 ORDER BY a; +a b +2 master +5 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +SELECT * FROM t2 ORDER BY a; +a b +5 master,slave +==== Cleanup ==== +**** On Master **** +DROP TABLE t1, t2; diff --git a/mysql-test/t/rpl_slave_skip-slave.opt b/mysql-test/t/rpl_slave_skip-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/t/rpl_slave_skip-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test new file mode 100644 index 00000000000..04aafc51129 --- /dev/null +++ b/mysql-test/t/rpl_slave_skip.test @@ -0,0 +1,203 @@ +source include/have_innodb.inc; +source include/master-slave.inc; + +# This test is for checking that the use of SQL_SLAVE_SKIP_COUNTER +# behaves as expected, i.e., that it is guaranteed to skip an entire +# group and not start executing in the middle of a transaction. + +# We are checking the correct behaviour when using both a +# transactional and non-transactional table. The non-transactional +# table comes into play when rolling back a transaction containing a +# write to this table. In that case, the transaction should still be +# written to the binary log, and the slave will apply it and then roll +# it back to get the non-transactional change into the table. + +--echo **** On Master **** +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; + +--echo ==== Skipping normal transactions ==== + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; + +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t1; +sync_slave_with_master; + +--echo ==== Skipping two normal transactions ==== + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; + +BEGIN; +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (4, 'master'); +INSERT INTO t1 VALUES (5, 'master'); +INSERT INTO t1 VALUES (6, 'master'); +COMMIT; + +BEGIN; +INSERT INTO t1 VALUES (7, 'master,slave'); +INSERT INTO t1 VALUES (8, 'master,slave'); +INSERT INTO t1 VALUES (9, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=8; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t1; +sync_slave_with_master; + +--echo ==== Skipping without autocommit ==== + +# Testing without using autocommit instead. It should still write a +# BEGIN event, so the behaviour should be the same + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t1 VALUES (1, 'master'); +INSERT INTO t1 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, 'master'); +COMMIT; + +INSERT INTO t1 VALUES (4, 'master,slave'); +INSERT INTO t1 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, 'master,slave'); +COMMIT; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; + +# This will skip a begin event and the first INSERT of the +# transaction, and it should keep skipping until it has reached the +# transaction terminator. + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +SELECT * FROM t1 ORDER BY a; + +# Testing with a non-transactional table in the transaction. This will +# log a ROLLBACK as a transaction terminator, which is a normal Query +# log event. + +--echo ==== Rollback of transaction with non-transactional change ==== + +--echo **** On Master **** +connection master; +DELETE FROM t1; +SET AUTOCOMMIT=1; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +disable_warnings; +BEGIN; +INSERT INTO t1 VALUES (1, ''); +INSERT INTO t2 VALUES (2, 'master'); +INSERT INTO t1 VALUES (3, ''); +ROLLBACK; + +BEGIN; +INSERT INTO t1 VALUES (4, ''); +INSERT INTO t2 VALUES (5, 'master,slave'); +INSERT INTO t1 VALUES (6, ''); +ROLLBACK; +enable_warnings; + +save_master_pos; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo ==== Cleanup ==== + +--echo **** On Master **** +connection master; +DROP TABLE t1, t2; +sync_slave_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index 0bc4bf7b32f..1509916fe91 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3279,7 +3279,43 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) now the relay log starts with its Format_desc, has a Rotate etc). */ - DBUG_PRINT("info",("type_code=%d, server_id=%d",type_code,ev->server_id)); + DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d", + type_code, ev->server_id, rli->slave_skip_counter)); + + /* + If the slave skip counter is positive, we still need to set the + OPTION_BEGIN flag correctly and not skip the log events that + start or end a transaction. If we do this, the slave will not + notice that it is inside a transaction, and happily start + executing from inside the transaction. + + Note that the code block below is strictly 5.0. + */ +#if MYSQL_VERSION_ID < 50100 + if (unlikely(rli->slave_skip_counter > 0)) + { + switch (type_code) + { + case QUERY_EVENT: + { + Query_log_event* const qev= (Query_log_event*) ev; + DBUG_PRINT("info", ("QUERY_EVENT { query: '%s', q_len: %u }", + qev->query, qev->q_len)); + if (memcmp("BEGIN", qev->query, qev->q_len+1) == 0) + thd->options|= OPTION_BEGIN; + else if (memcmp("COMMIT", qev->query, qev->q_len+1) == 0 || + memcmp("ROLLBACK", qev->query, qev->q_len+1) == 0) + thd->options&= ~OPTION_BEGIN; + } + break; + + case XID_EVENT: + DBUG_PRINT("info", ("XID_EVENT")); + thd->options&= ~OPTION_BEGIN; + break; + } + } +#endif if ((ev->server_id == (uint32) ::server_id && !replicate_same_server_id && @@ -3301,6 +3337,9 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) flush_relay_log_info(rli); } + DBUG_PRINT("info", ("thd->options: %s", + (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")) + /* Protect against common user error of setting the counter to 1 instead of 2 while recovering from an insert which used auto_increment, @@ -3311,6 +3350,15 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) type_code == RAND_EVENT || type_code == USER_VAR_EVENT) && rli->slave_skip_counter == 1) && +#if MYSQL_VERSION_ID < 50100 + /* + Decrease the slave skip counter only if we are not inside + a transaction or the slave skip counter is more than + 1. The slave skip counter will be decreased from 1 to 0 + when reaching the final ROLLBACK, COMMIT, or XID_EVENT. + */ + (!(thd->options & OPTION_BEGIN) || rli->slave_skip_counter > 1) && +#endif /* The events from ourselves which have something to do with the relay log itself must be skipped, true, but they mustn't decrement @@ -3321,8 +3369,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) would not be skipped. */ !(ev->server_id == (uint32) ::server_id && - (type_code == ROTATE_EVENT || type_code == STOP_EVENT || - type_code == START_EVENT_V3 || type_code == FORMAT_DESCRIPTION_EVENT))) + (type_code == ROTATE_EVENT || + type_code == STOP_EVENT || + type_code == START_EVENT_V3 || + type_code == FORMAT_DESCRIPTION_EVENT))) --rli->slave_skip_counter; pthread_mutex_unlock(&rli->data_lock); delete ev; |