Skip to content

Commit 23038ba

Browse files
author
Sven Sandberg
committed
Implemented a new "CHANGE MASTER TO MASTER_DELAY = X" option, which causes
the replication slave to be X seconds behind the master. This entails the following changes: - New syntax: CHANGE MASTER TO MASTER_DELAY = <int> - The SQL thread sleeps as needed. - SHOW SLAVE STATUS has three new fields with information about the delay and the SQL thread status. - When the slave SQL thread is sleeping, SHOW PROCESSLIST indicates this. - RESET SLAVE resets the delay. - The option is saved to the relay_log.info file. - The BINLOG statement no longer accepts event types other than Format_description_log_event or row events. In addition, some small refactorings and bug fixes were needed to make this work. See file-specific commit messages for details.
1 parent c85f476 commit 23038ba

26 files changed

+1259
-147
lines changed

client/mysqltest.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7778,6 +7778,10 @@ int main(int argc, char **argv)
77787778
1024, 0, 0, get_var_key, var_free, MYF(0)))
77797779
die("Variable hash initialization failed");
77807780

7781+
{
7782+
char path_separator[]= { FN_LIBCHAR, 0 };
7783+
var_set_string("SYSTEM_PATH_SEPARATOR", path_separator);
7784+
}
77817785
var_set_string("MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION);
77827786
var_set_string("MYSQL_SYSTEM_TYPE", SYSTEM_TYPE);
77837787
var_set_string("MYSQL_MACHINE_TYPE", MACHINE_TYPE);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# ==== Purpose ====
2+
#
3+
# Auxiliary file used by rpl_delayed_slave.test. This assumes that an
4+
# 'INSERT INTO t1...' query has been executed on the master. It does
5+
# this:
6+
#
7+
# - After half the delay, check the status. It should be delaying and
8+
# the query should not have executed.
9+
#
10+
# - After one and a half delay, check the status. It should not be
11+
# delaying and the query should be executed.
12+
#
13+
# ==== Usage ====
14+
#
15+
# --source extra/rpl_tests/delayed_slave_wait_on_query.inc
16+
17+
connection master;
18+
--echo [on slave]
19+
--let $slave_timeout= $time1
20+
21+
--source include/sync_slave_io_with_master.inc
22+
--echo # sleep 1*T
23+
--sleep $time1
24+
25+
--echo # Expect query not executed and status is 'Waiting until MASTER_DELAY...'
26+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
27+
--source include/show_delayed_slave_state.inc
28+
29+
--echo # sleep 1*T
30+
--sleep $time1
31+
32+
--echo # sync with master (with timeout 1*T)
33+
--source include/sync_with_master.inc
34+
35+
--echo # Expect query executed and status is 'Has read all relay log...'
36+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
37+
--source include/show_delayed_slave_state.inc
38+
39+
--source include/check_slave_is_running.inc
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# ==== Purpose ====
2+
#
3+
# Save the master file and position of the current connection in
4+
# internal variables. This can later be used together with
5+
# sync_with_master.inc
6+
#
7+
# ==== Usage ====
8+
#
9+
# --source include/save_master_pos.inc
10+
#
11+
# This will save the binlog position of the current connection in the
12+
# mysqltest variables $_saved_master_file and $_saved_master_pos.
13+
14+
let $_saved_master_file= query_get_value("SHOW MASTER STATUS", File, 1);
15+
let $_saved_master_pos= query_get_value("SHOW MASTER STATUS", Position, 1);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# ==== Purpose ====
2+
#
3+
# Display the delay state of the SQL thread.
4+
#
5+
# ==== Usage ====
6+
#
7+
# --let $verbose_delayed_slave_state= [0|1]
8+
# --source extra/rpl_tests/show_delayed_slave_state.inc
9+
#
10+
# By default, the output is normalized so that it does not depend on
11+
# exact timing or exact binlog positions. If
12+
# $verbose_delayed_slave_state is set, then it outputs exact times and
13+
# binlog positions. This can be useful for debugging.
14+
15+
--let $_delayed_slave_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running_State, 1)
16+
17+
--let $_delayed_slave_remaining_delay= query_get_value(SHOW SLAVE STATUS, SQL_Remaining_Delay, 1)
18+
--let $_delayed_slave_qualitative_delay= `SELECT CASE WHEN "$_delayed_slave_remaining_delay" = "NULL" THEN "NULL" WHEN "$_delayed_slave_remaining_delay" = "0" THEN "0" ELSE "greater than zero" END`
19+
20+
--let $_delayed_slave_io_pos= query_get_value(SHOW SLAVE STATUS, Read_Master_Log_Pos, 1)
21+
--let $_delayed_slave_sql_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1)
22+
--let $_delayed_slave_qualitative_log_pos= `SELECT IF($_delayed_slave_io_pos > $_delayed_slave_sql_pos, "behind", "in sync with")`
23+
24+
--echo Slave_SQL_Running_State='$_delayed_slave_status'; SQL_Remaining_Delay is $_delayed_slave_qualitative_delay; SQL thread is $_delayed_slave_qualitative_log_pos IO thread
25+
26+
if ($verbose_delayed_slave_state) {
27+
--echo SQL_Remaining_Delay='$_delayed_slave_remaining_delay'; Read_master_log_pos='$_delayed_slave_io_pos'; Exec_Master_Log_Pos='$_delayed_slave_sql_pos'
28+
}

mysql-test/include/sync_slave_io_with_master.inc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,18 @@
1818
# $master_connection. See wait_for_slave_param.inc for
1919
# descriptions.
2020

21-
let $_master_file= query_get_value("SHOW MASTER STATUS", File, 1);
22-
let $_master_pos= query_get_value("SHOW MASTER STATUS", Position, 1);
21+
--source include/save_master_pos.inc
2322

2423
connection slave;
2524

2625
let $slave_error_message= Failed while waiting for slave IO thread to sync;
2726

2827
let $slave_param= Master_Log_File;
29-
let $slave_param_value= $_master_file;
28+
let $slave_param_value= $_saved_master_file;
3029
source include/wait_for_slave_param.inc;
3130

3231
let $slave_param= Read_Master_Log_Pos;
33-
let $slave_param_value= $_master_pos;
32+
let $slave_param_value= $_saved_master_pos;
3433
source include/wait_for_slave_param.inc;
3534

3635
let $slave_error_message= ;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# ==== Purpose ====
2+
#
3+
# This file does the same as the built-in command sync_with_master,
4+
# but can be configured to use a custom timeout. This has the benefit
5+
# that it accepts the same $slave_timeout and $master_connection
6+
# parameters as wait_for_slave_param.inc
7+
#
8+
#
9+
# ==== Usage ====
10+
#
11+
# --connection master
12+
# --source include/save_master_pos.inc
13+
# --connection slave
14+
# --source include/sync_with_master.inc
15+
#
16+
# Parameters to this macro are $slave_timeout and
17+
# $master_connection. See wait_for_slave_param.inc for
18+
# descriptions.
19+
20+
--let $slave_param= Relay_Master_Log_File
21+
--let $slave_param_value= $_saved_master_file
22+
--source include/wait_for_slave_param.inc
23+
24+
--let $slave_param= Exec_Master_Log_Pos
25+
--let $slave_param_value= $_saved_master_pos
26+
--source include/wait_for_slave_param.inc
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.\slave-relay-bin.000001
2+
4
3+
4+
0
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
./slave-relay-bin.000001
2+
4
3+
4+
0
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
stop slave;
2+
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
3+
reset master;
4+
reset slave;
5+
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
6+
start slave;
7+
call mtr.add_suppression("Unsafe statement binlogged in statement format");
8+
call mtr.add_suppression("Unsafe statement binlogged in statement format");
9+
[on master]
10+
CREATE TABLE t1 (a VARCHAR(100), b INT AUTO_INCREMENT PRIMARY KEY);
11+
==== Normal setup ====
12+
[on slave]
13+
include/stop_slave.inc
14+
# CHANGE MASTER TO MASTER_DELAY = 2*T
15+
# Checking that delay is what we set it to
16+
# Expect status to be ''
17+
SELECT STATE FROM INFORMATION_SCHEMA.PROCESSLIST ORDER BY ID DESC LIMIT 1;
18+
STATE
19+
20+
include/start_slave.inc
21+
[on master]
22+
INSERT INTO t1(a) VALUES ('normal setup');
23+
[on slave]
24+
# sleep 1*T
25+
# Expect query not executed and status is 'Waiting until MASTER_DELAY...'
26+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
27+
a b
28+
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
29+
# sleep 1*T
30+
# sync with master (with timeout 1*T)
31+
# Expect query executed and status is 'Has read all relay log...'
32+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
33+
a b
34+
normal setup 1
35+
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
36+
Checking that both slave threads are running.
37+
==== Slave lags "naturally" after master ====
38+
[on master]
39+
# CREATE FUNCTION delay_on_slave(time_units INT) RETURNS INT BEGIN IF @@server_id = 2 THEN RETURN SLEEP(time_units * T); ELSE RETURN 0; END IF; END
40+
INSERT INTO t1(a) SELECT delay_on_slave(3);
41+
Warnings:
42+
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system variable whose value may differ on slave.
43+
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
44+
INSERT INTO t1(a) VALUES ('slave is already lagging: this statement should execute immediately');
45+
INSERT INTO t1(a) SELECT delay_on_slave(2);
46+
Warnings:
47+
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system variable whose value may differ on slave.
48+
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
49+
[on slave]
50+
# sleep 1*T
51+
# Expect no query executed and status is 'Waiting until MASTER_DELAY...'
52+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
53+
a b
54+
normal setup 1
55+
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
56+
# wait for first query to execute
57+
# sleep 1*T
58+
# Expect second query executed and status is executing third query (i.e., 'User sleep')
59+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
60+
a b
61+
slave is already lagging: this statement should execute immediately 3
62+
Slave_SQL_Running_State='User sleep'; SQL_Remaining_Delay is NULL; SQL thread is behind IO thread
63+
# sleep 2*T
64+
# Expect query executed and status is 'Has read all relay log...'
65+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
66+
a b
67+
0 4
68+
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
69+
==== Seconds_Behind_Master ====
70+
# Bring slave to sync.
71+
include/stop_slave.inc
72+
CHANGE MASTER TO MASTER_DELAY = 0;
73+
include/start_slave.inc
74+
INSERT INTO t1(a) VALUES ('Syncing slave');
75+
include/stop_slave.inc
76+
# CHANGE MASTER TO MASTER_DELAY = 2*T
77+
include/start_slave.inc
78+
INSERT INTO t1(a) VALUES (delay_on_slave(1));
79+
Warnings:
80+
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system variable whose value may differ on slave.
81+
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
82+
# sleep 1*T
83+
# sleep 1*T
84+
==== STOP SLAVE and START SLAVE ====
85+
include/stop_slave.inc
86+
# CHANGE MASTER TO MASTER_DELAY = 3*T
87+
include/start_slave.inc
88+
# Checking that delay is what we set it to
89+
[on master]
90+
INSERT INTO t1(a) VALUES ('stop slave and start slave');
91+
[on slave]
92+
# sleep 1*T
93+
SET @before_stop_slave= UNIX_TIMESTAMP();
94+
include/stop_slave.inc
95+
# STOP SLAVE finished in time.
96+
# Expect query not executed and status is ''
97+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
98+
a b
99+
0 6
100+
Slave_SQL_Running_State=''; SQL_Remaining_Delay is NULL; SQL thread is behind IO thread
101+
include/start_slave.inc
102+
# START SLAVE finished in time.
103+
[on slave]
104+
# sleep 1*T
105+
# Expect query not executed and status is 'Waiting until MASTER_DELAY...'
106+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
107+
a b
108+
0 6
109+
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
110+
# sleep 1*T
111+
# sync with master (with timeout 1*T)
112+
# Expect query executed and status is 'Has read all relay log...'
113+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
114+
a b
115+
stop slave and start slave 7
116+
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
117+
Checking that both slave threads are running.
118+
==== Change back to no delay ====
119+
[on slave]
120+
include/stop_slave.inc
121+
CHANGE MASTER TO MASTER_DELAY = 0;
122+
# Expect delay is 0.
123+
SQL_Delay='0'
124+
include/start_slave.inc
125+
[on master]
126+
INSERT INTO t1(a) VALUES ('change back to no delay');
127+
[on slave]
128+
# sleep 1*T
129+
# Expect query executed and status is 'Has read all relay log...'
130+
SELECT * FROM t1 ORDER BY b DESC LIMIT 1;
131+
a b
132+
change back to no delay 8
133+
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
134+
==== Reset delay with RESET SLAVE ====
135+
include/stop_slave.inc
136+
CHANGE MASTER TO MASTER_DELAY = 71;
137+
include/start_slave.inc
138+
# Expect delay is 71
139+
SQL_Delay='71'
140+
include/stop_slave.inc
141+
RESET SLAVE;
142+
[on master]
143+
RESET MASTER;
144+
[on slave]
145+
include/start_slave.inc
146+
# Expect delay is 0
147+
SQL_Delay='0'
148+
==== Set a bad value for the delay ====
149+
include/stop_slave.inc
150+
# Expect error for setting negative delay
151+
CHANGE MASTER TO MASTER_DELAY = -1;
152+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1' at line 1
153+
# Expect that it's ok to set delay of 2^31-1
154+
CHANGE MASTER TO MASTER_DELAY = 2147483647;
155+
# Expect error for setting delay between 2^31 and 2^32-1
156+
CHANGE MASTER TO MASTER_DELAY = 2147483648;
157+
ERROR HY000: The requested value 2147483648 for the master delay exceeds the maximum 2147483647
158+
# Expect error for setting delay to nonsense
159+
CHANGE MASTER TO MASTER_DELAY = blah;
160+
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'blah' at line 1
161+
CHANGE MASTER TO MASTER_DELAY = 0;
162+
include/start_slave.inc
163+
==== Clean up ====
164+
[on master]
165+
DROP TABLE t1;
166+
DROP FUNCTION delay_on_slave;
167+
[on slave]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
stop slave;
2+
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
3+
reset master;
4+
reset slave;
5+
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
6+
start slave;
7+
CREATE TABLE t1 (a INT);
8+
INSERT INTO t1 VALUES (1);
9+
DROP TABLE t1;
10+
==== Check that we still understand the old format of relay-log.info ====
11+
include/stop_slave.inc
12+
RESET SLAVE;
13+
# Read relay-log.info
14+
START SLAVE IO_THREAD;
15+
# Check that relay log coordinates are equal to those we saved in old-format_relay-log.info
16+
= , 0, slave-relay-bin.000001, 4

0 commit comments

Comments
 (0)