diff options
Diffstat (limited to 'storage/innobase/lock/lock0lock.cc')
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 157 |
1 files changed, 76 insertions, 81 deletions
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index b397735e997..7e7558aff32 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -72,44 +72,39 @@ extern "C" void thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd); extern "C" int thd_need_wait_reports(const MYSQL_THD thd); extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd); -/** Print info of a table lock. +/** Pretty-print a table lock. @param[in,out] file output stream @param[in] lock table lock */ -static -void -lock_table_print(FILE* file, const lock_t* lock); +static void lock_table_print(FILE* file, const lock_t* lock); -/** Print info of a record lock. +/** Pretty-print a record lock. @param[in,out] file output stream -@param[in] lock record lock */ -static -void -lock_rec_print(FILE* file, const lock_t* lock); +@param[in] lock record lock +@param[in,out] mtr mini-transaction for accessing the record */ +static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr); /** Deadlock checker. */ class DeadlockChecker { public: - /** Checks if a joining lock request results in a deadlock. If - a deadlock is found this function will resolve the deadlock - by choosing a victim transaction and rolling it back. It - will attempt to resolve all deadlocks. The returned transaction - id will be the joining transaction id or 0 if some other - transaction was chosen as a victim and rolled back or no - deadlock found. - - @param lock lock the transaction is requesting - @param trx transaction requesting the lock - - @return id of transaction chosen as victim or 0 */ - static const trx_t* check_and_resolve( - const lock_t* lock, - trx_t* trx); + /** Check if a joining lock request results in a deadlock. + If a deadlock is found, we will resolve the deadlock by + choosing a victim transaction and rolling it back. + We will attempt to resolve all deadlocks. + + @param[in] lock the lock request + @param[in,out] trx transaction requesting the lock + + @return trx if it was chosen as victim + @retval NULL if another victim was chosen, + or there is no deadlock (any more) */ + static const trx_t* check_and_resolve(const lock_t* lock, trx_t* trx); private: /** Do a shallow copy. Default destructor OK. @param trx the start transaction (start node) @param wait_lock lock that a transaction wants - @param mark_start visited node counter */ + @param mark_start visited node counter + @param report_waiters whether to call thd_rpl_deadlock_check() */ DeadlockChecker( const trx_t* trx, const lock_t* wait_lock, @@ -751,11 +746,12 @@ lock_rec_has_to_wait( thread, we need to look at trx ordering and lock types */ if (wsrep_thd_is_BF(trx->mysql_thd, FALSE) && wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + mtr_t mtr; if (wsrep_debug) { ib::info() << "BF-BF lock conflict, locking: " << for_locking; - lock_rec_print(stderr, lock2); + lock_rec_print(stderr, lock2, mtr); ib::info() << " SQL1: " << wsrep_thd_query(trx->mysql_thd) << " SQL2: " @@ -777,7 +773,7 @@ lock_rec_has_to_wait( << " locked " << wsrep_thd_transaction_state_str( lock2->trx->mysql_thd); - lock_rec_print(stderr, lock2); + lock_rec_print(stderr, lock2, mtr); ib::info() << " SQL1: " << wsrep_thd_query(trx->mysql_thd) << " SQL2: " @@ -1100,6 +1096,7 @@ wsrep_kill_victim( } my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE); + mtr_t mtr; if ((!bf_other) || (wsrep_thd_order_before( @@ -1127,7 +1124,7 @@ wsrep_kill_victim( ib::info() << "*** WAITING FOR THIS LOCK TO BE GRANTED:"; if (lock_get_type(lock) == LOCK_REC) { - lock_rec_print(stderr, lock); + lock_rec_print(stderr, lock, mtr); } else { lock_table_print(stderr, lock); } @@ -1293,6 +1290,7 @@ wsrep_print_wait_locks( lock_t* c_lock) /* conflicting lock to print */ { if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) { + mtr_t mtr; ib::info() << "WSREP: c_lock != wait lock"; ib::info() << " SQL: " << wsrep_thd_query(c_lock->trx->mysql_thd); @@ -1300,13 +1298,14 @@ wsrep_print_wait_locks( if (lock_get_type_low(c_lock) & LOCK_TABLE) { lock_table_print(stderr, c_lock); } else { - lock_rec_print(stderr, c_lock); + lock_rec_print(stderr, c_lock, mtr); } if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) { lock_table_print(stderr, c_lock->trx->lock.wait_lock); } else { - lock_rec_print(stderr, c_lock->trx->lock.wait_lock); + lock_rec_print(stderr, c_lock->trx->lock.wait_lock, + mtr); } } } @@ -1519,11 +1518,7 @@ If only one of them is a wait lock, it has lower priority. If either is a high priority transaction, the lock has higher priority. Otherwise, the one with an older transaction has higher priority. @returns true if lock1 has higher priority, false otherwise. */ -static -bool -has_higher_priority( - lock_t *lock1, - lock_t *lock2) +static bool has_higher_priority(lock_t *lock1, lock_t *lock2) { if (lock1 == NULL) { return false; @@ -1730,10 +1725,7 @@ lock_rec_enqueue_waiting( lock_prdt_set_prdt(lock, prdt); } - if ( -#ifdef UNIV_DEBUG - const trx_t* victim = -#endif + if (ut_d(const trx_t* victim =) DeadlockChecker::check_and_resolve(lock, trx)) { ut_ad(victim == trx); lock_reset_lock_and_trx_wait(lock); @@ -1757,7 +1749,7 @@ lock_rec_enqueue_waiting( trx->lock.que_state = TRX_QUE_LOCK_WAIT; trx->lock.was_chosen_as_deadlock_victim = false; - trx->lock.wait_started = ut_time(); + trx->lock.wait_started = time(NULL); ut_a(que_thr_stop(thr)); @@ -2067,12 +2059,13 @@ lock_rec_has_to_wait_in_queue( if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) { if (wsrep_debug) { + mtr_t mtr; ib::info() << "WSREP: waiting BF trx: " << ib::hex(wait_lock->trx->id) << " query: " << wsrep_thd_query(wait_lock->trx->mysql_thd); - lock_rec_print(stderr, wait_lock); + lock_rec_print(stderr, wait_lock, mtr); ib::info() << "WSREP: do not wait another BF trx: " << ib::hex(lock->trx->id) << " query: " << wsrep_thd_query(lock->trx->mysql_thd); - lock_rec_print(stderr, lock); + lock_rec_print(stderr, lock, mtr); } /* don't wait for another BF lock */ continue; @@ -3768,7 +3761,7 @@ lock_table_enqueue_waiting( ); const trx_t* victim_trx = - DeadlockChecker::check_and_resolve(lock, trx); + DeadlockChecker::check_and_resolve(lock, trx); if (victim_trx != 0) { ut_ad(victim_trx == trx); @@ -3789,7 +3782,7 @@ lock_table_enqueue_waiting( trx->lock.que_state = TRX_QUE_LOCK_WAIT; - trx->lock.wait_started = ut_time(); + trx->lock.wait_started = time(NULL); trx->lock.was_chosen_as_deadlock_victim = false; ut_a(que_thr_stop(thr)); @@ -4427,20 +4420,14 @@ lock_table_print(FILE* file, const lock_t* lock) putc('\n', file); } -/** Print info of a record lock. +/** Pretty-print a record lock. @param[in,out] file output stream -@param[in] lock record lock */ -static -void -lock_rec_print(FILE* file, const lock_t* lock) +@param[in] lock record lock +@param[in,out] mtr mini-transaction for accessing the record */ +static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr) { ulint space; ulint page_no; - mtr_t mtr; - mem_heap_t* heap = NULL; - ulint offsets_[REC_OFFS_NORMAL_SIZE]; - ulint* offsets = offsets_; - rec_offs_init(offsets_); ut_ad(lock_mutex_own()); ut_a(lock_get_type_low(lock) == LOCK_REC); @@ -4480,13 +4467,16 @@ lock_rec_print(FILE* file, const lock_t* lock) fputs(" waiting", file); } - mtr_start(&mtr); - putc('\n', file); - const buf_block_t* block; + mem_heap_t* heap = NULL; + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + rec_offs_init(offsets_); - block = buf_page_try_get(page_id_t(space, page_no), &mtr); + mtr.start(); + const buf_block_t* block = buf_page_try_get(page_id_t(space, page_no), + &mtr); for (ulint i = 0; i < lock_rec_get_n_bits(lock); ++i) { @@ -4515,9 +4505,9 @@ lock_rec_print(FILE* file, const lock_t* lock) putc('\n', file); } - mtr_commit(&mtr); + mtr.commit(); - if (heap) { + if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } } @@ -4620,11 +4610,10 @@ lock_print_info_summary( /** Prints transaction lock wait and MVCC state. @param[in,out] file file where to print -@param[in] trx transaction */ +@param[in] trx transaction +@param[in] now current time */ void -lock_trx_print_wait_and_mvcc_state( - FILE* file, - const trx_t* trx) +lock_trx_print_wait_and_mvcc_state(FILE* file, const trx_t* trx, time_t now) { fprintf(file, "---"); @@ -4644,10 +4633,11 @@ lock_trx_print_wait_and_mvcc_state( fprintf(file, "------- TRX HAS BEEN WAITING %lu SEC" " FOR THIS LOCK TO BE GRANTED:\n", - (ulong) difftime(ut_time(), trx->lock.wait_started)); + (ulong) difftime(now, trx->lock.wait_started)); if (lock_get_type_low(trx->lock.wait_lock) == LOCK_REC) { - lock_rec_print(file, trx->lock.wait_lock); + mtr_t mtr; + lock_rec_print(file, trx->lock.wait_lock, mtr); } else { lock_table_print(file, trx->lock.wait_lock); } @@ -4665,6 +4655,7 @@ lock_trx_print_locks( FILE* file, /*!< in/out: File to write */ const trx_t* trx) /*!< in: current transaction */ { + mtr_t mtr; uint32_t i= 0; /* Iterate over the transaction's locks. */ for (lock_t *lock = UT_LIST_GET_FIRST(trx->lock.trx_locks); @@ -4672,7 +4663,7 @@ lock_trx_print_locks( lock = UT_LIST_GET_NEXT(trx_locks, lock)) { if (lock_get_type_low(lock) == LOCK_REC) { - lock_rec_print(file, lock); + lock_rec_print(file, lock, mtr); } else { ut_ad(lock_get_type_low(lock) & LOCK_TABLE); @@ -4693,20 +4684,21 @@ lock_trx_print_locks( /** Functor to display all transactions */ struct lock_print_info { - lock_print_info(FILE* file) : file(file) {} + lock_print_info(FILE* file, time_t now) : file(file), now(now) {} void operator()(const trx_t* trx) const { ut_ad(mutex_own(&trx_sys.mutex)); if (trx == purge_sys.query->trx) return; - lock_trx_print_wait_and_mvcc_state(file, trx); + lock_trx_print_wait_and_mvcc_state(file, trx, now); if (trx->will_lock && srv_print_innodb_lock_monitor) lock_trx_print_locks(file, trx); } FILE* const file; + const time_t now; }; /*********************************************************************//** @@ -4721,9 +4713,10 @@ lock_print_info_all_transactions( ut_ad(lock_mutex_own()); fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); + const time_t now = time(NULL); mutex_enter(&trx_sys.mutex); - ut_list_map(trx_sys.trx_list, lock_print_info(file)); + ut_list_map(trx_sys.trx_list, lock_print_info(file, now)); mutex_exit(&trx_sys.mutex); lock_mutex_exit(); @@ -6549,10 +6542,11 @@ DeadlockChecker::print(const lock_t* lock) ut_ad(lock_mutex_own()); if (lock_get_type_low(lock) == LOCK_REC) { - lock_rec_print(lock_latest_err_file, lock); + mtr_t mtr; + lock_rec_print(lock_latest_err_file, lock, mtr); if (srv_print_all_deadlocks) { - lock_rec_print(stderr, lock); + lock_rec_print(stderr, lock, mtr); } } else { lock_table_print(lock_latest_err_file, lock); @@ -6847,7 +6841,7 @@ DeadlockChecker::search() @param trx transaction rolled back @param lock lock trx wants */ void -DeadlockChecker::rollback_print(const trx_t* trx, const lock_t* lock) +DeadlockChecker::rollback_print(const trx_t* trx, const lock_t* lock) { ut_ad(lock_mutex_own()); @@ -6892,16 +6886,17 @@ DeadlockChecker::trx_rollback() trx_mutex_exit(trx); } -/** Checks if a joining lock request results in a deadlock. If a deadlock is -found this function will resolve the deadlock by choosing a victim transaction -and rolling it back. It will attempt to resolve all deadlocks. The returned -transaction id will be the joining transaction instance or NULL if some other -transaction was chosen as a victim and rolled back or no deadlock found. +/** Check if a joining lock request results in a deadlock. +If a deadlock is found, we will resolve the deadlock by +choosing a victim transaction and rolling it back. +We will attempt to resolve all deadlocks. -@param[in] lock lock the transaction is requesting -@param[in,out] trx transaction requesting the lock +@param[in] lock the lock request +@param[in,out] trx transaction requesting the lock -@return transaction instanace chosen as victim or 0 */ +@return trx if it was chosen as victim +@retval NULL if another victim was chosen, +or there is no deadlock (any more) */ const trx_t* DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx) { |