Commit 81488071 authored by Kristian Nielsen's avatar Kristian Nielsen

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: default avatarKristian Nielsen <knielsen@knielsen-hq.org>
parent 851c401c
......@@ -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
# ==== 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=
......@@ -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);
......
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