diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-04-29 16:23:21 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-04-29 17:49:55 +0300 |
commit | 810f014ca7a705381e110cb26649c528bc00f179 (patch) | |
tree | 3ad34657ca4a061bf35763fe75c1917ab2a1e757 /storage | |
parent | 092602ac9b650f921ec5380866d17d740f0eedb4 (diff) | |
download | mariadb-git-810f014ca7a705381e110cb26649c528bc00f179.tar.gz |
MDEV-18429: Simpler implementation
This reverts commit 61f370a3c9997d2c7067b8cf5d39c8ad67dde5aa
and implements a simpler fix that is straightforward to merge to 10.3.
lock_print_info: Renamed from PrintNotStarted. Dump the
entire contents of trx_sys->mysql_trx_list.
lock_print_info_rw_recovered: Like lock_print_info, but dump
only recovered transactions in trx_sys->rw_trx_list.
lock_print_info_all_transactions(): Dump both trx_sys->mysql_trx_list
and trx_sys->rw_trx_list.
TrxLockIterator, TrxListIterator, lock_rec_fetch_page(): Remove.
This is a partial backport of the 10.3
commit a447980ff3ba000968d89e0c0c16239addeaf438
which removed the race-condition-prone ability of the InnoDB monitor
to read relevant pages into the buffer pool for some record locks.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 358 |
1 files changed, 51 insertions, 307 deletions
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 67adee94d14..fa0dae753dc 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4973,137 +4973,6 @@ lock_print_info_summary( return(TRUE); } -/** Prints not started transaction or puts it into set. -@param[in] trx transaction -@param[in,out] file fd where to print -@param[in,out] started put transaction here if is started */ -static void -print_not_started(const trx_t* trx, FILE* file, std::set<const trx_t*>& started) -{ - ut_ad(trx->in_mysql_trx_list); - ut_ad(mutex_own(&trx_sys->mutex)); - - /* See state transitions and locking rules in trx0trx.h */ - - if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { - - fputs("---", file); - trx_print_latched(file, trx, 600); - } else { - started.insert(trx); - } -} - -/** Iterate over a transaction's locks. Keeping track of the -iterator using an ordinal value. */ - -class TrxLockIterator { -public: - TrxLockIterator() { rewind(); } - - /** Get the m_index(th) lock of a transaction. - @return current lock or 0 */ - const lock_t* current(const trx_t* trx) const - { - lock_t* lock; - ulint i = 0; - - for (lock = UT_LIST_GET_FIRST(trx->lock.trx_locks); - lock != NULL && i < m_index; - lock = UT_LIST_GET_NEXT(trx_locks, lock), ++i) { - - /* No op */ - } - - return(lock); - } - - /** Set the ordinal value to 0 */ - void rewind() - { - m_index = 0; - } - - /** Increment the ordinal value. - @retun the current index value */ - ulint next() - { - return(++m_index); - } - -private: - /** Current iterator position */ - ulint m_index; -}; - -/** This iterates over both the RW and RO trx_sys lists. We need to keep -track where the iterator was up to and we do that using an ordinal value. */ - -class TrxListIterator { -public: - TrxListIterator() : m_index() - { - /* We iterate over the RW trx list first. */ - - m_trx_list = &trx_sys->rw_trx_list; - } - - /** Get the current transaction whose ordinality is m_index. - @return current transaction or 0 */ - - const trx_t* current() - { - return(reposition()); - } - - /** Advance the transaction current ordinal value and reset the - transaction lock ordinal value */ - - void next() - { - ++m_index; - m_lock_iter.rewind(); - } - - TrxLockIterator& lock_iter() - { - return(m_lock_iter); - } - -private: - /** Reposition the "cursor" on the current transaction. If it - is the first time then the "cursor" will be positioned on the - first transaction. - - @return transaction instance or 0 */ - const trx_t* reposition() const - { - ulint i; - trx_t* trx; - - /* Make the transaction at the ordinal value of m_index - the current transaction. ie. reposition/restore */ - - for (i = 0, trx = UT_LIST_GET_FIRST(*m_trx_list); - trx != NULL && (i < m_index); - trx = UT_LIST_GET_NEXT(trx_list, trx), ++i) { - - check_trx_state(trx); - } - - return(trx); - } - - /** Ordinal value of the transaction in the current transaction list */ - ulint m_index; - - /** Current transaction list */ - trx_ut_list_t* m_trx_list; - - /** For iterating over a transaction's locks */ - TrxLockIterator m_lock_iter; -}; - /** Prints transaction lock wait and MVCC state. @param[in,out] file file where to print @param[in] trx transaction */ @@ -5140,118 +5009,29 @@ lock_trx_print_wait_and_mvcc_state( } /*********************************************************************//** -Prints info of locks for a transaction. This function will release the -lock mutex and the trx_sys_t::mutex if the page was read from disk. -@return true if page was read from the tablespace */ -static -bool -lock_rec_fetch_page( -/*================*/ - const lock_t* lock) /*!< in: record lock */ -{ - ut_ad(lock_get_type_low(lock) == LOCK_REC); - - ulint space_id = lock->un_member.rec_lock.space; - fil_space_t* space; - bool found; - const page_size_t& page_size = fil_space_get_page_size(space_id, - &found); - ulint page_no = lock->un_member.rec_lock.page_no; - - /* Check if the .ibd file exists. */ - if (found) { - mtr_t mtr; - - lock_mutex_exit(); - - mutex_exit(&trx_sys->mutex); - - DEBUG_SYNC_C("innodb_monitor_before_lock_page_read"); - - /* Check if the space is exists or not. only - when the space is valid, try to get the page. */ - space = fil_space_acquire(space_id); - if (space) { - dberr_t err = DB_SUCCESS; - mtr_start(&mtr); - buf_page_get_gen( - page_id_t(space_id, page_no), page_size, - RW_NO_LATCH, NULL, - BUF_GET_POSSIBLY_FREED, - __FILE__, __LINE__, &mtr, &err); - mtr_commit(&mtr); - fil_space_release(space); - } - - lock_mutex_enter(); - - mutex_enter(&trx_sys->mutex); - - return(true); - } - - return(false); -} - -/*********************************************************************//** -Prints info of locks for a transaction. -@return true if all printed, false if latches were released. */ +Prints info of locks for a transaction. */ static -bool +void lock_trx_print_locks( /*=================*/ FILE* file, /*!< in/out: File to write */ - const trx_t* trx, /*!< in: current transaction */ - TrxLockIterator&iter, /*!< in: transaction lock iterator */ - bool load_block) /*!< in: if true then read block - from disk */ + const trx_t* trx) /*!< in: current transaction */ { - const lock_t* lock; - + uint32_t i= 0; /* Iterate over the transaction's locks. */ - while ((lock = iter.current(trx)) != 0) { - + for (lock_t *lock = UT_LIST_GET_FIRST(trx->lock.trx_locks); + lock != NULL; + lock = UT_LIST_GET_NEXT(trx_locks, lock)) { if (lock_get_type_low(lock) == LOCK_REC) { - if (load_block) { - - /* Note: lock_rec_fetch_page() will - release both the lock mutex and the - trx_sys_t::mutex if it does a read - from disk. */ - - if (lock_rec_fetch_page(lock)) { - /* We need to resync the - current transaction. */ - return(false); - } - - /* It is a single table tablespace - and the .ibd file is missing: - just print the lock without - attempting to load the page in the - buffer pool. */ - - fprintf(file, - "RECORD LOCKS on non-existing" - " space %u\n", - lock->un_member.rec_lock.space); - } - - /* Print all the record locks on the page from - the record lock bitmap */ - lock_rec_print(file, lock); - - load_block = true; - } else { ut_ad(lock_get_type_low(lock) & LOCK_TABLE); lock_table_print(file, lock); } - if (iter.next() >= 10) { + if (++i == 10) { fprintf(file, "10 LOCKS PRINTED FOR THIS TRX:" @@ -5260,10 +5040,48 @@ lock_trx_print_locks( break; } } - - return(true); } +/** Functor to display all transactions (except recovered ones) */ +struct lock_print_info +{ + lock_print_info(FILE* file) : file(file) {} + + void operator()(const trx_t* trx) const + { + ut_ad(mutex_own(&trx_sys->mutex)); + ut_ad(trx->in_mysql_trx_list); + lock_trx_print_wait_and_mvcc_state(file, trx); + + if (trx->will_lock && srv_print_innodb_lock_monitor) + lock_trx_print_locks(file, trx); + } + + FILE* const file; +}; + +/** Functor to display recovered read-write transactions */ +struct lock_print_info_rw_recovered +{ + lock_print_info_rw_recovered(FILE* file) : file(file) {} + + void operator()(const trx_t* trx) const + { + ut_ad(mutex_own(&trx_sys->mutex)); + ut_ad(trx->in_rw_trx_list); + if (trx->mysql_thd) + return; + ut_ad(!trx->in_mysql_trx_list); + + lock_trx_print_wait_and_mvcc_state(file, trx); + + if (trx->will_lock && srv_print_innodb_lock_monitor) + lock_trx_print_locks(file, trx); + } + + FILE* const file; +}; + /*********************************************************************//** Prints info of locks for each transaction. This function assumes that the caller holds the lock mutex and more importantly it will release the lock @@ -5278,84 +5096,10 @@ lock_print_info_all_transactions( fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); mutex_enter(&trx_sys->mutex); - - /* First print info on non-active transactions */ - - /* NOTE: information of auto-commit non-locking read-only - transactions will be omitted here. The information will be - available from INFORMATION_SCHEMA.INNODB_TRX. */ - - std::set<const trx_t*> not_printed_transactions; - for (const trx_t* trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); - trx; trx = UT_LIST_GET_NEXT(mysql_trx_list, trx)) { - print_not_started(trx, file, not_printed_transactions); - } - - const trx_t* trx; - TrxListIterator trx_iter; - const trx_t* prev_trx = 0; - - /* Control whether a block should be fetched from the buffer pool. */ - bool load_block = true; - bool monitor = srv_print_innodb_lock_monitor; - - while ((trx = trx_iter.current()) != 0) { - - check_trx_state(trx); - - not_printed_transactions.erase(trx); - - if (trx != prev_trx) { - lock_trx_print_wait_and_mvcc_state(file, trx); - prev_trx = trx; - - /* The transaction that read in the page is no - longer the one that read the page in. We need to - force a page read. */ - load_block = true; - } - - /* If we need to print the locked record contents then we - need to fetch the containing block from the buffer pool. */ - if (monitor) { - - /* Print the locks owned by the current transaction. */ - TrxLockIterator& lock_iter = trx_iter.lock_iter(); - - if (!lock_trx_print_locks( - file, trx, lock_iter, load_block)) { - - /* Resync trx_iter, the trx_sys->mutex and - the lock mutex were released. A page was - successfully read in. We need to print its - contents on the next call to - lock_trx_print_locks(). On the next call to - lock_trx_print_locks() we should simply print - the contents of the page just read in.*/ - load_block = false; - - continue; - } - } - - load_block = true; - - /* All record lock details were printed without fetching - a page from disk, or we didn't need to print the detail. */ - trx_iter.next(); - } - - for (std::set<const trx_t*>::const_iterator it - = not_printed_transactions.begin(), - end = not_printed_transactions.end(); - it != end; ++it) { - fputs("---", file); - trx_print_latched(file, *it, 600); - } - - lock_mutex_exit(); + ut_list_map(trx_sys->mysql_trx_list, lock_print_info(file)); + ut_list_map(trx_sys->rw_trx_list, lock_print_info_rw_recovered(file)); mutex_exit(&trx_sys->mutex); - + lock_mutex_exit(); ut_ad(lock_validate()); } |