From 150590a0bce917f7747765e1589fa37efa09fb53 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Dec 2007 16:07:54 +0100 Subject: [PATCH 1/2] BUG#12691 (Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER): Complementary patch since LOAD DATA INFILE was not covered in the previous patch. This patch adds a check so that the slave skip counter is not decreased to zero if seeing a BEGIN_LOAD_QUERY_EVENT, APPEND_BLOCK_EVENT, or CREATE_FILE_EVENT since these cannot end a group. The group is terminated by an EXECUTE_LOAD_QUERY_ EVENT or DELETE_FILE_EVENT. mysql-test/r/rpl_slave_skip.result: Result change. mysql-test/t/rpl_slave_skip.test: Adding tests to test that the first event of a LOAD DATA INFILE can be skipped safely for both transactional and non-transactional tables. Also include a case that will generate a DELETE_FILE event last in the group, and this should be properly skipped as well. sql/slave.cc: Not decrementing slave skip counter to zero when seeing a BEGIN_LOAD_QUERY_EVENT, APPEND_BLOCK_EVENT, or CREATE_FILE_EVENT since these cannot end a group. --- mysql-test/r/rpl_slave_skip.result | 104 +++++++++++++++++- mysql-test/t/rpl_slave_skip.test | 169 ++++++++++++++++++++++++++++- sql/slave.cc | 5 +- 3 files changed, 271 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/rpl_slave_skip.result b/mysql-test/r/rpl_slave_skip.result index a59ac3eb884..0e06e0951b3 100644 --- a/mysql-test/r/rpl_slave_skip.result +++ b/mysql-test/r/rpl_slave_skip.result @@ -5,8 +5,10 @@ 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; +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=InnoDB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MyISAM; +CREATE TABLE t3 (a CHAR(20), b SET('master','slave')) ENGINE=InnoDB; +CREATE TABLE t4 (a CHAR(20), b SET('master','slave')) ENGINE=MyISAM; ==== Skipping normal transactions ==== **** On Slave **** STOP SLAVE; @@ -139,6 +141,102 @@ a b SELECT * FROM t2 ORDER BY a; a b 5 master,slave +==== Skipping first event of a LOAD DATA for a transactional table ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +SET AUTOCOMMIT=1; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t3(a) SET b = 'master'; +INSERT INTO t3 VALUES ('Go Rin No Sho', 'master,slave'); +SELECT COUNT(*) FROM t3; +COUNT(*) +71 +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +-- Should only contain records marked 'master,slave' +SELECT * FROM t3 ORDER BY a; +a b +Go Rin No Sho master,slave +**** On Master **** +DELETE FROM t3; +==== Skipping first event of a LOAD DATA for a non-transactional table ==== +**** On Slave **** +STOP SLAVE; +**** On Master **** +SET AUTOCOMMIT=1; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t4(a) SET b = 'master'; +INSERT INTO t4 VALUES ('Go Rin No Sho', 'master,slave'); +SELECT COUNT(*) FROM t4; +COUNT(*) +71 +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +-- Should only contain records marked 'master,slave' +SELECT * FROM t4 ORDER BY a; +a b +Go Rin No Sho master,slave +**** On Master **** +DELETE FROM t4; +==== Try with a big file so that we get an append_block event as well +**** On Slave **** +STOP SLAVE; +**** On Master **** +SET AUTOCOMMIT=1; +SET SQL_LOG_BIN=0; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t4(a) SET b = 'master'; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +SELECT a FROM t4 INTO OUTFILE 'rpl_slave_skip_words.dat'; +SET SQL_LOG_BIN=1; +LOAD DATA INFILE 'rpl_slave_skip_words.dat' INTO TABLE t4(a) SET b = 'master'; +INSERT INTO t4 VALUES ('Go Rin No Sho', 'master,slave'); +SELECT COUNT(*) FROM t4; +COUNT(*) +286721 +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +-- Should only contain records marked 'master,slave' +SELECT * FROM t4 ORDER BY a; +a b +Go Rin No Sho master,slave +**** On Master **** +DELETE FROM t4; +**** On Master **** +CREATE TABLE t5 (a int, b int, c SET('master','slave'), PRIMARY KEY (a,b)) ENGINE=MyISAM; +LOAD DATA INFILE '../std_data_ln/loaddata5.dat' INTO TABLE t5 FIELDS TERMINATED BY '' ENCLOSED BY '' (a,b) SET c='master,slave'; +**** On Slave **** +STOP SLAVE; +**** On Master **** +LOAD DATA INFILE '../std_data_ln/loaddata5.dat' INTO TABLE t5 FIELDS TERMINATED BY '' ENCLOSED BY '' (a,b) SET c=''; +ERROR 23000: Duplicate entry '1-2' for key 1 +INSERT INTO t5 VALUES (42, 42, 'master,slave'); +SELECT * FROM t5; +a b c +1 2 master,slave +3 4 master,slave +5 6 master,slave +42 42 master,slave +**** On Slave **** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t5; +a b c +1 2 master,slave +3 4 master,slave +5 6 master,slave +42 42 master,slave ==== Cleanup ==== **** On Master **** -DROP TABLE t1, t2; +DROP TABLE t1, t2, t3, t4, t5; diff --git a/mysql-test/t/rpl_slave_skip.test b/mysql-test/t/rpl_slave_skip.test index 04aafc51129..71e951aceea 100644 --- a/mysql-test/t/rpl_slave_skip.test +++ b/mysql-test/t/rpl_slave_skip.test @@ -13,8 +13,10 @@ source include/master-slave.inc; # 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; +CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=InnoDB; +CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MyISAM; +CREATE TABLE t3 (a CHAR(20), b SET('master','slave')) ENGINE=InnoDB; +CREATE TABLE t4 (a CHAR(20), b SET('master','slave')) ENGINE=MyISAM; --echo ==== Skipping normal transactions ==== @@ -195,9 +197,170 @@ sync_with_master; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; +--echo ==== Skipping first event of a LOAD DATA for a transactional table ==== + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +SET AUTOCOMMIT=1; + +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t3(a) SET b = 'master'; +INSERT INTO t3 VALUES ('Go Rin No Sho', 'master,slave'); + +save_master_pos; + +SELECT COUNT(*) FROM t3; + +# 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=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +--echo -- Should only contain records marked 'master,slave' +SELECT * FROM t3 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t3; +sync_slave_with_master; + +--echo ==== Skipping first event of a LOAD DATA for a non-transactional table ==== + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +SET AUTOCOMMIT=1; + +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t4(a) SET b = 'master'; +INSERT INTO t4 VALUES ('Go Rin No Sho', 'master,slave'); + +save_master_pos; + +SELECT COUNT(*) FROM t4; + +# 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=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +--echo -- Should only contain records marked 'master,slave' +SELECT * FROM t4 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t4; +sync_slave_with_master; + +--echo ==== Try with a big file so that we get an append_block event as well + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +SET AUTOCOMMIT=1; + +# This contain about 70 words, so we double it a few times to get more than 128 KiB +SET SQL_LOG_BIN=0; +LOAD DATA INFILE '../std_data_ln/words.dat' INTO TABLE t4(a) SET b = 'master'; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +INSERT INTO t4 SELECT * FROM t4; +SELECT a FROM t4 INTO OUTFILE 'rpl_slave_skip_words.dat'; +SET SQL_LOG_BIN=1; + +# Start the real job +LOAD DATA INFILE 'rpl_slave_skip_words.dat' INTO TABLE t4(a) SET b = 'master'; +INSERT INTO t4 VALUES ('Go Rin No Sho', 'master,slave'); + +#SHOW BINLOG EVENTS; + +save_master_pos; + +SELECT COUNT(*) FROM t4; + +# 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=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; +--echo -- Should only contain records marked 'master,slave' +SELECT * FROM t4 ORDER BY a; + +--echo **** On Master **** +connection master; +DELETE FROM t4; +sync_slave_with_master; + +# Test to generate a Delete_file log event, and see that it works as well. +--echo **** On Master **** +connection master; +CREATE TABLE t5 (a int, b int, c SET('master','slave'), PRIMARY KEY (a,b)) ENGINE=MyISAM; +LOAD DATA INFILE '../std_data_ln/loaddata5.dat' INTO TABLE t5 FIELDS TERMINATED BY '' ENCLOSED BY '' (a,b) SET c='master,slave'; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +error ER_DUP_ENTRY; +LOAD DATA INFILE '../std_data_ln/loaddata5.dat' INTO TABLE t5 FIELDS TERMINATED BY '' ENCLOSED BY '' (a,b) SET c=''; +INSERT INTO t5 VALUES (42, 42, 'master,slave'); +save_master_pos; + +#SHOW BINLOG EVENTS; + +SELECT * FROM t5; + +--echo **** On Slave **** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; + +sync_with_master; +SELECT * FROM t5; + +connection slave; + --echo ==== Cleanup ==== --echo **** On Master **** connection master; -DROP TABLE t1, t2; +DROP TABLE t1, t2, t3, t4, t5; sync_slave_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index 1509916fe91..4a65e9aaa85 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3348,7 +3348,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) if (rli->slave_skip_counter && !((type_code == INTVAR_EVENT || type_code == RAND_EVENT || - type_code == USER_VAR_EVENT) && + type_code == USER_VAR_EVENT || + type_code == BEGIN_LOAD_QUERY_EVENT || + type_code == APPEND_BLOCK_EVENT || + type_code == CREATE_FILE_EVENT) && rli->slave_skip_counter == 1) && #if MYSQL_VERSION_ID < 50100 /* From e2937d7f430414607bbf8a56e5617b26e1fabdb3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Dec 2007 11:02:48 +0800 Subject: [PATCH 2/2] BUG#28908 Replication: set global server_id is not setting the session server_id When set the server-id dynamically, the server_id member of current thread is not updated. Update the server_id member of current thread after updated the global variable value. sql/set_var.cc: Update server_id of current thread mysql-test/r/rpl_server_id.result: Add test for BUG#28908 mysql-test/t/rpl_server_id.test: Add test for BUG#28908 --- mysql-test/r/rpl_server_id.result | 34 +++++++++++++++++++++++++++++++ mysql-test/t/rpl_server_id.test | 29 ++++++++++++++++++++++++++ sql/set_var.cc | 1 + 3 files changed, 64 insertions(+) create mode 100644 mysql-test/r/rpl_server_id.result create mode 100644 mysql-test/t/rpl_server_id.test diff --git a/mysql-test/r/rpl_server_id.result b/mysql-test/r/rpl_server_id.result new file mode 100644 index 00000000000..1e74394c122 --- /dev/null +++ b/mysql-test/r/rpl_server_id.result @@ -0,0 +1,34 @@ +set global server_id=1; +reset master; +drop table if exists t1,t2,t3; +create table t1 (a int); +select @@server_id; +@@server_id +1 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # use `test`; drop table if exists t1,t2,t3 +master-bin.000001 # Query 1 # use `test`; create table t1 (a int) +set global server_id=2; +create table t2 (b int); +select @@server_id; +@@server_id +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # use `test`; drop table if exists t1,t2,t3 +master-bin.000001 # Query 1 # use `test`; create table t1 (a int) +master-bin.000001 # Query 2 # use `test`; create table t2 (b int) +set global server_id=3; +create table t3 (c int); +select @@server_id; +@@server_id +3 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # use `test`; drop table if exists t1,t2,t3 +master-bin.000001 # Query 1 # use `test`; create table t1 (a int) +master-bin.000001 # Query 2 # use `test`; create table t2 (b int) +master-bin.000001 # Query 3 # use `test`; create table t3 (c int) +set global server_id=1; +drop table t1,t2,t3; diff --git a/mysql-test/t/rpl_server_id.test b/mysql-test/t/rpl_server_id.test new file mode 100644 index 00000000000..6e98ec6ee6d --- /dev/null +++ b/mysql-test/t/rpl_server_id.test @@ -0,0 +1,29 @@ +# Test for BUG#28908 Replication: set global server_id is not setting the session server_id + +-- source include/have_log_bin.inc + +let $saved_server_id=`select @@server_id`; +set global server_id=1; +reset master; + +-- disable_warnings +drop table if exists t1,t2,t3; +-- enable_warnings + +create table t1 (a int); +select @@server_id; +source include/show_binlog_events2.inc; + +set global server_id=2; +create table t2 (b int); +select @@server_id; +source include/show_binlog_events2.inc; + +set global server_id=3; +create table t3 (c int); +select @@server_id; +source include/show_binlog_events2.inc; + +# cleanup +eval set global server_id=$saved_server_id; +drop table t1,t2,t3; diff --git a/sql/set_var.cc b/sql/set_var.cc index a128529fcc7..fac5a431176 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1441,6 +1441,7 @@ static void fix_trans_mem_root(THD *thd, enum_var_type type) static void fix_server_id(THD *thd, enum_var_type type) { server_id_supplied = 1; + thd->server_id= server_id; }