From: Andrei Elkin Date: March 24 2011 5:17pm Subject: bzr commit into mysql-trunk branch (andrei.elkin:3311) Bug#11748510 List-Archive: http://lists.mysql.com/commits/133861 X-Bug: 11748510 Message-Id: <201103241717.p2OHHNmY018925@mysql1000.dsl.inet.fi> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0057092449==" --===============0057092449== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/andrei/MySQL/BZR/2a-23May/FIXES/bug11748510_36524-deadlock_overdram/ based on revid:magne.mahre@stripped 3311 Andrei Elkin 2011-03-24 bug#11748510 incident of deadlock on slave is overdramatized In cases of temporary errors in replication event execution (deadlock, timeout) the error log gained an overreacting error message whereas just a warning would be fine. Fixed with checking of the temporary status of the error inside Slave_reporting_capability::report() to demote the error to the warning level if needed. The warning gets converted into the error whenever number of successive attempts to re-apply the event(s) gets equal to @@global.slave_trans_retries. The patch also changes the slave service error gathering and reporting as the following. Slave_reporting_capability::report() populates thd->main_da the standard placeholder for the errors and calls the stderr writers for errors and lesser severity levels as specified by @@global_system_variables.log_warnings. That said report() mimics my_error(). Slave_reporting_capability::display() is introduced to display errors through show-slave-status interfaces. The latter mimics send_error(). Some number of test result files got affected and in some cases the new results revealed issues in the old versions. This patch contains a limited part dealing with the tests. See the following commit that completes the fixes. @ mysql-test/extra/rpl_tests/rpl_deadlock.test regression test is added to prove a temporary failure warning is escalated. @ mysql-test/include/check-testcase.test IO errors can be gathered during IO thread session time and can't be reset. So they are masked out until we will have gotten facility to wipe them out. @ mysql-test/suite/rpl/r/rpl_deadlock_innodb.result results get updated. @ sql/log_event.cc treating rli->report() as an error reporting similar to my_error(). Gathering errors in the diag area should be completed with displaying via rli->display() each time a slave thread breaks the applying loop. Relocating clear_all_errors() definition into rpl_slave.cc. @ sql/rpl_reporting.cc report() method is turned to be a wrapper of functions dealing with the diag area like my_error() and ones with the error log. One of its use case to register an error and print it out the error log. A new display() method copies the gathered errors the area of the Show Slave Status when a slave thread is about to exit. @ sql/rpl_reporting.h a new display() method added as well as comments for report(). @ sql/rpl_slave.cc exporting has_temporary_error() to be used in rpl_reporting.cc; docking definition of clear_all_errors() to use in both modules; run-out-of-tries case is finished with raising on the fatal error flag; finalizing the error branch of events execution with display() to make gathered error be saved in show-slave-status area; deploying display() at the end of io-thread and sql-thread. @ sql/rpl_slave.h exporting functions shared with slave.cc, rpl_reporting.cc, log_event.cc. modified: mysql-test/extra/rpl_tests/rpl_deadlock.test mysql-test/include/check-testcase.test mysql-test/suite/rpl/r/rpl_deadlock_innodb.result sql/log_event.cc sql/rpl_reporting.cc sql/rpl_reporting.h sql/rpl_slave.cc sql/rpl_slave.h === 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-24 17:17:13 +0000 @@ -10,6 +10,10 @@ --source include/master-slave.inc +connection slave; +call mtr.add_suppression("Could not execute Write_rows event on table test.t1,handler error HA_ERR_LOCK_WAIT_TIMEOUT"); +connection master; + # 0) Prepare tables and data --echo *** Prepare tables and data *** @@ -123,6 +127,58 @@ 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 deadlock *** + +# slow slave environment can report ER_LOCK_TIMEOUT +let $slave_sql_errno= 1213, 1205; # ER_LOCK_DEADLOCK or 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/include/check-testcase.test' --- a/mysql-test/include/check-testcase.test 2011-02-07 15:31:01 +0000 +++ b/mysql-test/include/check-testcase.test 2011-03-24 17:17:13 +0000 @@ -54,8 +54,8 @@ if ($tmp) --echo Master_SSL_Key --echo Seconds_Behind_Master NULL --echo Master_SSL_Verify_Server_Cert No - --echo Last_IO_Errno 0 - --echo Last_IO_Error + --echo Last_IO_Errno # + --echo Last_IO_Error # --echo Last_SQL_Errno 0 --echo Last_SQL_Error --echo Replicate_Ignore_Server_Ids @@ -72,7 +72,7 @@ if ($tmp) } if (!$tmp) { # Note: after WL#5177, fields 13-18 shall not be filtered-out. - --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 22 # 23 # 24 # 25 # 26 # 40 # 41 # 42 # 46 # + --replace_column 4 # 5 # 6 # 7 # 8 # 9 # 10 # 13 # 14 # 15 # 16 # 17 # 18 # 22 # 23 # 24 # 25 # 26 # 35 # 36 # 40 # 41 # 42 # 46 # query_vertical SHOW SLAVE STATUS; } === 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-24 17:17:13 +0000 @@ -1,5 +1,6 @@ include/master-slave.inc [connection master] +call mtr.add_suppression("Could not execute Write_rows event on table test.t1,handler error HA_ERR_LOCK_WAIT_TIMEOUT"); *** Prepare tables and data *** CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=innodb; CREATE TABLE t2 (a INT) ENGINE=innodb; @@ -103,6 +104,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 deadlock *** +include/wait_for_slave_sql_error.inc [errno=1213, 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/log_event.cc' --- a/sql/log_event.cc 2011-03-14 17:09:16 +0000 +++ b/sql/log_event.cc 2011-03-24 17:17:13 +0000 @@ -209,35 +209,21 @@ static void inline slave_rows_error_repo const char *log_name, ulong pos) { const char *handler_error= HA_ERR(ha_error); - char buff[MAX_SLAVE_ERRMSG], *slider; - const char *buff_end= buff + sizeof(buff); - uint len; - List_iterator_fast it(thd->warning_info->warn_list()); - MYSQL_ERROR *err; - buff[0]= 0; - - for (err= it++, slider= buff; err && slider < buff_end - 1; - slider += len, err= it++) - { - len= my_snprintf(slider, buff_end - slider, - " %s, Error_code: %d;", err->get_message_text(), - err->get_sql_errno()); - } if (ha_error != 0) rli->report(level, thd->is_error() ? thd->stmt_da->sql_errno() : 0, - "Could not execute %s event on table %s.%s;" - "%s handler error %s; " + "Could not execute %s event on table %s.%s," + "handler error %s, " "the event's master log %s, end_log_pos %lu", type, table->s->db.str, table->s->table_name.str, - buff, handler_error == NULL ? "" : handler_error, + handler_error == NULL ? "" : handler_error, log_name, pos); else rli->report(level, thd->is_error() ? thd->stmt_da->sql_errno() : 0, - "Could not execute %s event on table %s.%s;" - "%s the event's master log %s, end_log_pos %lu", + "Could not execute %s event on table %s.%s," + "the event's master log %s, end_log_pos %lu", type, table->s->db.str, table->s->table_name.str, - buff, log_name, pos); + log_name, pos); } static void set_thd_db(THD *thd, const char *db, uint32 db_len) @@ -293,13 +279,6 @@ static void pretty_print_str(IO_CACHE* c #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -static void clear_all_errors(THD *thd, Relay_log_info *rli) -{ - thd->is_slave_error = 0; - thd->clear_error(); - rli->clear_error(); -} - inline int idempotent_error_code(int err_code) { int ret= 0; @@ -3700,7 +3679,7 @@ compare_errors: !ignored_error_code(actual_error) && !ignored_error_code(expected_error)) { - rli->report(ERROR_LEVEL, 0, + rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR, "\ Query caused different errors on master and slave. \ Error on master: message (format)='%s' error code=%d ; \ === 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-24 17:17:13 +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,54 +26,153 @@ Slave_reporting_capability::Slave_report &err_lock, MY_MUTEX_INIT_FAST); } +/** + The method treats a supplied message depending on the level: + + - an error is queued in the diagnostic area + to be recorded eventually in Show Slave status area and + in the error log. + - a warning or an info level are optinally (log_warnings) + stored into the error log + + @param level severity of the message. + @param err_code the user level error code + @param msg the format string of the message, + can be followed with more arguments + providing the data for the format string + + @note Queueing in the da is protected by @err_lock mutex + to collabote with a concurrent reader from the da. +*/ void Slave_reporting_capability::report(loglevel level, int err_code, const char *msg, ...) const { + THD *thd= current_thd; void (*report_function)(const char *, ...); - char buff[MAX_SLAVE_ERRMSG]; + char buff[sizeof(m_last_error.message)]; 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); + my_vsnprintf(pbuff, sizeof(buff), msg, args); + va_end(args); mysql_mutex_lock(&err_lock); switch (level) { case ERROR_LEVEL: /* - It's an error, it must be reported in Last_error and Last_errno in SHOW - SLAVE STATUS. + It's an error, it goes in a slave thread's main_da. */ - pbuff= m_last_error.message; - pbuffsize= sizeof(m_last_error.message); - m_last_error.number = err_code; + m_last_error.number= err_code; m_last_error.update_timestamp(); + if (err_code > 0) + { + if (thd->stmt_da->is_set()) + thd->stmt_da->can_overwrite_status= TRUE; + my_printf_error(err_code, "%s", MYF(0), pbuff); + if (thd->stmt_da->can_overwrite_status) + thd->stmt_da->can_overwrite_status= FALSE; + } + 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 return; // don't crash production builds, just do nothing } - my_vsnprintf(pbuff, pbuffsize, msg, args); - + /* If the msg string ends with '.', do not add a ',' it would be ugly */ + if (report_function) + report_function("Slave %s: %s%s Error_code: %d", + m_thread_name, pbuff, + (pbuff[0] && *(strend(pbuff) - 1) == '.') ? "" : ",", + err_code); mysql_mutex_unlock(&err_lock); +} + +/** + compose Last_Error to be shown by SHOW SLAVE STATUS + + @param err_code The summary error code to display. If zero + the last reported default will be set to Last*Errno + + @param msg The summary message's format string optinally followed + by arguments. It can be NULL. + + @note The method tries gathering all queued *error-level* messages + into the limited-size buffer and may not compose the whole + list. In that case the rest can be found anyway in the error log. + The Last_Error's code corresponds to the last queued error if + the supplied @c err_code is zero. + + The gathering procedure is protected by @c err_lock + to provide collaboration with a concurrent reader such as + show slave status. +*/ +void +Slave_reporting_capability::display(int err_code, const char *msg, ...) const +{ + uint len, size= sizeof(m_last_error.message); + char *slider, *buff= m_last_error.message, *buff_end= buff + size; + List_iterator_fast it(current_thd->warning_info->warn_list()); + MYSQL_ERROR *err; + uint32 err_number; + const char err_code_fmt[]= ", Error_code: %d; "; + va_list args; + + va_start(args, msg); + len= msg == NULL? 0 : my_vsnprintf(buff, size, msg, args); va_end(args); + + mysql_mutex_lock(&err_lock); + + /* + In case of multiple errors the error codes are printed along with msgs ... + */ + for (err= it++, + err_number= 0, + slider= buff + len; + err; + slider += len, err= it++) + { + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR) + continue; + if (err_number != 0) + { + len= my_snprintf(slider, buff_end - slider, err_code_fmt, err_number); + slider += len; + } + err_number= err->get_sql_errno(); // Last*Errno is of the error level + if (slider < buff_end) + len= my_snprintf(slider, buff_end - slider,"%s", err->get_message_text()); + } + m_last_error.number= err_code == 0? err_number : err_code; + /* + ... except for the last error if its code is equal to @c err_code + the supplied summary's. + */ + if ((err_number != 0 && err_number != m_last_error.number) && + slider < buff_end) + my_snprintf(slider, buff_end - slider, err_code_fmt, err_number); + + mysql_mutex_unlock(&err_lock); - /* If the msg string ends with '.', do not add a ',' it would be ugly */ - report_function("Slave %s: %s%s Error_code: %d", - m_thread_name, pbuff, - (pbuff[0] && *(strend(pbuff)-1) == '.') ? "" : ",", - err_code); } + Slave_reporting_capability::~Slave_reporting_capability() { mysql_mutex_destroy(&err_lock); === 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-24 17:17:13 +0000 @@ -43,8 +43,7 @@ public: Slave_reporting_capability(char const *thread_name); /** - Writes a message and, if it's an error message, to Last_Error - (which will be displayed by SHOW SLAVE STATUS). + Writes a message into diag area and/or/either the error log @param level The severity level @param err_code The error code @@ -56,6 +55,14 @@ public: ATTRIBUTE_FORMAT(printf, 4, 5); /** + compose Last_Error to be shown by SHOW SLAVE STATUS + @param err_code The summary code to display instead of the last reported + @param msg A summary message to set afront of the reported errors + */ + void display(int err_code, const char *msg, ...) const + ATTRIBUTE_FORMAT(printf, 3, 4); + + /** Clear errors. They will not show up under SHOW SLAVE STATUS. */ === modified file 'sql/rpl_slave.cc' --- a/sql/rpl_slave.cc 2011-03-17 13:20:36 +0000 +++ b/sql/rpl_slave.cc 2011-03-24 17:17:13 +0000 @@ -2514,15 +2514,23 @@ 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. + + @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 have been reported errors stack. + + @return 1 as the positive and 0 as the negative verdict */ -static int has_temporary_error(THD *thd) +int has_temporary_error(THD *thd, uint error_arg) { + uint error; DBUG_ENTER("has_temporary_error"); DBUG_EXECUTE_IF("all_errors_are_temporary_errors", @@ -2537,16 +2545,17 @@ static int has_temporary_error(THD *thd) error or not. This is currently the case for Incident_log_event, which sets no message. Return FALSE. */ - if (!thd->is_error()) + 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 */ - if (thd->stmt_da->sql_errno() == ER_LOCK_DEADLOCK || - thd->stmt_da->sql_errno() == ER_LOCK_WAIT_TIMEOUT) + if (error == ER_LOCK_DEADLOCK || error == ER_LOCK_WAIT_TIMEOUT) DBUG_RETURN(1); #ifdef HAVE_NDB_BINLOG @@ -2637,6 +2646,13 @@ static int sql_delay_event(Log_event *ev DBUG_RETURN(0); } +void clear_all_errors(THD *thd, Relay_log_info *rli) +{ + thd->is_slave_error = 0; + thd->clear_error(); + rli->clear_error(); +} + /** Applies the given event and advances the relay log position. @@ -3007,10 +3023,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; // to force has_temporary_error() return 0 + } } else if ((exec_res && !temp_err) || (opt_using_transactions && @@ -3491,6 +3510,7 @@ err: mi->mysql=0; } write_ignored_events_info_to_relay_log(thd, mi); + mi->display(0, NULL); thd_proc_info(thd, "Waiting for slave mutex on exit"); mysql_mutex_lock(&mi->run_lock); @@ -3776,39 +3796,10 @@ log '%s' at position %s, relay log '%s' if (!sql_slave_killed(thd,rli)) { /* - retrieve as much info as possible from the thd and, error - codes and warnings and print this to the error log as to - allow the user to locate the error - */ - uint32 const last_errno= rli->last_error().number; - - if (thd->is_error()) - { - char const *const errmsg= thd->stmt_da->message(); - - DBUG_PRINT("info", - ("thd->stmt_da->sql_errno()=%d; rli->last_error.number=%d", - thd->stmt_da->sql_errno(), last_errno)); - if (last_errno == 0) - { - /* - This function is reporting an error which was not reported - while executing exec_relay_log_event(). - */ - rli->report(ERROR_LEVEL, thd->stmt_da->sql_errno(), "%s", errmsg); - } - else if (last_errno != thd->stmt_da->sql_errno()) - { - /* - * An error was reported while executing exec_relay_log_event() - * however the error code differs from what is in the thread. - * This function prints out more information to help finding - * what caused the problem. - */ - sql_print_error("Slave (additional info): %s Error_code: %d", - errmsg, thd->stmt_da->sql_errno()); - } - } + Reporting all gather errors while executing exec_relay_log_event() + analogously send_error() + */ + rli->display(0, NULL); /* Print any warnings issued */ List_iterator_fast it(thd->warning_info->warn_list()); @@ -3839,6 +3830,14 @@ llstr(rli->get_group_master_log_pos(), l } goto err; } + else + { + /* + Event applying succeeded, reset errors and diag area status + */ + clear_all_errors(thd, const_cast(rli)); + thd->stmt_da->reset_diagnostics_area(); + } } /* Thread stopped. Print the current replication position to the log */ @@ -3849,6 +3848,7 @@ llstr(rli->get_group_master_log_pos(), l err: + rli->display(0, NULL); /* Some events set some playgrounds, which won't be cleared because thread stops. Stopping of this thread may not be known to these events ("stop" === modified file 'sql/rpl_slave.h' --- a/sql/rpl_slave.h 2011-02-16 17:13:30 +0000 +++ b/sql/rpl_slave.h 2011-03-24 17:17:13 +0000 @@ -213,6 +213,8 @@ void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); int rotate_relay_log(Master_info* mi); +int has_temporary_error(THD *thd, uint err= 0); +void clear_all_errors(THD *thd, Relay_log_info *rli); pthread_handler_t handle_slave_io(void *arg); pthread_handler_t handle_slave_sql(void *arg); --===============0057092449== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/andrei.elkin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: andrei.elkin@stripped # target_branch: file:///home/andrei/MySQL/BZR/2a-23May/FIXES\ # /bug11748510_36524-deadlock_overdram/ # testament_sha1: 3e9b913da0c14e4ea51d452b7704ef19fb0b19a3 # timestamp: 2011-03-24 19:17:23 +0200 # base_revision_id: magne.mahre@stripped\ # y6p1m9y730lssgf7 # # Begin bundle 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 --===============0057092449==--