Commit 150590a0 authored by unknown's avatar unknown

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.
parent fff22e09
...@@ -5,8 +5,10 @@ reset slave; ...@@ -5,8 +5,10 @@ reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave; start slave;
**** On Master **** **** On Master ****
CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=InnoDB;
CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; 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 ==== ==== Skipping normal transactions ====
**** On Slave **** **** On Slave ****
STOP SLAVE; STOP SLAVE;
...@@ -139,6 +141,102 @@ a b ...@@ -139,6 +141,102 @@ a b
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
a b a b
5 master,slave 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 ==== ==== Cleanup ====
**** On Master **** **** On Master ****
DROP TABLE t1, t2; DROP TABLE t1, t2, t3, t4, t5;
...@@ -13,8 +13,10 @@ source include/master-slave.inc; ...@@ -13,8 +13,10 @@ source include/master-slave.inc;
# it back to get the non-transactional change into the table. # it back to get the non-transactional change into the table.
--echo **** On Master **** --echo **** On Master ****
CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=INNODB; CREATE TABLE t1 (a INT, b SET('master','slave')) ENGINE=InnoDB;
CREATE TABLE t2 (a INT, b SET('master','slave')) ENGINE=MYISAM; 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 ==== --echo ==== Skipping normal transactions ====
...@@ -195,9 +197,170 @@ sync_with_master; ...@@ -195,9 +197,170 @@ sync_with_master;
SELECT * FROM t1 ORDER BY a; SELECT * FROM t1 ORDER BY a;
SELECT * FROM t2 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 ==== Cleanup ====
--echo **** On Master **** --echo **** On Master ****
connection master; connection master;
DROP TABLE t1, t2; DROP TABLE t1, t2, t3, t4, t5;
sync_slave_with_master; sync_slave_with_master;
...@@ -3348,7 +3348,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) ...@@ -3348,7 +3348,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
if (rli->slave_skip_counter && if (rli->slave_skip_counter &&
!((type_code == INTVAR_EVENT || !((type_code == INTVAR_EVENT ||
type_code == RAND_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) && rli->slave_skip_counter == 1) &&
#if MYSQL_VERSION_ID < 50100 #if MYSQL_VERSION_ID < 50100
/* /*
......
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