1 # name : show_slave_status_nolock.patch
6 # Any small change to this file in the main branch
7 # should be done or reviewed by the maintainer!
9 +++ b/patch_info/show_slave_status_nolock.patch
11 +File=show_slave_status_nolock.patch
12 +Name= SHOW SLAVE STATUS NOLOCK
14 +Author=Percona <info@percona.com>
16 +Comment= Implement SHOW SLAVE STATUS without lock (STOP SLAVE lock the same mutex what lock SHOW SLAVE STATUS)
20 { "NONE", SYM(NONE_SYM)},
21 { "NOT", SYM(NOT_SYM)},
22 { "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG)},
23 + { "NOLOCK", SYM(NOLOCK_SYM)},
24 { "NULL", SYM(NULL_SYM)},
25 { "NUMERIC", SYM(NUMERIC_SYM)},
26 { "NVARCHAR", SYM(NVARCHAR_SYM)},
30 {"show_relaylog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_RELAYLOG_EVENTS]), SHOW_LONG_STATUS},
31 {"show_slave_hosts", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_HOSTS]), SHOW_LONG_STATUS},
32 {"show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS},
33 + {"show_slave_status_nolock", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_NOLOCK_STAT]), SHOW_LONG_STATUS},
34 {"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
35 {"show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
36 {"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS},
40 SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
41 SQLCOM_SIGNAL, SQLCOM_RESIGNAL,
42 SQLCOM_SHOW_RELAYLOG_EVENTS,
43 + /* SHOW SLAVE STATUS NOLOCK */
44 + SQLCOM_SHOW_SLAVE_NOLOCK_STAT,
46 When a command is added here, be sure it's also added in mysqld.cc
47 in "struct show_var_st status_vars[]= {" ...
48 --- a/sql/sql_parse.cc
49 +++ b/sql/sql_parse.cc
51 sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND;
52 sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
53 sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
54 + sql_command_flags[SQLCOM_SHOW_SLAVE_NOLOCK_STAT]= CF_STATUS_COMMAND;
55 sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
56 sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
57 sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND;
58 @@ -2393,12 +2394,17 @@
59 mysql_mutex_unlock(&LOCK_active_mi);
62 + case SQLCOM_SHOW_SLAVE_NOLOCK_STAT:
63 case SQLCOM_SHOW_SLAVE_STAT:
65 /* Accept one of two privileges */
66 if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
68 - mysql_mutex_lock(&LOCK_active_mi);
69 + bool do_lock=SQLCOM_SHOW_SLAVE_NOLOCK_STAT != lex->sql_command;
72 + mysql_mutex_lock(&LOCK_active_mi);
74 if (active_mi != NULL)
76 res = show_master_info(thd, active_mi);
77 @@ -2409,7 +2415,19 @@
78 WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO));
81 - mysql_mutex_unlock(&LOCK_active_mi);
84 + mysql_mutex_unlock(&LOCK_active_mi);
86 + DBUG_EXECUTE_IF("after_show_slave_status",
90 + "signal signal.after_show_slave_status";
91 + DBUG_ASSERT(opt_debug_sync_timeout > 0);
92 + DBUG_ASSERT(!debug_sync_set_action(current_thd,
93 + STRING_WITH_LEN(act)));
97 case SQLCOM_SHOW_MASTER_STAT:
100 @@ -1293,6 +1293,7 @@
102 %token START_SYM /* SQL-2003-R */
104 +%token NOLOCK_SYM /* SHOW SLAVE STATUS NOLOCK */
105 %token STDDEV_SAMP_SYM /* SQL-2003-N */
108 @@ -11111,6 +11112,11 @@
110 Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
112 + /* SHOW SLAVE STATUS NOLOCK */
113 + | SLAVE STATUS_SYM NOLOCK_SYM
115 + Lex->sql_command = SQLCOM_SHOW_SLAVE_NOLOCK_STAT; //SQLCOM_SHOW_SLAVE_NOLOCK_STAT;
117 | QUERY_RESPONSE_TIME_SYM wild_and_where
119 #ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
121 +++ b/mysql-test/t/percona_show_slave_status_nolock.test
123 +--source include/master-slave.inc
124 +--source include/have_debug_sync.inc
125 +--source include/have_binlog_format_statement.inc
127 +call mtr.add_suppression("Slave SQL: Request to stop slave SQL Thread received while applying a group that has non-transactional changes");
129 +--let $rpl_connection_name=slave_lock
130 +--let $rpl_server_number=2
131 +--source include/rpl_connect.inc
133 +--let $rpl_connection_name=slave_nolock
134 +--let $rpl_server_number=2
135 +--source include/rpl_connect.inc
137 +--let $show_statement= SHOW PROCESSLIST
143 +DROP TABLE IF EXISTS t;
145 +CREATE TABLE t(id INT);
146 +sync_slave_with_master;
150 +SET DEBUG_SYNC='RESET';
151 +SET GLOBAL DEBUG="+d,after_mysql_insert,after_show_slave_status";
155 +INSERT INTO t VALUES(0);
159 +--let $condition= 'INSERT INTO t VALUES(0)'
160 +--source include/wait_show_condition.inc
162 +--echo check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - both should work fine
163 +--source include/percona_show_slave_status_nolock.inc
167 +INSERT INTO t VALUES(1);
171 +--let $condition= 'INSERT INTO t VALUES(1)'
172 +--source include/wait_show_condition.inc
174 +--let $rpl_connection_name=slave_stop
175 +--let $rpl_server_number=2
176 +--source include/rpl_connect.inc
178 +connection slave_stop;
184 +--let $condition= 'STOP SLAVE'
185 +--source include/wait_show_condition.inc
187 +--echo check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - just NOLOCK version should works fine
188 +--source include/percona_show_slave_status_nolock.inc
191 +connection slave_stop;
194 +--source include/wait_for_slave_to_stop.inc
196 +--source include/wait_for_slave_to_start.inc
200 +SET DEBUG_SYNC='RESET';
204 +SET GLOBAL DEBUG='';
205 +SET DEBUG_SYNC='RESET';
210 +sync_slave_with_master;
212 +--source include/rpl_end.inc
214 +++ b/mysql-test/r/percona_show_slave_status_nolock.result
216 +include/master-slave.inc
218 +call mtr.add_suppression("Slave SQL: Request to stop slave SQL Thread received while applying a group that has non-transactional changes");
219 +include/rpl_connect.inc [creating slave_lock]
220 +include/rpl_connect.inc [creating slave_nolock]
222 +DROP TABLE IF EXISTS t;
223 +CREATE TABLE t(id INT);
225 +SET DEBUG_SYNC='RESET';
226 +SET GLOBAL DEBUG="+d,after_mysql_insert,after_show_slave_status";
228 +INSERT INTO t VALUES(0);
230 +check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - both should work fine
234 +SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
235 +SIGNAL after SHOW SLAVE STATUS is 'signal.after_show_slave_status'
237 +SET DEBUG_SYNC='now SIGNAL signal.empty';
239 +SHOW SLAVE STATUS NOLOCK;
240 +SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
241 +# should be 'signal.after_show_slave_status'
242 +SIGNAL after SHOW SLAVE STATUS NOLOCK is 'signal.after_show_slave_status'
244 +SET DEBUG_SYNC='now SIGNAL signal.continue';
246 +SET DEBUG_SYNC='now SIGNAL signal.empty';
249 +INSERT INTO t VALUES(1);
251 +include/rpl_connect.inc [creating slave_stop]
255 +check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - just NOLOCK version should works fine
259 +SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
260 +SIGNAL after SHOW SLAVE STATUS is 'signal.empty'
262 +SET DEBUG_SYNC='now SIGNAL signal.empty';
264 +SHOW SLAVE STATUS NOLOCK;
265 +SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
266 +# should be 'signal.after_show_slave_status'
267 +SIGNAL after SHOW SLAVE STATUS NOLOCK is 'signal.after_show_slave_status'
269 +SET DEBUG_SYNC='now SIGNAL signal.continue';
271 +SET DEBUG_SYNC='now SIGNAL signal.empty';
274 +include/wait_for_slave_to_stop.inc
276 +include/wait_for_slave_to_start.inc
278 +SET DEBUG_SYNC='RESET';
280 +SET GLOBAL DEBUG='';
281 +SET DEBUG_SYNC='RESET';
286 +++ b/mysql-test/include/percona_show_slave_status_nolock.inc
289 +--disable_result_log
290 +connection slave_lock;
292 +send SHOW SLAVE STATUS;
295 +--let $condition= 'SHOW SLAVE STATUS'
296 +--source include/wait_show_condition.inc
299 +SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
302 +--let current=`SELECT SUBSTR(Variable_value FROM 22) FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name = 'DEBUG_SYNC'`
303 +--echo SIGNAL after SHOW SLAVE STATUS is $current
307 +SET DEBUG_SYNC='now SIGNAL signal.empty';
309 +connection slave_nolock;
310 +--echo [slave_nolock]
311 +send SHOW SLAVE STATUS NOLOCK;
314 +--let $condition= 'SHOW SLAVE STATUS NOLOCK'
315 +--source include/wait_show_condition.inc
318 +SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
321 +--echo # should be 'signal.after_show_slave_status'
322 +--let current=`SELECT SUBSTR(Variable_value FROM 22) FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name = 'DEBUG_SYNC'`
323 +--echo SIGNAL after SHOW SLAVE STATUS NOLOCK is $current
327 +SET DEBUG_SYNC='now SIGNAL signal.continue';
329 +connection slave_lock;
330 +--disable_result_log
334 +connection slave_nolock;
335 +--disable_result_log
341 +SET DEBUG_SYNC='now SIGNAL signal.empty';
346 @@ -1816,6 +1816,7 @@
350 + bool do_lock=SQLCOM_SHOW_SLAVE_NOLOCK_STAT != thd->lex->sql_command;
351 DBUG_PRINT("info",("host is set: '%s'", mi->host));
352 String *packet= &thd->packet;
353 protocol->prepare_for_resend();
354 @@ -1824,9 +1825,15 @@
355 slave_running can be accessed without run_lock but not other
356 non-volotile members like mi->io_thd, which is guarded by the mutex.
358 - mysql_mutex_lock(&mi->run_lock);
361 + mysql_mutex_lock(&mi->run_lock);
363 protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin);
364 - mysql_mutex_unlock(&mi->run_lock);
367 + mysql_mutex_unlock(&mi->run_lock);
370 mysql_mutex_lock(&mi->data_lock);
371 mysql_mutex_lock(&mi->rli.data_lock);