summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2019-04-29 16:23:21 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2019-04-29 17:49:55 +0300
commit810f014ca7a705381e110cb26649c528bc00f179 (patch)
tree3ad34657ca4a061bf35763fe75c1917ab2a1e757
parent092602ac9b650f921ec5380866d17d740f0eedb4 (diff)
downloadmariadb-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.
-rw-r--r--storage/innobase/lock/lock0lock.cc358
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());
}