diff options
-rw-r--r-- | sql/sql_class.cc | 62 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 32 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 1 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 4 |
5 files changed, 57 insertions, 44 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1cc9a6a61d3..f4fd27ad5d1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1531,16 +1531,32 @@ void THD::reset_db(const LEX_CSTRING *new_db) /* Do operations that may take a long time */ -void THD::cleanup(void) +void THD::cleanup(bool have_mutex) { DBUG_ENTER("THD::cleanup"); DBUG_ASSERT(cleanup_done == 0); - set_killed(KILL_CONNECTION); + if (have_mutex) + set_killed_no_mutex(KILL_CONNECTION,0,0); + else + set_killed(KILL_CONNECTION); #ifdef WITH_WSREP if (wsrep_cs().state() != wsrep::client_state::s_none) { + // Below wsrep-lib function will take THD::LOCK_thd_data + // I do not like this, but at the moment there is no + // alternative. + if (have_mutex) + { + mysql_mutex_unlock(&LOCK_thd_kill); + mysql_mutex_unlock(&LOCK_thd_data); + } wsrep_cs().cleanup(); + if (have_mutex) + { + mysql_mutex_lock(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_kill); + } } wsrep_client_thread= false; #endif /* WITH_WSREP */ @@ -1614,6 +1630,28 @@ void THD::cleanup(void) void THD::free_connection() { DBUG_ASSERT(free_connection_done == 0); + /* Make sure threads are not available via server_threads. */ + assert_not_linked(); + + /* + Other threads may have a lock on THD::LOCK_thd_data or + THD::LOCK_thd_kill to ensure that this THD is not deleted + while they access it. The following mutex_lock ensures + that no one else is using this THD and it's now safe to + continue. + + For example consider KILL-statement execution on + sql_parse.cc kill_one_thread() that will use + THD::LOCK_thd_data to protect victim thread during + THD::awake(). + */ + mysql_mutex_lock(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_kill); + +#ifdef WITH_WSREP + delete wsrep_rgi; + wsrep_rgi= 0; +#endif my_free((char*) db.str); db= null_clex_str; #ifndef EMBEDDED_LIBRARY @@ -1622,8 +1660,8 @@ void THD::free_connection() net.vio= 0; net_end(&net); #endif - if (!cleanup_done) - cleanup(); + if (!cleanup_done) + cleanup(true); // We have locked THD::LOCK_thd_kill ha_close_connection(this); plugin_thdvar_cleanup(this); mysql_audit_free_thd(this); @@ -1635,6 +1673,8 @@ void THD::free_connection() profiling.restart(); // Reset profiling #endif debug_sync_reset_thread(this); + mysql_mutex_unlock(&LOCK_thd_kill); + mysql_mutex_unlock(&LOCK_thd_data); } /* @@ -1690,24 +1730,10 @@ THD::~THD() if (!status_in_global) add_status_to_global(); - /* - Other threads may have a lock on LOCK_thd_kill to ensure that this - THD is not deleted while they access it. The following mutex_lock - ensures that no one else is using this THD and it's now safe to delete - */ - if (WSREP_NNULL(this)) mysql_mutex_lock(&LOCK_thd_data); - mysql_mutex_lock(&LOCK_thd_kill); - mysql_mutex_unlock(&LOCK_thd_kill); - if (WSREP_NNULL(this)) mysql_mutex_unlock(&LOCK_thd_data); - if (!free_connection_done) free_connection(); #ifdef WITH_WSREP - if (wsrep_rgi != NULL) { - delete wsrep_rgi; - wsrep_rgi = NULL; - } mysql_cond_destroy(&COND_wsrep_thd); #endif mdl_context.destroy(); diff --git a/sql/sql_class.h b/sql/sql_class.h index 6bd08343c9e..3e8211389ce 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3462,7 +3462,7 @@ public: void update_all_stats(); void update_stats(void); void change_user(void); - void cleanup(void); + void cleanup(bool have_mutex=false); void cleanup_after_query(); void free_connection(); void reset_for_reuse(); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c4083f8aeb9..c106eda42c3 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4452,36 +4452,22 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels) if (trx_t* trx= thd_to_trx(thd)) { + ut_ad(trx->mysql_thd == thd); #ifdef WITH_WSREP + /* If victim has been signaled by BF thread and/or aborting is already + progressing, following query aborting is not necessary any more. + Also, BF thread should own trx mutex for the victim. */ if (trx->is_wsrep() && wsrep_thd_is_aborting(thd)) - /* if victim has been signaled by BF thread and/or aborting is already - progressing, following query aborting is not necessary any more. - Also, BF thread should own trx mutex for the victim. */ DBUG_VOID_RETURN; #endif /* WITH_WSREP */ lock_sys.mutex_lock(); - trx_sys.trx_list.freeze(); - trx->mutex.wr_lock(); - /* It is possible that innobase_close_connection() is concurrently - being executed on our victim. Even if the trx object is later - reused for another client connection or a background transaction, - its trx->mysql_thd will differ from our thd. - - trx_sys.trx_list is thread-safe. It's freezed to 'protect' - trx_t. However, trx_t::commit_in_memory() changes a trx_t::state - of autocommit non-locking transactions without any protection. - - At this point, trx may have been reallocated for another client - connection, or for a background operation. In that case, either - trx_t::state or trx_t::mysql_thd should not match our expectations. */ - bool cancel= trx->mysql_thd == thd && trx->state == TRX_STATE_ACTIVE && - !trx->lock.was_chosen_as_deadlock_victim; - trx_sys.trx_list.unfreeze(); - if (!cancel); - else if (lock_t *lock= trx->lock.wait_lock) + if (lock_t *lock= trx->lock.wait_lock) + { + trx->mutex.wr_lock(); lock_cancel_waiting_and_release(lock); + trx->mutex.wr_unlock(); + } lock_sys.mutex_unlock(); - trx->mutex.wr_unlock(); } DBUG_VOID_RETURN; diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 66644865309..a5536b17a94 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -5600,6 +5600,7 @@ lock_cancel_waiting_and_release( que_thr_t* thr; lock_sys.mutex_assert_locked(); + ut_ad(lock->trx->state == TRX_STATE_ACTIVE); lock->trx->lock.cancel = true; diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 50a78adcf53..7eb8493deaa 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -405,7 +405,7 @@ void trx_t::free() MEM_NOACCESS(&n_ref, sizeof n_ref); /* do not poison mutex */ MEM_NOACCESS(&id, sizeof id); - /* state is accessed by innobase_kill_connection() */ + MEM_NOACCESS(&state, sizeof state); MEM_NOACCESS(&is_recovered, sizeof is_recovered); /* wsrep is accessed by innobase_kill_connection() */ read_view.mem_noaccess(); @@ -425,7 +425,7 @@ void trx_t::free() MEM_NOACCESS(&start_time_micro, sizeof start_time_micro); MEM_NOACCESS(&commit_lsn, sizeof commit_lsn); MEM_NOACCESS(&table_id, sizeof table_id); - /* mysql_thd is accessed by innobase_kill_connection() */ + MEM_NOACCESS(&mysql_thd, sizeof mysql_thd); MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name); MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset); MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use); |