diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/Makefile.am | 2 | ||||
-rw-r--r-- | sql/log_event.cc | 164 | ||||
-rw-r--r-- | sql/rpl_mi.cc | 3 | ||||
-rw-r--r-- | sql/rpl_mi.h | 4 | ||||
-rw-r--r-- | sql/rpl_reporting.cc | 47 | ||||
-rw-r--r-- | sql/rpl_reporting.h | 78 | ||||
-rw-r--r-- | sql/rpl_rli.cc | 17 | ||||
-rw-r--r-- | sql/rpl_rli.h | 9 | ||||
-rw-r--r-- | sql/rpl_utility.cc | 24 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 14 | ||||
-rw-r--r-- | sql/slave.cc | 205 | ||||
-rw-r--r-- | sql/slave.h | 3 | ||||
-rw-r--r-- | sql/sql_repl.cc | 4 |
13 files changed, 343 insertions, 231 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index 91fe875c73d..d3e1f2c197e 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -54,6 +54,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ha_ndbcluster.h ha_ndbcluster_binlog.h \ ha_ndbcluster_tables.h \ opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \ + rpl_reporting.h \ log.h sql_show.h rpl_rli.h rpl_mi.h \ sql_select.h structs.h table.h sql_udf.h hash_filo.h \ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ @@ -95,6 +96,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \ rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_mi.cc \ + rpl_reporting.cc \ sql_union.cc sql_derived.cc \ client.c sql_client.cc mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc \ diff --git a/sql/log_event.cc b/sql/log_event.cc index 6b3902ba966..859f4c86776 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -158,12 +158,11 @@ valgrind_check_mem(void *ptr, size_t len) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -static void clear_all_errors(THD *thd, struct st_relay_log_info *rli) +static void clear_all_errors(THD *thd, RELAY_LOG_INFO *rli) { thd->query_error = 0; thd->clear_error(); - *rli->last_slave_error = 0; - rli->last_slave_errno = 0; + rli->clear_error(); } @@ -1989,7 +1988,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, clear_all_errors(thd, rli); /* Can ignore query */ else { - slave_print_msg(ERROR_LEVEL, rli, expected_error, + rli->report(ERROR_LEVEL, expected_error, "\ Query partially completed on the master (error on master: %d) \ and was aborted. There is a chance that your master is inconsistent at this \ @@ -2018,7 +2017,7 @@ compare_errors: !ignored_error_code(actual_error) && !ignored_error_code(expected_error)) { - slave_print_msg(ERROR_LEVEL, rli, 0, + rli->report(ERROR_LEVEL, 0, "\ Query caused different errors on master and slave. \ Error on master: '%s' (%d), Error on slave: '%s' (%d). \ @@ -2044,7 +2043,7 @@ Default database: '%s'. Query: '%s'", */ else if (thd->query_error || thd->is_fatal_error) { - slave_print_msg(ERROR_LEVEL, rli, actual_error, + rli->report(ERROR_LEVEL, actual_error, "Error '%s' on query. Default database: '%s'. Query: '%s'", (actual_error ? thd->net.last_error : "unexpected success or fatal error"), @@ -2524,11 +2523,11 @@ int Format_description_log_event::exec_event(struct st_relay_log_info* rli) if (!artificial_event && created && thd->transaction.all.nht) { /* This is not an error (XA is safe), just an information */ - slave_print_msg(INFORMATION_LEVEL, rli, 0, - "Rolling back unfinished transaction (no COMMIT " - "or ROLLBACK in relay log). A probable cause is that " - "the master died while writing the transaction to " - "its binary log, thus rolled back too."); + rli->report(INFORMATION_LEVEL, 0, + "Rolling back unfinished transaction (no COMMIT " + "or ROLLBACK in relay log). A probable cause is that " + "the master died while writing the transaction to " + "its binary log, thus rolled back too."); rli->cleanup_context(thd, 1); } #endif @@ -3284,6 +3283,10 @@ error: thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); close_thread_tables(thd); + + DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", + thd->query_error= 0; thd->is_fatal_error= 1;); + if (thd->query_error) { /* this err/sql_errno code is copy-paste from net_send_error() */ @@ -3296,19 +3299,25 @@ error: sql_errno=ER_UNKNOWN_ERROR; err=ER(sql_errno); } - slave_print_msg(ERROR_LEVEL, rli, sql_errno,"\ + rli->report(ERROR_LEVEL, sql_errno,"\ Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'", err, (char*)table_name, print_slave_db_safe(remember_db)); free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); return 1; } free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); - + if (thd->is_fatal_error) { - slave_print_msg(ERROR_LEVEL, rli, ER_UNKNOWN_ERROR, "\ -Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'", - (char*)table_name, print_slave_db_safe(remember_db)); + char buf[256]; + my_snprintf(buf, sizeof(buf), + "Running LOAD DATA INFILE on table '%-.64s'." + " Default database: '%-.64s'", + (char*)table_name, + print_slave_db_safe(remember_db)); + + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), buf); return 1; } @@ -4529,8 +4538,9 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, MYF(MY_WME|MY_NABP))) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, "Error in Create_file event: " - "could not open file '%s'", fname_buf); + rli->report(ERROR_LEVEL, my_errno, + "Error in Create_file event: could not open file '%s'", + fname_buf); goto err; } @@ -4540,9 +4550,9 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) if (write_base(&file)) { strmov(ext, ".info"); // to have it right in the error message - slave_print_msg(ERROR_LEVEL, rli, my_errno, - "Error in Create_file event: could not write to file '%s'", - fname_buf); + rli->report(ERROR_LEVEL, my_errno, + "Error in Create_file event: could not write to file '%s'", + fname_buf); goto err; } end_io_cache(&file); @@ -4554,14 +4564,16 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, MYF(MY_WME))) < 0) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, "Error in Create_file event: " - "could not open file '%s'", fname_buf); + rli->report(ERROR_LEVEL, my_errno, + "Error in Create_file event: could not open file '%s'", + fname_buf); goto err; } if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, "Error in Create_file event: " - "write to '%s' failed", fname_buf); + rli->report(ERROR_LEVEL, my_errno, + "Error in Create_file event: write to '%s' failed", + fname_buf); goto err; } error=0; // Everything is ok @@ -4700,25 +4712,25 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW, MYF(MY_WME))) < 0) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, - "Error in %s event: could not create file '%s'", - get_type_str(), fname); + rli->report(ERROR_LEVEL, my_errno, + "Error in %s event: could not create file '%s'", + get_type_str(), fname); goto err; } } else if ((fd = my_open(fname, O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW, MYF(MY_WME))) < 0) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, - "Error in %s event: could not open file '%s'", - get_type_str(), fname); + rli->report(ERROR_LEVEL, my_errno, + "Error in %s event: could not open file '%s'", + get_type_str(), fname); goto err; } if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, - "Error in %s event: write to '%s' failed", - get_type_str(), fname); + rli->report(ERROR_LEVEL, my_errno, + "Error in %s event: write to '%s' failed", + get_type_str(), fname); goto err; } error=0; @@ -4926,8 +4938,9 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0, MYF(MY_WME|MY_NABP))) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, "Error in Exec_load event: " - "could not open file '%s'", fname); + rli->report(ERROR_LEVEL, my_errno, + "Error in Exec_load event: could not open file '%s'", + fname); goto err; } if (!(lev = (Load_log_event*)Log_event::read_log_event(&file, @@ -4935,7 +4948,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) rli->relay_log.description_event_for_exec)) || lev->get_type_code() != NEW_LOAD_EVENT) { - slave_print_msg(ERROR_LEVEL, rli, 0, "Error in Exec_load event: " + rli->report(ERROR_LEVEL, 0, "Error in Exec_load event: " "file '%s' appears corrupted", fname); goto err; } @@ -4959,13 +4972,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) don't want to overwrite it with the filename. What we want instead is add the filename to the current error message. */ - char *tmp= my_strdup(rli->last_slave_error,MYF(MY_WME)); + char *tmp= my_strdup(rli->last_error.message, MYF(MY_WME)); if (tmp) { - slave_print_msg(ERROR_LEVEL, rli, - rli->last_slave_errno, /* ok to re-use error code */ - "%s. Failed executing load from '%s'", - tmp, fname); + rli->report(ERROR_LEVEL, rli->last_error.number, + "%s. Failed executing load from '%s'", tmp, fname); my_free(tmp,MYF(0)); } goto err; @@ -5168,11 +5179,16 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli) char *fname_end; int error; + buf= my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) + + (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME)); + + DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", buf= NULL;); + /* Replace filename and LOCAL keyword in query before executing it */ - if (!(buf = my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) + - (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME)))) + if (buf == NULL) { - slave_print_msg(ERROR_LEVEL, rli, my_errno, "Not enough memory"); + rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), "Not enough memory"); return 1; } @@ -5609,11 +5625,9 @@ unpack_row(RELAY_LOG_INFO *rli, (long) f->ptr)); if (event_type == WRITE_ROWS_EVENT && (f->flags & mask) == mask) { - slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD, - "Field `%s` of table `%s`.`%s` " - "has no default value and cannot be NULL", - (*field_ptr)->field_name, table->s->db.str, - table->s->table_name.str); + rli->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + (*field_ptr)->field_name); error = ER_NO_DEFAULT_FOR_FIELD; } else @@ -5678,9 +5692,9 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) { if (!need_reopen) { - slave_print_msg(ERROR_LEVEL, rli, error, - "Error in %s event: when locking tables", - get_type_str()); + rli->report(ERROR_LEVEL, error, + "Error in %s event: when locking tables", + get_type_str()); rli->clear_tables_to_lock(); DBUG_RETURN(error); } @@ -5711,10 +5725,10 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) simplifications (we don't honour --slave-skip-errors) */ uint actual_error= thd->net.last_errno; - slave_print_msg(ERROR_LEVEL, rli, actual_error, - "Error '%s' on reopening tables", - (actual_error ? thd->net.last_error : - "unexpected success or fatal error")); + rli->report(ERROR_LEVEL, actual_error, + "Error '%s' on reopening tables", + (actual_error ? thd->net.last_error : + "unexpected success or fatal error")); thd->query_error= 1; } rli->clear_tables_to_lock(); @@ -5805,9 +5819,9 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) break; default: - slave_print_msg(ERROR_LEVEL, rli, error, - "Error in %s event: row application failed", - get_type_str()); + rli->report(ERROR_LEVEL, error, + "Error in %s event: row application failed", + get_type_str()); thd->query_error= 1; break; } @@ -5826,11 +5840,11 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) if (error) { /* error has occured during the transaction */ - slave_print_msg(ERROR_LEVEL, rli, error, - "Error in %s event: error during transaction execution " - "on table %s.%s", - get_type_str(), table->s->db.str, - table->s->table_name.str); + rli->report(ERROR_LEVEL, error, + "Error in %s event: error during transaction execution " + "on table %s.%s", + get_type_str(), table->s->db.str, + table->s->table_name.str); /* If one day we honour --skip-slave-errors in row-based replication, and the error should be skipped, then we would clear mappings, rollback, @@ -5904,11 +5918,11 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) error= Log_event::exec_event(rli); } else - slave_print_msg(ERROR_LEVEL, rli, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), table->s->db.str, - table->s->table_name.str); + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), table->s->db.str, + table->s->table_name.str); DBUG_RETURN(error); } @@ -6245,11 +6259,11 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli) simplifications (we don't honour --slave-skip-errors) */ uint actual_error= thd->net.last_errno; - slave_print_msg(ERROR_LEVEL, rli, actual_error, - "Error '%s' on opening table `%s`.`%s`", - (actual_error ? thd->net.last_error : - "unexpected success or fatal error"), - table_list->db, table_list->table_name); + rli->report(ERROR_LEVEL, actual_error, + "Error '%s' on opening table `%s`.`%s`", + (actual_error ? thd->net.last_error : + "unexpected success or fatal error"), + table_list->db, table_list->table_name); thd->query_error= 1; } goto err; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index c89c8aa131e..d23d57c7eb7 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -29,7 +29,8 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val); MASTER_INFO::MASTER_INFO() - :ssl(0), fd(-1), io_thd(0), inited(0), + :Slave_reporting_capability("I/O"), + ssl(0), fd(-1), io_thd(0), inited(0), abort_slave(0),slave_running(0), slave_run_id(0) { host[0] = 0; user[0] = 0; password[0] = 0; diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index f0a7d6681fe..aac1072402f 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -19,6 +19,8 @@ #ifdef HAVE_REPLICATION +#include "rpl_reporting.h" + /***************************************************************************** Replication IO Thread @@ -52,7 +54,7 @@ *****************************************************************************/ -class MASTER_INFO +class MASTER_INFO : public Slave_reporting_capability { public: MASTER_INFO(); diff --git a/sql/rpl_reporting.cc b/sql/rpl_reporting.cc new file mode 100644 index 00000000000..d14dbdcc930 --- /dev/null +++ b/sql/rpl_reporting.cc @@ -0,0 +1,47 @@ + +#include "mysql_priv.h" +#include "rpl_reporting.h" + +void +Slave_reporting_capability::report(loglevel level, int err_code, const char *msg, ...) +{ + void (*report_function)(const char *, ...); + char buff[MAX_SLAVE_ERRMSG]; + char *pbuff= buff; + uint pbuffsize= sizeof(buff); + va_list args; + va_start(args, msg); + + switch (level) + { + case ERROR_LEVEL: + /* + It's an error, it must be reported in Last_error and Last_errno in SHOW + SLAVE STATUS. + */ + pbuff= last_error.message; + pbuffsize= sizeof(last_error.message); + last_error.number = err_code; + report_function= sql_print_error; + break; + case WARNING_LEVEL: + report_function= sql_print_warning; + break; + case INFORMATION_LEVEL: + report_function= sql_print_information; + break; + default: + DBUG_ASSERT(0); // should not come here + return; // don't crash production builds, just do nothing + } + + my_vsnprintf(pbuff, pbuffsize, msg, args); + + va_end(args); + + /* 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); +} diff --git a/sql/rpl_reporting.h b/sql/rpl_reporting.h new file mode 100644 index 00000000000..e3cd44d16c6 --- /dev/null +++ b/sql/rpl_reporting.h @@ -0,0 +1,78 @@ +#ifndef RPL_REPORTING_H +#define RPL_REPORTING_H + +/** + Mix-in to handle the message logging and reporting for relay log + info and master log info structures. + + By inheriting from this class, the class is imbued with + capabilities to do slave reporting. + */ +class Slave_reporting_capability +{ +public: + /** + Constructor. + + @param thread_name Printable name of the slave thread that is reporting. + */ + Slave_reporting_capability(char const *thread_name) + : m_thread_name(thread_name) + { + } + + /** + Writes a message and, if it's an error message, to Last_Error + (which will be displayed by SHOW SLAVE STATUS). + + @param level The severity level + @param err_code The error code + @param msg The message (usually related to the error + code, but can contain more information), in + printf() format. + */ + void report(loglevel level, int err_code, const char *msg, ...) + ATTRIBUTE_FORMAT(printf, 4, 5); + + /** + Clear errors. They will not show up under <code>SHOW SLAVE + STATUS</code>. + */ + void clear_error() { + last_error.clear(); + } + + /** + Error information structure. + */ + class Error { + friend class Slave_reporting_capability; + public: + Error() + { + clear(); + } + + void clear() + { + number= 0; + message[0]= '\0'; + } + + /** Error code */ + uint32 number; + /** Error message */ + char message[MAX_SLAVE_ERRMSG]; + }; + + /** + Last error produced by the I/O or SQL thread respectively. + */ + Error last_error; + +private: + char const *const m_thread_name; +}; + +#endif // RPL_REPORTING_H + diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index a2edb9dc8a8..104a2747eb4 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -29,10 +29,11 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, st_relay_log_info::st_relay_log_info() - :no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), + :Slave_reporting_capability("SQL"), + no_storage(FALSE), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), - abort_pos_wait(0), slave_run_id(0), sql_thd(0), last_slave_errno(0), + abort_pos_wait(0), slave_run_id(0), sql_thd(0), inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), until_log_pos(0), retried_trans(0), tables_to_lock(0), tables_to_lock_count(0), @@ -42,7 +43,7 @@ st_relay_log_info::st_relay_log_info() group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0; - last_slave_error[0]= until_log_name[0]= ign_master_log_name_end[0]= 0; + until_log_name[0]= ign_master_log_name_end[0]= 0; bzero((char*) &info_file, sizeof(info_file)); bzero((char*) &cache_buf, sizeof(cache_buf)); cached_charset_invalidate(); @@ -335,16 +336,6 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) } -void st_relay_log_info::clear_slave_error() -{ - DBUG_ENTER("clear_slave_error"); - - /* Clear the errors displayed by SHOW SLAVE STATUS */ - last_slave_error[0]= 0; - last_slave_errno= 0; - DBUG_VOID_RETURN; -} - /* Reset UNTIL condition for RELAY_LOG_INFO diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index d737055baf2..2761f3f5db7 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -20,7 +20,7 @@ #define MAX_SLAVE_ERRMSG 1024 #include "rpl_tblmap.h" - +#include "rpl_reporting.h" /**************************************************************************** @@ -48,7 +48,7 @@ *****************************************************************************/ -typedef struct st_relay_log_info +typedef struct st_relay_log_info : public Slave_reporting_capability { /* If flag set, then rli does not store its state in any info file. @@ -57,7 +57,7 @@ typedef struct st_relay_log_info */ bool no_storage; - /*** The following variables can only be read when protect by data lock ****/ + /* The following variables can only be read when protect by data lock */ /* info_fd - file descriptor of the info file. set only during @@ -165,7 +165,6 @@ typedef struct st_relay_log_info time_t last_master_timestamp; - void clear_slave_error(); void clear_until_condition(); /* @@ -179,11 +178,9 @@ typedef struct st_relay_log_info pthread_mutex_t log_space_lock; pthread_cond_t log_space_cond; THD * sql_thd; - int last_slave_errno; #ifndef DBUG_OFF int events_till_abort; #endif - char last_slave_error[MAX_SLAVE_ERRMSG]; /* if not set, the value of other members of the structure are undefined */ bool inited; diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 4bed1343e55..3241dd6edc0 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -128,11 +128,13 @@ table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table) { DBUG_ASSERT(tsh->db.str && tsh->table_name.str); error= 1; - slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_WRONG_TABLE_DEF, - "Table width mismatch - " - "received %u columns, %s.%s has %u columns", - (uint) size(), tsh->db.str, tsh->table_name.str, - tsh->fields); + char buf[256]; + my_snprintf(buf, sizeof(buf), "Table width mismatch - " + "received %u columns, %s.%s has %u columns", + (uint) size(), tsh->db.str, tsh->table_name.str, + tsh->fields); + rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF, + ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf); } for (uint col= 0 ; col < cols_to_check ; ++col) @@ -142,11 +144,13 @@ table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table) DBUG_ASSERT(col < size() && col < tsh->fields); DBUG_ASSERT(tsh->db.str && tsh->table_name.str); error= 1; - slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_WRONG_TABLE_DEF, - "Column %d type mismatch - " - "received type %d, %s.%s has type %d", - col, type(col), tsh->db.str, tsh->table_name.str, - table->field[col]->type()); + char buf[256]; + my_snprintf(buf, sizeof(buf), "Column %d type mismatch - " + "received type %d, %s.%s has type %d", + col, type(col), tsh->db.str, tsh->table_name.str, + table->field[col]->type()); + rli->report(ERROR_LEVEL, ER_BINLOG_ROW_WRONG_TABLE_DEF, + ER(ER_BINLOG_ROW_WRONG_TABLE_DEF), buf); } } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index c64f4da045e..48f2ecdee89 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5842,8 +5842,8 @@ ER_BINLOG_ROW_LOGGING_FAILED eng "Writing one row to the row-based binary log failed" ger "Schreiben einer Zeilen ins zeilenbasierte Binärlog fehlgeschlagen" ER_BINLOG_ROW_WRONG_TABLE_DEF - eng "Table definition on master and slave does not match" - ger "Tabellendefinition auf Master und Slave stimmt nicht überein" + eng "Table definition on master and slave does not match: %s" + ger "Tabellendefinition auf Master und Slave stimmt nicht überein: %s" ER_BINLOG_ROW_RBR_TO_SBR eng "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events" ger "Slave, die mit --log-slave-updates laufen, müssen zeilenbasiertes Loggen verwenden, um zeilenbasierte Binärlog-Ereignisse loggen zu können" @@ -6016,3 +6016,13 @@ ER_NATIVE_FCT_NAME_COLLISION eng "This function '%-.64s' has the same name as a native function." ER_BINLOG_PURGE_EMFILE eng "Too many files opened, please execute the command again" +ER_SLAVE_FATAL_ERROR + eng "Fatal error: %s" +ER_SLAVE_RELAY_LOG_READ_FAILURE + eng "Relay log read failure: %s" +ER_SLAVE_RELAY_LOG_WRITE_FAILURE + eng "Relay log write failure: %s" +ER_SLAVE_CREATE_EVENT_FAILURE + eng "Failed to create %s" +ER_SLAVE_MASTER_COM_FAILURE + eng "Master command %s failed: %s" diff --git a/sql/slave.cc b/sql/slave.cc index 67e8ba20c4f..2eb3557641c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -523,13 +523,13 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) "it some grace period")); if (difftime(time(0), rli->unsafe_to_stop_at) > 60) { - slave_print_msg(ERROR_LEVEL, rli, 0, - "SQL thread had to stop in an unsafe situation, in " - "the middle of applying updates to a " - "non-transactional table without any primary key. " - "There is a risk of duplicate updates when the slave " - "SQL thread is restarted. Please check your tables' " - "contents after restart."); + rli->report(ERROR_LEVEL, 0, + "SQL thread had to stop in an unsafe situation, in " + "the middle of applying updates to a " + "non-transactional table without any primary key. " + "There is a risk of duplicate updates when the slave " + "SQL thread is restarted. Please check your tables' " + "contents after restart."); DBUG_RETURN(1); } } @@ -538,70 +538,6 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) /* - Writes a message to stderr, and if it's an error message, to - rli->last_slave_error and rli->last_slave_errno (which will be displayed by - SHOW SLAVE STATUS). - - SYNOPSIS - slave_print_msg() - level The severity level - rli - err_code The error code - msg The message (usually related to the error code, but can - contain more information). - ... (this is printf-like format, with % symbols in msg) - - RETURN VALUES - void -*/ - -void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli, - int err_code, const char* msg, ...) -{ - void (*report_function)(const char *, ...); - char buff[MAX_SLAVE_ERRMSG], *pbuff= buff; - uint pbuffsize= sizeof(buff); - va_list args; - DBUG_ENTER("slave_print_msg"); - - va_start(args,msg); - switch (level) - { - case ERROR_LEVEL: - /* - This my_error call only has effect in client threads. - Slave threads do nothing in my_error(). - */ - my_error(ER_UNKNOWN_ERROR, MYF(0), msg); - /* - It's an error, it must be reported in Last_error and Last_errno in SHOW - SLAVE STATUS. - */ - pbuff= rli->last_slave_error; - pbuffsize= sizeof(rli->last_slave_error); - rli->last_slave_errno = err_code; - report_function= sql_print_error; - break; - case WARNING_LEVEL: - report_function= sql_print_warning; - break; - case INFORMATION_LEVEL: - report_function= sql_print_information; - break; - default: - DBUG_ASSERT(0); // should not come here - DBUG_VOID_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 (pbuff[0] && (*(strend(pbuff)-1) == '.')) - (*report_function)("Slave: %s Error_code: %d", pbuff, err_code); - else - (*report_function)("Slave: %s, Error_code: %d", pbuff, err_code); - DBUG_VOID_RETURN; -} - -/* skip_load_data_infile() NOTES @@ -768,7 +704,9 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi) /* as we are here, we tried to allocate the event */ if (!mi->rli.relay_log.description_event_for_queue) { - sql_print_error("Slave I/O thread failed to create a default Format_description_log_event"); + mi->report(ERROR_LEVEL, ER_SLAVE_CREATE_EVENT_FAILURE, + ER(ER_SLAVE_CREATE_EVENT_FAILURE), + "default Format_description_log_event"); DBUG_RETURN(1); } @@ -1128,18 +1066,21 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi) { ev->server_id= 0; // don't be ignored by slave SQL thread if (unlikely(rli->relay_log.append(ev))) - sql_print_error("Slave I/O thread failed to write a Rotate event" - " to the relay log, " - "SHOW SLAVE STATUS may be inaccurate"); + mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, + ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), + "failed to write a Rotate event" + " to the relay log, SHOW SLAVE STATUS may be" + " inaccurate"); rli->relay_log.harvest_bytes_written(&rli->log_space_total); if (flush_master_info(mi, 1)) sql_print_error("Failed to flush master info file"); delete ev; } else - sql_print_error("Slave I/O thread failed to create a Rotate event" - " (out of memory?), " - "SHOW SLAVE STATUS may be inaccurate"); + mi->report(ERROR_LEVEL, ER_SLAVE_CREATE_EVENT_FAILURE, + ER(ER_SLAVE_CREATE_EVENT_FAILURE), + "Rotate_event (out of memory?)," + " SHOW SLAVE STATUS may be inaccurate"); } else pthread_mutex_unlock(log_lock); @@ -1147,7 +1088,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, MASTER_INFO *mi) } -int register_slave_on_master(MYSQL* mysql) +int register_slave_on_master(MYSQL* mysql, MASTER_INFO *mi) { char buf[1024], *pos= buf; uint report_host_len, report_user_len=0, report_password_len=0; @@ -1177,9 +1118,11 @@ int register_slave_on_master(MYSQL* mysql) if (simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf, (uint) (pos- buf), 0)) { - sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'", - mysql_errno(mysql), - mysql_error(mysql)); + char buf[256]; + my_snprintf(buf, sizeof(buf), + "%s (Errno: %d)", mysql_error(mysql), mysql_errno(mysql)); + mi->report(ERROR_LEVEL, ER_SLAVE_MASTER_COM_FAILURE, + ER(ER_SLAVE_MASTER_COM_FAILURE), "COM_REGISTER_SLAVE", buf); DBUG_RETURN(1); } DBUG_RETURN(0); @@ -1247,6 +1190,10 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) sizeof(mi->ssl_key))); field_list.push_back(new Item_return_int("Seconds_Behind_Master", 10, MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("Last_IO_Errno", 4, MYSQL_TYPE_LONG)); + field_list.push_back(new Item_empty_string("Last_IO_Error", 20)); + field_list.push_back(new Item_return_int("Last_SQL_Errno", 4, MYSQL_TYPE_LONG)); + field_list.push_back(new Item_empty_string("Last_SQL_Error", 20)); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) @@ -1295,8 +1242,8 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) rpl_filter->get_wild_ignore_table(&tmp); protocol->store(&tmp); - protocol->store((uint32) mi->rli.last_slave_errno); - protocol->store(mi->rli.last_slave_error, &my_charset_bin); + protocol->store(mi->rli.last_error.number); + protocol->store(mi->rli.last_error.message, &my_charset_bin); protocol->store((uint32) mi->rli.slave_skip_counter); protocol->store((ulonglong) mi->rli.group_master_log_pos); protocol->store((ulonglong) mi->rli.log_space_total); @@ -1355,6 +1302,15 @@ bool show_master_info(THD* thd, MASTER_INFO* mi) else protocol->store_null(); + // Last_IO_Errno + protocol->store(mi->last_error.number); + // Last_IO_Error + protocol->store(mi->last_error.message, &my_charset_bin); + // Last_SQL_Errno + protocol->store(mi->rli.last_error.number); + // Last_SQL_Error + protocol->store(mi->rli.last_error.message, &my_charset_bin); + pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); @@ -1876,7 +1832,8 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) DBUG_RETURN(exec_res); } pthread_mutex_unlock(&rli->data_lock); - slave_print_msg(ERROR_LEVEL, rli, 0, "\ + rli->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_READ_FAILURE, + ER(ER_SLAVE_RELAY_LOG_READ_FAILURE), "\ Could not parse relay log event entry. The possible reasons are: the master's \ binary log is corrupted (you can check this by running 'mysqlbinlog' on the \ binary log), the slave's relay log is corrupted (you can check this by running \ @@ -1943,7 +1900,8 @@ pthread_handler_t handle_slave_io(void *arg) if (!(mi->mysql = mysql = mysql_init(NULL))) { - sql_print_error("Slave I/O thread: error in mysql_init()"); + mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), "error in mysql_init()"); goto err; } @@ -1986,7 +1944,7 @@ connected: on with life. */ thd->proc_info = "Registering slave on master"; - if (register_slave_on_master(mysql) || update_slave_list(mysql, mi)) + if (register_slave_on_master(mysql, mi) || update_slave_list(mysql, mi)) goto err; } @@ -2031,10 +1989,16 @@ dump"); } thd->proc_info = "Reconnecting after a failed binlog dump request"; - if (!suppress_warnings) - sql_print_error("Slave I/O thread: failed dump request, \ -reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME, - llstr(mi->master_log_pos,llbuff)); + if (!suppress_warnings) { + char buf[256]; + my_snprintf(buf, sizeof(buf), + "failed dump request, reconnecting to try again," + " log '%s' at postion %s", + IO_RPL_LOG_NAME, + llstr(mi->master_log_pos,llbuff)); + mi->report(WARNING_LEVEL, ER_SLAVE_MASTER_COM_FAILURE, + ER(ER_SLAVE_MASTER_COM_FAILURE), "COM_BINLOG_DUMP", buf); + } if (safe_reconnect(thd, mysql, mi, suppress_warnings) || io_slave_killed(thd,mi)) { @@ -2123,7 +2087,9 @@ reconnect done to recover from failed read"); if (queue_event(mi,(const char*)mysql->net.read_pos + 1, event_len)) { - sql_print_error("Slave I/O thread could not queue event from master"); + mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, + ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), + "could not queue event from master"); goto err; } if (flush_master_info(mi, 1)) @@ -2287,7 +2253,7 @@ pthread_handler_t handle_slave_sql(void *arg) now. But the master timestamp is reset by RESET SLAVE & CHANGE MASTER. */ - rli->clear_slave_error(); + rli->clear_error(); //tell the I/O thread to take relay_log_space_limit into account from now on pthread_mutex_lock(&rli->log_space_lock); @@ -2366,23 +2332,24 @@ Slave SQL thread aborted. Can't execute init_slave query"); 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 + 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->net.last_errno != 0) { - if (rli->last_slave_errno == 0) + char const *const errmsg= + thd->net.last_error ? thd->net.last_error : "<no message>"; + if (last_errno == 0) { - slave_print_msg(ERROR_LEVEL, rli, thd->net.last_errno, - thd->net.last_error ? - thd->net.last_error : "<no message>"); + rli->report(ERROR_LEVEL, thd->net.last_errno, errmsg); } - else if (rli->last_slave_errno != (int) thd->net.last_errno) + else if (last_errno != thd->net.last_errno) { sql_print_error("Slave (additional info): %s Error_code: %d", - thd->net.last_error ? - thd->net.last_error : "<no message>", - thd->net.last_errno); + errmsg, thd->net.last_errno); } } @@ -2530,8 +2497,9 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) xev.log_pos = cev->log_pos; if (unlikely(mi->rli.relay_log.append(&xev))) { - sql_print_error("Slave I/O: error writing Exec_load event to \ -relay log"); + mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, + ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), + "error writing Exec_load event to relay log"); goto err; } mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total); @@ -2543,8 +2511,9 @@ relay log"); cev->block_len = num_bytes; if (unlikely(mi->rli.relay_log.append(cev))) { - sql_print_error("Slave I/O: error writing Create_file event to \ -relay log"); + mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, + ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), + "error writing Create_file event to relay log"); goto err; } cev_not_written=0; @@ -2557,8 +2526,9 @@ relay log"); aev.log_pos = cev->log_pos; if (unlikely(mi->rli.relay_log.append(&aev))) { - sql_print_error("Slave I/O: error writing Append_block event to \ -relay log"); + mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, + ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), + "error writing Append_block event to relay log"); goto err; } mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total) ; @@ -2659,7 +2629,8 @@ static int queue_binlog_ver_1_event(MASTER_INFO *mi, const char *buf, { if (unlikely(!(tmp_buf=(char*)my_malloc(event_len+1,MYF(MY_WME))))) { - sql_print_error("Slave I/O: out of memory for Load event"); + mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, + ER(ER_SLAVE_FATAL_ERROR), "Memory allocation failed"); DBUG_RETURN(1); } memcpy(tmp_buf,buf,event_len); @@ -3107,14 +3078,12 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, { last_errno=mysql_errno(mysql); suppress_warnings= 0; - sql_print_error("Slave I/O thread: error %s to master " - "'%s@%s:%d': \ -Error: '%s' errno: %d retry-time: %d retries: %lu", - (reconnect ? "reconnecting" : "connecting"), - mi->user, mi->host, mi->port, - mysql_error(mysql), last_errno, - mi->connect_retry, - master_retry_count); + mi->report(ERROR_LEVEL, last_errno, + "error %s to master '%s@%s:%d'" + " - retry-time: %d retries: %lu", + (reconnect ? "reconnecting" : "connecting"), + mi->user, mi->host, mi->port, + mi->connect_retry, master_retry_count); } /* By default we try forever. The reason is that failure will trigger diff --git a/sql/slave.h b/sql/slave.h index 24ba09d78d3..078a98735ef 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -166,9 +166,6 @@ bool show_binlog_info(THD* thd); const char *print_slave_db_safe(const char *db); int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code); void skip_load_data_infile(NET* net); -void slave_print_msg(enum loglevel level, RELAY_LOG_INFO* rli, - int err_code, const char* msg, ...) - ATTRIBUTE_FORMAT(printf, 4, 5); void end_slave(); /* clean up */ void clear_until_condition(RELAY_LOG_INFO* rli); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 92c8aca0e0c..6238a801b9b 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -985,7 +985,7 @@ int reset_slave(THD *thd, MASTER_INFO* mi) Reset errors (the idea is that we forget about the old master). */ - mi->rli.clear_slave_error(); + mi->rli.clear_error(); mi->rli.clear_until_condition(); // close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0 @@ -1251,7 +1251,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) pthread_mutex_lock(&mi->rli.data_lock); mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */ /* Clear the errors, for a clean start */ - mi->rli.clear_slave_error(); + mi->rli.clear_error(); mi->rli.clear_until_condition(); /* If we don't write new coordinates to disk now, then old will remain in |