#At file:///home/andrei/MySQL/BZR/2a-23May/MERGE/mysql-trunk/ based on revid:andrei.elkin@stripped
3344 Andrei Elkin 2011-03-29 [merge]
merge from local bugfixing branch to local mysql-trunk prior to push
modified:
mysql-test/extra/rpl_tests/rpl_deadlock.test
mysql-test/suite/rpl/r/rpl_deadlock_innodb.result
sql/rpl_reporting.cc
sql/rpl_reporting.h
sql/rpl_slave.cc
=== modified file 'mysql-test/extra/rpl_tests/rpl_deadlock.test'
--- a/mysql-test/extra/rpl_tests/rpl_deadlock.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_deadlock.test 2011-03-27 18:16:32 +0000
@@ -123,6 +123,57 @@ SELECT * FROM t3;
source include/check_slave_is_running.inc;
--echo
+#
+# bug#11748510/36524 incident of deadlock on slave is overdramatized
+#
+# Observe that the slave stopped when the number of transation retries
+# exceeds @@global.slave_transaction_retries
+#
+connection master;
+
+--echo *** Test the deadlock warning to be escalated into the error ***
+
+delete from t1;
+delete from t2;
+delete from t3;
+
+sync_slave_with_master;
+
+# make sure slave's unilateral row gone as well
+delete from t1;
+delete from t2;
+delete from t3;
+
+# the first attempt to run a deadlock scenario of p 1) leads to the error
+set @save.slave_transaction_retries= @@global.slave_transaction_retries;
+set @@global.slave_transaction_retries= 0;
+source include/stop_slave.inc;
+
+connection master;
+
+BEGIN;
+INSERT INTO t1 VALUES (1);
+# We make a long transaction here
+INSERT INTO t2 VALUES (2), (2), (2), (2), (2), (2), (2), (2), (2), (2);
+INSERT INTO t3 VALUES (3);
+COMMIT;
+
+connection slave;
+BEGIN;
+SELECT count(*) as zero FROM t1 FOR UPDATE;
+
+start slave;
+
+--echo *** Now the slave must be stopped due to timeout ***
+
+let $slave_sql_errno= 1205; # ER_LOCK_TIMEOUT
+let $show_slave_sql_error= 0;
+source include/wait_for_slave_sql_error.inc;
+
+rollback;
+
+set @@global.slave_transaction_retries= @save.slave_transaction_retries;
+source include/start_slave.inc;
# Clean up
--echo *** Clean up ***
connection master;
=== modified file 'mysql-test/suite/rpl/r/rpl_deadlock_innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result 2010-12-19 17:22:30 +0000
+++ b/mysql-test/suite/rpl/r/rpl_deadlock_innodb.result 2011-03-27 18:16:32 +0000
@@ -103,6 +103,31 @@ a
3
include/check_slave_is_running.inc
+*** Test the deadlock warning to be escalated into the error ***
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t1;
+delete from t2;
+delete from t3;
+set @save.slave_transaction_retries= @@global.slave_transaction_retries;
+set @@global.slave_transaction_retries= 0;
+include/stop_slave.inc
+BEGIN;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t2 VALUES (2), (2), (2), (2), (2), (2), (2), (2), (2), (2);
+INSERT INTO t3 VALUES (3);
+COMMIT;
+BEGIN;
+SELECT count(*) as zero FROM t1 FOR UPDATE;
+zero
+0
+start slave;
+*** Now the slave must be stopped due to timeout ***
+include/wait_for_slave_sql_error.inc [errno=1205]
+rollback;
+set @@global.slave_transaction_retries= @save.slave_transaction_retries;
+include/start_slave.inc
*** Clean up ***
DROP TABLE t1,t2,t3;
SET global max_relay_log_size= @my_max_relay_log_size;
=== modified file 'sql/rpl_reporting.cc'
--- a/sql/rpl_reporting.cc 2010-08-05 17:45:25 +0000
+++ b/sql/rpl_reporting.cc 2011-03-28 13:19:08 +0000
@@ -17,6 +17,7 @@
#include "rpl_reporting.h"
#include "log.h" // sql_print_error, sql_print_warning,
// sql_print_information
+#include "rpl_slave.h"
Slave_reporting_capability::Slave_reporting_capability(char const *thread_name)
: m_thread_name(thread_name)
@@ -25,15 +26,94 @@ Slave_reporting_capability::Slave_report
&err_lock, MY_MUTEX_INIT_FAST);
}
+#if !defined(EMBEDDED_LIBRARY)
+/**
+ Check if the current error is of temporary nature or not.
+ Some errors are temporary in nature, such as
+ ER_LOCK_DEADLOCK and ER_LOCK_WAIT_TIMEOUT. Ndb also signals
+ that the error is temporary by pushing a warning with the error code
+ ER_GET_TEMPORARY_ERRMSG, if the originating error is temporary.
+
+ @param thd a THD instance, typically of the slave SQL thread's.
+ @error_arg the error code for assessment.
+ defaults to zero which makes the function check the top
+ of the reported errors stack.
+
+ @return 1 as the positive and 0 as the negative verdict
+*/
+int Slave_reporting_capability::has_temporary_error(THD *thd, uint error_arg) const
+{
+ uint error;
+ DBUG_ENTER("has_temporary_error");
+
+ DBUG_EXECUTE_IF("all_errors_are_temporary_errors",
+ if (thd->stmt_da->is_error())
+ {
+ thd->clear_error();
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ });
+
+ /*
+ The state of the slave thread can't be regarded as
+ experiencing a temporary failure in cases of @c is_slave_error was set TRUE,
+ or if there is no message in THD, we can't say if it's a temporary
+ error or not. This is currently the case for Incident_log_event,
+ which sets no message.
+ */
+ if (thd->is_fatal_error || !thd->is_error())
+ DBUG_RETURN(0);
+
+ error= (error_arg == 0)? thd->stmt_da->sql_errno() : error_arg;
+
+ /*
+ Temporary error codes:
+ currently, InnoDB deadlock detected by InnoDB or lock
+ wait timeout (innodb_lock_wait_timeout exceeded).
+ Notice, the temporary error requires slave_trans_retries != 0)
+ */
+ if (slave_trans_retries &&
+ (error == ER_LOCK_DEADLOCK || error == ER_LOCK_WAIT_TIMEOUT))
+ DBUG_RETURN(1);
+
+#ifdef HAVE_NDB_BINLOG
+ /*
+ currently temporary error set in ndbcluster
+ */
+ List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
+ MYSQL_ERROR *err;
+ while ((err= it++))
+ {
+ DBUG_PRINT("info", ("has condition %d %s", err->get_sql_errno(),
+ err->get_message_text()));
+ switch (err->get_sql_errno())
+ {
+ case ER_GET_TEMPORARY_ERRMSG:
+ DBUG_RETURN(1);
+ default:
+ break;
+ }
+ }
+#endif
+ DBUG_RETURN(0);
+}
+#endif // EMBEDDED_LIBRARY
+
+
void
Slave_reporting_capability::report(loglevel level, int err_code,
const char *msg, ...) const
{
+#if !defined(EMBEDDED_LIBRARY)
+ THD *thd= current_thd;
void (*report_function)(const char *, ...);
char buff[MAX_SLAVE_ERRMSG];
char *pbuff= buff;
uint pbuffsize= sizeof(buff);
va_list args;
+
+ if (level == ERROR_LEVEL && has_temporary_error(thd, err_code))
+ level= WARNING_LEVEL;
+
va_start(args, msg);
mysql_mutex_lock(&err_lock);
@@ -51,10 +131,12 @@ Slave_reporting_capability::report(logle
report_function= sql_print_error;
break;
case WARNING_LEVEL:
- report_function= sql_print_warning;
+ report_function= global_system_variables.log_warnings?
+ sql_print_warning : NULL;
break;
case INFORMATION_LEVEL:
- report_function= sql_print_information;
+ report_function= global_system_variables.log_warnings?
+ sql_print_information : NULL;
break;
default:
DBUG_ASSERT(0); // should not come here
@@ -71,6 +153,7 @@ Slave_reporting_capability::report(logle
m_thread_name, pbuff,
(pbuff[0] && *(strend(pbuff)-1) == '.') ? "" : ",",
err_code);
+#endif
}
Slave_reporting_capability::~Slave_reporting_capability()
=== modified file 'sql/rpl_reporting.h'
--- a/sql/rpl_reporting.h 2010-08-05 17:45:25 +0000
+++ b/sql/rpl_reporting.h 2011-03-28 13:19:08 +0000
@@ -23,6 +23,11 @@
*/
#define MAX_SLAVE_ERRMSG 1024
+// todo: consider to remove rpl_reporting.cc,h from building embedded
+#if !defined(EMBEDDED_LIBRARY)
+class THD;
+#endif
+
/**
Mix-in to handle the message logging and reporting for relay log
info and master log info structures.
@@ -65,6 +70,13 @@ public:
mysql_mutex_unlock(&err_lock);
}
+#if !defined(EMBEDDED_LIBRARY)
+ /**
+ Check if the current error is of temporary nature or not.
+ */
+ int has_temporary_error(THD *thd, uint error_arg= 0) const;
+#endif // EMBEDDED_LIBRARY
+
/**
Error information structure.
*/
=== modified file 'sql/rpl_slave.cc'
--- a/sql/rpl_slave.cc 2011-03-29 13:44:23 +0000
+++ b/sql/rpl_slave.cc 2011-03-29 14:56:01 +0000
@@ -2518,63 +2518,6 @@ static ulong read_event(MYSQL* mysql, Ma
DBUG_RETURN(len - 1);
}
-/*
- Check if the current error is of temporary nature of not.
- Some errors are temporary in nature, such as
- ER_LOCK_DEADLOCK and ER_LOCK_WAIT_TIMEOUT. Ndb also signals
- that the error is temporary by pushing a warning with the error code
- ER_GET_TEMPORARY_ERRMSG, if the originating error is temporary.
-*/
-static int has_temporary_error(THD *thd)
-{
- DBUG_ENTER("has_temporary_error");
-
- DBUG_EXECUTE_IF("all_errors_are_temporary_errors",
- if (thd->stmt_da->is_error())
- {
- thd->clear_error();
- my_error(ER_LOCK_DEADLOCK, MYF(0));
- });
-
- /*
- If there is no message in THD, we can't say if it's a temporary
- error or not. This is currently the case for Incident_log_event,
- which sets no message. Return FALSE.
- */
- if (!thd->is_error())
- DBUG_RETURN(0);
-
- /*
- Temporary error codes:
- currently, InnoDB deadlock detected by InnoDB or lock
- wait timeout (innodb_lock_wait_timeout exceeded
- */
- if (thd->stmt_da->sql_errno() == ER_LOCK_DEADLOCK ||
- thd->stmt_da->sql_errno() == ER_LOCK_WAIT_TIMEOUT)
- DBUG_RETURN(1);
-
-#ifdef HAVE_NDB_BINLOG
- /*
- currently temporary error set in ndbcluster
- */
- List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
- MYSQL_ERROR *err;
- while ((err= it++))
- {
- DBUG_PRINT("info", ("has condition %d %s", err->get_sql_errno(),
- err->get_message_text()));
- switch (err->get_sql_errno())
- {
- case ER_GET_TEMPORARY_ERRMSG:
- DBUG_RETURN(1);
- default:
- break;
- }
- }
-#endif
- DBUG_RETURN(0);
-}
-
/**
If this is a lagging slave (specified with CHANGE MASTER TO MASTER_DELAY = X), delays accordingly. Also unlocks rli->data_lock.
@@ -2965,7 +2908,7 @@ static int exec_relay_log_event(THD* thd
if (slave_trans_retries)
{
int UNINIT_VAR(temp_err);
- if (exec_res && (temp_err= has_temporary_error(thd)))
+ if (exec_res && (temp_err= rli->has_temporary_error(thd)))
{
const char *errmsg;
/*
@@ -3011,10 +2954,13 @@ static int exec_relay_log_event(THD* thd
}
}
else
- sql_print_error("Slave SQL thread retried transaction %lu time(s) "
- "in vain, giving up. Consider raising the value of "
- "the slave_transaction_retries variable.",
- slave_trans_retries);
+ {
+ thd->is_fatal_error= 1;
+ rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(),
+ "Slave SQL thread retried transaction %lu time(s) "
+ "in vain, giving up. Consider raising the value of "
+ "the slave_transaction_retries variable.", rli->trans_retries);
+ }
}
else if ((exec_res && !temp_err) ||
(opt_using_transactions &&
Attachment: [text/bzr-bundle] bzr/andrei.elkin@oracle.com-20110329145601-asqy5hj1a1gzrlra.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (andrei.elkin:3344) | Andrei Elkin | 29 Mar |