diff options
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 79 | ||||
-rw-r--r-- | storage/innobase/include/lock0lock.h | 5 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 46 |
3 files changed, 95 insertions, 35 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4440fe62fa5..7ffbe3fe374 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -18075,41 +18075,53 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id) { bool aborting= false; wsrep_thd_LOCK(vthd); - if (trx_t *vtrx= thd_to_trx(vthd)) + trx_t *vtrx= thd_to_trx(vthd); + if (vtrx) { lock_sys.wr_lock(SRW_LOCK_CALL); mysql_mutex_lock(&lock_sys.wait_mutex); vtrx->mutex_lock(); - if (vtrx->id == trx_id && vtrx->state == TRX_STATE_ACTIVE) + /* victim transaction is either active or prepared, if it has already + proceeded to replication phase */ + if (vtrx->id == trx_id) { - WSREP_LOG_CONFLICT(bf_thd, vthd, TRUE); - WSREP_DEBUG("Aborter BF trx_id: " TRX_ID_FMT " thread: %ld " - "seqno: %lld client_state: %s " - "client_mode: %s transaction_mode: %s query: %s", - bf_trx->id, - 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(vthd, false) ? "BF" : "normal", - vtrx->id, - thd_get_thread_id(vthd), - wsrep_thd_trx_seqno(vthd), - wsrep_thd_client_state_str(vthd), - wsrep_thd_client_mode_str(vthd), - wsrep_thd_transaction_state_str(vthd), - wsrep_thd_query(vthd)); - /* Mark transaction as a victim for Galera abort */ - vtrx->lock.was_chosen_as_deadlock_victim.fetch_or(2); - if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd)) - aborting= true; - else - WSREP_DEBUG("kill transaction skipped due to wsrep_aborter set"); + switch (vtrx->state) { + default: + break; + case TRX_STATE_PREPARED: + if (!wsrep_is_wsrep_xid(vtrx->xid)) + break; + /* fall through */ + case TRX_STATE_ACTIVE: + WSREP_LOG_CONFLICT(bf_thd, vthd, TRUE); + WSREP_DEBUG("Aborter BF trx_id: " TRX_ID_FMT " thread: %ld " + "seqno: %lld client_state: %s " + "client_mode: %s transaction_mode: %s query: %s", + bf_trx->id, + 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(vthd, false) ? "BF" : "normal", + vtrx->id, + thd_get_thread_id(vthd), + wsrep_thd_trx_seqno(vthd), + wsrep_thd_client_state_str(vthd), + wsrep_thd_client_mode_str(vthd), + wsrep_thd_transaction_state_str(vthd), + wsrep_thd_query(vthd)); + /* Mark transaction as a victim for Galera abort */ + vtrx->lock.was_chosen_as_deadlock_victim.fetch_or(2); + if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd)) + aborting= true; + else + WSREP_DEBUG("kill transaction skipped due to wsrep_aborter set"); + } } lock_sys.wr_unlock(); mysql_mutex_unlock(&lock_sys.wait_mutex); @@ -18118,6 +18130,11 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id) wsrep_thd_UNLOCK(vthd); if (aborting) { + /* if victim is waiting for some other lock, we have to cancel + that waiting + */ + lock_sys.cancel_lock_wait_for_trx(vtrx); + DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort"); wsrep_thd_bf_abort(bf_thd, vthd, true); } @@ -18146,7 +18163,7 @@ wsrep_abort_transaction( ut_ad(bf_thd); ut_ad(victim_thd); - trx_t* victim_trx = thd_to_trx(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), diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 8e38b99c121..b96f54e03a3 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -859,6 +859,11 @@ public: @param id page to be discarded @param page whether to discard also from lock_sys.prdt_hash */ void prdt_page_free_from_discard(const page_id_t id, bool all= false); + +#ifdef WITH_WSREP + /** Cancel possible lock waiting for a transaction */ + static void cancel_lock_wait_for_trx(trx_t *trx); +#endif /* WITH_WSREP */ }; /** The lock system */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 756902690c2..62582e61b0b 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -921,8 +921,13 @@ func_exit: dict_table_t *table= wait_lock->un_member.tab_lock.table; for (lock_t *lock= UT_LIST_GET_FIRST(table->locks); lock; lock= UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock)) - if (lock->trx != trx) + /* if victim has also BF status, but has earlier seqno, we have to wait */ + if (lock->trx != trx && + !(wsrep_thd_is_BF(lock->trx->mysql_thd, false) && + wsrep_thd_order_before(lock->trx->mysql_thd, trx->mysql_thd))) + { victims.emplace(lock->trx); + } } else { @@ -936,8 +941,13 @@ func_exit: if (!lock_rec_get_nth_bit(lock, heap_no)) lock= lock_rec_get_next(heap_no, lock); do - if (lock->trx != trx) + /* if victim has also BF status, but has earlier seqno, we have to wait */ + if (lock->trx != trx && + !(wsrep_thd_is_BF(lock->trx->mysql_thd, false) && + wsrep_thd_order_before(lock->trx->mysql_thd, trx->mysql_thd))) + { victims.emplace(lock->trx); + } while ((lock= lock_rec_get_next(heap_no, lock))); } } @@ -5362,6 +5372,21 @@ static void lock_cancel_waiting_and_release(lock_t *lock) lock_wait_end(trx); trx->mutex_unlock(); } +#ifdef WITH_WSREP +void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx) +{ + lock_sys.wr_lock(SRW_LOCK_CALL); + mysql_mutex_lock(&lock_sys.wait_mutex); + if (lock_t *lock= trx->lock.wait_lock) + { + /* check if victim is still waiting */ + if (lock->is_waiting()) + lock_cancel_waiting_and_release(lock); + } + lock_sys.wr_unlock(); + mysql_mutex_unlock(&lock_sys.wait_mutex); +} +#endif /* WITH_WSREP */ /** Cancel a waiting lock request. @param lock waiting lock request @@ -5758,8 +5783,15 @@ namespace Deadlock If current_trx=false, a concurrent commit is protected by both lock_sys.latch and lock_sys.wait_mutex. */ const undo_no_t trx_weight= TRX_WEIGHT(trx) | - (trx->mysql_thd && thd_has_edited_nontrans_tables(trx->mysql_thd) + (trx->mysql_thd && +#ifdef WITH_WSREP + (thd_has_edited_nontrans_tables(trx->mysql_thd) || + (trx->is_wsrep() && wsrep_thd_is_BF(trx->mysql_thd, false))) +#else + thd_has_edited_nontrans_tables(trx->mysql_thd) +#endif /* WITH_WSREP */ ? 1ULL << 63 : 0); + trx_t *victim= nullptr; undo_no_t victim_weight= ~0ULL; unsigned victim_pos= 0, trx_pos= 0; @@ -5782,7 +5814,13 @@ namespace Deadlock { next= next->lock.wait_trx; const undo_no_t next_weight= TRX_WEIGHT(next) | - (next->mysql_thd && thd_has_edited_nontrans_tables(next->mysql_thd) + (next->mysql_thd && +#ifdef WITH_WSREP + (thd_has_edited_nontrans_tables(next->mysql_thd) || + (next->is_wsrep() && wsrep_thd_is_BF(next->mysql_thd, false))) +#else + thd_has_edited_nontrans_tables(next->mysql_thd) +#endif /* WITH_WSREP */ ? 1ULL << 63 : 0); if (next_weight < victim_weight) { |