diff options
Diffstat (limited to 'sql/slave.cc')
-rw-r--r-- | sql/slave.cc | 181 |
1 files changed, 136 insertions, 45 deletions
diff --git a/sql/slave.cc b/sql/slave.cc index 94e35bec4f8..1ee745ced6a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -72,6 +72,9 @@ bool use_slave_mask = 0; MY_BITMAP slave_error_mask; char slave_skip_error_names[SHOW_VAR_FUNC_BUFF_SIZE]; +uint *slave_transaction_retry_errors; +uint slave_transaction_retry_error_length= 0; +char slave_transaction_retry_error_names[SHOW_VAR_FUNC_BUFF_SIZE]; char* slave_load_tmpdir = 0; Master_info *active_mi= 0; @@ -156,7 +159,8 @@ static bool wait_for_relay_log_space(Relay_log_info* rli); static bool io_slave_killed(Master_info* mi); static bool sql_slave_killed(rpl_group_info *rgi); static int init_slave_thread(THD*, Master_info *, SLAVE_THD_TYPE); -static void print_slave_skip_errors(void); +static void make_slave_skip_errors_printable(void); +static void make_slave_transaction_retry_errors_printable(void); static int safe_connect(THD* thd, MYSQL* mysql, Master_info* mi); static int safe_reconnect(THD*, MYSQL*, Master_info*, bool); static int connect_to_master(THD*, MYSQL*, Master_info*, bool, bool); @@ -635,7 +639,6 @@ start_slave_background_thread() sql_print_error("Failed to create thread while initialising slave"); return 1; } - mysql_mutex_lock(&LOCK_slave_background); while (!slave_background_thread_gtid_loaded) mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); @@ -707,15 +710,6 @@ int init_slave() } /* - If --slave-skip-errors=... was not used, the string value for the - system variable has not been set up yet. Do it now. - */ - if (!use_slave_mask) - { - print_slave_skip_errors(); - } - - /* If master_host is not specified, try to read it from the master_info file. If master_host is specified, create the master_info file if it doesn't exists. @@ -812,12 +806,12 @@ int init_recovery(Master_info* mi, const char** errmsg) DBUG_RETURN(0); } - + /** Convert slave skip errors bitmap into a printable string. */ -static void print_slave_skip_errors(void) +static void make_slave_skip_errors_printable(void) { /* To be safe, we want 10 characters of room in the buffer for a number @@ -826,7 +820,7 @@ static void print_slave_skip_errors(void) plus a NUL terminator. That is a max 6 digit number. */ const size_t MIN_ROOM= 10; - DBUG_ENTER("print_slave_skip_errors"); + DBUG_ENTER("make_slave_skip_errors_printable"); DBUG_ASSERT(sizeof(slave_skip_error_names) > MIN_ROOM); DBUG_ASSERT(MAX_SLAVE_ERROR <= 999999); // 6 digits @@ -848,14 +842,14 @@ static void print_slave_skip_errors(void) else { char *buff= slave_skip_error_names; - char *bend= buff + sizeof(slave_skip_error_names); + char *bend= buff + sizeof(slave_skip_error_names) - MIN_ROOM; int errnum; for (errnum= 0; errnum < MAX_SLAVE_ERROR; errnum++) { if (bitmap_is_set(&slave_error_mask, errnum)) { - if (buff + MIN_ROOM >= bend) + if (buff >= bend) break; /* purecov: tested */ buff= int10_to_str(errnum, buff, 10); *buff++= ','; @@ -885,24 +879,24 @@ static void print_slave_skip_errors(void) Called from get_options() in mysqld.cc on start-up */ -void init_slave_skip_errors(const char* arg) +bool init_slave_skip_errors(const char* arg) { const char *p; DBUG_ENTER("init_slave_skip_errors"); + if (!arg || !*arg) // No errors defined + goto end; + if (my_bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0)) - { - fprintf(stderr, "Badly out of memory, please check your system status\n"); - exit(1); - } - use_slave_mask = 1; + DBUG_RETURN(1); + + use_slave_mask= 1; for (;my_isspace(system_charset_info,*arg);++arg) /* empty */; if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4)) { bitmap_set_all(&slave_error_mask); - print_slave_skip_errors(); - DBUG_VOID_RETURN; + goto end; } for (p= arg ; *p; ) { @@ -914,11 +908,109 @@ void init_slave_skip_errors(const char* arg) while (!my_isdigit(system_charset_info,*p) && *p) p++; } - /* Convert slave skip errors bitmap into a printable string. */ - print_slave_skip_errors(); + +end: + make_slave_skip_errors_printable(); + DBUG_RETURN(0); +} + +/** + Make printable version if slave_transaction_retry_errors + This is never empty as at least ER_LOCK_DEADLOCK and ER_LOCK_WAIT_TIMEOUT + will be there +*/ + +static void make_slave_transaction_retry_errors_printable(void) +{ + /* + To be safe, we want 10 characters of room in the buffer for a number + plus terminators. Also, we need some space for constant strings. + 10 characters must be sufficient for a number plus {',' | '...'} + plus a NUL terminator. That is a max 6 digit number. + */ + const size_t MIN_ROOM= 10; + char *buff= slave_transaction_retry_error_names; + char *bend= buff + sizeof(slave_transaction_retry_error_names) - MIN_ROOM; + uint i; + DBUG_ENTER("make_slave_transaction_retry_errors_printable"); + DBUG_ASSERT(sizeof(slave_transaction_retry_error_names) > MIN_ROOM); + + /* Make @@slave_transaction_retry_errors show a human-readable value */ + opt_slave_transaction_retry_errors= slave_transaction_retry_error_names; + + for (i= 0; i < slave_transaction_retry_error_length && buff < bend; i++) + { + buff= int10_to_str(slave_transaction_retry_errors[i], buff, 10); + *buff++= ','; + } + if (buff != slave_transaction_retry_error_names) + buff--; // Remove last ',' + if (i < slave_transaction_retry_error_length) + { + /* Couldn't show all errors */ + buff= strmov(buff, "..."); /* purecov: tested */ + } + *buff=0; + DBUG_PRINT("exit", ("error_names: '%s'", + slave_transaction_retry_error_names)); DBUG_VOID_RETURN; } + +bool init_slave_transaction_retry_errors(const char* arg) +{ + const char *p; + long err_code; + uint i; + DBUG_ENTER("init_slave_transaction_retry_errors"); + + /* Handle empty strings */ + if (!arg) + arg= ""; + + slave_transaction_retry_error_length= 2; + for (;my_isspace(system_charset_info,*arg);++arg) + /* empty */; + for (p= arg; *p; ) + { + if (!(p= str2int(p, 10, 0, LONG_MAX, &err_code))) + break; + slave_transaction_retry_error_length++; + while (!my_isdigit(system_charset_info,*p) && *p) + p++; + } + + if (!(slave_transaction_retry_errors= + (uint *) my_once_alloc(sizeof(int) * + slave_transaction_retry_error_length, + MYF(MY_WME)))) + DBUG_RETURN(1); + + /* + Temporary error codes: + currently, InnoDB deadlock detected by InnoDB or lock + wait timeout (innodb_lock_wait_timeout exceeded + */ + slave_transaction_retry_errors[0]= ER_LOCK_DEADLOCK; + slave_transaction_retry_errors[1]= ER_LOCK_WAIT_TIMEOUT; + + /* Add user codes after this */ + for (p= arg, i= 2; *p; ) + { + if (!(p= str2int(p, 10, 0, LONG_MAX, &err_code))) + break; + if (err_code > 0 && err_code < ER_ERROR_LAST) + slave_transaction_retry_errors[i++]= (uint) err_code; + while (!my_isdigit(system_charset_info,*p) && *p) + p++; + } + slave_transaction_retry_error_length= i; + + make_slave_transaction_retry_errors_printable(); + DBUG_RETURN(0); +} + + int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) { DBUG_ENTER("terminate_slave_threads"); @@ -987,7 +1079,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) mysql_mutex_unlock(log_lock); } - DBUG_RETURN(retval); + DBUG_RETURN(retval); } @@ -3598,14 +3690,20 @@ static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings, 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. + + @retval 0 if fatal error + @retval 1 temporary error, do retry */ + int has_temporary_error(THD *thd) { + uint current_errno; DBUG_ENTER("has_temporary_error"); DBUG_EXECUTE_IF("all_errors_are_temporary_errors", @@ -3623,14 +3721,12 @@ has_temporary_error(THD *thd) 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->get_stmt_da()->sql_errno() == ER_LOCK_DEADLOCK || - thd->get_stmt_da()->sql_errno() == ER_LOCK_WAIT_TIMEOUT) - DBUG_RETURN(1); + current_errno= thd->get_stmt_da()->sql_errno(); + for (uint i= 0; i < slave_transaction_retry_error_length; i++) + { + if (current_errno == slave_transaction_retry_errors[i]) + DBUG_RETURN(1); + } DBUG_RETURN(0); } @@ -4281,8 +4377,9 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, exec_res= 0; serial_rgi->cleanup_context(thd, 1); /* chance for concurrent connection to get more locks */ - slave_sleep(thd, MY_MIN(serial_rgi->trans_retries, + slave_sleep(thd, MY_MAX(MY_MIN(serial_rgi->trans_retries, MAX_SLAVE_RETRY_PAUSE), + slave_trans_retry_interval), sql_slave_killed, serial_rgi); serial_rgi->trans_retries++; mysql_mutex_lock(&rli->data_lock); // because of SHOW STATUS @@ -4367,7 +4464,7 @@ static bool check_io_slave_killed(Master_info *mi, const char *info) @param[in] mysql MySQL connection. @param[in] mi Master connection information. @param[in,out] retry_count Number of attempts to reconnect. - @param[in] suppress_warnings TRUE when a normal net read timeout + @param[in] suppress_warnings TRUE when a normal net read timeout has caused to reconnecting. @param[in] messages Messages to print/log, see reconnect_messages[] array. @@ -4870,9 +4967,7 @@ err_during_init: // TODO: make rpl_status part of Master_info change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE); - mysql_mutex_lock(&LOCK_thread_count); - thd->unlink(); - mysql_mutex_unlock(&LOCK_thread_count); + thd->assert_not_linked(); delete thd; thread_safe_decrement32(&service_thread_count); signal_thd_deleted(); @@ -5551,11 +5646,7 @@ err_during_init: rpl_parallel_resize_pool_if_no_slaves(); - /* TODO: Check if this lock is needed */ - mysql_mutex_lock(&LOCK_thread_count); delete serial_rgi; - mysql_mutex_unlock(&LOCK_thread_count); - delete thd; thread_safe_decrement32(&service_thread_count); signal_thd_deleted(); |