November 9, 2012

[MySQL 源码] 从buffer pool中获取空闲block流程

当我们将一个page读入内存时,需要先为其分配一个block,从buffer pool中获取。入口函数为buf_LRU_get_free_block 之前在http://mysqllover.com/?p=303有简要介绍,这里详细看看,当然,跟最近博客的主题一样,我们还是主要针对压缩表来分析。 以下分析基于Percona Server 5.5.18 buf_LRU_get_free_block loop: 1.block = buf_LRU_get_free_only(buf_pool) 首先从buf_pool->free链表尾部读取,如果有空闲页,则将其从buf_pool->free中移除,设置bpage->state=BUF_BLOCK_READY_FOR_USE,然后返回 上述流程需要加buf_pool->free_list_mutex锁 2.如果1获得了一个block,还需要重置压缩页描述符block->page.zip为0,然后直接返回 3.如果在buf_pool->free上没有block,则从buf_pool->LRU或unzip_LRU的尾部开始扫描,尝试找一个空闲block. freed = buf_LRU_search_and_free_block(buf_pool, n_iterations); //n_iterations是一个计数器,表示尝试释放但失败的次数。 A.持有buf_pool->LRU_list_mutex锁 B.首先,尝试从buf_pool->unzip_LRU上释放block,这种情况下不会释放压缩页数据 freed = buf_LRU_free_from_unzip_LRU_list(buf_pool, n_iterations, have_LRU_mutex); >>判断是否从unzip_LRU上驱逐block 理论上讲,从buf_pool->unzip_LRU上应该更容易获得一个block,因为我们可以选择一个脏块(只驱逐解压页),但当我们尝试5次还是没有找到时,则直接返回到正常的驱逐block的逻辑,即从LRU上获取 另外也有函数buf_LRU_evict_from_unzip_LRU用来判断是否从unzip_LRU上驱逐block,其判断逻辑如下: >>>需要持有buf_pool->LRU_list_mutex >>>如果buf_pool->unzip_LRU长度为0 ,返回FALSE >>>如果buf_pool->unzip_LRU小于buf_pool->LRU的十分之一,返回FALSE >>>如果buf_pool->freed_page_clock == 0,表示之前没有进行过任何block驱逐,默认假设工作负载为disk bound,返回TRUE freed_page_clock是一个序列号,用来计数从LRU尾部移除的block数,可以不加锁读取该变量 >>>计算最近的平均IO量     io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL         + buf_LRU_stat_cur.io; 最近50秒的平均IO+当前的IO,获得最近的平均IO负载   […]