mysql doble write_[MySQL 5.6] double write buffer的几个关键函数-阿里云开发者社区

mysql doble write_[MySQL 5.6] double write buffer的几个关键函数-阿里云开发者社区一个 double write buffer 有 2MB 共 128 个 page 在 MySQL 5 6 中 默认有 120 个 page 用于批量刷新 如 LRU Flush 或者 FLUSH LIST FLUSH 剩下的 8 个 Page 用于单个 page 的 flush 在 DEBUG 版本下

大家好,我是讯享网,很高兴认识大家。

一个double write buffer 有2MB, 共128个page,在MySQL 5.6中, 默认有120个page用于批量刷新(如 LRU Flush 或者FLUSH LIST FLUSH),剩下的8个Page用于单个page的flush。

在DEBUG版本下,120是可以通过参数innodb_doublewrite_batch_size来配置的,好吧。我已经不安分的把DEBUG宏给去掉了。

全局对象buf_dblwr, 对应结构体为buf_dblwr_t:

ib_mutex_t

mutex

互斥量

ulint

block1

第一个doubewrite 块(64个page)的page no

ulint

block2

第二个double write 块的page no

ulint

first_free

在write_buf中第一个空闲的位置

ulint

s_reserved

为单个page刷新预留的slot数,当flush类型为BUF_FLUSH_SINGLE_PAGE时,会进入到函数buf_dblwr_write_single_page来写一个Page

ulint

b_reserved

为batch flush 预留的slot数

ibool*

in_use

用于标记一个slot是否被使用,只用于single page flush

ibool

batch_running

当设置为TRUE时,表明有一次batch flush正在进行

byte*

write_buf

double write buffer在内存的缓存,以UNIV_PAGE_SIZE对其

byte*

write_buf_unaligned

未对齐的write_buf

buf_page_t

buf_block_arr

存储已经cache到write_buf的block的指针

这里解释一下FLUSH操作的类型,总的来说,有三种刷新类型

BUF_FLUSH_LRU:表示从Buffer Pool的LRU上扫描并刷新

BUF_FLUSH_LIST:表示从Buffer Pool的FLUSH LIST上扫描并刷新

BUF_FLUSH_SINGLE_PAGE:从LRU上只刷新一个Page

前两种属于BATCH FLUSH, 最后一种属于SINGLE FLUSH

BUF_FLUSH_SINGLE_PAGE在几种情况下使用到:

1.buf_flush_or_remove_page

2.buf_flush_single_page_from_LRU,这在FREE LIST不够用时,IO-bound场景下,可能频繁调用到(buf_LRU_get_free_block)

3.buf_flush_page_try

TODO:下一篇博客再介绍这几种刷page的类型

quoted code in buf_flush_write_block_low

938         if (!srv_use_doublewrite_buf || !buf_dblwr) {

939                 fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,

940                        FALSE, buf_page_get_space(bpage), zip_size,

941                        buf_page_get_page_no(bpage), 0,

942                        zip_size ? zip_size : UNIV_PAGE_SIZE,

943                        frame, bpage);

944         } else if (flush_type == BUF_FLUSH_SINGLE_PAGE) {


讯享网

945                 buf_dblwr_write_single_page(bpage);

946         } else {

947                 buf_dblwr_add_to_batch(bpage);

948         }

这里根据flush的类型来判断对应的逻辑,如果刷新类型为BUF_FLUSH_SINGLE_PAGE,则调用buf_dblwr_write_single_page,否则调用buf_dblwr_add_to_batch

A.

buf_dblwr_write_single_page(page):用于将一个page加入到double write buffer中,并完成写操作

主要流程如下:

1.

最大为单个page刷新预留的dblwr  page数为:

2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE-srv_doublewrite_batch_size

默认为8个page

当s_reserved值等于最大page数量时,线程会去sleep后retry

2.从srv_doublewrite_batch_size开始,找到一个buf_dblwr->in_use[i] 不为TRUE的slot。分配给当前page

将in_use[i]设为TRUE,并递增s_reserved++

3.将单个page写入到double write buffer中。注意,这里已经释放了buf_dblwr->mutex

4.刷double write buffer (fil_flush(TRX_SYS_SPACE)),然后再将数据写入到磁盘中(buf_dblwr_write_block_to_datafile,buf_flush_sync_datafiles)

注意在函数buf_flush_sync_datafiles中会唤醒IO线程,等待写入完成,因此这是同步写操作

5.再次持有buf_dblwr->mutex,将s_reserved–, in_use[i], buf_block_arr[i]置为NULL。

B.

buf_dblwr_add_to_batch(bpage):将一个page加入到double write buffer中,如果batch满了,则刷double write buffer到磁盘

该函数的逻辑如下:

1.持有buf_dblwr->mutex

2.如果batch_running为TRUE,表示已经有人在开始做batch flush来刷dblwr,释放互斥锁,sleep一段时间后,回到1retry

3.如果batch满了(即buf_dblwr->first_free == srv_doublewrite_batch_size),则释放mutex, 主动调用buf_dblwr_flush_buffered_writes()把dblwr的写到磁盘,然后回到1   retry

4. 将page拷贝到第buf_dblwr->first_free个槽位,并设置:

buf_dblwr->buf_block_arr[buf_dblwr->first_free] = page;

buf_dblwr->first_free++;

buf_dblwr->b_reserved++;

5.再次检查batch flush的槽位是否已满(buf_dblwr->first_free == srv_doublewrite_batch_size) ,如果满了,则释放mutex,进行一次flush(buf_dblwr_flush_buffered_writes()),从函数返回

6.最后释放mutex.

C.

buf_dblwr_flush_buffered_writes() : 批量刷double write buffer的函数(只涉及batch flush的page)

流程如下:

1.持有buf_dblwr->mutex

2.如果fist_free为0,表示当前double write buffer为空,释放mutex,返回

3.如果batch_running为TRUE,表示正有线程在做batch flush,释放Mutex, sleep一段时间后回到1 retry

4.将batch_running设置为TRUE,避免并发写

5.释放buf_dblwr->mutex

6.检查每一个将要写dblwr的block以及write_buf中的page是否被损坏或者LSN值是否正确

buf_dblwr_check_block(block) 以及 buf_dblwr_check_page_lsn(write_buf + len2)

7.将write_buf中的page写入到文件中

先写第一个block(<=64个page),再写第二个block(<=64个page),

也就是说最多一次写入1M, 分两次写的原因是??

8.将double write buffer刷到磁盘后(fil_flush(TRX_SYS_SPACE);),逐个开始写数据文件(OS_AIO_SIMULATED_WAKE_LATER)

866                 buf_dblwr_write_block_to_datafile(

867                         buf_dblwr->buf_block_arr[i]);

9.唤醒IO线程(os_aio_simulated_wake_handler_threads)

注意这里,在函数结束时并没有将batch_running设置为FALSE,因为这里对数据文件做的是异步写,设置标记位的工作留给了IO线程来完成

io_handler_thread-> fil_aio_wait-> buf_page_io_complete->buf_flush_write_complete->buf_dblwr_update():

看起来在double write buffer中,BATCH FLUSH 和SINGER PAGE FLUSH对应的slot非常独立,那么我们是否可以把这个mutex拆成两个呢?

简单的测试了一把,结果是。。。。。差别不大

我把自己的想法提到buglist上了,不知道官方的怎么看。。。

小讯
上一篇 2025-01-07 18:37
下一篇 2025-01-27 07:55

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/38904.html