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);
} }
......
...@@ -1147,7 +1147,7 @@ void buf_pool_t::page_hash_table::create(ulint n) ...@@ -1147,7 +1147,7 @@ void buf_pool_t::page_hash_table::create(ulint n)
const size_t size= pad(n_cells) * sizeof *array; const size_t size= pad(n_cells) * sizeof *array;
void* v= aligned_malloc(size, CPU_LEVEL1_DCACHE_LINESIZE); void* v= aligned_malloc(size, CPU_LEVEL1_DCACHE_LINESIZE);
memset(v, 0, size); memset(v, 0, size);
array= static_cast<hash_cell_t*>(v); array= static_cast<hash_chain*>(v);
} }
/** Create the buffer pool. /** Create the buffer pool.
...@@ -1336,9 +1336,10 @@ inline bool buf_pool_t::realloc(buf_block_t *block) ...@@ -1336,9 +1336,10 @@ inline bool buf_pool_t::realloc(buf_block_t *block)
return(false); /* free list was not enough */ return(false); /* free list was not enough */
} }
const page_id_t id(block->page.id()); const page_id_t id{block->page.id()};
page_hash_latch* hash_lock = hash_lock_get(id); hash_chain& chain = page_hash.cell_get(id.fold());
hash_lock->write_lock(); page_hash_latch& hash_lock = page_hash.lock_get(chain);
hash_lock.write_lock();
if (block->page.can_relocate()) { if (block->page.can_relocate()) {
memcpy_aligned<OS_FILE_LOG_BLOCK_SIZE>( memcpy_aligned<OS_FILE_LOG_BLOCK_SIZE>(
...@@ -1382,14 +1383,10 @@ inline bool buf_pool_t::realloc(buf_block_t *block) ...@@ -1382,14 +1383,10 @@ inline bool buf_pool_t::realloc(buf_block_t *block)
} }
/* relocate page_hash */ /* relocate page_hash */
ut_ad(block->page.in_page_hash); hash_chain& chain = page_hash.cell_get(id.fold());
ut_ad(new_block->page.in_page_hash); ut_ad(&block->page == page_hash.get(id, chain));
const ulint fold = id.fold(); buf_pool.page_hash.replace(chain, &block->page,
ut_ad(&block->page == page_hash_get_low(id, fold)); &new_block->page);
ut_d(block->page.in_page_hash = false);
HASH_REPLACE(buf_page_t, hash, &page_hash, fold,
&block->page, &new_block->page);
buf_block_modify_clock_inc(block); buf_block_modify_clock_inc(block);
static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment"); static_assert(FIL_PAGE_OFFSET % 4 == 0, "alignment");
memset_aligned<4>(block->frame + FIL_PAGE_OFFSET, 0xff, 4); memset_aligned<4>(block->frame + FIL_PAGE_OFFSET, 0xff, 4);
...@@ -1424,7 +1421,7 @@ inline bool buf_pool_t::realloc(buf_block_t *block) ...@@ -1424,7 +1421,7 @@ inline bool buf_pool_t::realloc(buf_block_t *block)
new_block = block; new_block = block;
} }
hash_lock->write_unlock(); hash_lock.write_unlock();
buf_LRU_block_free_non_file_page(new_block); buf_LRU_block_free_non_file_page(new_block);
return(true); /* free_list was enough */ return(true); /* free_list was enough */
} }
...@@ -2049,13 +2046,14 @@ The caller must relocate bpage->list. ...@@ -2049,13 +2046,14 @@ The caller must relocate bpage->list.
@param dpage destination control block */ @param dpage destination control block */
static void buf_relocate(buf_page_t *bpage, buf_page_t *dpage) static void buf_relocate(buf_page_t *bpage, buf_page_t *dpage)
{ {
const ulint fold= bpage->id().fold(); const page_id_t id= bpage->id();
buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold());
ut_ad(bpage->state() == BUF_BLOCK_ZIP_PAGE); ut_ad(bpage->state() == BUF_BLOCK_ZIP_PAGE);
mysql_mutex_assert_owner(&buf_pool.mutex); mysql_mutex_assert_owner(&buf_pool.mutex);
ut_ad(buf_pool.hash_lock_get(bpage->id())->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());
ut_ad(bpage == buf_pool.page_hash_get_low(bpage->id(), fold)); ut_ad(bpage == buf_pool.page_hash.get(id, chain));
ut_ad(!buf_pool.watch_is_sentinel(*bpage)); ut_ad(!buf_pool.watch_is_sentinel(*bpage));
ut_ad(bpage->state() == BUF_BLOCK_ZIP_PAGE); ut_ad(bpage->state() == BUF_BLOCK_ZIP_PAGE);
...@@ -2090,29 +2088,24 @@ static void buf_relocate(buf_page_t *bpage, buf_page_t *dpage) ...@@ -2090,29 +2088,24 @@ static void buf_relocate(buf_page_t *bpage, buf_page_t *dpage)
ut_d(CheckInLRUList::validate()); ut_d(CheckInLRUList::validate());
/* relocate buf_pool.page_hash */ buf_pool.page_hash.replace(chain, bpage, dpage);
ut_ad(bpage->in_page_hash);
ut_ad(dpage->in_page_hash);
ut_d(bpage->in_page_hash= false);
HASH_REPLACE(buf_page_t, hash, &buf_pool.page_hash, fold, bpage, dpage);
} }
/** Register a watch for a page identifier. The caller must hold an /** Register a watch for a page identifier. The caller must hold an
exclusive page hash latch. The *hash_lock may be released, exclusive page hash latch. The *hash_lock may be released,
relocated, and reacquired. relocated, and reacquired.
@param id page identifier @param id page identifier
@param hash_lock exclusively held page_hash latch @param chain hash table chain with exclusively held page_hash
@return a buffer pool block corresponding to id @return a buffer pool block corresponding to id
@retval nullptr if the block was not present, and a watch was installed */ @retval nullptr if the block was not present, and a watch was installed */
inline buf_page_t *buf_pool_t::watch_set(const page_id_t id, inline buf_page_t *buf_pool_t::watch_set(const page_id_t id,
page_hash_latch **hash_lock) buf_pool_t::hash_chain &chain)
{ {
const ulint fold= id.fold(); ut_ad(&chain == &page_hash.cell_get(id.fold()));
ut_ad(*hash_lock == page_hash.lock_get(fold)); ut_ad(page_hash.lock_get(chain).is_write_locked());
ut_ad((*hash_lock)->is_write_locked());
retry: retry:
if (buf_page_t *bpage= page_hash_get_low(id, fold)) if (buf_page_t *bpage= page_hash.get(id, chain))
{ {
if (!watch_is_sentinel(*bpage)) if (!watch_is_sentinel(*bpage))
/* The page was loaded meanwhile. */ /* The page was loaded meanwhile. */
...@@ -2122,7 +2115,7 @@ inline buf_page_t *buf_pool_t::watch_set(const page_id_t id, ...@@ -2122,7 +2115,7 @@ inline buf_page_t *buf_pool_t::watch_set(const page_id_t id,
return nullptr; return nullptr;
} }
(*hash_lock)->write_unlock(); page_hash.lock_get(chain).write_unlock();
/* Allocate a watch[] and then try to insert it into the page_hash. */ /* Allocate a watch[] and then try to insert it into the page_hash. */
mysql_mutex_lock(&mutex); mysql_mutex_lock(&mutex);
...@@ -2142,28 +2135,23 @@ inline buf_page_t *buf_pool_t::watch_set(const page_id_t id, ...@@ -2142,28 +2135,23 @@ inline buf_page_t *buf_pool_t::watch_set(const page_id_t id,
ut_ad(!w->buf_fix_count()); ut_ad(!w->buf_fix_count());
/* w is pointing to watch[], which is protected by mutex. /* w is pointing to watch[], which is protected by mutex.
Normally, buf_page_t::id for objects that are reachable by Normally, buf_page_t::id for objects that are reachable by
page_hash_get_low(id, fold) are protected by hash_lock. */ page_hash.get(id, chain) are protected by hash_lock. */
w->set_state(BUF_BLOCK_ZIP_PAGE); w->set_state(BUF_BLOCK_ZIP_PAGE);
w->id_= id; w->id_= id;
*hash_lock= page_hash.lock_get(fold); buf_page_t *bpage= page_hash.get(id, chain);
buf_page_t *bpage= page_hash_get_low(id, fold);
if (UNIV_LIKELY_NULL(bpage)) if (UNIV_LIKELY_NULL(bpage))
{ {
w->set_state(BUF_BLOCK_NOT_USED); w->set_state(BUF_BLOCK_NOT_USED);
*hash_lock= page_hash.lock_get(fold); page_hash.lock_get(chain).write_lock();
(*hash_lock)->write_lock();
mysql_mutex_unlock(&mutex); mysql_mutex_unlock(&mutex);
goto retry; goto retry;
} }
(*hash_lock)->write_lock(); page_hash.lock_get(chain).write_lock();
ut_ad(!w->buf_fix_count_); ut_ad(!w->buf_fix_count_);
w->buf_fix_count_= 1; w->buf_fix_count_= 1;
ut_ad(!w->in_page_hash); buf_pool.page_hash.append(chain, w);
ut_d(w->in_page_hash= true);
HASH_INSERT(buf_page_t, hash, &page_hash, fold, w);
mysql_mutex_unlock(&mutex); mysql_mutex_unlock(&mutex);
return nullptr; return nullptr;
} }
...@@ -2175,43 +2163,40 @@ inline buf_page_t *buf_pool_t::watch_set(const page_id_t id, ...@@ -2175,43 +2163,40 @@ inline buf_page_t *buf_pool_t::watch_set(const page_id_t id,
/** Stop watching whether a page has been read in. /** Stop watching whether a page has been read in.
watch_set(id) must have returned nullptr before. watch_set(id) must have returned nullptr before.
@param id page identifier */ @param id page identifier
void buf_pool_t::watch_unset(const page_id_t id) @param chain unlocked hash table chain */
void buf_pool_t::watch_unset(const page_id_t id, buf_pool_t::hash_chain &chain)
{ {
mysql_mutex_assert_not_owner(&mutex); mysql_mutex_assert_not_owner(&mutex);
const ulint fold= id.fold(); page_hash_latch &hash_lock= page_hash.lock_get(chain);
page_hash_latch *hash_lock= page_hash.lock<true>(fold); hash_lock.write_lock();
/* The page must exist because watch_set() increments buf_fix_count. */ /* The page must exist because watch_set() increments buf_fix_count. */
buf_page_t *w= page_hash_get_low(id, fold); buf_page_t *w= page_hash.get(id, chain);
const auto buf_fix_count= w->buf_fix_count(); const auto buf_fix_count= w->buf_fix_count();
ut_ad(buf_fix_count); ut_ad(buf_fix_count);
const bool must_remove= buf_fix_count == 1 && watch_is_sentinel(*w); const bool must_remove= buf_fix_count == 1 && watch_is_sentinel(*w);
ut_ad(w->in_page_hash);
if (!must_remove) if (!must_remove)
w->unfix(); w->unfix();
hash_lock->write_unlock(); hash_lock.write_unlock();
if (must_remove) if (must_remove)
{ {
const auto old= w; const auto old= w;
/* The following is based on buf_pool_t::watch_remove(). */ /* The following is based on buf_pool_t::watch_remove(). */
mysql_mutex_lock(&mutex); mysql_mutex_lock(&mutex);
w= page_hash_get_low(id, fold); w= page_hash.get(id, chain);
page_hash_latch *hash_lock= buf_pool.page_hash.lock_get(fold); hash_lock.write_lock();
hash_lock->write_lock();
if (w->unfix() == 0 && w == old) if (w->unfix() == 0 && w == old)
{ {
ut_ad(w->in_page_hash); page_hash.remove(chain, w);
ut_d(w->in_page_hash= false);
HASH_DELETE(buf_page_t, hash, &page_hash, fold, w);
// Now that the watch is detached from page_hash, release it to watch[]. // Now that the watch is detached from page_hash, release it to watch[].
ut_ad(w->id_ == id); ut_ad(w->id_ == id);
ut_ad(!w->buf_fix_count()); ut_ad(!w->buf_fix_count());
ut_ad(w->state() == BUF_BLOCK_ZIP_PAGE); ut_ad(w->state() == BUF_BLOCK_ZIP_PAGE);
w->set_state(BUF_BLOCK_NOT_USED); w->set_state(BUF_BLOCK_NOT_USED);
} }
hash_lock->write_unlock();
mysql_mutex_unlock(&mutex); mysql_mutex_unlock(&mutex);
hash_lock.write_unlock();
} }
} }
...@@ -2233,10 +2218,11 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr) ...@@ -2233,10 +2218,11 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr)
++buf_pool.stat.n_page_gets; ++buf_pool.stat.n_page_gets;
const page_id_t page_id(space->id, page); const page_id_t page_id(space->id, page);
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<false>(fold); page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
hash_lock.read_lock();
if (buf_block_t *block= reinterpret_cast<buf_block_t*> if (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->page.state() != BUF_BLOCK_FILE_PAGE) if (block->page.state() != BUF_BLOCK_FILE_PAGE)
/* FIXME: convert, but avoid buf_zip_decompress() */; /* FIXME: convert, but avoid buf_zip_decompress() */;
...@@ -2244,7 +2230,7 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr) ...@@ -2244,7 +2230,7 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr)
{ {
buf_block_buf_fix_inc(block); buf_block_buf_fix_inc(block);
ut_ad(block->page.buf_fix_count()); ut_ad(block->page.buf_fix_count());
hash_lock->read_unlock(); hash_lock.read_unlock();
mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX);
block->lock.x_lock(); block->lock.x_lock();
...@@ -2254,7 +2240,7 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr) ...@@ -2254,7 +2240,7 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr)
} }
} }
hash_lock->read_unlock(); hash_lock.read_unlock();
} }
/** Get read access to a compressed page (usually of type /** Get read access to a compressed page (usually of type
...@@ -2274,16 +2260,18 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size) ...@@ -2274,16 +2260,18 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size)
++buf_pool.stat.n_page_gets; ++buf_pool.stat.n_page_gets;
bool discard_attempted= false; bool discard_attempted= false;
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);
buf_page_t *bpage; buf_page_t *bpage;
page_hash_latch *hash_lock;
for (;;) for (;;)
{ {
lookup: lookup:
bpage= buf_pool.page_hash_get_locked<false>(page_id, fold, &hash_lock); hash_lock.read_lock();
bpage= buf_pool.page_hash.get(page_id, chain);
if (bpage) if (bpage)
break; break;
hash_lock.read_unlock();
dberr_t err= buf_read_page(page_id, zip_size); dberr_t err= buf_read_page(page_id, zip_size);
...@@ -2299,13 +2287,11 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size) ...@@ -2299,13 +2287,11 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size)
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
} }
ut_ad(hash_lock->is_locked());
if (!bpage->zip.data) if (!bpage->zip.data)
{ {
/* There is no compressed page. */ /* There is no compressed page. */
err_exit: err_exit:
hash_lock->read_unlock(); hash_lock.read_unlock();
return nullptr; return nullptr;
} }
...@@ -2317,9 +2303,9 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size) ...@@ -2317,9 +2303,9 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size)
if (!discard_attempted) if (!discard_attempted)
{ {
discard_attempted= true; discard_attempted= true;
hash_lock->read_unlock(); hash_lock.read_unlock();
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))
buf_LRU_free_page(bpage, false); buf_LRU_free_page(bpage, false);
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
goto lookup; goto lookup;
...@@ -2337,7 +2323,7 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size) ...@@ -2337,7 +2323,7 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size)
got_block: got_block:
bool must_read= bpage->io_fix() == BUF_IO_READ; bool must_read= bpage->io_fix() == BUF_IO_READ;
hash_lock->read_unlock(); hash_lock.read_unlock();
DBUG_ASSERT(bpage->status != buf_page_t::FREED); DBUG_ASSERT(bpage->status != buf_page_t::FREED);
...@@ -2521,7 +2507,6 @@ buf_page_get_low( ...@@ -2521,7 +2507,6 @@ buf_page_get_low(
buf_block_t* block; buf_block_t* block;
unsigned access_time; unsigned access_time;
ulint retries = 0; ulint retries = 0;
const ulint fold = page_id.fold();
ut_ad((mtr == NULL) == (mode == BUF_EVICT_IF_IN_POOL)); ut_ad((mtr == NULL) == (mode == BUF_EVICT_IF_IN_POOL));
ut_ad(!mtr || mtr->is_active()); ut_ad(!mtr || mtr->is_active());
...@@ -2572,57 +2557,53 @@ buf_page_get_low( ...@@ -2572,57 +2557,53 @@ buf_page_get_low(
|| ibuf_page_low(page_id, zip_size, FALSE, NULL)); || ibuf_page_low(page_id, zip_size, FALSE, NULL));
++buf_pool.stat.n_page_gets; ++buf_pool.stat.n_page_gets;
auto& chain= buf_pool.page_hash.cell_get(page_id.fold());
page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain);
loop: loop:
buf_block_t* fix_block; buf_block_t* fix_block;
block = guess; hash_lock.read_lock();
page_hash_latch* hash_lock = buf_pool.page_hash.lock<false>(fold); /* If the guess is a compressed page descriptor that
has been allocated by buf_page_alloc_descriptor(),
if (block) { it may have been freed by buf_relocate(). */
if (guess && buf_pool.is_uncompressed(guess)
&& page_id == guess->page.id()
&& guess->page.state() == BUF_BLOCK_FILE_PAGE) {
ut_ad(!guess->page.in_zip_hash);
block = guess;
goto have_block;
}
/* If the guess is a compressed page descriptor that guess = nullptr;
has been allocated by buf_page_alloc_descriptor(), block = reinterpret_cast<buf_block_t*>(
it may have been freed by buf_relocate(). */ buf_pool.page_hash.get(page_id, chain));
if (!buf_pool.is_uncompressed(block) if (block && !buf_pool.watch_is_sentinel(block->page)) {
|| page_id != block->page.id() have_block:
|| block->page.state() != BUF_BLOCK_FILE_PAGE) { fix_block = block;
/* Our guess was bogus or things have changed
since. */
guess = nullptr;
goto lookup;
} else {
ut_ad(!block->page.in_zip_hash);
}
} else { } else {
lookup: hash_lock.read_unlock();
block = reinterpret_cast<buf_block_t*>( fix_block = block = nullptr;
buf_pool.page_hash_get_low(page_id, fold));
}
if (!block || buf_pool.watch_is_sentinel(block->page)) {
hash_lock->read_unlock();
block = nullptr;
}
if (UNIV_UNLIKELY(!block)) {
/* Page not in buf_pool: needs to be read from file */ /* Page not in buf_pool: needs to be read from file */
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) { if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
hash_lock = buf_pool.page_hash.lock<true>(fold); hash_lock.write_lock();
if (buf_page_t *bpage= buf_pool.watch_set( if (buf_page_t *bpage= buf_pool.watch_set(page_id,
page_id, &hash_lock)) { chain)) {
/* We can release hash_lock after we /* We can release hash_lock after we
increment the fix count to make increment the fix count to make
sure that no state change takes place. */ sure that no state change takes place. */
bpage->fix(); bpage->fix();
hash_lock->write_unlock(); hash_lock.write_unlock();
block = reinterpret_cast<buf_block_t*>(bpage); block = reinterpret_cast<buf_block_t*>(bpage);
fix_block = block; fix_block = block;
goto got_block; goto got_block;
} }
hash_lock->write_unlock(); hash_lock.write_unlock();
} }
switch (mode) { switch (mode) {
...@@ -2714,12 +2695,10 @@ buf_page_get_low( ...@@ -2714,12 +2695,10 @@ buf_page_get_low(
if (!(++buf_dbg_counter % 5771)) buf_pool.validate(); if (!(++buf_dbg_counter % 5771)) buf_pool.validate();
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
goto loop; goto loop;
} else {
fix_block = block;
} }
fix_block->fix(); fix_block->fix();
hash_lock->read_unlock(); hash_lock.read_unlock();
got_block: got_block:
switch (mode) { switch (mode) {
...@@ -2811,12 +2790,10 @@ buf_page_get_low( ...@@ -2811,12 +2790,10 @@ buf_page_get_low(
buf_block_init_low(block); buf_block_init_low(block);
mysql_mutex_lock(&buf_pool.mutex); mysql_mutex_lock(&buf_pool.mutex);
hash_lock = buf_pool.page_hash.lock_get(fold); hash_lock.write_lock();
hash_lock->write_lock();
/* Buffer-fixing prevents the page_hash from changing. */ /* Buffer-fixing prevents the page_hash from changing. */
ut_ad(bpage == buf_pool.page_hash_get_low(page_id, fold)); ut_ad(bpage == buf_pool.page_hash.get(page_id, chain));
fix_block->unfix(); /* hash_lock protects us after this */ fix_block->unfix(); /* hash_lock protects us after this */
...@@ -2827,7 +2804,7 @@ buf_page_get_low( ...@@ -2827,7 +2804,7 @@ buf_page_get_low(
This should be extremely unlikely, for example, This should be extremely unlikely, for example,
if buf_page_get_zip() was invoked. */ if buf_page_get_zip() was invoked. */
hash_lock->write_unlock(); hash_lock.write_unlock();
buf_LRU_block_free_non_file_page(block); buf_LRU_block_free_non_file_page(block);
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
...@@ -2866,7 +2843,7 @@ buf_page_get_low( ...@@ -2866,7 +2843,7 @@ buf_page_get_low(
MEM_UNDEFINED(bpage, sizeof *bpage); MEM_UNDEFINED(bpage, sizeof *bpage);
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
hash_lock->write_unlock(); hash_lock.write_unlock();
buf_pool.n_pend_unzip++; buf_pool.n_pend_unzip++;
access_time = block->page.is_accessed(); access_time = block->page.is_accessed();
...@@ -2923,17 +2900,16 @@ buf_page_get_low( ...@@ -2923,17 +2900,16 @@ buf_page_get_low(
space->release(); space->release();
if (evicted) { if (evicted) {
hash_lock = buf_pool.page_hash.lock_get(fold); hash_lock.write_lock();
hash_lock->write_lock();
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
/* We may set the watch, as it would have /* We may set the watch, as it would have
been set if the page were not in the been set if the page were not in the
buffer pool in the first place. */ buffer pool in the first place. */
block= reinterpret_cast<buf_block_t*>( block= reinterpret_cast<buf_block_t*>(
mode == BUF_GET_IF_IN_POOL_OR_WATCH mode == BUF_GET_IF_IN_POOL_OR_WATCH
? buf_pool.watch_set(page_id, &hash_lock) ? buf_pool.watch_set(page_id, chain)
: buf_pool.page_hash_get_low(page_id, fold)); : buf_pool.page_hash.get(page_id, chain));
hash_lock->write_unlock(); hash_lock.write_unlock();
if (block != NULL) { if (block != NULL) {
/* Either the page has been read in or /* Either the page has been read in or
...@@ -3114,20 +3090,20 @@ buf_page_optimistic_get( ...@@ -3114,20 +3090,20 @@ buf_page_optimistic_get(
return FALSE; return FALSE;
} }
const page_id_t id(block->page.id()); const page_id_t id{block->page.id()};
buf_pool_t::hash_chain& chain = buf_pool.page_hash.cell_get(id.fold());
page_hash_latch *hash_lock = buf_pool.hash_lock_get(id); page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain);
hash_lock->read_lock(); hash_lock.read_lock();
if (UNIV_UNLIKELY(id != block->page.id() if (UNIV_UNLIKELY(id != block->page.id()
|| block->page.state() != BUF_BLOCK_FILE_PAGE || block->page.state() != BUF_BLOCK_FILE_PAGE
|| block->page.io_fix() != BUF_IO_NONE)) { || block->page.io_fix() != BUF_IO_NONE)) {
hash_lock->read_unlock(); hash_lock.read_unlock();
return(FALSE); return(FALSE);
} }
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();
...@@ -3194,21 +3170,19 @@ buf_block_t *buf_page_try_get(const page_id_t page_id, mtr_t *mtr) ...@@ -3194,21 +3170,19 @@ buf_block_t *buf_page_try_get(const page_id_t page_id, mtr_t *mtr)
ut_ad(mtr); ut_ad(mtr);
ut_ad(mtr->is_active()); ut_ad(mtr->is_active());
page_hash_latch *hash_lock; buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(page_id.fold());
buf_page_t *bpage= buf_pool.page_hash_get_locked<false>(page_id, page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
page_id.fold(), hash_lock.read_lock();
&hash_lock); buf_page_t *bpage= buf_pool.page_hash.get(page_id, chain);
if (!bpage) if (!bpage || bpage->state() != BUF_BLOCK_FILE_PAGE)
return nullptr;
if (bpage->state() != BUF_BLOCK_FILE_PAGE)
{ {
hash_lock->read_unlock(); hash_lock.read_unlock();
return nullptr; return nullptr;
} }
buf_block_t *block= reinterpret_cast<buf_block_t*>(bpage); buf_block_t *block= reinterpret_cast<buf_block_t*>(bpage);
buf_block_buf_fix_inc(block); buf_block_buf_fix_inc(block);
hash_lock->read_unlock(); hash_lock.read_unlock();
if (!block->lock.s_lock_try()) if (!block->lock.s_lock_try())
{ {
...@@ -3250,12 +3224,12 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size, ...@@ -3250,12 +3224,12 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
free_block->initialise(page_id, zip_size, 1); free_block->initialise(page_id, zip_size, 1);
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);
loop: loop:
buf_block_t *block= reinterpret_cast<buf_block_t*> 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.in_file() && if (block && block->page.in_file() &&
!buf_pool.watch_is_sentinel(block->page)) !buf_pool.watch_is_sentinel(block->page))
...@@ -3294,11 +3268,11 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size, ...@@ -3294,11 +3268,11 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
#endif #endif
break; break;
case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_PAGE:
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();
if (block->page.io_fix() != BUF_IO_NONE) if (block->page.io_fix() != BUF_IO_NONE)
{ {
hash_lock->write_unlock(); hash_lock.write_unlock();
/* Wait for buf_page_write_complete() to release the I/O fix. */ /* Wait for buf_page_write_complete() to release the I/O fix. */
timespec abstime; timespec abstime;
set_timespec_nsec(abstime, 1000000); set_timespec_nsec(abstime, 1000000);
...@@ -3315,7 +3289,7 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size, ...@@ -3315,7 +3289,7 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
free_block->page.set_state(BUF_BLOCK_FILE_PAGE); free_block->page.set_state(BUF_BLOCK_FILE_PAGE);
buf_unzip_LRU_add_block(free_block, FALSE); buf_unzip_LRU_add_block(free_block, FALSE);
hash_lock->write_unlock(); hash_lock.write_unlock();
buf_page_free_descriptor(&block->page); buf_page_free_descriptor(&block->page);
block= free_block; block= free_block;
buf_block_buf_fix_inc(block); buf_block_buf_fix_inc(block);
...@@ -3351,11 +3325,10 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size, ...@@ -3351,11 +3325,10 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
/* The block must be put to the LRU list */ /* The block must be put to the LRU list */
buf_LRU_add_block(&block->page, false); buf_LRU_add_block(&block->page, false);
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();
block->page.set_state(BUF_BLOCK_FILE_PAGE); block->page.set_state(BUF_BLOCK_FILE_PAGE);
ut_d(block->page.in_page_hash= true); buf_pool.page_hash.append(chain, &block->page);
HASH_INSERT(buf_page_t, hash, &buf_pool.page_hash, fold, &block->page);
block->lock.x_lock(); block->lock.x_lock();
if (UNIV_UNLIKELY(zip_size)) if (UNIV_UNLIKELY(zip_size))
...@@ -3364,7 +3337,7 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size, ...@@ -3364,7 +3337,7 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
release and reacquire buf_pool.mutex, by IO-fixing and X-latching release and reacquire buf_pool.mutex, by IO-fixing and X-latching
the block. */ the block. */
block->page.set_io_fix(BUF_IO_READ); block->page.set_io_fix(BUF_IO_READ);
hash_lock->write_unlock(); hash_lock.write_unlock();
/* buf_pool.mutex may be released and reacquired by /* buf_pool.mutex may be released and reacquired by
buf_buddy_alloc(). We must defer this operation until buf_buddy_alloc(). We must defer this operation until
...@@ -3381,7 +3354,7 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size, ...@@ -3381,7 +3354,7 @@ static buf_block_t* buf_page_create_low(page_id_t page_id, ulint zip_size,
block->page.set_io_fix(BUF_IO_NONE); block->page.set_io_fix(BUF_IO_NONE);
} }
else else
hash_lock->write_unlock(); hash_lock.write_unlock();
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
...@@ -3564,32 +3537,6 @@ static void buf_mark_space_corrupt(buf_page_t* bpage, const fil_space_t& space) ...@@ -3564,32 +3537,6 @@ static void buf_mark_space_corrupt(buf_page_t* bpage, const fil_space_t& space)
} }
} }
/** Release and evict a corrupted page.
@param bpage page that was being read */
ATTRIBUTE_COLD void buf_pool_t::corrupted_evict(buf_page_t *bpage)
{
const page_id_t id(bpage->id());
page_hash_latch *hash_lock= hash_lock_get(id);
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();
if (bpage->state() == BUF_BLOCK_FILE_PAGE)
reinterpret_cast<buf_block_t*>(bpage)->lock.x_unlock(true);
bpage->io_unfix();
/* remove from LRU and page_hash */
buf_LRU_free_one_page(bpage, id, hash_lock);
mysql_mutex_unlock(&mutex);
ut_d(auto n=) n_pend_reads--;
ut_ad(n > 0);
}
/** Mark a table corrupted. /** Mark a table corrupted.
@param[in] bpage Corrupted page @param[in] bpage Corrupted page
@param[in] node data file @param[in] node data file
...@@ -3955,7 +3902,8 @@ void buf_pool_t::validate() ...@@ -3955,7 +3902,8 @@ void buf_pool_t::validate()
case BUF_BLOCK_FILE_PAGE: case BUF_BLOCK_FILE_PAGE:
const page_id_t id = block->page.id(); const page_id_t id = block->page.id();
ut_ad(page_hash_get_low(id, id.fold()) ut_ad(page_hash.get(id, page_hash.cell_get(
id.fold()))
== &block->page); == &block->page);
n_lru++; n_lru++;
break; break;
...@@ -3988,7 +3936,7 @@ void buf_pool_t::validate() ...@@ -3988,7 +3936,7 @@ void buf_pool_t::validate()
break; break;
} }
const page_id_t id = b->id(); const page_id_t id = b->id();
ut_ad(page_hash_get_low(id, id.fold()) == b); ut_ad(page_hash.get(id, page_hash.cell_get(id.fold())) == b);
} }
ut_ad(UT_LIST_GET_LEN(flush_list) == n_flushing); ut_ad(UT_LIST_GET_LEN(flush_list) == n_flushing);
......
...@@ -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
......
...@@ -36,7 +36,6 @@ Created 11/5/1995 Heikki Tuuri ...@@ -36,7 +36,6 @@ Created 11/5/1995 Heikki Tuuri
#include "assume_aligned.h" #include "assume_aligned.h"
#include "buf0types.h" #include "buf0types.h"
#ifndef UNIV_INNOCHECKSUM #ifndef UNIV_INNOCHECKSUM
#include "hash0hash.h"
#include "ut0byte.h" #include "ut0byte.h"
#include "page0types.h" #include "page0types.h"
#include "log0log.h" #include "log0log.h"
...@@ -169,30 +168,10 @@ operator<<( ...@@ -169,30 +168,10 @@ operator<<(
const page_id_t page_id); const page_id_t page_id);
#ifndef UNIV_INNOCHECKSUM #ifndef UNIV_INNOCHECKSUM
/*********************************************************************//** # define buf_pool_get_curr_size() srv_buf_pool_curr_size
Gets the current size of buffer buf_pool in bytes. # define buf_page_alloc_descriptor() \
@return size in bytes */ static_cast<buf_page_t*>(ut_zalloc_nokey(sizeof(buf_page_t)))
UNIV_INLINE # define buf_page_free_descriptor(bpage) ut_free(bpage)
ulint
buf_pool_get_curr_size(void);
/*========================*/
/********************************************************************//**
Allocates a buf_page_t descriptor. This function must succeed. In case
of failure we assert in this function. */
UNIV_INLINE
buf_page_t*
buf_page_alloc_descriptor(void)
/*===========================*/
MY_ATTRIBUTE((malloc));
/********************************************************************//**
Free a buf_page_t descriptor. */
UNIV_INLINE
void
buf_page_free_descriptor(
/*=====================*/
buf_page_t* bpage) /*!< in: bpage descriptor to free. */
MY_ATTRIBUTE((nonnull));
/** 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 */
...@@ -349,25 +328,6 @@ void buf_page_make_young(buf_page_t *bpage); ...@@ -349,25 +328,6 @@ void buf_page_make_young(buf_page_t *bpage);
@param[in,out] mtr mini-transaction */ @param[in,out] mtr mini-transaction */
void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr); void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr);
/********************************************************************//**
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 */
MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
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 */
MY_ATTRIBUTE((warn_unused_result));
/** 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.
...@@ -665,7 +625,7 @@ class buf_page_t ...@@ -665,7 +625,7 @@ class buf_page_t
/* @{ */ /* @{ */
public: // FIXME: fix fil_iterate() public: // FIXME: fix fil_iterate()
/** Page id. Protected by buf_pool.hash_lock_get(id) when /** Page id. Protected by buf_pool.page_hash.lock_get() when
the page is in buf_pool.page_hash. */ the page is in buf_pool.page_hash. */
page_id_t id_; page_id_t id_;
private: private:
...@@ -687,13 +647,13 @@ class buf_page_t ...@@ -687,13 +647,13 @@ class buf_page_t
Atomic_relaxed<buf_io_fix> io_fix_; Atomic_relaxed<buf_io_fix> io_fix_;
/** Block state. @see in_file(). /** Block state. @see in_file().
State transitions between in_file() states and to State transitions between in_file() states and to
BUF_BLOCK_REMOVE_HASH are protected by buf_pool.hash_lock_get(id) BUF_BLOCK_REMOVE_HASH are protected by buf_pool.page_hash.lock_get()
when the block is in buf_pool.page_hash. when the block is in buf_pool.page_hash.
Other transitions when in_LRU_list are protected by buf_pool.mutex. */ Other transitions when in_LRU_list are protected by buf_pool.mutex. */
buf_page_state state_; buf_page_state state_;
public: public:
/** buf_pool.page_hash link; protected by buf_pool.hash_lock_get(id) */ /** buf_pool.page_hash link; protected by buf_pool.page_hash.lock_get() */
buf_page_t *hash; buf_page_t *hash;
/* @} */ /* @} */
page_zip_des_t zip; /*!< compressed page; zip.data page_zip_des_t zip; /*!< compressed page; zip.data
...@@ -801,7 +761,6 @@ class buf_page_t ...@@ -801,7 +761,6 @@ class buf_page_t
ut_d(in_free_list= false); ut_d(in_free_list= false);
ut_d(in_LRU_list= false); ut_d(in_LRU_list= false);
ut_d(in_page_hash= false); ut_d(in_page_hash= false);
HASH_INVALIDATE(this, hash);
} }
/** Initialize some more fields */ /** Initialize some more fields */
...@@ -819,6 +778,7 @@ class buf_page_t ...@@ -819,6 +778,7 @@ class buf_page_t
init(); init();
id_= id; id_= id;
buf_fix_count_= buf_fix_count; buf_fix_count_= buf_fix_count;
hash= nullptr;
} }
public: public:
...@@ -1347,7 +1307,14 @@ class buf_pool_t ...@@ -1347,7 +1307,14 @@ class buf_pool_t
inline const buf_block_t *not_freed() const; inline const buf_block_t *not_freed() const;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
}; };
public:
/** Hash cell chain in page_hash_table */
struct hash_chain
{
/** pointer to the first block */
buf_page_t *first;
};
private:
/** Withdraw blocks from the buffer pool until meeting withdraw_target. /** Withdraw blocks from the buffer pool until meeting withdraw_target.
@return whether retry is needed */ @return whether retry is needed */
inline bool withdraw_blocks(); inline bool withdraw_blocks();
...@@ -1509,89 +1476,29 @@ class buf_pool_t ...@@ -1509,89 +1476,29 @@ class buf_pool_t
return is_block_field(reinterpret_cast<const void*>(block)); return is_block_field(reinterpret_cast<const void*>(block));
} }
/** Get the page_hash latch for a page */ public:
page_hash_latch *hash_lock_get(const page_id_t id) const /** @return whether the buffer pool contains a page
{
return page_hash.lock_get(id.fold());
}
/** Look up a block descriptor.
@param id page identifier
@param fold id.fold()
@return block descriptor, possibly in watch[]
@retval nullptr if not found*/
buf_page_t *page_hash_get_low(const page_id_t id, const ulint fold)
{
ut_ad(id.fold() == fold);
#ifdef SAFE_MUTEX
DBUG_ASSERT(mysql_mutex_is_owner(&mutex) ||
page_hash.lock_get(fold)->is_locked());
#endif /* SAFE_MUTEX */
buf_page_t *bpage;
/* Look for the page in the hash table */
HASH_SEARCH(hash, &page_hash, fold, buf_page_t*, bpage,
ut_ad(bpage->in_page_hash), id == bpage->id());
return bpage;
}
private:
/** Look up a block descriptor.
@tparam exclusive whether the latch is to be acquired exclusively
@tparam watch whether to allow watch_is_sentinel() @tparam watch whether to allow watch_is_sentinel()
@param page_id page identifier @param page_id page identifier
@param fold page_id.fold() @param chain hash table chain for page_id.fold() */
@param hash_lock pointer to the acquired latch (to be released by caller) template<bool watch= false>
@return pointer to the block bool page_hash_contains(const page_id_t page_id, hash_chain &chain)
@retval nullptr if no block was found; !lock || !*lock will also hold */
template<bool exclusive,bool watch>
buf_page_t *page_hash_get_locked(const page_id_t page_id, ulint fold,
page_hash_latch **hash_lock)
{ {
ut_ad(hash_lock || !exclusive); page_hash_latch &latch= page_hash.lock_get(chain);
page_hash_latch *latch= page_hash.lock<exclusive>(fold); latch.read_lock();
buf_page_t *bpage= page_hash_get_low(page_id, fold); buf_page_t *bpage= page_hash.get(page_id, chain);
if (!bpage || watch_is_sentinel(*bpage)) if (!bpage || watch_is_sentinel(*bpage))
{ {
if (exclusive) latch.read_unlock();
latch->write_unlock();
else
latch->read_unlock();
if (hash_lock)
*hash_lock= nullptr;
return watch ? bpage : nullptr; return watch ? bpage : nullptr;
} }
ut_ad(bpage->in_file()); ut_ad(bpage->in_file());
ut_ad(page_id == bpage->id()); ut_ad(page_id == bpage->id());
if (hash_lock) latch.read_unlock();
*hash_lock= latch; /* to be released by the caller */
else if (exclusive)
latch->write_unlock();
else
latch->read_unlock();
return bpage; return bpage;
} }
public:
/** Look up a block descriptor.
@tparam exclusive whether the latch is to be acquired exclusively
@param page_id page identifier
@param fold page_id.fold()
@param hash_lock pointer to the acquired latch (to be released by caller)
@return pointer to the block
@retval nullptr if no block was found; !lock || !*lock will also hold */
template<bool exclusive>
buf_page_t *page_hash_get_locked(const page_id_t page_id, ulint fold,
page_hash_latch **hash_lock)
{ return page_hash_get_locked<exclusive,false>(page_id, fold, hash_lock); }
/** @return whether the buffer pool contains a page
@tparam watch whether to allow watch_is_sentinel()
@param page_id page identifier */
template<bool watch= false>
bool page_hash_contains(const page_id_t page_id)
{
return page_hash_get_locked<false,watch>(page_id, page_id.fold(), nullptr);
}
/** Determine if a block is a sentinel for a buffer pool watch. /** Determine if a block is a sentinel for a buffer pool watch.
@param bpage page descriptor @param bpage page descriptor
...@@ -1600,7 +1507,8 @@ class buf_pool_t ...@@ -1600,7 +1507,8 @@ class buf_pool_t
{ {
#ifdef SAFE_MUTEX #ifdef SAFE_MUTEX
DBUG_ASSERT(mysql_mutex_is_owner(&mutex) || DBUG_ASSERT(mysql_mutex_is_owner(&mutex) ||
hash_lock_get(bpage.id())->is_locked()); page_hash.lock_get(page_hash.cell_get(bpage.id().fold())).
is_locked());
#endif /* SAFE_MUTEX */ #endif /* SAFE_MUTEX */
ut_ad(bpage.in_file()); ut_ad(bpage.in_file());
...@@ -1622,12 +1530,13 @@ class buf_pool_t ...@@ -1622,12 +1530,13 @@ class buf_pool_t
@return whether the page was read to the buffer pool */ @return whether the page was read to the buffer pool */
bool watch_occurred(const page_id_t id) bool watch_occurred(const page_id_t id)
{ {
const ulint fold= id.fold(); hash_chain &chain= page_hash.cell_get(id.fold());
page_hash_latch *hash_lock= page_hash.lock<false>(fold); page_hash_latch &latch= page_hash.lock_get(chain);
latch.read_lock();
/* The page must exist because watch_set() increments buf_fix_count. */ /* The page must exist because watch_set() increments buf_fix_count. */
buf_page_t *bpage= page_hash_get_low(id, fold); buf_page_t *bpage= page_hash.get(id, chain);
const bool is_sentinel= watch_is_sentinel(*bpage); const bool is_sentinel= watch_is_sentinel(*bpage);
hash_lock->read_unlock(); latch.read_unlock();
return !is_sentinel; return !is_sentinel;
} }
...@@ -1635,22 +1544,23 @@ class buf_pool_t ...@@ -1635,22 +1544,23 @@ class buf_pool_t
exclusive page hash latch. The *hash_lock may be released, exclusive page hash latch. The *hash_lock may be released,
relocated, and reacquired. relocated, and reacquired.
@param id page identifier @param id page identifier
@param hash_lock exclusively held page_hash latch @param chain hash table chain with exclusively held page_hash
@return a buffer pool block corresponding to id @return a buffer pool block corresponding to id
@retval nullptr if the block was not present, and a watch was installed */ @retval nullptr if the block was not present, and a watch was installed */
inline buf_page_t *watch_set(const page_id_t id, inline buf_page_t *watch_set(const page_id_t id, hash_chain &chain);
page_hash_latch **hash_lock);
/** Stop watching whether a page has been read in. /** Stop watching whether a page has been read in.
watch_set(id) must have returned nullptr before. watch_set(id) must have returned nullptr before.
@param id page identifier */ @param id page identifier
void watch_unset(const page_id_t id); @param chain unlocked hash table chain */
void watch_unset(const page_id_t id, hash_chain &chain);
/** 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 watch_remove(buf_page_t *watch); @param chain locked hash table chain */
inline void watch_remove(buf_page_t *watch, hash_chain &chain);
/** @return whether less than 1/4 of the buffer pool is available */ /** @return whether less than 1/4 of the buffer pool is available */
bool running_out() const bool running_out() const
...@@ -1728,7 +1638,7 @@ class buf_pool_t ...@@ -1728,7 +1638,7 @@ class buf_pool_t
/** read-ahead request size in pages */ /** read-ahead request size in pages */
Atomic_counter<uint32_t> read_ahead_area; Atomic_counter<uint32_t> read_ahead_area;
/** Hash table with singly-linked overflow lists. @see hash_table_t */ /** Hash table with singly-linked overflow lists */
struct page_hash_table struct page_hash_table
{ {
static_assert(CPU_LEVEL1_DCACHE_LINESIZE >= 64, "less than 64 bytes"); static_assert(CPU_LEVEL1_DCACHE_LINESIZE >= 64, "less than 64 bytes");
...@@ -1744,7 +1654,7 @@ class buf_pool_t ...@@ -1744,7 +1654,7 @@ class buf_pool_t
/** number of payload elements in array[] */ /** number of payload elements in array[] */
Atomic_relaxed<ulint> n_cells; Atomic_relaxed<ulint> n_cells;
/** the hash table, with pad(n_cells) elements, aligned to L1 cache size */ /** the hash table, with pad(n_cells) elements, aligned to L1 cache size */
hash_cell_t *array; hash_chain *array;
/** Create the hash table. /** Create the hash table.
@param n the lower bound of n_cells */ @param n the lower bound of n_cells */
...@@ -1771,32 +1681,72 @@ class buf_pool_t ...@@ -1771,32 +1681,72 @@ class buf_pool_t
{ {
return pad(hash(fold, n_cells)); return pad(hash(fold, n_cells));
} }
/** Get a page_hash latch. */ public:
page_hash_latch *lock_get(ulint fold, ulint n) const /** @return the latch covering a hash table chain */
static page_hash_latch &lock_get(hash_chain &chain)
{ {
static_assert(!((ELEMENTS_PER_LATCH + 1) & ELEMENTS_PER_LATCH), static_assert(!((ELEMENTS_PER_LATCH + 1) & ELEMENTS_PER_LATCH),
"must be one less than a power of 2"); "must be one less than a power of 2");
return reinterpret_cast<page_hash_latch*> const size_t addr= reinterpret_cast<size_t>(&chain);
(&array[calc_hash(fold, n) & ~ELEMENTS_PER_LATCH]); ut_ad(addr & (ELEMENTS_PER_LATCH * sizeof chain));
return *reinterpret_cast<page_hash_latch*>
(addr & ~(ELEMENTS_PER_LATCH * sizeof chain));
} }
public:
/** Get a page_hash latch. */ /** Get a hash table slot. */
page_hash_latch *lock_get(ulint fold) const hash_chain &cell_get(ulint fold) const
{ return lock_get(fold, n_cells); } { return array[calc_hash(fold, n_cells)]; }
/** Acquire an array latch. /** Append a block descriptor to a hash bucket chain. */
@tparam exclusive whether the latch is to be acquired exclusively void append(hash_chain &chain, buf_page_t *bpage)
@param fold hash bucket key */ {
template<bool exclusive> page_hash_latch *lock(ulint fold) ut_ad(!bpage->in_page_hash);
ut_ad(!bpage->hash);
ut_d(bpage->in_page_hash= true);
buf_page_t **prev= &chain.first;
while (*prev)
{
ut_ad((*prev)->in_page_hash);
prev= &(*prev)->hash;
}
*prev= bpage;
}
/** Remove a block descriptor from a hash bucket chain. */
void remove(hash_chain &chain, buf_page_t *bpage)
{
ut_ad(bpage->in_page_hash);
buf_page_t **prev= &chain.first;
while (*prev != bpage)
{
ut_ad((*prev)->in_page_hash);
prev= &(*prev)->hash;
}
*prev= bpage->hash;
ut_d(bpage->in_page_hash= false);
bpage->hash= nullptr;
}
/** Replace a block descriptor with another. */
void replace(hash_chain &chain, buf_page_t *old, buf_page_t *bpage)
{ {
page_hash_latch *latch= lock_get(fold, n_cells); ut_ad(old->in_page_hash);
if (exclusive) ut_ad(bpage->in_page_hash);
latch->write_lock(); ut_d(old->in_page_hash= false);
else ut_ad(bpage->hash == old->hash);
latch->read_lock(); old->hash= nullptr;
return latch; buf_page_t **prev= &chain.first;
while (*prev != old)
{
ut_ad((*prev)->in_page_hash);
prev= &(*prev)->hash;
}
*prev= bpage;
} }
/** Look up a page in a hash bucket chain. */
inline buf_page_t *get(const page_id_t id, const hash_chain &chain) const;
/** Exclusively aqcuire all latches */ /** Exclusively aqcuire all latches */
inline void write_lock_all(); inline void write_lock_all();
...@@ -2032,6 +1982,23 @@ class buf_pool_t ...@@ -2032,6 +1982,23 @@ class buf_pool_t
/** The InnoDB buffer pool */ /** The InnoDB buffer pool */
extern buf_pool_t buf_pool; extern buf_pool_t buf_pool;
inline buf_page_t *buf_pool_t::page_hash_table::get(const page_id_t id,
const hash_chain &chain)
const
{
#ifdef SAFE_MUTEX
DBUG_ASSERT(mysql_mutex_is_owner(&buf_pool.mutex) ||
lock_get(const_cast<hash_chain&>(chain)).is_locked());
#endif /* SAFE_MUTEX */
for (buf_page_t *bpage= chain.first; bpage; bpage= bpage->hash)
{
ut_ad(bpage->in_page_hash);
if (bpage->id() == id)
return bpage;
}
return nullptr;
}
#ifdef SUX_LOCK_GENERIC #ifdef SUX_LOCK_GENERIC
inline void page_hash_latch::read_lock() inline void page_hash_latch::read_lock()
{ {
...@@ -2070,18 +2037,17 @@ inline void buf_page_t::set_state(buf_page_state state) ...@@ -2070,18 +2037,17 @@ inline void buf_page_t::set_state(buf_page_state state)
we are holding the hash_lock. */ we are holding the hash_lock. */
break; break;
case BUF_BLOCK_MEMORY: case BUF_BLOCK_MEMORY:
if (!in_file()) break;
/* fall through */
case BUF_BLOCK_FILE_PAGE:
ut_ad(buf_pool.hash_lock_get(id_)->is_write_locked());
break; break;
case BUF_BLOCK_NOT_USED: case BUF_BLOCK_NOT_USED:
if (!in_file()) break; break;
/* fall through */
case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_PAGE:
ut_ad(buf_pool.hash_lock_get(id_)->is_write_locked() || if (this >= &buf_pool.watch[0] &&
(this >= &buf_pool.watch[0] && this <= &buf_pool.watch[UT_ARR_SIZE(buf_pool.watch)])
this <= &buf_pool.watch[UT_ARR_SIZE(buf_pool.watch)])); break;
/* fall through */
case BUF_BLOCK_FILE_PAGE:
ut_ad(buf_pool.page_hash.lock_get(buf_pool.page_hash.cell_get(id_.fold())).
is_write_locked());
break; break;
} }
#endif #endif
...@@ -2113,7 +2079,8 @@ inline void buf_page_t::set_corrupt_id() ...@@ -2113,7 +2079,8 @@ inline void buf_page_t::set_corrupt_id()
break; break;
case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_FILE_PAGE: case BUF_BLOCK_FILE_PAGE:
ut_ad(buf_pool.hash_lock_get(id_)->is_write_locked()); ut_ad(buf_pool.page_hash.lock_get(buf_pool.page_hash.cell_get(id_.fold())).
is_write_locked());
break; break;
case BUF_BLOCK_NOT_USED: case BUF_BLOCK_NOT_USED:
case BUF_BLOCK_MEMORY: case BUF_BLOCK_MEMORY:
......
...@@ -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