mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 02:51:44 +01:00
manual merge
This commit is contained in:
parent
01f86563cb
commit
c2b0410ca1
4 changed files with 8 additions and 453 deletions
|
@ -1,144 +0,0 @@
|
|||
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;
|
|
@ -1 +0,0 @@
|
|||
--innodb
|
|
@ -1,203 +0,0 @@
|
|||
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;
|
113
sql/slave.cc
113
sql/slave.cc
|
@ -1804,6 +1804,14 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
|
|||
int const type_code= ev->get_type_code();
|
||||
int exec_res= 0;
|
||||
|
||||
DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)",
|
||||
ev->get_type_str(), type_code, ev->server_id));
|
||||
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
|
||||
FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
|
||||
FLAGSTR(thd->options, OPTION_BEGIN),
|
||||
rli->last_event_start_time));
|
||||
|
||||
|
||||
/*
|
||||
Execute the event to change the database and update the binary
|
||||
log coordinates, but first we set some data that is needed for
|
||||
|
@ -1828,111 +1836,6 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
|
|||
has a Rotate etc).
|
||||
*/
|
||||
|
||||
DBUG_PRINT("info",("type_code: %d; server_id: %d; slave_skip_counter: %d",
|
||||
type_code, ev->server_id, rli->slave_skip_counter));
|
||||
|
||||
DBUG_PRINT("info", ("thd->options: %s%s; rli->last_event_start_time: %lu",
|
||||
FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
|
||||
FLAGSTR(thd->options, OPTION_BEGIN),
|
||||
rli->last_event_start_time));
|
||||
|
||||
/*
|
||||
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 &&
|
||||
type_code != FORMAT_DESCRIPTION_EVENT) ||
|
||||
(rli->slave_skip_counter &&
|
||||
type_code != ROTATE_EVENT && type_code != STOP_EVENT &&
|
||||
type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
|
||||
{
|
||||
DBUG_PRINT("info", ("event skipped"));
|
||||
if (thd->options & OPTION_BEGIN)
|
||||
rli->inc_event_relay_log_pos();
|
||||
else
|
||||
{
|
||||
rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT ||
|
||||
type_code == STOP_EVENT ||
|
||||
type_code == FORMAT_DESCRIPTION_EVENT) ?
|
||||
LL(0) : ev->log_pos,
|
||||
1/* skip lock*/);
|
||||
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,
|
||||
rand or user var.
|
||||
*/
|
||||
if (rli->slave_skip_counter &&
|
||||
!((type_code == INTVAR_EVENT ||
|
||||
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
|
||||
rli->slave_skip_counter, because the user is supposed to not see
|
||||
these events (they are not in the master's binlog) and if we
|
||||
decremented, START SLAVE would for example decrement when it sees
|
||||
the Rotate, so the event which the user probably wanted to skip
|
||||
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)))
|
||||
--rli->slave_skip_counter;
|
||||
pthread_mutex_unlock(&rli->data_lock);
|
||||
delete ev;
|
||||
return 0; // avoid infinite update loops
|
||||
}
|
||||
|
||||
thd->server_id = ev->server_id; // use the original server id for logging
|
||||
thd->set_time(); // time the query
|
||||
thd->lex->current_select= 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue