#!!! notice !!!
# Any small change to this file in the main branch
# should be done or reviewed by the maintainer!
-diff -ruN /dev/null b/patch_info/show_slave_status_nolock.patch
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ b/patch_info/show_slave_status_nolock.patch 2011-04-10 11:29:06.000000000 +0400
+--- /dev/null
++++ b/patch_info/show_slave_status_nolock.patch
@@ -0,0 +1,6 @@
+File=show_slave_status_nolock.patch
+Name= SHOW SLAVE STATUS NOLOCK
+Author=Percona <info@percona.com>
+License=GPL
+Comment= Implement SHOW SLAVE STATUS without lock (STOP SLAVE lock the same mutex what lock SHOW SLAVE STATUS)
-diff -ruN a/sql/lex.h b/sql/lex.h
---- a/sql/lex.h 2011-04-10 11:29:05.000000000 +0400
-+++ b/sql/lex.h 2011-04-10 11:29:06.000000000 +0400
+--- a/sql/lex.h
++++ b/sql/lex.h
@@ -378,6 +378,7 @@
{ "NONE", SYM(NONE_SYM)},
{ "NOT", SYM(NOT_SYM)},
{ "NULL", SYM(NULL_SYM)},
{ "NUMERIC", SYM(NUMERIC_SYM)},
{ "NVARCHAR", SYM(NVARCHAR_SYM)},
-diff -ruN a/sql/mysqld.cc b/sql/mysqld.cc
---- a/sql/mysqld.cc 2011-04-10 11:29:05.000000000 +0400
-+++ b/sql/mysqld.cc 2011-04-10 11:29:06.000000000 +0400
-@@ -3071,6 +3071,7 @@
+--- a/sql/mysqld.cc
++++ b/sql/mysqld.cc
+@@ -2971,6 +2971,7 @@
{"show_relaylog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_RELAYLOG_EVENTS]), SHOW_LONG_STATUS},
{"show_slave_hosts", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_HOSTS]), SHOW_LONG_STATUS},
{"show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS},
{"show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
{"show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
{"show_table_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLE_STATUS]), SHOW_LONG_STATUS},
-diff -ruN a/sql/sql_lex.h b/sql/sql_lex.h
---- a/sql/sql_lex.h 2011-04-10 11:29:05.000000000 +0400
-+++ b/sql/sql_lex.h 2011-04-10 11:29:06.000000000 +0400
+--- a/sql/sql_lex.h
++++ b/sql/sql_lex.h
@@ -190,6 +190,8 @@
SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES,
SQLCOM_SIGNAL, SQLCOM_RESIGNAL,
/*
When a command is added here, be sure it's also added in mysqld.cc
in "struct show_var_st status_vars[]= {" ...
-diff -ruN a/sql/sql_parse.cc b/sql/sql_parse.cc
---- a/sql/sql_parse.cc 2011-04-10 11:28:51.000000000 +0400
-+++ b/sql/sql_parse.cc 2011-04-10 11:29:06.000000000 +0400
-@@ -335,6 +335,7 @@
+--- a/sql/sql_parse.cc
++++ b/sql/sql_parse.cc
+@@ -336,6 +336,7 @@
sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND;
-@@ -2293,12 +2294,16 @@
+@@ -2393,12 +2394,17 @@
mysql_mutex_unlock(&LOCK_active_mi);
break;
}
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
- mysql_mutex_lock(&LOCK_active_mi);
-+ if(SQLCOM_SHOW_SLAVE_NOLOCK_STAT != lex->sql_command)
++ bool do_lock=SQLCOM_SHOW_SLAVE_NOLOCK_STAT != lex->sql_command;
++ if(do_lock)
+ {
+ mysql_mutex_lock(&LOCK_active_mi);
+ }
if (active_mi != NULL)
{
res = show_master_info(thd, active_mi);
-@@ -2309,7 +2314,10 @@
+@@ -2409,7 +2415,19 @@
WARN_NO_MASTER_INFO, ER(WARN_NO_MASTER_INFO));
my_ok(thd);
}
- mysql_mutex_unlock(&LOCK_active_mi);
-+ if(SQLCOM_SHOW_SLAVE_NOLOCK_STAT != lex->sql_command)
++ if(do_lock)
+ {
+ mysql_mutex_unlock(&LOCK_active_mi);
+ }
++ DBUG_EXECUTE_IF("after_show_slave_status",
++ {
++ const char act[]=
++ "now "
++ "signal signal.after_show_slave_status";
++ DBUG_ASSERT(opt_debug_sync_timeout > 0);
++ DBUG_ASSERT(!debug_sync_set_action(current_thd,
++ STRING_WITH_LEN(act)));
++ };);
break;
}
case SQLCOM_SHOW_MASTER_STAT:
-diff -ruN a/sql/sql_yacc.yy b/sql/sql_yacc.yy
---- a/sql/sql_yacc.yy 2011-04-10 11:29:05.000000000 +0400
-+++ b/sql/sql_yacc.yy 2011-04-10 11:29:06.000000000 +0400
-@@ -1292,6 +1292,7 @@
+--- a/sql/sql_yacc.yy
++++ b/sql/sql_yacc.yy
+@@ -1293,6 +1293,7 @@
%token STARTS_SYM
%token START_SYM /* SQL-2003-R */
%token STATUS_SYM
%token STDDEV_SAMP_SYM /* SQL-2003-N */
%token STD_SYM
%token STOP_SYM
-@@ -11082,6 +11083,10 @@
+@@ -11111,6 +11112,11 @@
{
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
}
++ /* SHOW SLAVE STATUS NOLOCK */
+ | SLAVE STATUS_SYM NOLOCK_SYM
+ {
+ Lex->sql_command = SQLCOM_SHOW_SLAVE_NOLOCK_STAT; //SQLCOM_SHOW_SLAVE_NOLOCK_STAT;
| QUERY_RESPONSE_TIME_SYM wild_and_where
{
#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
+--- /dev/null
++++ b/mysql-test/t/percona_show_slave_status_nolock.test
+@@ -0,0 +1,90 @@
++--source include/master-slave.inc
++--source include/have_debug_sync.inc
++--source include/have_binlog_format_statement.inc
++
++call mtr.add_suppression("Slave SQL: Request to stop slave SQL Thread received while applying a group that has non-transactional changes");
++
++--let $rpl_connection_name=slave_lock
++--let $rpl_server_number=2
++--source include/rpl_connect.inc
++
++--let $rpl_connection_name=slave_nolock
++--let $rpl_server_number=2
++--source include/rpl_connect.inc
++
++--let $show_statement= SHOW PROCESSLIST
++--let $field= Info
++
++connection master;
++--echo [master]
++--disable_warnings
++DROP TABLE IF EXISTS t;
++--enable_warnings
++CREATE TABLE t(id INT);
++sync_slave_with_master;
++
++connection slave;
++--echo [slave]
++SET DEBUG_SYNC='RESET';
++SET GLOBAL DEBUG="+d,after_mysql_insert,after_show_slave_status";
++
++connection master;
++--echo [master]
++INSERT INTO t VALUES(0);
++
++connection slave;
++--echo [slave]
++--let $condition= 'INSERT INTO t VALUES(0)'
++--source include/wait_show_condition.inc
++
++--echo check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - both should work fine
++--source include/percona_show_slave_status_nolock.inc
++
++connection master;
++--echo [master]
++INSERT INTO t VALUES(1);
++
++connection slave;
++--echo [slave]
++--let $condition= 'INSERT INTO t VALUES(1)'
++--source include/wait_show_condition.inc
++
++--let $rpl_connection_name=slave_stop
++--let $rpl_server_number=2
++--source include/rpl_connect.inc
++
++connection slave_stop;
++--echo [slave_stop]
++send STOP SLAVE;
++
++connection slave;
++--echo [slave]
++--let $condition= 'STOP SLAVE'
++--source include/wait_show_condition.inc
++
++--echo check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - just NOLOCK version should works fine
++--source include/percona_show_slave_status_nolock.inc
++
++
++connection slave_stop;
++--echo [slave_stop]
++reap;
++--source include/wait_for_slave_to_stop.inc
++START SLAVE;
++--source include/wait_for_slave_to_start.inc
++
++connection master;
++--echo [master]
++SET DEBUG_SYNC='RESET';
++
++connection slave;
++--echo [slave]
++SET GLOBAL DEBUG='';
++SET DEBUG_SYNC='RESET';
++
++connection master;
++--echo [master]
++DROP TABLE t;
++sync_slave_with_master;
++
++--source include/rpl_end.inc
+--- /dev/null
++++ b/mysql-test/r/percona_show_slave_status_nolock.result
+@@ -0,0 +1,69 @@
++include/master-slave.inc
++[connection master]
++call mtr.add_suppression("Slave SQL: Request to stop slave SQL Thread received while applying a group that has non-transactional changes");
++include/rpl_connect.inc [creating slave_lock]
++include/rpl_connect.inc [creating slave_nolock]
++[master]
++DROP TABLE IF EXISTS t;
++CREATE TABLE t(id INT);
++[slave]
++SET DEBUG_SYNC='RESET';
++SET GLOBAL DEBUG="+d,after_mysql_insert,after_show_slave_status";
++[master]
++INSERT INTO t VALUES(0);
++[slave]
++check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - both should work fine
++
++[slave_lock]
++SHOW SLAVE STATUS;
++SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
++SIGNAL after SHOW SLAVE STATUS is 'signal.after_show_slave_status'
++[slave]
++SET DEBUG_SYNC='now SIGNAL signal.empty';
++[slave_nolock]
++SHOW SLAVE STATUS NOLOCK;
++SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
++# should be 'signal.after_show_slave_status'
++SIGNAL after SHOW SLAVE STATUS NOLOCK is 'signal.after_show_slave_status'
++[slave]
++SET DEBUG_SYNC='now SIGNAL signal.continue';
++[slave]
++SET DEBUG_SYNC='now SIGNAL signal.empty';
++
++[master]
++INSERT INTO t VALUES(1);
++[slave]
++include/rpl_connect.inc [creating slave_stop]
++[slave_stop]
++STOP SLAVE;
++[slave]
++check 'SHOW SLAVE STATUS' and 'SHOW SLAVE STATUS NOLOCK' - just NOLOCK version should works fine
++
++[slave_lock]
++SHOW SLAVE STATUS;
++SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
++SIGNAL after SHOW SLAVE STATUS is 'signal.empty'
++[slave]
++SET DEBUG_SYNC='now SIGNAL signal.empty';
++[slave_nolock]
++SHOW SLAVE STATUS NOLOCK;
++SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
++# should be 'signal.after_show_slave_status'
++SIGNAL after SHOW SLAVE STATUS NOLOCK is 'signal.after_show_slave_status'
++[slave]
++SET DEBUG_SYNC='now SIGNAL signal.continue';
++[slave]
++SET DEBUG_SYNC='now SIGNAL signal.empty';
++
++[slave_stop]
++include/wait_for_slave_to_stop.inc
++START SLAVE;
++include/wait_for_slave_to_start.inc
++[master]
++SET DEBUG_SYNC='RESET';
++[slave]
++SET GLOBAL DEBUG='';
++SET DEBUG_SYNC='RESET';
++[master]
++DROP TABLE t;
++include/rpl_end.inc
+--- /dev/null
++++ b/mysql-test/include/percona_show_slave_status_nolock.inc
+@@ -0,0 +1,56 @@
++--echo
++--disable_result_log
++connection slave_lock;
++--echo [slave_lock]
++send SHOW SLAVE STATUS;
++
++connection slave;
++--let $condition= 'SHOW SLAVE STATUS'
++--source include/wait_show_condition.inc
++
++--disable_warnings
++SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
++--enable_warnings
++
++--let current=`SELECT SUBSTR(Variable_value FROM 22) FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name = 'DEBUG_SYNC'`
++--echo SIGNAL after SHOW SLAVE STATUS is $current
++
++connection slave;
++--echo [slave]
++SET DEBUG_SYNC='now SIGNAL signal.empty';
++
++connection slave_nolock;
++--echo [slave_nolock]
++send SHOW SLAVE STATUS NOLOCK;
++
++connection slave;
++--let $condition= 'SHOW SLAVE STATUS NOLOCK'
++--source include/wait_show_condition.inc
++
++--disable_warnings
++SET DEBUG_SYNC='now WAIT_FOR signal.after_show_slave_status TIMEOUT 1';
++--enable_warnings
++
++--echo # should be 'signal.after_show_slave_status'
++--let current=`SELECT SUBSTR(Variable_value FROM 22) FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE Variable_name = 'DEBUG_SYNC'`
++--echo SIGNAL after SHOW SLAVE STATUS NOLOCK is $current
++
++connection slave;
++--echo [slave]
++SET DEBUG_SYNC='now SIGNAL signal.continue';
++
++connection slave_lock;
++--disable_result_log
++reap;
++--enable_result_log
++
++connection slave_nolock;
++--disable_result_log
++reap;
++--enable_result_log
++
++connection slave;
++--echo [slave]
++SET DEBUG_SYNC='now SIGNAL signal.empty';
++--enable_result_log
++--echo
+--- a/sql/slave.cc
++++ b/sql/slave.cc
+@@ -1816,6 +1816,7 @@
+
+ if (mi->host[0])
+ {
++ bool do_lock=SQLCOM_SHOW_SLAVE_NOLOCK_STAT != thd->lex->sql_command;
+ DBUG_PRINT("info",("host is set: '%s'", mi->host));
+ String *packet= &thd->packet;
+ protocol->prepare_for_resend();
+@@ -1824,9 +1825,15 @@
+ slave_running can be accessed without run_lock but not other
+ non-volotile members like mi->io_thd, which is guarded by the mutex.
+ */
+- mysql_mutex_lock(&mi->run_lock);
++ if (do_lock)
++ {
++ mysql_mutex_lock(&mi->run_lock);
++ }
+ protocol->store(mi->io_thd ? mi->io_thd->proc_info : "", &my_charset_bin);
+- mysql_mutex_unlock(&mi->run_lock);
++ if (do_lock)
++ {
++ mysql_mutex_unlock(&mi->run_lock);
++ }
+
+ mysql_mutex_lock(&mi->data_lock);
+ mysql_mutex_lock(&mi->rli.data_lock);