Commit 810f014c authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-18429: Simpler implementation

This reverts commit 61f370a3
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 a447980f
which removed the race-condition-prone ability of the InnoDB monitor
to read relevant pages into the buffer pool for some record locks.
parent 092602ac
......@@ -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,102 +5040,66 @@ lock_trx_print_locks(
break;
}
}
return(true);
}
/*********************************************************************//**
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
mutex on behalf of the caller. (This should be fixed in the future). */
void
lock_print_info_all_transactions(
/*=============================*/
FILE* file) /*!< in/out: file where to print */
/** Functor to display all transactions (except recovered ones) */
struct lock_print_info
{
ut_ad(lock_mutex_own());
lock_print_info(FILE* file) : file(file) {}
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) {
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);
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 (trx->will_lock && srv_print_innodb_lock_monitor)
lock_trx_print_locks(file, trx);
}
/* If we need to print the locked record contents then we
need to fetch the containing block from the buffer pool. */
if (monitor) {
FILE* const file;
};
/* Print the locks owned by the current transaction. */
TrxLockIterator& lock_iter = trx_iter.lock_iter();
/** Functor to display recovered read-write transactions */
struct lock_print_info_rw_recovered
{
lock_print_info_rw_recovered(FILE* file) : file(file) {}
if (!lock_trx_print_locks(
file, trx, lock_iter, load_block)) {
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);
/* 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;
lock_trx_print_wait_and_mvcc_state(file, trx);
continue;
}
if (trx->will_lock && srv_print_innodb_lock_monitor)
lock_trx_print_locks(file, trx);
}
load_block = true;
FILE* const file;
};
/* All record lock details were printed without fetching
a page from disk, or we didn't need to print the detail. */
trx_iter.next();
}
/*********************************************************************//**
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
mutex on behalf of the caller. (This should be fixed in the future). */
void
lock_print_info_all_transactions(
/*=============================*/
FILE* file) /*!< in/out: file where to print */
{
ut_ad(lock_mutex_own());
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);
}
fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n");
lock_mutex_exit();
mutex_enter(&trx_sys->mutex);
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());
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment