diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-11-17 09:39:36 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-11-17 17:56:50 +0200 |
commit | 83a55670a68a772c52aeb7b6b9ecfc6b417255e3 (patch) | |
tree | 5901f458842870ec0850ad22ec425278e6765c62 | |
parent | 694926a4f749f54f8a3d537e9ff77ad9e89f4dc3 (diff) | |
download | mariadb-git-83a55670a68a772c52aeb7b6b9ecfc6b417255e3.tar.gz |
MDEV-24188 fixup: Simplify the wait loop
Starting with commit 7cffb5f6e8a231a041152447be8980ce35d2c9b8 (MDEV-23399)
the function buf_flush_page() will first acquire block->lock and only
after that invoke set_io_fix(). Before that, it was possible to reach
a livelock between buf_page_create() and buf_flush_page().
buf_page_create(): Directly try acquiring the exclusive page latch
without checking whether the page is io-fixed or buffer-fixed.
(As a matter of fact, the have_x_latch() check is not strictly necessary,
because we still support recursive X-latches.)
In case of a latch conflict, wait while allowing buf_page_write_complete()
to acquire buf_pool.mutex and release the block->lock.
An attempt to wait for exclusive block->lock while holding buf_pool.mutex
would lead to a hang in the tests parts.part_supported_sql_func_innodb
and stress.ddl_innodb, due to a deadlock between buf_page_write_complete()
and buf_page_create().
Similarly, in case of an I/O fixed compressed-only
ROW_FORMAT=COMPRESSED page, we will sleep before retrying.
In both cases, we will sleep for 1ms or until a flush batch is completed.
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index acd221b8b52..eb8cc8f71d3 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3755,9 +3755,9 @@ buf_page_create(fil_space_t *space, uint32_t offset, free_block->initialise(page_id, zip_size, 1); const ulint fold= page_id.fold(); -loop: mysql_mutex_lock(&buf_pool.mutex); +loop: buf_block_t *block= reinterpret_cast<buf_block_t*> (buf_pool.page_hash_get_low(page_id, fold)); @@ -3775,17 +3775,15 @@ loop: if (!mtr->have_x_latch(*block)) { buf_block_buf_fix_inc(block, __FILE__, __LINE__); + while (!rw_lock_x_lock_nowait(&block->lock)) { - while (block->page.io_fix() != BUF_IO_NONE || - block->page.buf_fix_count() != 1) - { - timespec abstime; - set_timespec_nsec(abstime, 1000000); - mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex, - &abstime); - } + /* Wait for buf_page_write_complete() to release block->lock. + We must not hold buf_pool.mutex while waiting. */ + timespec abstime; + set_timespec_nsec(abstime, 1000000); + mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex, + &abstime); } - rw_lock_x_lock(&block->lock); mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); } else @@ -3805,7 +3803,11 @@ loop: if (block->page.io_fix() != BUF_IO_NONE) { hash_lock->write_unlock(); - mysql_mutex_unlock(&buf_pool.mutex); + /* Wait for buf_page_write_complete() to release the I/O fix. */ + timespec abstime; + set_timespec_nsec(abstime, 1000000); + mysql_cond_timedwait(&buf_pool.done_flush_list, &buf_pool.mutex, + &abstime); goto loop; } |