diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-06-15 17:00:05 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-06-15 17:00:05 +0300 |
commit | 253806dffc6e80a3bebb1d7fa2fa4b1899252306 (patch) | |
tree | 6ecc64a4f2acdd74afc48a91a47fa4cf1224b0f4 | |
parent | 0850267d006b6eaac26af387f149d13b908a0103 (diff) | |
download | mariadb-git-253806dffc6e80a3bebb1d7fa2fa4b1899252306.tar.gz |
MDEV-28845 InnoDB: Failing assertion: bpage->can_relocate() in buf0lru.cc
Since commit 0b47c126e31cddda1e94588799599e138400bcf8 (MDEV-13542)
we treat all-zero pages as corrupted ones.
During a stress test, a read-ahead of an all-zero page was triggered
and the page read was completed concurrently with buf_page_create_low().
This caused the assertion to fail, because buf_page_create_low() was
waiting for the page latch.
buf_page_get_low(): Only invoke buf_pool_t::corrupted_evict()
if the block was not already marked as corrupted.
buf_page_create_low(): On page identifier mismatch, retry the
buf_pool.page_hash lookup.
buf_pool_t::corrupted_evict(): Set the state of the block to FREED
so that a concurrent buf_page_get_low() will refuse to load the page.
Wait for the page latch to be vacant before proceeding to remove
the block from buf_pool.page_hash and buf_pool.LRU.
page_id_t::set_corrupted(), page_id_t::is_corrupted(): Accessors
for indicating a corrupted page identifier.
Tested by Matthias Leich
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 11 | ||||
-rw-r--r-- | storage/innobase/buf/buf0lru.cc | 8 | ||||
-rw-r--r-- | storage/innobase/include/buf0buf.h | 2 | ||||
-rw-r--r-- | storage/innobase/include/buf0types.h | 6 |
4 files changed, 21 insertions, 6 deletions
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index e0632513584..bec4aa46701 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2872,7 +2872,9 @@ ibuf_merge_corrupted: *err = e; } - buf_pool.corrupted_evict(&block->page, state); + if (block->page.id().is_corrupted()) { + buf_pool.corrupted_evict(&block->page, state); + } return nullptr; } @@ -3210,6 +3212,7 @@ static buf_block_t *buf_page_create_low(page_id_t page_id, ulint zip_size, free_block->initialise(page_id, zip_size, buf_page_t::MEMORY); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(page_id.fold()); +retry: mysql_mutex_lock(&buf_pool.mutex); buf_page_t *bpage= buf_pool.page_hash.get(page_id, chain); @@ -3228,6 +3231,12 @@ static buf_block_t *buf_page_create_low(page_id_t page_id, ulint zip_size, { mysql_mutex_unlock(&buf_pool.mutex); bpage->lock.x_lock(); + const page_id_t id{bpage->id()}; + if (UNIV_UNLIKELY(id != page_id)) + { + ut_ad(id.is_corrupted()); + goto retry; + } mysql_mutex_lock(&buf_pool.mutex); } diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 92f4efb7747..c01b0e4ee66 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -1218,14 +1218,14 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage, uint32_t state) ut_ad(!bpage->oldest_modification()); bpage->set_corrupt_id(); - auto unfix= state - buf_page_t::UNFIXED; + auto unfix= state - buf_page_t::FREED; auto s= bpage->zip.fix.fetch_sub(unfix) - unfix; bpage->lock.x_unlock(true); - while (s != buf_page_t::UNFIXED) + while (s != buf_page_t::FREED || bpage->lock.is_locked_or_waiting()) { - ut_ad(s > buf_page_t::UNFIXED); - ut_ad(s < buf_page_t::READ_FIX); + ut_ad(s >= buf_page_t::FREED); + ut_ad(s < buf_page_t::UNFIXED); /* Wait for other threads to release the fix count before releasing the bpage from LRU list. */ (void) LF_BACKOFF(); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 9440672aba1..6f1bfa4cfcd 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -2011,7 +2011,7 @@ inline void buf_page_t::set_corrupt_id() is_write_locked()); } #endif - id_= page_id_t(~0ULL); + id_.set_corrupted(); } /** Set oldest_modification when adding to buf_pool.flush_list */ diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index 3cc71a3f503..c69c07d66e1 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -148,6 +148,12 @@ public: constexpr ulonglong raw() const { return m_id; } + /** Flag the page identifier as corrupted. */ + void set_corrupted() { m_id= ~0ULL; } + + /** @return whether the page identifier belongs to a corrupted page */ + constexpr bool is_corrupted() const { return m_id == ~0ULL; } + private: /** The page identifier */ uint64_t m_id; |