diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-11-09 07:59:36 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-11-09 07:59:36 +0200 |
commit | f7054ff5dfea7b84afdde11c14898cff7154521e (patch) | |
tree | 97d33d01294e148cf245d16bdab42f7d3cd2a4c6 /sql | |
parent | e026eddc7dc3b17e7120adfded1d53da0e7ec9f0 (diff) | |
parent | a2f147af35480e27bd599462db59b9b95f71acd9 (diff) | |
download | mariadb-git-f7054ff5dfea7b84afdde11c14898cff7154521e.tar.gz |
Merge mariadb-10.3.32 into 10.3
Diffstat (limited to 'sql')
-rw-r--r-- | sql/handler.cc | 2 | ||||
-rw-r--r-- | sql/handler.h | 12 | ||||
-rw-r--r-- | sql/log.cc | 37 | ||||
-rw-r--r-- | sql/sp_head.cc | 8 | ||||
-rw-r--r-- | sql/sql_class.cc | 27 | ||||
-rw-r--r-- | sql/sql_class.h | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 36 | ||||
-rw-r--r-- | sql/threadpool_generic.cc | 4 | ||||
-rw-r--r-- | sql/wsrep_mysqld.cc | 61 | ||||
-rw-r--r-- | sql/wsrep_thd.cc | 11 |
10 files changed, 143 insertions, 58 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index 47f78283897..11a387fb4e3 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -835,11 +835,9 @@ static my_bool kill_handlerton(THD *thd, plugin_ref plugin, { handlerton *hton= plugin_hton(plugin); - mysql_mutex_lock(&thd->LOCK_thd_data); if (hton->state == SHOW_OPTION_YES && hton->kill_query && thd_get_ha_data(thd, hton)) hton->kill_query(hton, thd, *(enum thd_kill_levels *) level); - mysql_mutex_unlock(&thd->LOCK_thd_data); return FALSE; } diff --git a/sql/handler.h b/sql/handler.h index e56ac9fab6e..91225982e9e 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1730,9 +1730,13 @@ struct THD_TRANS /* Define the type of statements which cannot be rolled back safely. Each type occupies one bit in m_unsafe_rollback_flags. + MODIFIED_NON_TRANS_TABLE is limited to mark only the temporary + non-transactional table *when* it's cached along with the transactional + events; the regular table is covered by the "namesake" bool var. */ enum unsafe_statement_types { + MODIFIED_NON_TRANS_TABLE= 1, CREATED_TEMP_TABLE= 2, DROPPED_TEMP_TABLE= 4, DID_WAIT= 8, @@ -1740,6 +1744,14 @@ struct THD_TRANS EXECUTED_TABLE_ADMIN_CMD= 0x20 }; + void mark_modified_non_trans_temp_table() + { + m_unsafe_rollback_flags|= MODIFIED_NON_TRANS_TABLE; + } + bool has_modified_non_trans_temp_table() const + { + return (m_unsafe_rollback_flags & MODIFIED_NON_TRANS_TABLE) != 0; + } void mark_executed_table_admin_cmd() { DBUG_PRINT("debug", ("mark_executed_table_admin_cmd")); diff --git a/sql/log.cc b/sql/log.cc index 95cb60ea829..1e4b9d9f1f4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -263,7 +263,7 @@ class binlog_cache_data public: binlog_cache_data(): m_pending(0), status(0), before_stmt_pos(MY_OFF_T_UNDEF), - incident(FALSE), changes_to_non_trans_temp_table_flag(FALSE), + incident(FALSE), saved_max_binlog_cache_size(0), ptr_binlog_cache_use(0), ptr_binlog_cache_disk_use(0) { } @@ -312,16 +312,6 @@ public: return(incident); } - void set_changes_to_non_trans_temp_table() - { - changes_to_non_trans_temp_table_flag= TRUE; - } - - bool changes_to_non_trans_temp_table() - { - return (changes_to_non_trans_temp_table_flag); - } - void reset() { bool cache_was_empty= empty(); @@ -333,7 +323,6 @@ public: if (truncate_file) my_chsize(cache_log.file, 0, 0, MYF(MY_WME)); - changes_to_non_trans_temp_table_flag= FALSE; status= 0; incident= FALSE; before_stmt_pos= MY_OFF_T_UNDEF; @@ -432,12 +421,6 @@ private: */ bool incident; - /* - This flag indicates if the cache has changes to temporary tables. - @TODO This a temporary fix and should be removed after BUG#54562. - */ - bool changes_to_non_trans_temp_table_flag; - /** This function computes binlog cache and disk usage. */ @@ -1977,13 +1960,12 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) */ static bool trans_cannot_safely_rollback(THD *thd, bool all) { - binlog_cache_mngr *const cache_mngr= - (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton); + DBUG_ASSERT(ending_trans(thd, all)); return ((thd->variables.option_bits & OPTION_KEEP_LOG) || (trans_has_updated_non_trans_table(thd) && thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT) || - (cache_mngr->trx_cache.changes_to_non_trans_temp_table() && + (thd->transaction.all.has_modified_non_trans_temp_table() && thd->wsrep_binlog_format() == BINLOG_FORMAT_MIXED) || (trans_has_updated_non_trans_table(thd) && ending_single_stmt_trans(thd,all) && @@ -2134,17 +2116,19 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) /* Truncate the cache if: . aborting a single or multi-statement transaction or; - . the OPTION_KEEP_LOG is not active and; + . the current statement created or dropped a temporary table + while having actual STATEMENT format; . the format is not STMT or no non-trans table was updated and; . the format is not MIXED or no temporary non-trans table was updated. */ else if (ending_trans(thd, all) || - (!(thd->variables.option_bits & OPTION_KEEP_LOG) && + (!(thd->transaction.stmt.has_created_dropped_temp_table() && + !thd->is_current_stmt_binlog_format_row()) && (!stmt_has_updated_non_trans_table(thd) || thd->wsrep_binlog_format() != BINLOG_FORMAT_STMT) && - (!cache_mngr->trx_cache.changes_to_non_trans_temp_table() || + (!thd->transaction.stmt.has_modified_non_trans_temp_table() || thd->wsrep_binlog_format() != BINLOG_FORMAT_MIXED))) error= binlog_truncate_trx_cache(thd, cache_mngr, all); } @@ -6340,9 +6324,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache); file= &cache_data->cache_log; - if (thd->lex->stmt_accessed_non_trans_temp_table()) - cache_data->set_changes_to_non_trans_temp_table(); - + if (thd->lex->stmt_accessed_non_trans_temp_table() && is_trans_cache) + thd->transaction.stmt.mark_modified_non_trans_temp_table(); thd->binlog_start_trans_and_stmt(); } DBUG_PRINT("info",("event type: %d",event_info->get_type_code())); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 525d836b8c3..57ab31d9edf 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3379,8 +3379,13 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, It's reset further in the common code part. It's merged with the saved parent's value at the exit of this func. */ - bool parent_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table; + bool parent_modified_non_trans_table= + thd->transaction.stmt.modified_non_trans_table; + unsigned int parent_unsafe_rollback_flags= + thd->transaction.stmt.m_unsafe_rollback_flags; thd->transaction.stmt.modified_non_trans_table= FALSE; + thd->transaction.stmt.m_unsafe_rollback_flags= 0; + DBUG_ASSERT(!thd->derived_tables); DBUG_ASSERT(thd->Item_change_list::is_empty()); /* @@ -3496,6 +3501,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, what is needed from the substatement gained */ thd->transaction.stmt.modified_non_trans_table |= parent_modified_non_trans_table; + thd->transaction.stmt.m_unsafe_rollback_flags |= parent_unsafe_rollback_flags; TRANSACT_TRACKER(add_trx_state_from_thd(thd)); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d3c090c3308..fbfb742d9ee 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1977,7 +1977,9 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, if (needs_thr_lock_abort) { + bool mutex_released= false; mysql_mutex_lock(&in_use->LOCK_thd_data); + mysql_mutex_lock(&in_use->LOCK_thd_kill); /* If not already dying */ if (in_use->killed != KILL_CONNECTION_HARD) { @@ -1993,18 +1995,25 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use, thread can see those instances (e.g. see partitioning code). */ if (!thd_table->needs_reopen()) - { signalled|= mysql_lock_abort_for_thread(this, thd_table); - if (WSREP(this) && wsrep_thd_is_BF(this, FALSE)) - { - WSREP_DEBUG("remove_table_from_cache: %llu", - (unsigned long long) this->real_id); - wsrep_abort_thd((void *)this, (void *)in_use, FALSE); - } - } } +#ifdef WITH_WSREP + if (WSREP(this) && wsrep_thd_is_BF(this, false)) + { + WSREP_DEBUG("notify_shared_lock: BF thread %llu query %s" + " victim %llu query %s", + this->real_id, wsrep_thd_query(this), + in_use->real_id, wsrep_thd_query(in_use)); + wsrep_abort_thd((void *)this, (void *)in_use, false); + mutex_released= true; + } +#endif /* WITH_WSREP */ + } + if (!mutex_released) + { + mysql_mutex_unlock(&in_use->LOCK_thd_kill); + mysql_mutex_unlock(&in_use->LOCK_thd_data); } - mysql_mutex_unlock(&in_use->LOCK_thd_data); } DBUG_RETURN(signalled); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 1df9a9dc718..4dcb0a0d5a5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4816,7 +4816,8 @@ public: transaction.all.modified_non_trans_table= TRUE; transaction.all.m_unsafe_rollback_flags|= (transaction.stmt.m_unsafe_rollback_flags & - (THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE | + (THD_TRANS::MODIFIED_NON_TRANS_TABLE | + THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE | THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL | THD_TRANS::EXECUTED_TABLE_ADMIN_CMD)); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 95c04321b4d..4ff1776e244 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9157,6 +9157,18 @@ static void sql_kill(THD *thd, longlong id, killed_state state, killed_type type) { uint error; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + WSREP_DEBUG("sql_kill called"); + if (thd->wsrep_applier) + { + WSREP_DEBUG("KILL in applying, bailing out here"); + return; + } + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + } +#endif /* WITH_WSREP */ if (likely(!(error= kill_one_thread(thd, id, state, type)))) { if (!thd->killed) @@ -9166,6 +9178,13 @@ void sql_kill(THD *thd, longlong id, killed_state state, killed_type type) } else my_error(error, MYF(0), id); +#ifdef WITH_WSREP + return; + wsrep_error_label: + error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : + ER_KILL_DENIED_ERROR); + my_error(error, MYF(0), id); +#endif /* WITH_WSREP */ } @@ -9174,6 +9193,18 @@ void sql_kill_user(THD *thd, LEX_USER *user, killed_state state) { uint error; ha_rows rows; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + WSREP_DEBUG("sql_kill_user called"); + if (thd->wsrep_applier) + { + WSREP_DEBUG("KILL in applying, bailing out here"); + return; + } + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + } +#endif /* WITH_WSREP */ if (likely(!(error= kill_threads_for_user(thd, user, state, &rows)))) my_ok(thd, rows); else @@ -9184,6 +9215,11 @@ void sql_kill_user(THD *thd, LEX_USER *user, killed_state state) */ my_error(error, MYF(0), user->host.str, user->user.str); } +#ifdef WITH_WSREP + return; + wsrep_error_label: + my_error(ER_CANNOT_USER, MYF(0), user ? user->user.str : "NULL"); +#endif /* WITH_WSREP */ } diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index 8b424591ba6..74b1a778647 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1787,9 +1787,9 @@ static void print_pool_blocked_message(bool max_threads_reached) if (now > pool_block_start + BLOCK_MSG_DELAY && !msg_written) { if (max_threads_reached) - sql_print_error(MAX_THREADS_REACHED_MSG); + sql_print_warning(MAX_THREADS_REACHED_MSG); else - sql_print_error(CREATE_THREAD_ERROR_MSG, my_errno); + sql_print_warning(CREATE_THREAD_ERROR_MSG, my_errno); sql_print_information("Threadpool has been blocked for %u seconds\n", (uint)((now- pool_block_start)/1000000)); diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index ce798a918e3..fcb7de9ca58 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2015 Codership Oy <http://www.codership.com> +/* Copyright 2008-2021 Codership Oy <http://www.codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -833,13 +833,25 @@ void wsrep_thr_init() DBUG_VOID_RETURN; } +/* This is wrapper for wsrep_break_lock in thr_lock.c */ +static int wsrep_thr_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) +{ + THD* victim_thd= (THD *) victim_thd_ptr; + /* We need to lock THD::LOCK_thd_data to protect victim + from concurrent usage or disconnect or delete. */ + wsrep_thd_LOCK(victim_thd); + int res= wsrep_abort_thd(bf_thd_ptr, victim_thd_ptr, signal); + return res; +} + + void wsrep_init_startup (bool first) { if (wsrep_init()) unireg_abort(1); wsrep_thr_lock_init( (wsrep_thd_is_brute_force_fun)wsrep_thd_is_BF, - (wsrep_abort_thd_fun)wsrep_abort_thd, + (wsrep_abort_thd_fun)wsrep_thr_abort_thd, wsrep_debug, wsrep_convert_LOCK_to_trx, (wsrep_on_fun)wsrep_on); @@ -1685,6 +1697,11 @@ static int wsrep_TOI_begin(THD *thd, const char *db_, const char *table_, case SQLCOM_DROP_TABLE: buf_err= wsrep_drop_table_query(thd, &buf, &buf_len); break; + case SQLCOM_KILL: + WSREP_DEBUG("KILL as TOI: %s", thd->query()); + buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), + &buf, &buf_len); + break; case SQLCOM_CREATE_ROLE: if (sp_process_definer(thd)) { @@ -2005,14 +2022,14 @@ bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx, request_thd, granted_thd); ticket->wsrep_report(wsrep_debug); - mysql_mutex_lock(&granted_thd->LOCK_thd_data); + wsrep_thd_LOCK(granted_thd); if (granted_thd->wsrep_exec_mode == TOTAL_ORDER || granted_thd->wsrep_exec_mode == REPL_RECV) { WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", schema, schema_len, request_thd, granted_thd); ticket->wsrep_report(true); - mysql_mutex_unlock(&granted_thd->LOCK_thd_data); + wsrep_thd_UNLOCK(granted_thd); ret= true; } else if (granted_thd->lex->sql_command == SQLCOM_FLUSH || @@ -2020,7 +2037,7 @@ bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx, { WSREP_DEBUG("BF thread waiting for FLUSH"); ticket->wsrep_report(wsrep_debug); - mysql_mutex_unlock(&granted_thd->LOCK_thd_data); + wsrep_thd_UNLOCK(granted_thd); ret= false; } else @@ -2045,8 +2062,10 @@ bool wsrep_grant_mdl_exception(MDL_context *requestor_ctx, ticket->wsrep_report(true); } - mysql_mutex_unlock(&granted_thd->LOCK_thd_data); - wsrep_abort_thd((void *) request_thd, (void *) granted_thd, 1); + /* This will call wsrep_abort_transaction so we should hold + THD::LOCK_thd_data to protect victim from concurrent usage + or disconnect or delete. */ + wsrep_abort_thd((void *) request_thd, (void *) granted_thd, true); ret= false; } } @@ -2221,6 +2240,7 @@ error: static bool abort_replicated(THD *thd) { bool ret_code= false; + wsrep_thd_LOCK(thd); if (thd->wsrep_query_state== QUERY_COMMITTING) { WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id)); @@ -2228,6 +2248,8 @@ static bool abort_replicated(THD *thd) (void)wsrep_abort_thd(thd, thd, TRUE); ret_code= true; } + else + wsrep_thd_UNLOCK(thd); return ret_code; } @@ -2274,6 +2296,8 @@ static bool have_client_connections() (longlong) tmp->thread_id)); if (is_client_connection(tmp) && tmp->killed == KILL_CONNECTION) { + WSREP_DEBUG("Informing thread %lld that it's time to die", + (longlong)tmp->thread_id); (void)abort_replicated(tmp); return true; } @@ -2358,6 +2382,8 @@ void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd) { DBUG_PRINT("quit",("Informing thread %lld that it's time to die", (longlong) tmp->thread_id)); + WSREP_DEBUG("Informing thread %lld that it's time to die", + (longlong)tmp->thread_id); /* We skip slave threads & scheduler on this first loop through. */ if (!is_client_connection(tmp)) continue; @@ -2374,15 +2400,18 @@ void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd) continue; } - /* replicated transactions must be skipped */ + /* replicated transactions must be skipped and aborted + with wsrep_abort_thd. */ if (abort_replicated(tmp)) continue; WSREP_DEBUG("closing connection %lld", (longlong) tmp->thread_id); /* - instead of wsrep_close_thread() we do now soft kill by THD::awake - */ + instead of wsrep_close_thread() we do now soft kill by + THD::awake(). Here also victim needs to be protected from + concurrent usage or disconnect or delete. + */ tmp->awake(KILL_CONNECTION); } mysql_mutex_unlock(&LOCK_thread_count); @@ -2398,7 +2427,6 @@ void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd) I_List_iterator<THD> it2(threads); while ((tmp=it2++)) { -#ifndef __bsdi__ // Bug in BSDI kernel if (is_client_connection(tmp) && !abort_replicated(tmp) && !is_replaying_connection(tmp) && @@ -2407,7 +2435,6 @@ void wsrep_close_client_connections(my_bool wait_to_end, THD *except_caller_thd) WSREP_INFO("killing local connection: %lld", (longlong) tmp->thread_id); close_connection(tmp,0); } -#endif } DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); @@ -2594,7 +2621,8 @@ extern "C" void wsrep_thd_set_query_state( void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state) { - if (WSREP(thd)) thd->wsrep_conflict_state= state; + mysql_mutex_assert_owner(&thd->LOCK_thd_data); + thd->wsrep_conflict_state= state; } @@ -2662,11 +2690,13 @@ wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd) void wsrep_thd_LOCK(THD *thd) { mysql_mutex_lock(&thd->LOCK_thd_data); + mysql_mutex_lock(&thd->LOCK_thd_kill); } void wsrep_thd_UNLOCK(THD *thd) { + mysql_mutex_unlock(&thd->LOCK_thd_kill); mysql_mutex_unlock(&thd->LOCK_thd_data); } @@ -2747,6 +2777,11 @@ extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) { if (signal) { + /* Here we should hold THD::LOCK_thd_data to + protect from concurrent usage and + THD::LOCK_thd_kill from disconnect or delete */ + mysql_mutex_assert_owner(&thd->LOCK_thd_data); + mysql_mutex_assert_owner(&thd->LOCK_thd_kill); thd->awake_no_mutex(KILL_QUERY); } else diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 6fd57edc692..f8eaa14d176 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 Codership Oy <info@codership.com> +/* Copyright (C) 2013-2021 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -803,10 +803,13 @@ my_bool wsrep_thd_is_local(void *thd_ptr, my_bool sync) int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) { - THD *victim_thd = (THD *) victim_thd_ptr; - THD *bf_thd = (THD *) bf_thd_ptr; + THD *victim_thd= (THD *) victim_thd_ptr; + THD *bf_thd= (THD *) bf_thd_ptr; DBUG_ENTER("wsrep_abort_thd"); + mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data); + mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill); + if ( (WSREP(bf_thd) || ( (WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) && bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) && @@ -820,6 +823,7 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) "aborted. Ignoring.", (bf_thd) ? (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id); + wsrep_thd_UNLOCK(victim_thd); DBUG_RETURN(1); } @@ -830,6 +834,7 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) else { WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd); + wsrep_thd_UNLOCK(victim_thd); } DBUG_RETURN(1); |