mirror of
https://github.com/MariaDB/server.git
synced 2025-01-30 10:31:54 +01:00
Bug#13789853 SHOW ENGINE INNODB STATUS HANGS DUE TO EXCESSIVE WORK
IN LOCK_VALIDATE() rb://917 approved by: Marko Makela In lock_validate() the limit is used to release the kernel_mutex during the validation, to obey the latching order. If we do the limit++ then we are rechecking the same lock most times on each iteration because limit is being incremented by one and <space, page_no> will nearly always be > limit. If we set the limit correctly to (space, page+1) then we are actually making progress during the iteration.
This commit is contained in:
parent
aaead0efb4
commit
273c626269
1 changed files with 78 additions and 49 deletions
|
@ -4964,6 +4964,74 @@ function_exit:
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************//**
|
||||||
|
Validate record locks up to a limit.
|
||||||
|
@return lock at limit or NULL if no more locks in the hash bucket */
|
||||||
|
static __attribute__((nonnull, warn_unused_result))
|
||||||
|
const lock_t*
|
||||||
|
lock_rec_validate(
|
||||||
|
/*==============*/
|
||||||
|
ulint start, /*!< in: lock_sys->rec_hash
|
||||||
|
bucket */
|
||||||
|
ib_uint64_t* limit) /*!< in/out: upper limit of
|
||||||
|
(space, page_no) */
|
||||||
|
{
|
||||||
|
lock_t* lock;
|
||||||
|
ut_ad(mutex_own(&kernel_mutex));
|
||||||
|
|
||||||
|
for (lock = HASH_GET_FIRST(lock_sys->rec_hash, start);
|
||||||
|
lock != NULL;
|
||||||
|
lock = HASH_GET_NEXT(hash, lock)) {
|
||||||
|
|
||||||
|
ib_uint64_t current;
|
||||||
|
|
||||||
|
ut_a(trx_in_trx_list(lock->trx));
|
||||||
|
ut_a(lock_get_type(lock) == LOCK_REC);
|
||||||
|
|
||||||
|
current = ut_ull_create(
|
||||||
|
lock->un_member.rec_lock.space,
|
||||||
|
lock->un_member.rec_lock.page_no);
|
||||||
|
|
||||||
|
if (current > *limit) {
|
||||||
|
*limit = current + 1;
|
||||||
|
return(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************//**
|
||||||
|
Validate a record lock's block */
|
||||||
|
static
|
||||||
|
void
|
||||||
|
lock_rec_block_validate(
|
||||||
|
/*====================*/
|
||||||
|
ulint space,
|
||||||
|
ulint page_no)
|
||||||
|
{
|
||||||
|
/* The lock and the block that it is referring to may be freed at
|
||||||
|
this point. We pass BUF_GET_POSSIBLY_FREED to skip a debug check.
|
||||||
|
If the lock exists in lock_rec_validate_page() we assert
|
||||||
|
!block->page.file_page_was_freed. */
|
||||||
|
|
||||||
|
mtr_t mtr;
|
||||||
|
buf_block_t* block;
|
||||||
|
|
||||||
|
mtr_start(&mtr);
|
||||||
|
|
||||||
|
block = buf_page_get_gen(
|
||||||
|
space, fil_space_get_zip_size(space),
|
||||||
|
page_no, RW_X_LATCH, NULL,
|
||||||
|
BUF_GET_POSSIBLY_FREED,
|
||||||
|
__FILE__, __LINE__, &mtr);
|
||||||
|
|
||||||
|
buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
|
||||||
|
|
||||||
|
ut_ad(lock_rec_validate_page(block));
|
||||||
|
mtr_commit(&mtr);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
Validates the lock system.
|
Validates the lock system.
|
||||||
@return TRUE if ok */
|
@return TRUE if ok */
|
||||||
|
@ -4996,60 +5064,21 @@ lock_validate(void)
|
||||||
trx = UT_LIST_GET_NEXT(trx_list, trx);
|
trx = UT_LIST_GET_NEXT(trx_list, trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Iterate over all the record locks and validate the locks. We
|
||||||
|
don't want to hog the lock_sys_t::mutex and the trx_sys_t::mutex.
|
||||||
|
Release both mutexes during the validation check. */
|
||||||
|
|
||||||
for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
|
for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
|
||||||
|
const lock_t* lock;
|
||||||
|
ib_uint64_t limit = 0;
|
||||||
|
|
||||||
ulint space;
|
while ((lock = lock_rec_validate(i, &limit)) != NULL) {
|
||||||
ulint page_no;
|
|
||||||
ib_uint64_t limit = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
ulint space = lock->un_member.rec_lock.space;
|
||||||
mtr_t mtr;
|
ulint page_no = lock->un_member.rec_lock.page_no;
|
||||||
buf_block_t* block;
|
|
||||||
|
|
||||||
lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
|
|
||||||
|
|
||||||
while (lock) {
|
|
||||||
ib_uint64_t space_page;
|
|
||||||
ut_a(trx_in_trx_list(lock->trx));
|
|
||||||
|
|
||||||
space = lock->un_member.rec_lock.space;
|
|
||||||
page_no = lock->un_member.rec_lock.page_no;
|
|
||||||
|
|
||||||
space_page = ut_ull_create(space, page_no);
|
|
||||||
|
|
||||||
if (space_page >= limit) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock = HASH_GET_NEXT(hash, lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lock) {
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock_mutex_exit_kernel();
|
lock_mutex_exit_kernel();
|
||||||
|
lock_rec_block_validate(space, page_no);
|
||||||
/* The lock and the block that it is referring
|
|
||||||
to may be freed at this point. We pass
|
|
||||||
BUF_GET_POSSIBLY_FREED to skip a debug check.
|
|
||||||
If the lock exists in lock_rec_validate_page()
|
|
||||||
we assert !block->page.file_page_was_freed. */
|
|
||||||
|
|
||||||
mtr_start(&mtr);
|
|
||||||
block = buf_page_get_gen(
|
|
||||||
space, fil_space_get_zip_size(space),
|
|
||||||
page_no, RW_X_LATCH, NULL,
|
|
||||||
BUF_GET_POSSIBLY_FREED,
|
|
||||||
__FILE__, __LINE__, &mtr);
|
|
||||||
buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
|
|
||||||
|
|
||||||
ut_ad(lock_rec_validate_page(block));
|
|
||||||
mtr_commit(&mtr);
|
|
||||||
|
|
||||||
limit++;
|
|
||||||
|
|
||||||
lock_mutex_enter_kernel();
|
lock_mutex_enter_kernel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue