/** The number of blocks from the LRU_old pointer onward, including theblockpointedto,mustbebuf_pool.LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV ofthewholeLRUlistlength,exceptthatthetolerancedefinedbelow isallowed.Notethatthetolerancemustbesmallenoughsuchthatfor eventheBUF_LRU_OLD_MIN_LENlongLRUlist,theLRU_oldpointerisnot
allowed to point to either end of the LRU list. */
/** The minimum amount of non-old blocks when the LRU_old list exists (thatis,whentherearemorethanBUF_LRU_OLD_MIN_LENblocks).
@see buf_LRU_old_adjust_len */ #define BUF_LRU_NON_OLD_MIN_LEN 5
/** If we switch on the InnoDB monitor because there are too few available
frames in the buffer pool, we set this to TRUE */ staticbool buf_lru_switched_on_innodb_mon = false;
/******************************************************************//**
These statistics are not'of' LRU but 'for' LRU. We keep count of I/O and page_zip_decompress() operations. Based on the statistics,
buf_LRU_evict_from_unzip_LRU() decides if we want to evict from
unzip_LRU or the regular LRU. From unzip_LRU, we will only evict the
uncompressed frame (meaning we can evict dirty blocks as well). From
the regular LRU, we will evict the entire block (i.e.: both the
uncompressed and compressed data), which must be clean. */
/* @{ */
/** Number of intervals for which we keep the history of these stats.
Updated at SRV_MONITOR_INTERVAL (the buf_LRU_stat_update() call rate). */ static constexpr ulint BUF_LRU_STAT_N_INTERVAL= 4;
/** Co-efficient with which we multiply I/O operations to equate them
with page_zip_decompress() operations. */ static constexpr ulint BUF_LRU_IO_TO_UNZIP_FACTOR= 50;
/** Sampled values buf_LRU_stat_cur.
Not protected by any mutex. Updated by buf_LRU_stat_update(). */ static buf_LRU_stat_t buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL];
/** Cursor to buf_LRU_stat_arr[] that is updated in a round-robin fashion. */ static ulint buf_LRU_stat_arr_ind;
/** Current operation counters. Not protected by any mutex. Cleared
by buf_LRU_stat_update(). */
buf_LRU_stat_t buf_LRU_stat_cur;
/** Running sum of past values of buf_LRU_stat_cur.
Updated by buf_LRU_stat_update(). Not Protected by any mutex. */
buf_LRU_stat_t buf_LRU_stat_sum;
/* @} */
/** @name Heuristics for detecting index scan @{ */ /** Move blocks to "new" LRU list only if the first access was at
least this many milliseconds ago. Not protected by any mutex or latch. */
uint buf_LRU_old_threshold_ms; /* @} */
/** Remove bpage from buf_pool.LRU and buf_pool.page_hash.
Ifacompressedpageisfreedothercompressedpagesmayberelocated. @retvaltrueifbpagewithbpage->framewasremovedfrompage_hash.The callerneedstofreethepagetothefreelist @retvalfalseifblockwithoutbpage->framewasremovedfrompage_hash.In
this case the block is already returned to the buddy allocator. */ staticbool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
buf_pool_t::hash_chain &chain, bool zip);
/** Free a block to buf_pool */ staticvoid buf_LRU_block_free_hashed_page(buf_block_t *block)
{
block->page.free_file_page();
buf_LRU_block_free_non_file_page(block);
}
/** Increase LRU size in bytes by the page size.
@param[in] bpage control block */ staticinlinevoid incr_LRU_size_in_bytes(const buf_page_t* bpage)
{
mysql_mutex_assert_owner(&buf_pool.mutex);
/** @return whether the unzip_LRU list should be used for evicting a victim
instead of the general LRU list */ bool buf_LRU_evict_from_unzip_LRU()
{
mysql_mutex_assert_owner(&buf_pool.mutex);
/* If the unzip_LRU list is empty, we can only use the LRU. */ if (UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0) { returnfalse;
}
/* If unzip_LRU is at most 10% of the size of the LRU list, thenusetheLRU.Thisslackallowsustokeephot
decompressed pages in the buffer pool. */ if (UT_LIST_GET_LEN(buf_pool.unzip_LRU)
<= UT_LIST_GET_LEN(buf_pool.LRU) / 10) { returnfalse;
}
/* If eviction hasn't started yet, we assume by default
that a workload is disk bound. */ if (buf_pool.freed_page_clock == 0) { returntrue;
}
/* Calculate the average over past intervals, and add the values
of the current interval. */
ulint io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL
+ buf_LRU_stat_cur.io;
/* Decide based on our formula. If the load is I/O bound (unzip_avgissmallerthantheweightedio_avg),evictan uncompressedframefromunzip_LRU.Otherwiseweassumethat
the load is CPU bound and evict from the regular LRU. */ return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
}
/** Try to free an uncompressed page of a compressed block from the unzip LRUlist.Thecompressedpageispreserved,anditneednotbeclean. @paramlimitmaximumnumberofblockstoscan
@return true if freed */ staticbool buf_LRU_free_from_unzip_LRU_list(ulint limit)
{ if (!buf_LRU_evict_from_unzip_LRU()) { return(false);
}
freed = buf_LRU_free_page(&block->page, false); if (freed) {
scanned++; break;
}
block = prev_block;
}
if (scanned) {
MONITOR_INC_VALUE_CUMULATIVE(
MONITOR_LRU_UNZIP_SEARCH_SCANNED,
MONITOR_LRU_UNZIP_SEARCH_SCANNED_NUM_CALL,
MONITOR_LRU_UNZIP_SEARCH_SCANNED_PER_CALL,
scanned);
}
return(freed);
}
/** Try to free a clean page from the common LRU list. @paramlimitmaximumnumberofblockstoscan
@return whether a page was freed */ staticbool buf_LRU_free_from_common_LRU_list(ulint limit)
{
mysql_mutex_assert_owner(&buf_pool.mutex);
if (buf_LRU_free_page(bpage, true)) { if (!accessed) { /* Keep track of pages that are evicted without everbeingaccessed.Thisgivesusameasureof
the effectiveness of readahead */
++buf_pool.stat.n_ra_pages_evicted;
}
/******************************************************************//**
Checks how much of buf_pool is occupied by non-data objects like
AHI, lock heaps etc. Depending on the size of non-data objects this
function will either assert or issue a warning andswitch on the
status monitor. */ staticvoid buf_LRU_check_size_of_non_data_objects() noexcept
{
mysql_mutex_assert_owner(&buf_pool.mutex);
if (recv_recovery_is_on()) return;
const size_t curr_size{buf_pool.usable_size()};
auto s= UT_LIST_GET_LEN(buf_pool.free) + UT_LIST_GET_LEN(buf_pool.LRU);
if (s >= curr_size / 20); elseif (buf_pool.is_shrinking())
buf_pool.LRU_warn(); else
{
sql_print_error("[FATAL] InnoDB: Over 95 percent of the buffer pool is" " occupied by lock heaps" #ifdef BTR_CUR_HASH_ADAPT " or the adaptive hash index" #endif/* BTR_CUR_HASH_ADAPT */ "! Check that your transactions do not set too many" " row locks, or review if innodb_buffer_pool_size=%zuM" " could be bigger",
curr_size >> (20 - srv_page_size_shift));
abort();
}
if (s < curr_size / 3)
{ if (!buf_lru_switched_on_innodb_mon && srv_monitor_timer)
{ /* Over 67 % of the buffer pool is occupied by lock heaps or
the adaptive hash index. This may be a memory leak! */
sql_print_warning("InnoDB: Over 67 percent of the buffer pool is" " occupied by lock heaps" #ifdef BTR_CUR_HASH_ADAPT " or the adaptive hash index" #endif/* BTR_CUR_HASH_ADAPT */ "! Check that your transactions do not set too many" " row locks. innodb_buffer_pool_size=%zuM." " Starting the InnoDB Monitor to print diagnostics.",
curr_size >> (20 - srv_page_size_shift));
buf_lru_switched_on_innodb_mon= true;
srv_print_innodb_monitor= TRUE;
srv_monitor_timer_schedule_now();
}
} elseif (buf_lru_switched_on_innodb_mon)
{ /* Switch off the InnoDB Monitor; this is a simple way to stop the monitorifthesituationbecomeslessurgent,butmayalso
surprise users who did SET GLOBAL innodb_status_output=ON earlier! */
buf_lru_switched_on_innodb_mon= false;
srv_print_innodb_monitor= FALSE;
}
}
/** Get a block from the buf_pool.free list. Ifthelistisempty,blockswillbemovedfromtheendofbuf_pool.LRU tobuf_pool.free.
@paramgethowtoallocatetheblock @returnthefreecontrolblock,instateBUF_BLOCK_MEMORY
@retval nullptr if get==have_no_mutex_soft and memory was not available */
buf_block_t* buf_LRU_get_free_block(buf_LRU_get get)
{ bool waited= false;
MONITOR_INC(MONITOR_LRU_GET_FREE_SEARCH); if (UNIV_LIKELY(get != have_mutex))
mysql_mutex_lock(&buf_pool.mutex);
buf_LRU_check_size_of_non_data_objects();
buf_block_t *block;
retry: /* If there is a block in the free list, take it */
block= buf_pool.allocate(); if (block)
{
got_block: const ulint LRU_size= UT_LIST_GET_LEN(buf_pool.LRU); const ulint available= UT_LIST_GET_LEN(buf_pool.free); const size_t scan_depth{buf_pool.LRU_scan_depth / 2};
ut_ad(LRU_size <= BUF_LRU_MIN_LEN || available >= scan_depth ||
buf_pool.is_shrinking() || buf_pool.need_LRU_eviction());
ut_d(bool signalled = false);
if (UNIV_UNLIKELY(available < scan_depth) && LRU_size > BUF_LRU_MIN_LEN)
{
mysql_mutex_lock(&buf_pool.flush_list_mutex); if (!buf_pool.page_cleaner_active())
{
buf_pool.page_cleaner_wakeup(true);
ut_d(signalled = true);
}
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
}
if (UNIV_LIKELY(get != have_mutex))
mysql_mutex_unlock(&buf_pool.mutex);
MONITOR_INC(MONITOR_LRU_GET_FREE_LOOPS); if (waited || buf_pool.try_LRU_scan)
{ /* If no block was in the free list, search from the end of the LRUlistandtrytofreeablockthere.Ifwearedoingforthe firsttimewe'llscanonlytailoftheLRUlistotherwisewescan
the whole LRU list. */ if (buf_LRU_scan_and_free_block(waited ? ULINT_UNDEFINED : 100)) goto retry;
/* Tell other threads that there is no point in scanning the LRU
list. */
buf_pool.try_LRU_scan= false;
}
if (get == have_no_mutex_soft)
{
mysql_mutex_unlock(&buf_pool.mutex); return nullptr;
}
waited= true;
while (!(block= buf_pool.allocate()))
{
buf_pool.stat.LRU_waits++;
timespec abstime;
set_timespec(abstime, 1);
mysql_mutex_lock(&buf_pool.flush_list_mutex); if (!buf_pool.page_cleaner_active())
buf_pool.page_cleaner_wakeup(true);
mysql_mutex_unlock(&buf_pool.flush_list_mutex); if (my_cond_timedwait(&buf_pool.done_free, &buf_pool.mutex.m_mutex,
&abstime))
{
buf_pool.LRU_warn();
buf_LRU_check_size_of_non_data_objects();
}
}
goto got_block;
}
/** Move the LRU_old pointer so that the length of the old blocks list
is inside the allowed limits. */ staticvoid buf_LRU_old_adjust_len()
{
ulint old_len;
ulint new_len;
#ifdef UNIV_LRU_DEBUG /* buf_pool.LRU_old must be the first item in the LRU list
whose "old" flag is set. */
ut_a(buf_pool.LRU_old->old);
ut_a(!UT_LIST_GET_PREV(LRU, buf_pool.LRU_old)
|| !UT_LIST_GET_PREV(LRU, buf_pool.LRU_old)->old);
ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool.LRU_old)
|| UT_LIST_GET_NEXT(LRU, buf_pool.LRU_old)->old); #endif/* UNIV_LRU_DEBUG */
/** Initialize the old blocks pointer in the LRU list. This function should be
called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */ staticvoid buf_LRU_old_init()
{
mysql_mutex_assert_owner(&buf_pool.mutex);
ut_a(UT_LIST_GET_LEN(buf_pool.LRU) == BUF_LRU_OLD_MIN_LEN);
/* We first initialize all blocks in the LRU list as old and then use theadjustfunctiontomovetheLRU_oldpointertotheright
position */
/** Remove a block from the unzip_LRU list if it belonged to the list.
@param[in] bpage control block */ staticvoid buf_unzip_LRU_remove_block_if_needed(buf_page_t* bpage)
{
ut_ad(bpage->in_file());
mysql_mutex_assert_owner(&buf_pool.mutex);
if (bpage->belongs_to_unzip_LRU()) {
buf_block_t* block = reinterpret_cast<buf_block_t*>(bpage);
/** Removes a block from the LRU list.
@param[in] bpage control block */ staticinlinevoid buf_LRU_remove_block(buf_page_t* bpage)
{ /* Important that we adjust the hazard pointers before removing
bpage from the LRU list. */
buf_page_t* prev_bpage = buf_pool.LRU_remove(bpage);
/* If the LRU_old pointer is defined and points to just this block,
move it backward one step */
if (bpage == buf_pool.LRU_old) {
/* Below: the previous block is guaranteed to exist, becausetheLRU_oldpointerisonlyallowedtodiffer byBUF_LRU_OLD_TOLERANCEfromstrict buf_pool.LRU_old_ratio/BUF_LRU_OLD_RATIO_DIVoftheLRU
list length. */
ut_a(prev_bpage); #ifdef UNIV_LRU_DEBUG
ut_a(!prev_bpage->old); #endif/* UNIV_LRU_DEBUG */
buf_pool.LRU_old = prev_bpage;
prev_bpage->set_old(true);
/* If the LRU list is so short that LRU_old is not defined,
clear the "old" flags and return */ if (UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN) {
/* Update the LRU_old_len field if necessary */ if (bpage->old) {
buf_pool.LRU_old_len--;
}
/* Adjust the length of the old block list if necessary */
buf_LRU_old_adjust_len();
}
/******************************************************************//**
Adds a block to the LRU list of decompressed zip pages. */ void
buf_unzip_LRU_add_block( /*====================*/
buf_block_t* block, /*!< in: control block */
ibool old) /*!< in: TRUE if should be put to the end
of the list, else put to the start */
{
mysql_mutex_assert_owner(&buf_pool.mutex);
ut_a(block->page.belongs_to_unzip_LRU());
ut_ad(!block->in_unzip_LRU_list);
ut_d(block->in_unzip_LRU_list = true);
/******************************************************************//**
Adds a block to the LRU list. Please make sure that the page_size is
already set when invoking the function, so that we can get correct
page_size from the buffer page when adding a block into LRU */ void
buf_LRU_add_block(
buf_page_t* bpage, /*!< in: control block */ bool old) /*!< in: true if should be put to the old blocks intheLRUlist,elseputtothestart;ifthe LRUlistisveryshort,theblockisaddedto
the start, regardless of this parameter */
{
mysql_mutex_assert_owner(&buf_pool.mutex);
ut_ad(!bpage->in_LRU_list);
if (!old || (UT_LIST_GET_LEN(buf_pool.LRU) < BUF_LRU_OLD_MIN_LEN)) {
UT_LIST_ADD_FIRST(buf_pool.LRU, bpage);
bpage->freed_page_clock = buf_pool.freed_page_clock
& ((1U << 31) - 1);
} else { #ifdef UNIV_LRU_DEBUG /* buf_pool.LRU_old must be the first item in the LRU list
whose "old" flag is set. */
ut_a(buf_pool.LRU_old->old);
ut_a(!UT_LIST_GET_PREV(LRU, buf_pool.LRU_old)
|| !UT_LIST_GET_PREV(LRU, buf_pool.LRU_old)->old);
ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool.LRU_old)
|| UT_LIST_GET_NEXT(LRU, buf_pool.LRU_old)->old); #endif/* UNIV_LRU_DEBUG */
UT_LIST_INSERT_AFTER(buf_pool.LRU, buf_pool.LRU_old,
bpage);
buf_pool.LRU_old_len++;
}
ut_d(bpage->in_LRU_list = TRUE);
incr_LRU_size_in_bytes(bpage);
if (UT_LIST_GET_LEN(buf_pool.LRU) > BUF_LRU_OLD_MIN_LEN) {
ut_ad(buf_pool.LRU_old);
/* Adjust the length of the old block list if necessary */
/* If this is a zipped block with decompressed frame as well
then put it on the unzip_LRU list */ if (bpage->belongs_to_unzip_LRU()) {
buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
}
}
/** Move a block to the start of the LRU list. */ void buf_page_make_young(buf_page_t *bpage)
{ if (bpage->is_read_fixed()) return;
ut_ad(bpage->in_file());
mysql_mutex_lock(&buf_pool.mutex);
if (UNIV_UNLIKELY(bpage->old))
buf_pool.stat.n_pages_made_young++;
/** Try to free a block. If bpage is a descriptor of a compressed-only ROW_FORMAT=COMPRESSEDpage,thebuf_page_tobjectwillbefreedaswell. Thecallermustholdbuf_pool.mutex. @parambpageblocktobefreed @paramzipwhethertoremovebothcopiesofaROW_FORMAT=COMPRESSEDpage @retvaltrueiffreedandbuf_pool.mutexmayhavebeentemporarilyreleased
@retval false if the page was not freed */ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
{ const page_id_t id{bpage->id()};
buf_page_t* b = nullptr;
mysql_mutex_assert_owner(&buf_pool.mutex);
/* First, perform a quick check before we acquire hash_lock. */ if (!bpage->can_relocate()) { returnfalse;
}
/* We must hold an exclusive hash_lock to prevent bpage->can_relocate()fromchangingduetoaconcurrent
execution of buf_page_get_gen(). */
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); /* We cannot use transactional_lock_guard here,
because buf_buddy_relocate() in buf_buddy_free() could get stuck. */
hash_lock.lock(); const lsn_t oldest_modification = bpage->oldest_modification_acquire();
if (UNIV_UNLIKELY(!bpage->can_relocate())) { /* Do not free buffer fixed and I/O-fixed blocks. */ goto func_exit;
}
switch (oldest_modification) { case2:
ut_ad(id.space() == SRV_TMP_SPACE_ID);
ut_ad(!bpage->zip.data); if (!bpage->is_freed()) { goto func_exit;
}
bpage->clear_oldest_modification(); break; case1:
mysql_mutex_lock(&buf_pool.flush_list_mutex); if (ut_d(const lsn_t om =) bpage->oldest_modification()) {
ut_ad(om == 1);
buf_pool.delete_from_flush_list(bpage);
}
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
ut_ad(!bpage->oldest_modification()); /* fall through */ case0: if (zip || !bpage->zip.data || !bpage->frame) { break;
}
mysql_mutex_lock(&buf_pool.flush_list_mutex);
relocate_compressed:
b = static_cast<buf_page_t*>(ut_zalloc_nokey(sizeof *b));
ut_a(b); new (b) buf_page_t(*bpage);
b->frame = nullptr;
{
ut_d(uint32_t s=) b->fix();
ut_ad(s == buf_page_t::FREED
|| s == buf_page_t::UNFIXED
|| s == buf_page_t::REINIT);
} break; default: if (zip || !bpage->zip.data || !bpage->frame) { /* This would completely free the block. */ /* Do not completely free dirty blocks. */
func_exit:
hash_lock.unlock(); return(false);
}
mysql_mutex_lock(&buf_pool.flush_list_mutex); if (bpage->can_relocate()) { goto relocate_compressed;
}
mysql_mutex_unlock(&buf_pool.flush_list_mutex); goto func_exit;
}
if (!buf_LRU_block_remove_hashed(bpage, id, chain, zip)) {
ut_ad(!b);
mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); return(true);
}
/* We have just freed a BUF_BLOCK_FILE_PAGE. If b != nullptr thenitwasacompressedpagewithanuncompressedframeand weareinterestedinfreeingonlytheuncompressedframe. Thereforewehavetoreinsertthecompressedpagedescriptor intotheLRUandpage_hash(andpossiblyflush_list).
if !b then it was a regular page that has been freed */
if (UNIV_LIKELY_NULL(b)) {
buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b);
/* The field in_LRU_list of theto-be-freedblockdescriptorshouldhave beenclearedin buf_LRU_block_remove_hashed(),which
invokes buf_LRU_remove_block(). */
ut_ad(!bpage->in_LRU_list);
ut_ad(bpage->frame);
ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
/* The fields of bpage were copied to b before
buf_LRU_block_remove_hashed() was invoked. */
ut_ad(b->in_LRU_list);
ut_ad(b->in_page_hash);
ut_d(b->in_page_hash = false);
b->hash = nullptr;
buf_pool.page_hash.append(chain, b);
/* Insert b where bpage was in the LRU list. */ if (prev_b) {
ulint lru_len;
if (b->is_old()) {
buf_pool.LRU_old_len++; if (buf_pool.LRU_old
== UT_LIST_GET_NEXT(LRU, b)) {
buf_pool.LRU_old = b;
}
}
lru_len = UT_LIST_GET_LEN(buf_pool.LRU);
if (lru_len > BUF_LRU_OLD_MIN_LEN) {
ut_ad(buf_pool.LRU_old); /* Adjust the length of the
old block list if necessary */
buf_LRU_old_adjust_len();
} elseif (lru_len == BUF_LRU_OLD_MIN_LEN) { /* The LRU list is now long enoughforLRU_oldtobecome
defined: init it */
buf_LRU_old_init();
} #ifdef UNIV_LRU_DEBUG /* Check that the "old" flag is consistent
in the block and its neighbours. */
b->set_old(b->is_old()); #endif/* UNIV_LRU_DEBUG */
} else {
ut_d(b->in_LRU_list = FALSE);
buf_LRU_add_block(b, b->old);
}
#ifdef BTR_CUR_HASH_ADAPT if (block->index) {
mysql_mutex_unlock(&buf_pool.mutex);
/* Remove the adaptive hash index on the page. Thepagewasdeclareduninitializedby buf_LRU_block_remove_hashed().Weneedtoflag thecontentsofthepagevalid(whichitstillis)in
order to avoid bogus Valgrind or MSAN warnings.*/
/******************************************************************//**
Puts a block back to the free list. */ void
buf_LRU_block_free_non_file_page( /*=============================*/
buf_block_t* block) /*!< in: block, must not contain a file page */
{ void* data;
Ifacompressedpageisfreedothercompressedpagesmayberelocated. @retvaltrueifBUF_BLOCK_FILE_PAGEwasremovedfrompage_hash.The callerneedstofreethepagetothefreelist @retvalfalseifBUF_BLOCK_ZIP_PAGEwasremovedfrompage_hash.In
this case the block is already returned to the buddy allocator. */ staticbool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
buf_pool_t::hash_chain &chain, bool zip)
{
ut_a(bpage->can_relocate());
ut_ad(buf_pool.page_hash.lock_get(chain).is_write_locked());
ut_a(!zip || !bpage->oldest_modification());
ut_ad(bpage->zip_size()); /* Skip consistency checks if the page was freed. Inrecovery,wecouldgetasoleFREE_PAGErecord andnothingelse,foraROW_FORMAT=COMPRESSEDpage.
Its contents would be garbage. */ if (!bpage->is_freed()) switch (fil_page_get_type(page)) { case FIL_PAGE_TYPE_ALLOCATED: case FIL_PAGE_INODE: case FIL_PAGE_IBUF_BITMAP: case FIL_PAGE_TYPE_FSP_HDR: case FIL_PAGE_TYPE_XDES: /* These are essentially uncompressed pages. */ if (!zip) { /* InnoDB writes the data to the uncompressedpageframe.Copyit tothecompressedpage,whichwill
be preserved. */
memcpy(bpage->zip.data, page,
bpage->zip_size());
} break; case FIL_PAGE_TYPE_ZBLOB: case FIL_PAGE_TYPE_ZBLOB2: case FIL_PAGE_INDEX: case FIL_PAGE_RTREE: break; default:
ib::error() << "The compressed page to be" " evicted seems corrupt:";
ut_print_buf(stderr, page, srv_page_size);
ib::error() << "Possibly older version of" " the page:";
/** Release and evict a corrupted page. @parambpagex-latchedpagethatwasfoundcorrupted
@param state expected current state of the page */
ATTRIBUTE_COLD void buf_pool_t::corrupted_evict(buf_page_t *bpage, uint32_t state) noexcept
{ 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.lock();
ut_ad(!bpage->oldest_modification());
bpage->set_corrupt_id(); auto unfix= state - buf_page_t::FREED; auto s= bpage->zip.fix.fetch_sub(unfix) - unfix;
bpage->lock.x_unlock(true);
while (s != buf_page_t::FREED || bpage->lock.is_locked_or_waiting())
{
ut_ad(s >= buf_page_t::FREED);
ut_ad(s < buf_page_t::UNFIXED); /* Wait for other threads to release the fix count
before releasing the bpage from LRU list. */
(void) LF_BACKOFF();
s= bpage->state();
}
/* 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));
if (ratio != buf_pool.LRU_old_ratio) {
buf_pool.LRU_old_ratio = ratio;
if (UT_LIST_GET_LEN(buf_pool.LRU)
>= BUF_LRU_OLD_MIN_LEN) {
buf_LRU_old_adjust_len();
}
}
mysql_mutex_unlock(&buf_pool.mutex);
} else {
buf_pool.LRU_old_ratio = ratio;
} /* the reverse of
ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */ return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5));
}
/********************************************************************//**
Update the historical stats that we are collecting for LRU eviction
policy at the end of each interval. */ void
buf_LRU_stat_update()
{
buf_LRU_stat_t* item;
buf_LRU_stat_t cur_stat;
if (!buf_pool.freed_page_clock) { goto func_exit;
}
/* Add the current value and subtract the obsolete entry. Sincebuf_LRU_stat_curisnotprotectedbyanymutex, itcanbechangingbetweenaddingtobuf_LRU_stat_sum andcopyingtoitem.Assignittolocalvariablestomake surethesamevalueassigntothebuf_LRU_stat_sum
and item */
cur_stat = buf_LRU_stat_cur;
/* Put current entry in the array. */
memcpy(item, &cur_stat, sizeof *item);
func_exit: /* Clear the current entry. */
memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur);
}
#ifdefined __aarch64__&&defined __GNUC__&&__GNUC__==4&&!defined __clang__ /* Avoid GCC 4.8.5 internal compiler error "could not split insn". Wewouldonlyneedthisforbuf_LRU_scan_and_free_block(),
but GCC 4.8.5 does not support pop_options. */ # pragma GCC optimize ("O0") #endif /** Try to free a replaceable block. @paramlimitmaximumnumberofblockstoscan
@return true if found and freed */ bool buf_LRU_scan_and_free_block(ulint limit)
{
mysql_mutex_assert_owner(&buf_pool.mutex);