mirror of
https://github.com/MariaDB/server.git
synced 2025-01-28 17:54:16 +01:00
BUG#56442: Slave executes delayed statements when STOP SLAVE is issued
Problem: When using the delayed slave feature, and the SQL thread is delaying, and the user issues STOP SLAVE, the event we wait for was executed. It should not be executed. Fix: Check the return value from the delay function, slave.cc:slave_sleep(). If the return value is 1, it means the thread has been stopped, in this case we don't execute the statement. Also, refactored the test case for delayed slave a little: added the test script include/rpl_assert.inc, which asserts that a condition holds and prints a message if not. Made rpl_delayed_slave.test use this. The advantage is that the test file is much easier to read and maintain, because it is clear what is an assertion and what is not, and also the expected result can be found in the test file, you don't have to compare it to the result file. Manually merged into MariaDB from MySQL commit fd2b210383358fe7697f201e19ac9779879ba72a Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
parent
851c401c0d
commit
814880711f
5 changed files with 372 additions and 173 deletions
|
@ -10,21 +10,32 @@
|
|||
# - After one and a half delay, check the status. It should not be
|
||||
# delaying and the query should be executed.
|
||||
#
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# --let $query_number= 4
|
||||
# --source extra/rpl_tests/delayed_slave_wait_on_query.inc
|
||||
#
|
||||
# Parameters:
|
||||
# $query_number
|
||||
# The value of the 'b' column in t1 for the row inserted by the query
|
||||
# we are waiting for.
|
||||
|
||||
connection master;
|
||||
|
||||
--echo [on slave]
|
||||
--let $slave_timeout= $time1
|
||||
|
||||
--source include/sync_slave_io_with_master.inc
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--echo # Expect query not executed and status is 'Waiting until MASTER_DELAY...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= Query $query_number should not be executed
|
||||
--let $assert_cond= MAX(b) < $query_number FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Waiting until MASTER_DELAY...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
@ -32,8 +43,13 @@ SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
|||
--echo # sync with master (with timeout 1*T)
|
||||
--source include/sync_with_master.inc
|
||||
|
||||
--echo # Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= Query $query_number should be executed
|
||||
--let $assert_cond= MAX(b) = $query_number FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Has read all relay log...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
|
||||
--source include/check_slave_is_running.inc
|
||||
|
|
118
mysql-test/include/rpl_assert.inc
Normal file
118
mysql-test/include/rpl_assert.inc
Normal file
|
@ -0,0 +1,118 @@
|
|||
# ==== Purpose ====
|
||||
#
|
||||
# Check if a condition holds, fail with debug info if not.
|
||||
#
|
||||
# The condition is parsed before executed. The following constructs
|
||||
# are supported:
|
||||
#
|
||||
# [SQL STATEMENT, COLUMN, ROW]
|
||||
# The square bracket is replaced by the result from SQL STATEMENT,
|
||||
# in the given COLUMN and ROW.
|
||||
#
|
||||
# <1>
|
||||
# This is a shorthand for the result of the first executed square
|
||||
# bracket. <2> is a shorthand for the second executed square
|
||||
# bracket, and so on.
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# --let $assert_text= Relay_Log_Pos must be smaller than pos.
|
||||
# --let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] >= $min_pos AND <1> <= $max_pos
|
||||
# [--let $assert_quiet= 1]
|
||||
# [--let $rpl_debug= 1]
|
||||
# --source include/rpl_assert.inc
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# $assert_text
|
||||
# Text that describes what is being checked. By default, this text
|
||||
# is written to the query log.
|
||||
#
|
||||
# $assert_cond
|
||||
# Condition to check. See above for details about the format. The
|
||||
# condition will be executed as `SELECT $assert_cond`. Note: this
|
||||
# condition is parsed using SQL statements, quoted inside single
|
||||
# quotes, so it must not contain single quotes itself (use double
|
||||
# quotes for strings).
|
||||
#
|
||||
# $assert_quiet
|
||||
# Do not print $assert_text to the query log.
|
||||
#
|
||||
# $rpl_debug
|
||||
# Print extra debug info.
|
||||
|
||||
|
||||
if ($rpl_debug)
|
||||
{
|
||||
--echo # debug: assert_text='$assert_text' assert_cond='$assert_cond'
|
||||
}
|
||||
|
||||
# Sanity-check input
|
||||
if (`SELECT "$assert_text" = ""`)
|
||||
{
|
||||
--die ERROR IN TEST: the mysqltest variable rpl_test must be set
|
||||
}
|
||||
|
||||
# Evaluate square brackets in cond.
|
||||
--let $_rpl_assert_substmt_number= 1
|
||||
--let $_rpl_interpolated_cond= $assert_cond
|
||||
--let $_rpl_assert_lbracket= `SELECT LOCATE('[', '$_rpl_interpolated_cond')`
|
||||
while ($_rpl_assert_lbracket)
|
||||
{
|
||||
# Get position of right bracket
|
||||
--let $_rpl_assert_rbracket= `SELECT LOCATE(']', '$_rpl_interpolated_cond')`
|
||||
if (!$_rpl_assert_rbracket)
|
||||
{
|
||||
--echo BUG IN TEST: Mismatching square brackets in assert_cond: '$assert_cond'
|
||||
--die BUG IN TEST: Mismatching square brackets in $assert_cond
|
||||
}
|
||||
# Get sub-statement and result of it
|
||||
--let $_rpl_assert_substmt= `SELECT SUBSTRING('$_rpl_interpolated_cond', $_rpl_assert_lbracket + 1, $_rpl_assert_rbracket - $_rpl_assert_lbracket - 1)`
|
||||
--let $_rpl_assert_substmt_result= query_get_value($_rpl_assert_substmt)
|
||||
if ($rpl_debug)
|
||||
{
|
||||
--echo # debug: sub-statement='$_rpl_assert_substmt' result='$rpl_assert_result'
|
||||
}
|
||||
# Replace sub-statement by its result
|
||||
--let $_rpl_interpolated_cond= `SELECT REPLACE('$_rpl_interpolated_cond', '[$_rpl_assert_substmt]', '$_rpl_assert_substmt_result')`
|
||||
# Replace result references by result
|
||||
--let $_rpl_interpolated_cond= `SELECT REPLACE('$_rpl_interpolated_cond', '<$_rpl_assert_substmt_number>', '$_rpl_assert_substmt_result')`
|
||||
|
||||
--let $_rpl_assert_lbracket= `SELECT LOCATE('[', '$_rpl_interpolated_cond')`
|
||||
|
||||
--inc $_rpl_assert_substmt_number
|
||||
}
|
||||
|
||||
if ($rpl_debug)
|
||||
{
|
||||
--echo # debug: interpolated_cond='$_rpl_interpolated_cond'
|
||||
}
|
||||
|
||||
# Execute.
|
||||
--let $_rpl_assert_result= `SELECT $_rpl_interpolated_cond`
|
||||
|
||||
if ($rpl_debug)
|
||||
{
|
||||
--echo # debug: result='$_rpl_assert_result'
|
||||
}
|
||||
|
||||
# Check.
|
||||
if (!$_rpl_assert_result)
|
||||
{
|
||||
--echo ######## Test assertion failed: $assert_text ########
|
||||
--echo Dumping debug info:
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--echo Assertion text: '$assert_text'
|
||||
--echo Assertion condition: '$assert_cond'
|
||||
--echo Assertion condition, interpolated: '$_rpl_interpolated_cond'
|
||||
--echo Assertion result: '$_rpl_assert_result'
|
||||
--die Test assertion failed in rpl_assertion.inc
|
||||
}
|
||||
|
||||
if (!$assert_quiet)
|
||||
{
|
||||
--echo # Asserted this: $assert_text
|
||||
}
|
||||
|
||||
--let $assert_text=
|
||||
--let $assert_cond=
|
|
@ -3,153 +3,146 @@ include/master-slave.inc
|
|||
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||
call mtr.add_suppression("Unsafe statement written to the binary log using statement format");
|
||||
[on master]
|
||||
CREATE TABLE t1 (a VARCHAR(100), b INT AUTO_INCREMENT PRIMARY KEY);
|
||||
CREATE TABLE t1 (a VARCHAR(100), b INT);
|
||||
INSERT INTO t1 VALUES ("zero", 0);
|
||||
==== Normal setup ====
|
||||
[on slave]
|
||||
include/stop_slave.inc
|
||||
# CHANGE MASTER TO MASTER_DELAY = 2*T
|
||||
# Checking that delay is what we set it to
|
||||
# Expect status to be ''
|
||||
SELECT STATE FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY ID DESC LIMIT 1;
|
||||
STATE
|
||||
|
||||
include/start_slave.inc
|
||||
# Asserted this: SHOW SLAVE STATUS should return the same delay that we set with CHANGE MASTER
|
||||
[on master]
|
||||
INSERT INTO t1(a) VALUES ('normal setup');
|
||||
INSERT INTO t1 VALUES ('normal setup', 1);
|
||||
[on slave]
|
||||
include/sync_slave_io_with_master.inc
|
||||
# sleep 1*T
|
||||
# Expect query not executed and status is 'Waiting until MASTER_DELAY...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
Slave_SQL_Running_State='Waiting until MASTER_DELAY seconds after master executed event'; SQL_Remaining_Delay is greater than zero; SQL thread is behind IO thread
|
||||
# Asserted this: Query 1 should not be executed
|
||||
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
|
||||
# sleep 1*T
|
||||
# sync with master (with timeout 1*T)
|
||||
include/wait_for_slave_param.inc [Relay_Master_Log_File]
|
||||
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
|
||||
# Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
normal setup 1
|
||||
Slave_SQL_Running_State='Slave has read all relay log; waiting for the slave I/O thread to update it'; SQL_Remaining_Delay is NULL; SQL thread is in sync with IO thread
|
||||
# Asserted this: Query 1 should be executed
|
||||
# Asserted this: Status should be 'Has read all relay log...'
|
||||
include/check_slave_is_running.inc
|
||||
==== Slave lags "naturally" after master ====
|
||||
[on master]
|
||||
# CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * T); ELSE RETURN 0; END IF; END
|
||||
INSERT INTO t1(a) SELECT delay_on_slave(3);
|
||||
INSERT INTO t1 SELECT delay_on_slave(3), 2;
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave.
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave.
|
||||
INSERT INTO t1(a) VALUES ('slave is already lagging: this statement should execute immediately');
|
||||
INSERT INTO t1(a) SELECT delay_on_slave(2);
|
||||
INSERT INTO t1 VALUES ('slave is already lagging: this statement should execute immediately', 3);
|
||||
INSERT INTO t1 SELECT delay_on_slave(2), 4;
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave.
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave.
|
||||
[on slave]
|
||||
include/sync_slave_io_with_master.inc
|
||||
# sleep 1*T
|
||||
# Expect no query executed and status is 'Waiting until MASTER_DELAY...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
normal setup 1
|
||||
Slave_SQL_Running_State='Waiting until MASTER_DELAY seconds after master executed event'; SQL_Remaining_Delay is greater than zero; SQL thread is behind IO thread
|
||||
# Asserted this: No query executed
|
||||
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
|
||||
# wait for first query to execute
|
||||
# sleep 1*T
|
||||
# Expect second query executed and status is executing third query (i.e., 'User sleep')
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
slave is already lagging: this statement should execute immediately 3
|
||||
Slave_SQL_Running_State='User sleep'; SQL_Remaining_Delay is NULL; SQL thread is behind IO thread
|
||||
# Asserted this: Second query executed
|
||||
# Asserted this: Status should be executing third query (i.e., 'User sleep')
|
||||
# sleep 2*T
|
||||
# Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
0 4
|
||||
Slave_SQL_Running_State='Slave has read all relay log; waiting for the slave I/O thread to update it'; SQL_Remaining_Delay is NULL; SQL thread is in sync with IO thread
|
||||
# Asserted this: Third query executed
|
||||
# Asserted this: Status should be 'Has read all relay log...'
|
||||
==== Seconds_Behind_Master ====
|
||||
# Bring slave to sync.
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO MASTER_DELAY = 0;
|
||||
include/start_slave.inc
|
||||
INSERT INTO t1(a) VALUES ('Syncing slave');
|
||||
INSERT INTO t1 VALUES ('Syncing slave', 5);
|
||||
include/stop_slave.inc
|
||||
# CHANGE MASTER TO MASTER_DELAY = 2*T
|
||||
include/start_slave.inc
|
||||
INSERT INTO t1(a) VALUES (delay_on_slave(1));
|
||||
INSERT INTO t1 VALUES (delay_on_slave(1), 6);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system variable that may have a different value on the slave.
|
||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave.
|
||||
# sleep 1*T
|
||||
# Asserted this: Seconds_Behind_Master should be between 0 and the 2*T
|
||||
# sleep 1*T
|
||||
==== STOP SLAVE and START SLAVE ====
|
||||
# Asserted this: Seconds_Behind_Master should be at least 2*T
|
||||
==== STOP SLAVE / START SLAVE + DML ====
|
||||
include/stop_slave.inc
|
||||
# CHANGE MASTER TO MASTER_DELAY = 3*T
|
||||
include/start_slave.inc
|
||||
# Checking that delay is what we set it to
|
||||
[on master]
|
||||
INSERT INTO t1(a) VALUES ('stop slave and start slave');
|
||||
INSERT INTO t1 VALUES ('stop slave and start slave: DML', 7);
|
||||
[on slave]
|
||||
# sleep 1*T
|
||||
SET @before_stop_slave= UNIX_TIMESTAMP();
|
||||
include/stop_slave.inc
|
||||
# STOP SLAVE finished in time.
|
||||
# Expect query not executed and status is ''
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
0 6
|
||||
Slave_SQL_Running_State=''; SQL_Remaining_Delay is NULL; SQL thread is behind IO thread
|
||||
# Asserted this: STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
|
||||
# Asserted this: SQL thread position should not increase after STOP SLAVE
|
||||
# Asserted this: Query should not be executed after STOP SLAVE
|
||||
# Asserted this: Status should be '' after STOP SLAVE
|
||||
include/start_slave.inc
|
||||
# START SLAVE finished in time.
|
||||
# Asserted this: START SLAVE should finish quickly
|
||||
[on slave]
|
||||
include/sync_slave_io_with_master.inc
|
||||
# sleep 1*T
|
||||
# Expect query not executed and status is 'Waiting until MASTER_DELAY...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
0 6
|
||||
Slave_SQL_Running_State='Waiting until MASTER_DELAY seconds after master executed event'; SQL_Remaining_Delay is greater than zero; SQL thread is behind IO thread
|
||||
# Asserted this: Query 7 should not be executed
|
||||
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
|
||||
# sleep 1*T
|
||||
# sync with master (with timeout 1*T)
|
||||
include/wait_for_slave_param.inc [Relay_Master_Log_File]
|
||||
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
|
||||
# Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
stop slave and start slave 7
|
||||
Slave_SQL_Running_State='Slave has read all relay log; waiting for the slave I/O thread to update it'; SQL_Remaining_Delay is NULL; SQL thread is in sync with IO thread
|
||||
# Asserted this: Query 7 should be executed
|
||||
# Asserted this: Status should be 'Has read all relay log...'
|
||||
include/check_slave_is_running.inc
|
||||
==== STOP SLAVE / START SLAVE + DDL ====
|
||||
This verifies BUG#56442
|
||||
[on master]
|
||||
CREATE TABLE t_check_dml_not_executed_prematurely (a INT);
|
||||
include/save_master_pos.inc
|
||||
[on slave]
|
||||
# sleep 1*T
|
||||
include/stop_slave.inc
|
||||
# Asserted this: STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
|
||||
# Asserted this: SQL thread position should not increase after STOP SLAVE
|
||||
# Asserted this: Query should not be executed after STOP SLAVE
|
||||
# Asserted this: Status should be '' after STOP SLAVE
|
||||
include/start_slave.inc
|
||||
# Asserted this: START SLAVE should finish quickly
|
||||
# sleep 1*T
|
||||
# Asserted this: DDL Query should not be executed after START SLAVE
|
||||
# Asserted this: Status should be 'Waiting until MASTER_DELAY...'
|
||||
# sleep 1*T
|
||||
# sync with master (with timeout 1*T)
|
||||
include/wait_for_slave_param.inc [Relay_Master_Log_File]
|
||||
include/wait_for_slave_param.inc [Exec_Master_Log_Pos]
|
||||
# Asserted this: DDL Query should be executed
|
||||
# Asserted this: Status should be 'Has read all relay log...'
|
||||
include/check_slave_is_running.inc
|
||||
==== Change back to no delay ====
|
||||
[on slave]
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO MASTER_DELAY = 0;
|
||||
# Expect delay is 0.
|
||||
SQL_Delay='0'
|
||||
# Asserted this: Delay should be 0 when we set it to 0
|
||||
include/start_slave.inc
|
||||
[on master]
|
||||
INSERT INTO t1(a) VALUES ('change back to no delay');
|
||||
INSERT INTO t1 VALUES ('change back to no delay', 8);
|
||||
[on slave]
|
||||
include/sync_slave_io_with_master.inc
|
||||
# sleep 1*T
|
||||
# Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
a b
|
||||
change back to no delay 8
|
||||
Slave_SQL_Running_State='Slave has read all relay log; waiting for the slave I/O thread to update it'; SQL_Remaining_Delay is NULL; SQL thread is in sync with IO thread
|
||||
# Asserted this: Query should be executed
|
||||
# Asserted this: Status should be 'Slave has read all relay log...'
|
||||
==== Reset delay with RESET SLAVE ====
|
||||
include/stop_slave.inc
|
||||
CHANGE MASTER TO MASTER_DELAY = 71;
|
||||
include/start_slave.inc
|
||||
# Expect delay is 71
|
||||
SQL_Delay='71'
|
||||
# Asserted this: Delay should be 71 when we set it to 71
|
||||
include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
[on master]
|
||||
RESET MASTER;
|
||||
[on slave]
|
||||
include/start_slave.inc
|
||||
# Expect delay is 0
|
||||
SQL_Delay='0'
|
||||
==== Set a bad value for the delay ====
|
||||
# Asserted this: Delay should be 0 after RESET SLAVE
|
||||
==== Set an invalid value for the delay ====
|
||||
include/stop_slave.inc
|
||||
# Expect error for setting negative delay
|
||||
CHANGE MASTER TO MASTER_DELAY = -1;
|
||||
|
@ -166,7 +159,7 @@ CHANGE MASTER TO MASTER_DELAY = 0;
|
|||
include/start_slave.inc
|
||||
==== Clean up ====
|
||||
[on master]
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t1, t_check_dml_not_executed_prematurely;
|
||||
DROP FUNCTION delay_on_slave;
|
||||
[on slave]
|
||||
include/rpl_end.inc
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# - Verify that slave has executed the events after but not before the
|
||||
# delay timeout.
|
||||
#
|
||||
# - Verify that delay is correct works when slave is already lagging
|
||||
# - Verify that delay is correct when slave is already lagging
|
||||
# due to slow queries.
|
||||
#
|
||||
# - Verify that Seconds_Behind_Master is greater than or equal to the
|
||||
|
@ -44,6 +44,7 @@
|
|||
# BUG#28760: Simulating a replication lag
|
||||
# [duplicate] BUG#22072: configurable delayed replication
|
||||
# [duplicate] BUG#21639: Add Replication Delay parameter
|
||||
# BUG#56442: Slave executes delayed statements when STOP SLAVE is issued
|
||||
#
|
||||
# ==== Issues with this Test Case ====
|
||||
#
|
||||
|
@ -79,7 +80,8 @@ if (`SELECT '$max_query_execution_time' > 0`) {
|
|||
|
||||
|
||||
--echo [on master]
|
||||
CREATE TABLE t1 (a VARCHAR(100), b INT AUTO_INCREMENT PRIMARY KEY);
|
||||
CREATE TABLE t1 (a VARCHAR(100), b INT);
|
||||
INSERT INTO t1 VALUES ("zero", 0);
|
||||
|
||||
|
||||
--echo ==== Normal setup ====
|
||||
|
@ -94,23 +96,17 @@ CREATE TABLE t1 (a VARCHAR(100), b INT AUTO_INCREMENT PRIMARY KEY);
|
|||
eval CHANGE MASTER TO MASTER_DELAY = $time2;
|
||||
--enable_query_log
|
||||
|
||||
--echo # Checking that delay is what we set it to
|
||||
--let $delay= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1)
|
||||
if (`SELECT $delay != $time2`) {
|
||||
--echo Delay is wrong! Expected $time2, got $delay
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--die wrong delay
|
||||
}
|
||||
|
||||
--echo # Expect status to be ''
|
||||
SELECT STATE FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY ID DESC LIMIT 1;
|
||||
|
||||
--source include/start_slave.inc
|
||||
|
||||
--let $assert_text= SHOW SLAVE STATUS should return the same delay that we set with CHANGE MASTER
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = $time2
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
INSERT INTO t1(a) VALUES ('normal setup');
|
||||
INSERT INTO t1 VALUES ('normal setup', 1);
|
||||
|
||||
--let $query_number= 1
|
||||
--source extra/rpl_tests/delayed_slave_wait_on_query.inc
|
||||
|
||||
|
||||
|
@ -124,20 +120,24 @@ INSERT INTO t1(a) VALUES ('normal setup');
|
|||
--eval CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@GLOBAL.server_id = 2 THEN RETURN SLEEP(time_units * $time1); ELSE RETURN 0; END IF; END
|
||||
--enable_query_log
|
||||
|
||||
INSERT INTO t1(a) SELECT delay_on_slave(3);
|
||||
INSERT INTO t1 SELECT delay_on_slave(3), 2;
|
||||
|
||||
--save_master_pos
|
||||
INSERT INTO t1(a) VALUES ('slave is already lagging: this statement should execute immediately');
|
||||
INSERT INTO t1(a) SELECT delay_on_slave(2);
|
||||
INSERT INTO t1 VALUES ('slave is already lagging: this statement should execute immediately', 3);
|
||||
INSERT INTO t1 SELECT delay_on_slave(2), 4;
|
||||
|
||||
--echo [on slave]
|
||||
--source include/sync_slave_io_with_master.inc
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--echo # Expect no query executed and status is 'Waiting until MASTER_DELAY...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= No query executed
|
||||
--let $assert_cond= MAX(b) = 1 FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Waiting until MASTER_DELAY...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo # wait for first query to execute
|
||||
--sync_with_master
|
||||
|
@ -145,27 +145,35 @@ SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
|||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--echo # Expect second query executed and status is executing third query (i.e., 'User sleep')
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= Second query executed
|
||||
--let $assert_cond= MAX(b) = 3 FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be executing third query (i.e., 'User sleep')
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = "User sleep"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo # sleep 2*T
|
||||
--sleep $time2
|
||||
|
||||
--echo # Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= Third query executed
|
||||
--let $assert_cond= MAX(b) = 4 FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Has read all relay log...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
|
||||
--echo ==== Seconds_Behind_Master ====
|
||||
|
||||
--echo # Bring slave to sync.
|
||||
--source include/stop_slave.inc
|
||||
eval CHANGE MASTER TO MASTER_DELAY = 0;
|
||||
CHANGE MASTER TO MASTER_DELAY = 0;
|
||||
--source include/start_slave.inc
|
||||
|
||||
--connection master
|
||||
INSERT INTO t1(a) VALUES ('Syncing slave');
|
||||
INSERT INTO t1 VALUES ('Syncing slave', 5);
|
||||
--sync_slave_with_master
|
||||
|
||||
--source include/stop_slave.inc
|
||||
|
@ -176,38 +184,28 @@ eval CHANGE MASTER TO MASTER_DELAY = $time2;
|
|||
--source include/start_slave.inc
|
||||
|
||||
--connection master
|
||||
INSERT INTO t1(a) VALUES (delay_on_slave(1));
|
||||
INSERT INTO t1 VALUES (delay_on_slave(1), 6);
|
||||
--save_master_pos
|
||||
--connection slave
|
||||
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
if ($bug_53167_is_fixed) {
|
||||
|
||||
--let $seconds_behind_master= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1)
|
||||
if (`SELECT $seconds_behind_master <= 0 OR $seconds_behind_master >= $time2`) {
|
||||
--echo Seconds_Behind_Master was $seconds_behind_master. Expected that 0 < Seconds_Behind_Master < SQL_Delay = $time2
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--die Seconds_Behind_Master was wrong
|
||||
}
|
||||
|
||||
}
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] >= 0 AND <1> < $time2
|
||||
--let $assert_text= Seconds_Behind_Master should be between 0 and the 2*T
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--let $seconds_behind_master= query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1)
|
||||
if (`SELECT $seconds_behind_master < $time2`) {
|
||||
--echo Seconds_Behind_Master was $seconds_behind_master. Expected it to be >= SQL_Delay = $time2
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--die Seconds_Behind_Master was < SQL_Delay
|
||||
}
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, Seconds_Behind_Master, 1] >= $time2
|
||||
--let $assert_text= Seconds_Behind_Master should be at least 2*T
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--sync_with_master
|
||||
|
||||
|
||||
--echo ==== STOP SLAVE and START SLAVE ====
|
||||
--echo ==== STOP SLAVE / START SLAVE + DML ====
|
||||
|
||||
# Set up a longer delay.
|
||||
--source include/stop_slave.inc
|
||||
|
@ -219,71 +217,141 @@ eval CHANGE MASTER TO MASTER_DELAY = $time3;
|
|||
|
||||
--source include/start_slave.inc
|
||||
|
||||
--echo # Checking that delay is what we set it to
|
||||
--let $delay= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1)
|
||||
if (`SELECT $delay != $time3`) {
|
||||
--echo Delay is wrong! Expected $time2, got $delay
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--die wrong delay
|
||||
}
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
INSERT INTO t1(a) VALUES ('stop slave and start slave');
|
||||
INSERT INTO t1 VALUES ('stop slave and start slave: DML', 7);
|
||||
|
||||
--echo [on slave]
|
||||
--connection slave
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
SET @before_stop_slave= UNIX_TIMESTAMP();
|
||||
--let $timestamp_before_stop= `SELECT UNIX_TIMESTAMP()`
|
||||
--let $relay_log_pos_before_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1)
|
||||
--source include/stop_slave.inc
|
||||
if (`SELECT UNIX_TIMESTAMP() - @before_stop_slave >= $time1`)
|
||||
{
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--die STOP SLAVE did not finish in time
|
||||
}
|
||||
--echo # STOP SLAVE finished in time.
|
||||
|
||||
--echo # Expect query not executed and status is ''
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
|
||||
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= SQL thread position should not increase after STOP SLAVE
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = $relay_log_pos_before_stop
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Query should not be executed after STOP SLAVE
|
||||
--let $assert_cond= MAX(b) = 6 FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be '' after STOP SLAVE
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = ""
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--source include/start_slave.inc
|
||||
if (`SELECT UNIX_TIMESTAMP() - @before_stop_slave >= $time1`)
|
||||
{
|
||||
--source include/show_rpl_debug_info.inc
|
||||
--die START SLAVE did not finish in time
|
||||
}
|
||||
--echo # START SLAVE finished in time.
|
||||
|
||||
--let $assert_text= START SLAVE should finish quickly
|
||||
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $query_number= 7
|
||||
--source extra/rpl_tests/delayed_slave_wait_on_query.inc
|
||||
|
||||
|
||||
--echo ==== STOP SLAVE / START SLAVE + DDL ====
|
||||
|
||||
--echo This verifies BUG#56442
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
CREATE TABLE t_check_dml_not_executed_prematurely (a INT);
|
||||
--source include/save_master_pos.inc
|
||||
|
||||
--echo [on slave]
|
||||
--connection slave
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--let $timestamp_before_stop= `SELECT UNIX_TIMESTAMP()`
|
||||
--let $relay_log_pos_before_stop= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1)
|
||||
--source include/stop_slave.inc
|
||||
|
||||
--let $assert_text= STOP SLAVE should finish quickly, not wait for the ongoing sleep to finish
|
||||
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= SQL thread position should not increase after STOP SLAVE
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = $relay_log_pos_before_stop
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Query should not be executed after STOP SLAVE
|
||||
--let $assert_cond= COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be '' after STOP SLAVE
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" = ""
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--source include/start_slave.inc
|
||||
|
||||
--let $assert_text= START SLAVE should finish quickly
|
||||
--let $assert_cond= UNIX_TIMESTAMP() - $timestamp_before_stop < $time1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--let $assert_text= DDL Query should not be executed after START SLAVE
|
||||
--let $assert_cond= COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Waiting until MASTER_DELAY...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Waiting until MASTER_DELAY%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--echo # sync with master (with timeout 1*T)
|
||||
--source include/sync_with_master.inc
|
||||
|
||||
--let $assert_text= DDL Query should be executed
|
||||
--let $assert_cond= COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = "t_check_dml_not_executed_prematurely"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Has read all relay log...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" LIKE "Slave has read all relay log%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--source include/check_slave_is_running.inc
|
||||
|
||||
|
||||
--echo ==== Change back to no delay ====
|
||||
|
||||
--echo [on slave]
|
||||
--connection slave
|
||||
--source include/stop_slave.inc
|
||||
eval CHANGE MASTER TO MASTER_DELAY = 0;
|
||||
CHANGE MASTER TO MASTER_DELAY = 0;
|
||||
|
||||
--echo # Expect delay is 0.
|
||||
--let $delay= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1)
|
||||
--echo SQL_Delay='$delay'
|
||||
--let $assert_text= Delay should be 0 when we set it to 0
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 0
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--source include/start_slave.inc
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
INSERT INTO t1(a) VALUES ('change back to no delay');
|
||||
INSERT INTO t1 VALUES ('change back to no delay', 8);
|
||||
|
||||
--echo [on slave]
|
||||
--source include/sync_slave_io_with_master.inc
|
||||
--echo # sleep 1*T
|
||||
--sleep $time1
|
||||
|
||||
--echo # Expect query executed and status is 'Has read all relay log...'
|
||||
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
||||
--source include/show_delayed_slave_state.inc
|
||||
--let $assert_text= Query should be executed
|
||||
--let $assert_cond= MAX(b) = 8 FROM t1
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--let $assert_text= Status should be 'Slave has read all relay log...'
|
||||
--let $assert_cond= "[SHOW SLAVE STATUS, Slave_SQL_Running_State, 1]" Like "Slave has read all relay log%"
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
|
||||
--echo ==== Reset delay with RESET SLAVE ====
|
||||
|
@ -292,9 +360,9 @@ SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
|
|||
CHANGE MASTER TO MASTER_DELAY = 71;
|
||||
--source include/start_slave.inc
|
||||
|
||||
--echo # Expect delay is 71
|
||||
--let $delay= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1)
|
||||
--echo SQL_Delay='$delay'
|
||||
--let $assert_text= Delay should be 71 when we set it to 71
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 71
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
--source include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
|
@ -305,12 +373,12 @@ RESET MASTER;
|
|||
--connection slave
|
||||
--source include/start_slave.inc
|
||||
|
||||
--echo # Expect delay is 0
|
||||
--let $delay= query_get_value(SHOW SLAVE STATUS, SQL_Delay, 1)
|
||||
--echo SQL_Delay='$delay'
|
||||
--let $assert_text= Delay should be 0 after RESET SLAVE
|
||||
--let $assert_cond= [SHOW SLAVE STATUS, SQL_Delay, 1] = 0
|
||||
--source include/rpl_assert.inc
|
||||
|
||||
|
||||
--echo ==== Set a bad value for the delay ====
|
||||
--echo ==== Set an invalid value for the delay ====
|
||||
|
||||
--source include/stop_slave.inc
|
||||
|
||||
|
@ -339,7 +407,7 @@ CHANGE MASTER TO MASTER_DELAY = 0;
|
|||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t1, t_check_dml_not_executed_prematurely;
|
||||
DROP FUNCTION delay_on_slave;
|
||||
|
||||
--echo [on slave]
|
||||
|
|
20
sql/slave.cc
20
sql/slave.cc
|
@ -3410,17 +3410,21 @@ has_temporary_error(THD *thd)
|
|||
/**
|
||||
If this is a lagging slave (specified with CHANGE MASTER TO MASTER_DELAY = X), delays accordingly. Also unlocks rli->data_lock.
|
||||
|
||||
Design note: this is the place to unlock rli->data_lock here since
|
||||
it should be held when reading delay info from rli, but it should
|
||||
not be held while sleeping.
|
||||
Design note: this is the place to unlock rli->data_lock. The lock
|
||||
must be held when reading delay info from rli, but it should not be
|
||||
held while sleeping.
|
||||
|
||||
@param ev Event that is about to be executed.
|
||||
|
||||
@param thd The sql thread's THD object.
|
||||
|
||||
@param rli The sql thread's Relay_log_info structure.
|
||||
|
||||
@retval 0 If the delay timed out and the event shall be executed.
|
||||
|
||||
@retval nonzero If the delay was interrupted and the event shall be skipped.
|
||||
*/
|
||||
static void sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi)
|
||||
static int sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi)
|
||||
{
|
||||
Relay_log_info* rli= rgi->rli;
|
||||
long sql_delay= rli->get_sql_delay();
|
||||
|
@ -3459,14 +3463,13 @@ static void sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi)
|
|||
nap_time));
|
||||
rli->start_sql_delay(sql_delay_end);
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
slave_sleep(thd, nap_time, sql_slave_killed, rgi);
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(slave_sleep(thd, nap_time, sql_slave_killed, rgi));
|
||||
}
|
||||
}
|
||||
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3696,7 +3699,8 @@ apply_event_and_update_pos(Log_event* ev, THD* thd, rpl_group_info *rgi)
|
|||
if (reason == Log_event::EVENT_SKIP_NOT)
|
||||
{
|
||||
// Sleeps if needed, and unlocks rli->data_lock.
|
||||
sql_delay_event(ev, thd, rgi);
|
||||
if (sql_delay_event(ev, thd, rgi))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
mysql_mutex_unlock(&rli->data_lock);
|
||||
|
|
Loading…
Add table
Reference in a new issue