mysql lru scan depth_MySQL-Innodb-buf_LRU_get_free_block

调用栈

buf_LRU_get_free_block

----buf_LRU_scan_and_free_block/* 先看看能不能找到可以replaced */

----buf_flush_single_page_from_LRU/* 不行再刷新 */

--------buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, true)

------------buf_flush_write_block_low(bpage, flush_type, sync);

------------if (flush_type == BUF_FLUSH_SINGLE_PAGE) {

buf_dblwr_write_single_page(bpage, sync);

}

if (sync) {

ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE);

fil_flush(bpage->id.space());

/* true means we want to evict this page from the

LRU list as well. */

buf_page_io_complete(bpage, true);

}

----------------buf_page_io_complete

--------------------buf_flush_write_complete

------------------------buf_flush_remove

----------------------------UT_LIST_REMOVE(buf_pool->flush_list, bpage);

----------------buf_LRU_free_page(bpage, true); //从lru free page

LRU中的flush会从flush list中remove掉,相反flush list的flush不会从lru中remove,因为可能是读热点。

/* If no block was in the free list, search from the end of the LRU list and try to free a block there. If we are doing for the first time we'll scan only tail of the LRU list otherwise we scan the whole LRU list. */

buf_LRU_scan_and_free_block第一轮会迭代innodb_lru_scan_depth个对象,如果没有找到第二轮会迭代整个LRU list,参见buf_LRU_get_free_block完整代码

/******************************************************************//**

Returns a free block from the buf_pool. The block is taken off the

free list. If free list is empty, blocks are moved from the end of the

LRU list to the free list.

This function is called from a user thread when it needs a clean

block to read in a page. Note that we only ever get a block from

the free list. Even when we flush a page or find a page in LRU scan

we put it to free list to be used.

* iteration 0:

* get a block from free list, success:done

* if buf_pool->try_LRU_scan is set

* scan LRU up to srv_LRU_scan_depth to find a clean block

* the above will put the block on free list

* success:retry the free list

* flush one dirty page from tail of LRU to disk

* the above will put the block on free list

* success: retry the free list

* iteration 1:

* same as iteration 0 except:

* scan whole LRU list

* scan LRU list even if buf_pool->try_LRU_scan is not set

* iteration > 1:

* same as iteration 1 but sleep 10ms

@return the free control block, in state BUF_BLOCK_READY_FOR_USE */

buf_block_t*

buf_LRU_get_free_block(

/*===================*/

buf_pool_t* buf_pool) /*!< in/out: buffer pool instance */

{

buf_block_t* block = NULL;

bool freed = false;

ulint n_iterations = 0;

ulint flush_failures = 0;

bool mon_value_was = false;

bool started_monitor = false;

MONITOR_INC(MONITOR_LRU_GET_FREE_SEARCH);

loop:

buf_pool_mutex_enter(buf_pool);

buf_LRU_check_size_of_non_data_objects(buf_pool);

/* If there is a block in the free list, take it */

block = buf_LRU_get_free_only(buf_pool);

if (block != NULL) {

buf_pool_mutex_exit(buf_pool);

ut_ad(buf_pool_from_block(block) == buf_pool);

memset(&block->page.zip, 0, sizeof block->page.zip);

if (started_monitor) {

srv_print_innodb_monitor =

static_cast(mon_value_was);

}

block->skip_flush_check = false;

block->page.flush_observer = NULL;

return(block);

}

MONITOR_INC( MONITOR_LRU_GET_FREE_LOOPS );

freed = false;

if (buf_pool->try_LRU_scan || n_iterations > 0) {

/* If no block was in the free list, search from the

end of the LRU list and try to free a block there.

If we are doing for the first time we'll scan only

tail of the LRU list otherwise we scan the whole LRU

list. */

freed = buf_LRU_scan_and_free_block(

buf_pool, n_iterations > 0);

if (!freed && n_iterations == 0) {

/* Tell other threads that there is no point

in scanning the LRU list. This flag is set to

TRUE again when we flush a batch from this

buffer pool. */

buf_pool->try_LRU_scan = FALSE;

}

}

buf_pool_mutex_exit(buf_pool);

if (freed) {

goto loop;

}

if (n_iterations > 20

&& srv_buf_pool_old_size == srv_buf_pool_size) {

ib::warn() << "Difficult to find free blocks in the buffer pool"

" (" << n_iterations << " search iterations)! "

<< flush_failures << " failed attempts to"

" flush a page! Consider increasing the buffer pool"

" size. It is also possible that in your Unix version"

" fsync is very slow, or completely frozen inside"

" the OS kernel. Then upgrading to a newer version"

" of your operating system may help. Look at the"

" number of fsyncs in diagnostic info below."

" Pending flushes (fsync) log: "

<< fil_n_pending_log_flushes

<< "; buffer pool: "

<< fil_n_pending_tablespace_flushes

<< ". " << os_n_file_reads << " OS file reads, "

<< os_n_file_writes << " OS file writes, "

<< os_n_fsyncs

<< " OS fsyncs. Starting InnoDB Monitor to print"

" further diagnostics to the standard output.";

mon_value_was = srv_print_innodb_monitor;

started_monitor = true;

srv_print_innodb_monitor = true;

os_event_set(lock_sys->timeout_event);

}

/* If we have scanned the whole LRU and still are unable to

find a free block then we should sleep here to let the

page_cleaner do an LRU batch for us. */

if (!srv_read_only_mode) {

os_event_set(buf_flush_event);

}

if (n_iterations > 1) {

MONITOR_INC( MONITOR_LRU_GET_FREE_WAITS );

os_thread_sleep(10000);

}

/* No free block was found: try to flush the LRU list.

This call will flush one page from the LRU and put it on the

free list. That means that the free block is up for grabs for

all user threads.

TODO: A more elegant way would have been to return the freed

up block to the caller here but the code that deals with

removing the block from page_hash and LRU_list is fairly

involved (particularly in case of compressed pages). We

can do that in a separate patch sometime in future. */

if (!buf_flush_single_page_from_LRU(buf_pool)) {

MONITOR_INC(MONITOR_LRU_SINGLE_FLUSH_FAILURE_COUNT);

++flush_failures;

}

srv_stats.buf_pool_wait_free.add(n_iterations, 1);

n_iterations++;

goto loop;

}

问题:

什么Page是可以Replace的。

有没有可能一个用户线程free出来的page被其他用户线程用了?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值