Commit c091a0bc authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-26826 Duplicated computations of buf_pool.page_hash addresses

Since commit bd5a6403 (MDEV-26033)
we can actually calculate the buf_pool.page_hash cell and latch
addresses while not holding buf_pool.mutex.

buf_page_alloc_descriptor(): Remove the MEM_UNDEFINED.
We now expect buf_page_t::hash to be zero-initialized.

buf_pool_t::hash_chain: Dedicated data type for buf_pool.page_hash.array.

buf_LRU_free_one_page(): Merged to the only caller
buf_pool_t::corrupted_evict().
parent fdae71f8
...@@ -856,9 +856,10 @@ PageBulk::latch() ...@@ -856,9 +856,10 @@ PageBulk::latch()
ut_ad(m_block->page.buf_fix_count()); ut_ad(m_block->page.buf_fix_count());
/* In case the block is S-latched by page_cleaner. */ /* In case the block is U-latched by page_cleaner. */
if (!buf_page_optimistic_get(RW_X_LATCH, m_block, m_modify_clock, if (!buf_page_optimistic_get(RW_X_LATCH, m_block, m_modify_clock,
&m_mtr)) { &m_mtr)) {
/* FIXME: avoid another lookup */
m_block = buf_page_get_gen(page_id_t(m_index->table->space_id, m_block = buf_page_get_gen(page_id_t(m_index->table->space_id,
m_page_no), m_page_no),
0, RW_X_LATCH, 0, RW_X_LATCH,
......
...@@ -1630,6 +1630,9 @@ btr_cur_search_to_nth_level_func( ...@@ -1630,6 +1630,9 @@ btr_cur_search_to_nth_level_func(
ut_ad(cursor->thr); ut_ad(cursor->thr);
switch (btr_op) { switch (btr_op) {
default:
ut_error;
break;
case BTR_INSERT_OP: case BTR_INSERT_OP:
case BTR_INSERT_IGNORE_UNIQUE_OP: case BTR_INSERT_IGNORE_UNIQUE_OP:
ut_ad(buf_mode == BUF_GET_IF_IN_POOL); ut_ad(buf_mode == BUF_GET_IF_IN_POOL);
...@@ -1662,6 +1665,8 @@ btr_cur_search_to_nth_level_func( ...@@ -1662,6 +1665,8 @@ btr_cur_search_to_nth_level_func(
case BTR_DELETE_OP: case BTR_DELETE_OP:
ut_ad(buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH); ut_ad(buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH);
ut_ad(!dict_index_is_spatial(index)); ut_ad(!dict_index_is_spatial(index));
auto& chain = buf_pool.page_hash.cell_get(
page_id.fold());
if (!row_purge_poss_sec(cursor->purge_node, if (!row_purge_poss_sec(cursor->purge_node,
index, tuple)) { index, tuple)) {
...@@ -1676,15 +1681,12 @@ btr_cur_search_to_nth_level_func( ...@@ -1676,15 +1681,12 @@ btr_cur_search_to_nth_level_func(
cursor->flag = BTR_CUR_DELETE_IBUF; cursor->flag = BTR_CUR_DELETE_IBUF;
} else { } else {
/* The purge could not be buffered. */ /* The purge could not be buffered. */
buf_pool.watch_unset(page_id); buf_pool.watch_unset(page_id, chain);
break; break;
} }
buf_pool.watch_unset(page_id); buf_pool.watch_unset(page_id, chain);
goto func_exit; goto func_exit;
default:
ut_error;
} }
/* Insert to the insert/delete buffer did not succeed, we /* Insert to the insert/delete buffer did not succeed, we
...@@ -6743,11 +6745,10 @@ static void btr_blob_free(buf_block_t *block, bool all, mtr_t *mtr) ...@@ -6743,11 +6745,10 @@ static void btr_blob_free(buf_block_t *block, bool all, mtr_t *mtr)
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
mtr->commit(); mtr->commit();
const ulint fold= page_id.fold(); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(page_id.fold());
mysql_mutex_lock(&buf_pool.mutex); mysql_mutex_lock(&buf_pool.mutex);
if (buf_page_t *bpage= buf_pool.page_hash_get_low(page_id, fold)) if (buf_page_t *bpage= buf_pool.page_hash.get(page_id, chain))
if (!buf_LRU_free_page(bpage, all) && all && bpage->zip.data) if (!buf_LRU_free_page(bpage, all) && all && bpage->zip.data)
/* Attempt to deallocate the redundant copy of the uncompressed page /* Attempt to deallocate the redundant copy of the uncompressed page
if the whole ROW_FORMAT=COMPRESSED block cannot be deallocted. */ if the whole ROW_FORMAT=COMPRESSED block cannot be deallocted. */
......
...@@ -1090,15 +1090,16 @@ btr_search_guess_on_hash( ...@@ -1090,15 +1090,16 @@ btr_search_guess_on_hash(
buf_block_t* block = buf_pool.block_from_ahi(rec); buf_block_t* block = buf_pool.block_from_ahi(rec);
if (!ahi_latch) { if (!ahi_latch) {
page_hash_latch* hash_lock = buf_pool.hash_lock_get( buf_pool_t::hash_chain& chain = buf_pool.page_hash.cell_get(
block->page.id()); block->page.id().fold());
hash_lock->read_lock(); page_hash_latch&hash_lock = buf_pool.page_hash.lock_get(chain);
hash_lock.read_lock();
if (block->page.state() == BUF_BLOCK_REMOVE_HASH) { if (block->page.state() == BUF_BLOCK_REMOVE_HASH) {
/* Another thread is just freeing the block /* Another thread is just freeing the block
from the LRU list of the buffer pool: do not from the LRU list of the buffer pool: do not
try to access this page. */ try to access this page. */
hash_lock->read_unlock(); hash_lock.read_unlock();
goto fail; goto fail;
} }
...@@ -1109,7 +1110,7 @@ btr_search_guess_on_hash( ...@@ -1109,7 +1110,7 @@ btr_search_guess_on_hash(
DBUG_ASSERT(fail || block->page.status != buf_page_t::FREED); DBUG_ASSERT(fail || block->page.status != buf_page_t::FREED);
buf_block_buf_fix_inc(block); buf_block_buf_fix_inc(block);
hash_lock->read_unlock(); hash_lock.read_unlock();
block->page.set_accessed(); block->page.set_accessed();
buf_page_make_young_if_needed(&block->page); buf_page_make_young_if_needed(&block->page);
...@@ -2209,8 +2210,9 @@ btr_search_hash_table_validate(ulint hash_table_id) ...@@ -2209,8 +2210,9 @@ btr_search_hash_table_validate(ulint hash_table_id)
assertion and the comment below) */ assertion and the comment below) */
const page_id_t id(block->page.id()); const page_id_t id(block->page.id());
if (const buf_page_t* hash_page if (const buf_page_t* hash_page
= buf_pool.page_hash_get_low( = buf_pool.page_hash.get(
id, id.fold())) { id, buf_pool.page_hash.cell_get(
id.fold()))) {
ut_ad(hash_page == &block->page); ut_ad(hash_page == &block->page);
goto state_ok; goto state_ok;
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2020, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2020, MariaDB Corporation. Copyright (c) 2020, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the the terms of the GNU General Public License, version 2.0, as published by the
...@@ -46,14 +46,15 @@ void Block_hint::buffer_fix_block_if_still_valid() ...@@ -46,14 +46,15 @@ void Block_hint::buffer_fix_block_if_still_valid()
validate m_block->state() to ensure that the block is not being freed. */ validate m_block->state() to ensure that the block is not being freed. */
if (m_block) if (m_block)
{ {
const ulint fold= m_page_id.fold(); auto &cell= buf_pool.page_hash.cell_get(m_page_id.fold());
page_hash_latch *hash_lock= buf_pool.page_hash.lock<false>(fold); page_hash_latch &latch= buf_pool.page_hash.lock_get(cell);
latch.read_lock();
if (buf_pool.is_uncompressed(m_block) && m_page_id == m_block->page.id() && if (buf_pool.is_uncompressed(m_block) && m_page_id == m_block->page.id() &&
m_block->page.state() == BUF_BLOCK_FILE_PAGE) m_block->page.state() == BUF_BLOCK_FILE_PAGE)
buf_block_buf_fix_inc(m_block); buf_block_buf_fix_inc(m_block);
else else
clear(); clear();
hash_lock->read_unlock(); latch.read_unlock();
} }
} }
} // namespace buf } // namespace buf
/***************************************************************************** /*****************************************************************************
Copyright (c) 2006, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2006, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, 2020, MariaDB Corporation. Copyright (c) 2018, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -499,9 +499,10 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) ...@@ -499,9 +499,10 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force)
ut_ad(space != BUF_BUDDY_STAMP_FREE); ut_ad(space != BUF_BUDDY_STAMP_FREE);
const page_id_t page_id(space, offset); const page_id_t page_id(space, offset);
const ulint fold= page_id.fold(); /* FIXME: we are computing this while holding buf_pool.mutex */
auto &cell= buf_pool.page_hash.cell_get(page_id.fold());
bpage = buf_pool.page_hash_get_low(page_id, fold); bpage = buf_pool.page_hash.get(page_id, cell);
if (!bpage || bpage->zip.data != src) { if (!bpage || bpage->zip.data != src) {
/* The block has probably been freshly /* The block has probably been freshly
...@@ -546,8 +547,8 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) ...@@ -546,8 +547,8 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force)
return false; return false;
} }
page_hash_latch *hash_lock = buf_pool.page_hash.lock_get(fold); page_hash_latch &hash_lock = buf_pool.page_hash.lock_get(cell);
hash_lock->write_lock(); hash_lock.write_lock();
if (bpage->can_relocate()) { if (bpage->can_relocate()) {
/* Relocate the compressed page. */ /* Relocate the compressed page. */
...@@ -558,7 +559,7 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) ...@@ -558,7 +559,7 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force)
memcpy(dst, src, size); memcpy(dst, src, size);
bpage->zip.data = reinterpret_cast<page_zip_t*>(dst); bpage->zip.data = reinterpret_cast<page_zip_t*>(dst);
hash_lock->write_unlock(); hash_lock.write_unlock();
buf_buddy_mem_invalid( buf_buddy_mem_invalid(
reinterpret_cast<buf_buddy_free_t*>(src), i); reinterpret_cast<buf_buddy_free_t*>(src), i);
...@@ -569,7 +570,7 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force) ...@@ -569,7 +570,7 @@ static bool buf_buddy_relocate(void* src, void* dst, ulint i, bool force)
return(true); return(true);
} }
hash_lock->write_unlock(); hash_lock.write_unlock();
return(false); return(false);
} }
......
This diff is collapsed.
...@@ -947,7 +947,9 @@ static bool buf_flush_check_neighbor(const page_id_t id, ulint fold, bool lru) ...@@ -947,7 +947,9 @@ static bool buf_flush_check_neighbor(const page_id_t id, ulint fold, bool lru)
mysql_mutex_assert_owner(&buf_pool.mutex); mysql_mutex_assert_owner(&buf_pool.mutex);
ut_ad(fold == id.fold()); ut_ad(fold == id.fold());
buf_page_t *bpage= buf_pool.page_hash_get_low(id, fold); /* FIXME: cell_get() is being invoked while holding buf_pool.mutex */
const buf_page_t *bpage=
buf_pool.page_hash.get(id, buf_pool.page_hash.cell_get(fold));
if (!bpage || buf_pool.watch_is_sentinel(*bpage)) if (!bpage || buf_pool.watch_is_sentinel(*bpage))
return false; return false;
...@@ -1107,9 +1109,10 @@ static ulint buf_flush_try_neighbors(fil_space_t *space, ...@@ -1107,9 +1109,10 @@ static ulint buf_flush_try_neighbors(fil_space_t *space,
id_fold= id.fold(); id_fold= id.fold();
} }
const buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id_fold);
mysql_mutex_lock(&buf_pool.mutex); mysql_mutex_lock(&buf_pool.mutex);
if (buf_page_t *bpage= buf_pool.page_hash_get_low(id, id_fold)) if (buf_page_t *bpage= buf_pool.page_hash.get(id, chain))
{ {
ut_ad(bpage->in_file()); ut_ad(bpage->in_file());
/* We avoid flushing 'non-old' blocks in an LRU flush, /* We avoid flushing 'non-old' blocks in an LRU flush,
......
...@@ -113,7 +113,7 @@ the object will be freed. ...@@ -113,7 +113,7 @@ the object will be freed.
@param bpage buffer block @param bpage buffer block
@param id page identifier @param id page identifier
@param hash_lock buf_pool.page_hash latch (will be released here) @param chain locked buf_pool.page_hash chain (will be released here)
@param zip whether bpage->zip of BUF_BLOCK_FILE_PAGE should be freed @param zip whether bpage->zip of BUF_BLOCK_FILE_PAGE should be freed
If a compressed page is freed other compressed pages may be relocated. If a compressed page is freed other compressed pages may be relocated.
...@@ -122,7 +122,8 @@ caller needs to free the page to the free list ...@@ -122,7 +122,8 @@ caller needs to free the page to the free list
@retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In @retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In
this case the block is already returned to the buddy allocator. */ this case the block is already returned to the buddy allocator. */
static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
page_hash_latch *hash_lock, bool zip); buf_pool_t::hash_chain &chain,
bool zip);
/** Free a block to buf_pool */ /** Free a block to buf_pool */
static void buf_LRU_block_free_hashed_page(buf_block_t *block) static void buf_LRU_block_free_hashed_page(buf_block_t *block)
...@@ -807,9 +808,9 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) ...@@ -807,9 +808,9 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
/* We must hold an exclusive hash_lock to prevent /* We must hold an exclusive hash_lock to prevent
bpage->can_relocate() from changing due to a concurrent bpage->can_relocate() from changing due to a concurrent
execution of buf_page_get_low(). */ execution of buf_page_get_low(). */
const ulint fold = id.fold(); buf_pool_t::hash_chain& chain= buf_pool.page_hash.cell_get(id.fold());
page_hash_latch* hash_lock = buf_pool.page_hash.lock_get(fold); page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain);
hash_lock->write_lock(); hash_lock.write_lock();
lsn_t oldest_modification = bpage->oldest_modification_acquire(); lsn_t oldest_modification = bpage->oldest_modification_acquire();
if (UNIV_UNLIKELY(!bpage->can_relocate())) { if (UNIV_UNLIKELY(!bpage->can_relocate())) {
...@@ -839,7 +840,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) ...@@ -839,7 +840,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
} else if (oldest_modification } else if (oldest_modification
&& bpage->state() != BUF_BLOCK_FILE_PAGE) { && bpage->state() != BUF_BLOCK_FILE_PAGE) {
func_exit: func_exit:
hash_lock->write_unlock(); hash_lock.write_unlock();
return(false); return(false);
} else if (bpage->state() == BUF_BLOCK_FILE_PAGE) { } else if (bpage->state() == BUF_BLOCK_FILE_PAGE) {
...@@ -859,7 +860,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) ...@@ -859,7 +860,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
ut_ad(bpage->can_relocate()); ut_ad(bpage->can_relocate());
if (!buf_LRU_block_remove_hashed(bpage, id, hash_lock, zip)) { if (!buf_LRU_block_remove_hashed(bpage, id, chain, zip)) {
ut_ad(!b); ut_ad(!b);
mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
return(true); return(true);
...@@ -875,7 +876,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) ...@@ -875,7 +876,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
if (UNIV_LIKELY_NULL(b)) { if (UNIV_LIKELY_NULL(b)) {
buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b); buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b);
ut_ad(!buf_pool.page_hash_get_low(id, fold)); ut_ad(!buf_pool.page_hash.get(id, chain));
ut_ad(b->zip_size()); ut_ad(b->zip_size());
/* The field in_LRU_list of /* The field in_LRU_list of
...@@ -894,8 +895,10 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) ...@@ -894,8 +895,10 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
ut_ad(!b->in_zip_hash); ut_ad(!b->in_zip_hash);
ut_ad(b->in_LRU_list); ut_ad(b->in_LRU_list);
ut_ad(b->in_page_hash); ut_ad(b->in_page_hash);
ut_d(b->in_page_hash = false);
b->hash = nullptr;
HASH_INSERT(buf_page_t, hash, &buf_pool.page_hash, fold, b); buf_pool.page_hash.append(chain, b);
/* Insert b where bpage was in the LRU list. */ /* Insert b where bpage was in the LRU list. */
if (prev_b) { if (prev_b) {
...@@ -951,9 +954,9 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) ...@@ -951,9 +954,9 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
decompressing the block while we release decompressing the block while we release
hash_lock. */ hash_lock. */
b->set_io_fix(BUF_IO_PIN); b->set_io_fix(BUF_IO_PIN);
hash_lock->write_unlock(); hash_lock.write_unlock();
} else if (!zip) { } else if (!zip) {
hash_lock->write_unlock(); hash_lock.write_unlock();
} }
buf_block_t* block = reinterpret_cast<buf_block_t*>(bpage); buf_block_t* block = reinterpret_cast<buf_block_t*>(bpage);
...@@ -1063,7 +1066,7 @@ the object will be freed. ...@@ -1063,7 +1066,7 @@ the object will be freed.
@param bpage buffer block @param bpage buffer block
@param id page identifier @param id page identifier
@param hash_lock buf_pool.page_hash latch (will be released here) @param chain locked buf_pool.page_hash chain (will be released here)
@param zip whether bpage->zip of BUF_BLOCK_FILE_PAGE should be freed @param zip whether bpage->zip of BUF_BLOCK_FILE_PAGE should be freed
If a compressed page is freed other compressed pages may be relocated. If a compressed page is freed other compressed pages may be relocated.
...@@ -1072,10 +1075,11 @@ caller needs to free the page to the free list ...@@ -1072,10 +1075,11 @@ caller needs to free the page to the free list
@retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In @retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In
this case the block is already returned to the buddy allocator. */ this case the block is already returned to the buddy allocator. */
static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
page_hash_latch *hash_lock, bool zip) buf_pool_t::hash_chain &chain,
bool zip)
{ {
mysql_mutex_assert_owner(&buf_pool.mutex); mysql_mutex_assert_owner(&buf_pool.mutex);
ut_ad(hash_lock->is_write_locked()); ut_ad(buf_pool.page_hash.lock_get(chain).is_write_locked());
ut_a(bpage->io_fix() == BUF_IO_NONE); ut_a(bpage->io_fix() == BUF_IO_NONE);
ut_a(!bpage->buf_fix_count()); ut_a(!bpage->buf_fix_count());
...@@ -1155,7 +1159,8 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, ...@@ -1155,7 +1159,8 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
} }
ut_ad(!bpage->in_zip_hash); ut_ad(!bpage->in_zip_hash);
HASH_DELETE(buf_page_t, hash, &buf_pool.page_hash, id.fold(), bpage); buf_pool.page_hash.remove(chain, bpage);
page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain);
switch (bpage->state()) { switch (bpage->state()) {
case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_PAGE:
...@@ -1165,7 +1170,7 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, ...@@ -1165,7 +1170,7 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
ut_a(bpage->zip.ssize); ut_a(bpage->zip.ssize);
ut_ad(!bpage->oldest_modification()); ut_ad(!bpage->oldest_modification());
hash_lock->write_unlock(); hash_lock.write_unlock();
buf_pool_mutex_exit_forbid(); buf_pool_mutex_exit_forbid();
buf_buddy_free(bpage->zip.data, bpage->zip_size()); buf_buddy_free(bpage->zip.data, bpage->zip_size());
...@@ -1209,7 +1214,7 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, ...@@ -1209,7 +1214,7 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
and by the time we'll release it in the caller we'd and by the time we'll release it in the caller we'd
have inserted the compressed only descriptor in the have inserted the compressed only descriptor in the
page_hash. */ page_hash. */
hash_lock->write_unlock(); hash_lock.write_unlock();
if (bpage->zip.data) { if (bpage->zip.data) {
/* Free the compressed page. */ /* Free the compressed page. */
...@@ -1240,20 +1245,38 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id, ...@@ -1240,20 +1245,38 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
return(false); return(false);
} }
/** Remove one page from LRU list and put it to free list. /** Release and evict a corrupted page.
@param bpage file page to be freed @param bpage page that was being read */
@param id page identifier ATTRIBUTE_COLD void buf_pool_t::corrupted_evict(buf_page_t *bpage)
@param hash_lock buf_pool.page_hash latch (will be released here) */
void buf_LRU_free_one_page(buf_page_t *bpage, const page_id_t id,
page_hash_latch *hash_lock)
{ {
const page_id_t id(bpage->id());
buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold());
page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
mysql_mutex_lock(&mutex);
hash_lock.write_lock();
ut_ad(bpage->io_fix() == BUF_IO_READ);
ut_ad(!bpage->oldest_modification());
bpage->set_corrupt_id();
bpage->io_unfix();
if (bpage->state() == BUF_BLOCK_FILE_PAGE)
reinterpret_cast<buf_block_t*>(bpage)->lock.x_unlock(true);
while (bpage->buf_fix_count()) while (bpage->buf_fix_count())
/* Wait for other threads to release the fix count /* Wait for other threads to release the fix count
before releasing the bpage from LRU list. */ before releasing the bpage from LRU list. */
(void) LF_BACKOFF(); (void) LF_BACKOFF();
if (buf_LRU_block_remove_hashed(bpage, id, hash_lock, true)) /* remove from LRU and page_hash */
if (buf_LRU_block_remove_hashed(bpage, id, chain, true))
buf_LRU_block_free_hashed_page(reinterpret_cast<buf_block_t*>(bpage)); buf_LRU_block_free_hashed_page(reinterpret_cast<buf_block_t*>(bpage));
mysql_mutex_unlock(&mutex);
ut_d(auto n=) n_pend_reads--;
ut_ad(n > 0);
} }
/** Update buf_pool.LRU_old_ratio. /** Update buf_pool.LRU_old_ratio.
......
...@@ -50,17 +50,17 @@ i/o-fixed buffer blocks */ ...@@ -50,17 +50,17 @@ i/o-fixed buffer blocks */
/** Remove the sentinel block for the watch before replacing it with a /** Remove the sentinel block for the watch before replacing it with a
real block. watch_unset() or watch_occurred() will notice real block. watch_unset() or watch_occurred() will notice
that the block has been replaced with the real block. that the block has been replaced with the real block.
@param watch sentinel */ @param watch sentinel
inline void buf_pool_t::watch_remove(buf_page_t *watch) @param chain locked hash table chain */
inline void buf_pool_t::watch_remove(buf_page_t *watch,
buf_pool_t::hash_chain &chain)
{ {
mysql_mutex_assert_owner(&buf_pool.mutex); mysql_mutex_assert_owner(&buf_pool.mutex);
ut_ad(hash_lock_get(watch->id())->is_write_locked()); ut_ad(page_hash.lock_get(chain).is_write_locked());
ut_a(watch_is_sentinel(*watch)); ut_a(watch_is_sentinel(*watch));
if (watch->buf_fix_count()) if (watch->buf_fix_count())
{ {
ut_ad(watch->in_page_hash); page_hash.remove(chain, watch);
ut_d(watch->in_page_hash= false);
HASH_DELETE(buf_page_t, hash, &page_hash, watch->id().fold(), watch);
watch->set_buf_fix_count(0); watch->set_buf_fix_count(0);
} }
ut_ad(!watch->in_page_hash); ut_ad(!watch->in_page_hash);
...@@ -114,11 +114,12 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, ...@@ -114,11 +114,12 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id,
block->lock.x_lock(true); block->lock.x_lock(true);
} }
const ulint fold= page_id.fold(); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(page_id.fold());
page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
mysql_mutex_lock(&buf_pool.mutex); mysql_mutex_lock(&buf_pool.mutex);
buf_page_t *hash_page= buf_pool.page_hash_get_low(page_id, fold); buf_page_t *hash_page= buf_pool.page_hash.get(page_id, chain);
if (hash_page && !buf_pool.watch_is_sentinel(*hash_page)) if (hash_page && !buf_pool.watch_is_sentinel(*hash_page))
{ {
/* The page is already in the buffer pool. */ /* The page is already in the buffer pool. */
...@@ -135,8 +136,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, ...@@ -135,8 +136,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id,
bpage= &block->page; bpage= &block->page;
/* Insert into the hash table of file pages */ /* Insert into the hash table of file pages */
page_hash_latch *hash_lock= buf_pool.page_hash.lock_get(fold); hash_lock.write_lock();
hash_lock->write_lock();
if (hash_page) if (hash_page)
{ {
...@@ -144,18 +144,16 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, ...@@ -144,18 +144,16 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id,
auto buf_fix_count= hash_page->buf_fix_count(); auto buf_fix_count= hash_page->buf_fix_count();
ut_a(buf_fix_count > 0); ut_a(buf_fix_count > 0);
block->page.add_buf_fix_count(buf_fix_count); block->page.add_buf_fix_count(buf_fix_count);
buf_pool.watch_remove(hash_page); buf_pool.watch_remove(hash_page, chain);
} }
block->page.set_io_fix(BUF_IO_READ); block->page.set_io_fix(BUF_IO_READ);
block->page.set_state(BUF_BLOCK_FILE_PAGE); block->page.set_state(BUF_BLOCK_FILE_PAGE);
ut_ad(!block->page.in_page_hash); buf_pool.page_hash.append(chain, &block->page);
ut_d(block->page.in_page_hash= true); hash_lock.write_unlock();
HASH_INSERT(buf_page_t, hash, &buf_pool.page_hash, fold, bpage);
hash_lock->write_unlock();
/* The block must be put to the LRU list, to the old blocks */ /* The block must be put to the LRU list, to the old blocks */
buf_LRU_add_block(bpage, true/* to old blocks */); buf_LRU_add_block(&block->page, true/* to old blocks */);
if (UNIV_UNLIKELY(zip_size)) if (UNIV_UNLIKELY(zip_size))
{ {
...@@ -188,7 +186,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, ...@@ -188,7 +186,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id,
check the page_hash again, as it may have been modified. */ check the page_hash again, as it may have been modified. */
if (UNIV_UNLIKELY(lru)) if (UNIV_UNLIKELY(lru))
{ {
hash_page= buf_pool.page_hash_get_low(page_id, fold); hash_page= buf_pool.page_hash.get(page_id, chain);
if (UNIV_UNLIKELY(hash_page && !buf_pool.watch_is_sentinel(*hash_page))) if (UNIV_UNLIKELY(hash_page && !buf_pool.watch_is_sentinel(*hash_page)))
{ {
...@@ -206,8 +204,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, ...@@ -206,8 +204,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id,
bpage->init(BUF_BLOCK_ZIP_PAGE, page_id); bpage->init(BUF_BLOCK_ZIP_PAGE, page_id);
page_hash_latch *hash_lock= buf_pool.page_hash.lock_get(fold); hash_lock.write_lock();
hash_lock->write_lock();
if (hash_page) if (hash_page)
{ {
...@@ -215,14 +212,12 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, ...@@ -215,14 +212,12 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id,
buf_pool_t::watch_unset() is executing concurrently, buf_pool_t::watch_unset() is executing concurrently,
waiting for buf_pool.mutex, which we are holding. */ waiting for buf_pool.mutex, which we are holding. */
bpage->add_buf_fix_count(hash_page->buf_fix_count()); bpage->add_buf_fix_count(hash_page->buf_fix_count());
buf_pool.watch_remove(hash_page); buf_pool.watch_remove(hash_page, chain);
} }
ut_ad(!bpage->in_page_hash); buf_pool.page_hash.append(chain, bpage);
ut_d(bpage->in_page_hash= true);
HASH_INSERT(buf_page_t, hash, &buf_pool.page_hash, fold, bpage);
bpage->set_io_fix(BUF_IO_READ); bpage->set_io_fix(BUF_IO_READ);
hash_lock->write_unlock(); hash_lock.write_unlock();
/* The block must be put to the LRU list, to the old blocks. /* The block must be put to the LRU list, to the old blocks.
The zip size is already set into the page zip */ The zip size is already set into the page zip */
...@@ -408,11 +403,12 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf) ...@@ -408,11 +403,12 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf)
for (page_id_t i= low; i < high; ++i) for (page_id_t i= low; i < high; ++i)
{ {
const ulint fold= i.fold(); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(i.fold());
page_hash_latch *hash_lock= buf_pool.page_hash.lock<false>(fold); page_hash_latch &latch= buf_pool.page_hash.lock_get(chain);
const buf_page_t *bpage= buf_pool.page_hash_get_low(i, fold); latch.read_lock();
const buf_page_t *bpage= buf_pool.page_hash.get(i, chain);
bool found= bpage && bpage->is_accessed() && buf_page_peek_if_young(bpage); bool found= bpage && bpage->is_accessed() && buf_page_peek_if_young(bpage);
hash_lock->read_unlock(); latch.read_unlock();
if (found && !--count) if (found && !--count)
goto read_ahead; goto read_ahead;
} }
...@@ -608,9 +604,10 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) ...@@ -608,9 +604,10 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
unsigned prev_accessed= 0; unsigned prev_accessed= 0;
for (page_id_t i= low; i != high_1; ++i) for (page_id_t i= low; i != high_1; ++i)
{ {
const ulint fold= i.fold(); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(i.fold());
page_hash_latch *hash_lock= buf_pool.page_hash.lock<false>(fold); page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
const buf_page_t* bpage= buf_pool.page_hash_get_low(i, fold); hash_lock.read_lock();
const buf_page_t* bpage= buf_pool.page_hash.get(i, chain);
if (i == page_id) if (i == page_id)
{ {
/* Read the natural predecessor and successor page addresses from /* Read the natural predecessor and successor page addresses from
...@@ -621,7 +618,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) ...@@ -621,7 +618,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
if (!bpage) if (!bpage)
{ {
hard_fail: hard_fail:
hash_lock->read_unlock(); hash_lock.read_unlock();
goto fail; goto fail;
} }
const byte *f; const byte *f;
...@@ -661,7 +658,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) ...@@ -661,7 +658,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
else if (!bpage) else if (!bpage)
{ {
failed: failed:
hash_lock->read_unlock(); hash_lock.read_unlock();
if (--count) if (--count)
continue; continue;
goto fail; goto fail;
...@@ -681,7 +678,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) ...@@ -681,7 +678,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
prev_accessed= accessed; prev_accessed= accessed;
if (fail) if (fail)
goto failed; goto failed;
hash_lock->read_unlock(); hash_lock.read_unlock();
} }
/* If we got this far, read-ahead can be sensible: do it */ /* If we got this far, read-ahead can be sensible: do it */
......
...@@ -1052,10 +1052,10 @@ fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr) ...@@ -1052,10 +1052,10 @@ fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr)
if (UNIV_UNLIKELY(space->is_being_truncated)) if (UNIV_UNLIKELY(space->is_being_truncated))
{ {
const page_id_t page_id{space->id, offset}; const page_id_t page_id{space->id, offset};
const ulint fold= page_id.fold(); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(page_id.fold());
mysql_mutex_lock(&buf_pool.mutex); mysql_mutex_lock(&buf_pool.mutex);
block= reinterpret_cast<buf_block_t*> block= reinterpret_cast<buf_block_t*>
(buf_pool.page_hash_get_low(page_id, fold)); (buf_pool.page_hash.get(page_id, chain));
if (block && block->page.oldest_modification() <= 1) if (block && block->page.oldest_modification() <= 1)
block= nullptr; block= nullptr;
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
......
...@@ -3310,7 +3310,8 @@ ibuf_insert_low( ...@@ -3310,7 +3310,8 @@ ibuf_insert_low(
/* We check if the index page is suitable for buffered entries */ /* We check if the index page is suitable for buffered entries */
if (buf_pool.page_hash_contains(page_id)) { if (buf_pool.page_hash_contains(
page_id, buf_pool.page_hash.cell_get(page_id.fold()))) {
commit_exit: commit_exit:
ibuf_mtr_commit(&bitmap_mtr); ibuf_mtr_commit(&bitmap_mtr);
goto fail_exit; goto fail_exit;
...@@ -3556,7 +3557,8 @@ ibuf_insert( ...@@ -3556,7 +3557,8 @@ ibuf_insert(
that the issuer of IBUF_OP_DELETE has called that the issuer of IBUF_OP_DELETE has called
buf_pool_t::watch_set(). */ buf_pool_t::watch_set(). */
if (buf_pool.page_hash_contains<true>(page_id)) { if (buf_pool.page_hash_contains<true>(
page_id, buf_pool.page_hash.cell_get(page_id.fold()))) {
/* A buffer pool watch has been set or the /* A buffer pool watch has been set or the
page has been read into the buffer pool. page has been read into the buffer pool.
Do not buffer the request. If a purge operation Do not buffer the request. If a purge operation
......
This diff is collapsed.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc. Copyright (c) 2008, Google Inc.
Copyright (c) 2014, 2020, MariaDB Corporation. Copyright (c) 2014, 2021, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described Google, Inc. Those modifications are gratefully acknowledged and are described
...@@ -37,42 +37,6 @@ Created 11/5/1995 Heikki Tuuri ...@@ -37,42 +37,6 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0rea.h" #include "buf0rea.h"
#include "fsp0types.h" #include "fsp0types.h"
/*********************************************************************//**
Gets the current size of buffer buf_pool in bytes.
@return size in bytes */
UNIV_INLINE
ulint
buf_pool_get_curr_size(void)
/*========================*/
{
return(srv_buf_pool_curr_size);
}
/********************************************************************//**
Reads the freed_page_clock of a buffer block.
@return freed_page_clock */
UNIV_INLINE
unsigned
buf_page_get_freed_page_clock(
/*==========================*/
const buf_page_t* bpage) /*!< in: block */
{
/* This is sometimes read without holding buf_pool.mutex. */
return(bpage->freed_page_clock);
}
/********************************************************************//**
Reads the freed_page_clock of a buffer block.
@return freed_page_clock */
UNIV_INLINE
unsigned
buf_block_get_freed_page_clock(
/*===========================*/
const buf_block_t* block) /*!< in: block */
{
return(buf_page_get_freed_page_clock(&block->page));
}
/** Determine if a block is still close enough to the MRU end of the LRU list /** Determine if a block is still close enough to the MRU end of the LRU list
meaning that it is not in danger of getting evicted and also implying meaning that it is not in danger of getting evicted and also implying
that it has been accessed recently. that it has been accessed recently.
...@@ -154,35 +118,6 @@ ok: ...@@ -154,35 +118,6 @@ ok:
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
/********************************************************************//**
Allocates a buf_page_t descriptor. This function must succeed. In case
of failure we assert in this function.
@return: the allocated descriptor. */
UNIV_INLINE
buf_page_t*
buf_page_alloc_descriptor(void)
/*===========================*/
{
buf_page_t* bpage;
bpage = (buf_page_t*) ut_zalloc_nokey(sizeof *bpage);
ut_ad(bpage);
MEM_UNDEFINED(bpage, sizeof *bpage);
return(bpage);
}
/********************************************************************//**
Free a buf_page_t descriptor. */
UNIV_INLINE
void
buf_page_free_descriptor(
/*=====================*/
buf_page_t* bpage) /*!< in: bpage descriptor to free. */
{
ut_free(bpage);
}
/** Allocate a buffer block. /** Allocate a buffer block.
@return own: the allocated block, in state BUF_BLOCK_MEMORY */ @return own: the allocated block, in state BUF_BLOCK_MEMORY */
inline buf_block_t *buf_block_alloc() inline buf_block_t *buf_block_alloc()
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -24,11 +24,10 @@ The database buffer pool LRU replacement algorithm ...@@ -24,11 +24,10 @@ The database buffer pool LRU replacement algorithm
Created 11/5/1995 Heikki Tuuri Created 11/5/1995 Heikki Tuuri
*******************************************************/ *******************************************************/
#ifndef buf0lru_h #pragma once
#define buf0lru_h
#include "ut0byte.h"
#include "buf0types.h" #include "buf0types.h"
#include "hash0hash.h"
// Forward declaration // Forward declaration
struct trx_t; struct trx_t;
...@@ -132,14 +131,6 @@ policy at the end of each interval. */ ...@@ -132,14 +131,6 @@ policy at the end of each interval. */
void void
buf_LRU_stat_update(); buf_LRU_stat_update();
/** Remove one page from LRU list and put it to free list.
@param bpage file page to be freed
@param id page identifier
@param hash_lock buf_pool.page_hash latch (will be released here) */
void buf_LRU_free_one_page(buf_page_t *bpage, const page_id_t id,
page_hash_latch *hash_lock)
MY_ATTRIBUTE((nonnull));
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** Validate the LRU list. */ /** Validate the LRU list. */
void buf_LRU_validate(); void buf_LRU_validate();
...@@ -200,5 +191,3 @@ Increments the I/O counter in buf_LRU_stat_cur. */ ...@@ -200,5 +191,3 @@ Increments the I/O counter in buf_LRU_stat_cur. */
/********************************************************************//** /********************************************************************//**
Increments the page_zip_decompress() counter in buf_LRU_stat_cur. */ Increments the page_zip_decompress() counter in buf_LRU_stat_cur. */
#define buf_LRU_stat_inc_unzip() buf_LRU_stat_cur.unzip++ #define buf_LRU_stat_inc_unzip() buf_LRU_stat_cur.unzip++
#endif
...@@ -181,12 +181,11 @@ enum rw_lock_type_t ...@@ -181,12 +181,11 @@ enum rw_lock_type_t
#ifdef SUX_LOCK_GENERIC #ifdef SUX_LOCK_GENERIC
class page_hash_latch : public rw_lock class page_hash_latch : public rw_lock
{ {
public:
/** Wait for a shared lock */ /** Wait for a shared lock */
void read_lock_wait(); void read_lock_wait();
/** Wait for an exclusive lock */ /** Wait for an exclusive lock */
void write_lock_wait(); void write_lock_wait();
public:
/** Acquire a shared lock */ /** Acquire a shared lock */
inline void read_lock(); inline void read_lock();
/** Acquire an exclusive lock */ /** Acquire an exclusive lock */
......
...@@ -117,18 +117,6 @@ do {\ ...@@ -117,18 +117,6 @@ do {\
HASH_INVALIDATE(DATA, NAME);\ HASH_INVALIDATE(DATA, NAME);\
} while (0) } while (0)
#define HASH_REPLACE(TYPE, NAME, TABLE, FOLD, DATA_OLD, DATA_NEW) \
do { \
(DATA_NEW)->NAME = (DATA_OLD)->NAME; \
\
hash_cell_t& cell3333 \
= (TABLE)->array[(TABLE)->calc_hash(FOLD)]; \
TYPE** struct3333 = (TYPE**)&cell3333.node; \
while (*struct3333 != DATA_OLD) { \
struct3333 = &((*struct3333)->NAME); \
} \
*struct3333 = DATA_NEW; \
} while (0)
/*******************************************************************//** /*******************************************************************//**
Gets the first struct in a hash chain, NULL if none. */ Gets the first struct in a hash chain, NULL if none. */
......
...@@ -841,6 +841,8 @@ constexpr const char* const auto_event_names[] = ...@@ -841,6 +841,8 @@ constexpr const char* const auto_event_names[] =
"buf0buf", "buf0buf",
"buf0dblwr", "buf0dblwr",
"buf0dump", "buf0dump",
"buf0lru",
"buf0rea",
"dict0dict", "dict0dict",
"dict0mem", "dict0mem",
"dict0stats", "dict0stats",
......
...@@ -2862,7 +2862,9 @@ static void recv_read_in_area(page_id_t page_id) ...@@ -2862,7 +2862,9 @@ static void recv_read_in_area(page_id_t page_id)
&& i->first.space() == page_id.space() && i->first.space() == page_id.space()
&& i->first.page_no() < up_limit; i++) { && i->first.page_no() < up_limit; i++) {
if (i->second.state == page_recv_t::RECV_NOT_PROCESSED if (i->second.state == page_recv_t::RECV_NOT_PROCESSED
&& !buf_pool.page_hash_contains(i->first)) { && !buf_pool.page_hash_contains(
i->first,
buf_pool.page_hash.cell_get(i->first.fold()))) {
i->second.state = page_recv_t::RECV_BEING_READ; i->second.state = page_recv_t::RECV_BEING_READ;
*p++ = i->first.page_no(); *p++ = i->first.page_no();
} }
......
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