diff options
Diffstat (limited to 'storage/innobase/handler/ha_innodb.cc')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 225 |
1 files changed, 126 insertions, 99 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 9188b2c8f47..23df38c64ab 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5193,7 +5193,7 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels) { ut_ad(trx->mysql_thd == thd); #ifdef WITH_WSREP - if (trx->is_wsrep() && wsrep_thd_is_aborting(thd)) + if (wsrep_thd_is_aborting(thd) || trx->lock.was_chosen_as_wsrep_victim) /* 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. */ @@ -5203,6 +5203,8 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels) if (lock_t *lock= trx->lock.wait_lock) { trx_mutex_enter(trx); + if (trx->is_wsrep() && wsrep_thd_is_aborting(thd)) + trx->lock.was_chosen_as_deadlock_victim= TRUE; lock_cancel_waiting_and_release(lock); trx_mutex_exit(trx); } @@ -18604,6 +18606,40 @@ static struct st_mysql_storage_engine innobase_storage_engine= #ifdef WITH_WSREP +static +void +wsrep_kill_victim( + MYSQL_THD const bf_thd, + MYSQL_THD thd, + trx_t* victim_trx, + my_bool signal) +{ + DBUG_ENTER("wsrep_kill_victim"); + + /* Mark transaction as a victim for Galera abort */ + victim_trx->lock.was_chosen_as_wsrep_victim= true; + if (wsrep_thd_set_wsrep_aborter(bf_thd, thd)) + { + WSREP_DEBUG("innodb kill transaction skipped due to wsrep_aborter set"); + wsrep_thd_UNLOCK(thd); + DBUG_VOID_RETURN; + } + + if (wsrep_thd_bf_abort(bf_thd, thd, signal)) + { + lock_t* wait_lock= victim_trx->lock.wait_lock; + if (wait_lock) + { + DBUG_ASSERT(victim_trx->is_wsrep()); + WSREP_DEBUG("victim has wait flag: %lu", thd_get_thread_id(thd)); + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + lock_cancel_waiting_and_release(wait_lock); + } + } + + DBUG_VOID_RETURN; +} + /** This function is used to kill one transaction. This transaction was open on this node (not-yet-committed), and a @@ -18627,87 +18663,65 @@ comparison as in the local certification failure. @param[in] bf_thd Brute force (BF) thread @param[in,out] victim_trx Vimtim trx to be killed @param[in] signal Should victim be signaled */ -UNIV_INTERN void wsrep_innobase_kill_one_trx( - THD* bf_thd, + MYSQL_THD const bf_thd, trx_t *victim_trx, - bool signal) + my_bool signal) { - ut_ad(bf_thd); - ut_ad(victim_trx); - ut_ad(lock_mutex_own()); - ut_ad(trx_mutex_own(victim_trx)); - - DBUG_ENTER("wsrep_innobase_kill_one_trx"); - - THD *thd= (THD *) victim_trx->mysql_thd; - ut_ad(thd); - /* Note that bf_trx might not exist here e.g. on MDL conflict - case (test: galera_concurrent_ctas). Similarly, BF thread - could be also acquiring MDL-lock causing victim to be - aborted. However, we have not yet called innobase_trx_init() - for BF transaction (test: galera_many_columns)*/ - trx_t* bf_trx= thd_to_trx(bf_thd); - DBUG_ASSERT(wsrep_on(bf_thd)); - - wsrep_thd_LOCK(thd); - - WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); - - WSREP_DEBUG("Aborter %s trx_id: " TRX_ID_FMT " thread: %ld " - "seqno: %lld client_state: %s client_mode: %s transaction_mode: %s " - "query: %s", - wsrep_thd_is_BF(bf_thd, false) ? "BF" : "normal", - bf_trx ? bf_trx->id : TRX_ID_MAX, - thd_get_thread_id(bf_thd), - wsrep_thd_trx_seqno(bf_thd), - wsrep_thd_client_state_str(bf_thd), - wsrep_thd_client_mode_str(bf_thd), - wsrep_thd_transaction_state_str(bf_thd), - wsrep_thd_query(bf_thd)); - - WSREP_DEBUG("Victim %s trx_id: " TRX_ID_FMT " thread: %ld " - "seqno: %lld client_state: %s client_mode: %s transaction_mode: %s " - "query: %s", - wsrep_thd_is_BF(thd, false) ? "BF" : "normal", - victim_trx->id, - thd_get_thread_id(thd), - wsrep_thd_trx_seqno(thd), - wsrep_thd_client_state_str(thd), - wsrep_thd_client_mode_str(thd), - wsrep_thd_transaction_state_str(thd), - wsrep_thd_query(thd)); - - /* Mark transaction as a victim for Galera abort */ - victim_trx->lock.was_chosen_as_wsrep_victim= true; - if (wsrep_thd_set_wsrep_aborter(bf_thd, thd)) - { - WSREP_DEBUG("innodb kill transaction skipped due to wsrep_aborter set"); - wsrep_thd_UNLOCK(thd); - DBUG_VOID_RETURN; - } + ut_ad(bf_thd); + ut_ad(victim_trx); + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(victim_trx)); - /* Note that we need to release this as it will be acquired - below in wsrep-lib */ - wsrep_thd_UNLOCK(thd); - DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort"); + DBUG_ENTER("wsrep_innobase_kill_one_trx"); + THD *thd= (THD *) victim_trx->mysql_thd; + /* Note that bf_trx might not exist here e.g. on MDL conflict + case (test: galera_concurrent_ctas).*/ + trx_t* bf_trx= (trx_t*)thd_to_trx(bf_thd); - if (wsrep_thd_bf_abort(bf_thd, thd, signal)) - { - lock_t* wait_lock = victim_trx->lock.wait_lock; - if (wait_lock) { - DBUG_ASSERT(victim_trx->is_wsrep()); - WSREP_DEBUG("victim has wait flag: %lu", - thd_get_thread_id(thd)); - - WSREP_DEBUG("canceling wait lock"); - victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; - lock_cancel_waiting_and_release(wait_lock); - } - } + if (!thd) + { + WSREP_WARN("no THD for trx: " TRX_ID_FMT, victim_trx->id); + DBUG_VOID_RETURN; + } - DBUG_VOID_RETURN; + /* Here we need to lock THD::LOCK_thd_data to protect from + concurrent usage or disconnect or delete. */ + DEBUG_SYNC(bf_thd, "wsrep_before_BF_victim_lock"); + wsrep_thd_LOCK(thd); + DEBUG_SYNC(bf_thd, "wsrep_after_BF_victim_lock"); + + WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); + + WSREP_DEBUG("wsrep_innobase_kill_one_trx: Aborter %s " + "trx_id: " TRX_ID_FMT " thread: %ld " + "seqno: %lld client_state: %s client_mode: %s " + "trx_state %s query: %s", + wsrep_thd_is_BF(bf_thd, false) ? "BF" : "normal", + bf_trx ? bf_trx->id : TRX_ID_MAX, + thd_get_thread_id(bf_thd), + wsrep_thd_trx_seqno(bf_thd), + wsrep_thd_client_state_str(bf_thd), + wsrep_thd_client_mode_str(bf_thd), + wsrep_thd_transaction_state_str(bf_thd), + wsrep_thd_query(bf_thd)); + + WSREP_DEBUG("wsrep_innobase_kill_one_trx: Victim %s " + "trx_id: " TRX_ID_FMT " thread: %ld " + "seqno: %lld client_state: %s client_mode: %s " + "trx_state %s query: %s", + wsrep_thd_is_BF(thd, false) ? "BF" : "normal", + victim_trx->id, + thd_get_thread_id(thd), + wsrep_thd_trx_seqno(thd), + wsrep_thd_client_state_str(thd), + wsrep_thd_client_mode_str(thd), + wsrep_thd_transaction_state_str(thd), + wsrep_thd_query(thd)); + + wsrep_kill_victim(bf_thd, thd, victim_trx, signal); + DBUG_VOID_RETURN; } /** This function forces the victim transaction to abort. Aborting the @@ -18727,30 +18741,43 @@ wsrep_abort_transaction( THD *victim_thd, my_bool signal) { - DBUG_ENTER("wsrep_abort_transaction"); - ut_ad(bf_thd); - ut_ad(victim_thd); - - trx_t* victim_trx = thd_to_trx(victim_thd); - - WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s", - wsrep_thd_query(bf_thd), - wsrep_thd_query(victim_thd), - wsrep_thd_transaction_state_str(victim_thd)); - - if (victim_trx) { - lock_mutex_enter(); - trx_mutex_enter(victim_trx); - wsrep_innobase_kill_one_trx(bf_thd, victim_trx, signal); - trx_mutex_exit(victim_trx); - lock_mutex_exit(); - wsrep_srv_conc_cancel_wait(victim_trx); - DBUG_VOID_RETURN; - } else { - wsrep_thd_bf_abort(bf_thd, victim_thd, signal); - } - - DBUG_VOID_RETURN; + /* Note that victim thd is protected with + THD::LOCK_thd_data and THD::LOCK_thd_kill here. */ + trx_t* victim_trx= thd_to_trx(victim_thd); + trx_t* bf_trx= thd_to_trx(bf_thd); + WSREP_DEBUG("wsrep_abort_transaction: BF:" + " thread %ld client_state %s client_mode %s" + " trans_state %s query %s trx " TRX_ID_FMT, + thd_get_thread_id(bf_thd), + wsrep_thd_client_state_str(bf_thd), + wsrep_thd_client_mode_str(bf_thd), + wsrep_thd_transaction_state_str(bf_thd), + wsrep_thd_query(bf_thd), + bf_trx ? bf_trx->id : 0); + + WSREP_DEBUG("wsrep_abort_transaction: victim:" + " thread %ld client_state %s client_mode %s" + " trans_state %s query %s trx " TRX_ID_FMT, + thd_get_thread_id(victim_thd), + wsrep_thd_client_state_str(victim_thd), + wsrep_thd_client_mode_str(victim_thd), + wsrep_thd_transaction_state_str(victim_thd), + wsrep_thd_query(victim_thd), + victim_trx ? victim_trx->id : 0); + + if (victim_trx) + { + lock_mutex_enter(); + trx_mutex_enter(victim_trx); + wsrep_kill_victim(bf_thd, victim_thd, victim_trx, signal); + lock_mutex_exit(); + trx_mutex_exit(victim_trx); + wsrep_srv_conc_cancel_wait(victim_trx); + } + else + { + wsrep_thd_bf_abort(bf_thd, victim_thd, signal); + } } static |