图解MySQL系列(4)-Buffer Pool中的free链表

1 MySQL如何初始化Buffer Pool

Buffer Pool中有N多缓存页,每个缓存页还有个描述信息。DB启动后,按BP大小向os申请一块内存区域,作为BP的内存区域。

当内存区域申请完后,DB按默认缓存页及对应描述信息快,在BP中划出一块块内存,当DB把BP划分完后:

image

这时,BP中的一个个缓存页还都是空的,要等DB运行起来后,当我们要对数据执行CRUD操作时,才会把数据对应的页从磁盘文件里读取出来,放入BP中的缓存页。

哪些缓存页空闲?

DB运行后,肯定执行大量CRUD,就需不停的从磁盘上读取一个个数据页放入BP中的对应的缓存页里去,把数据缓存起来,后续就能对该数据在内存里执行CRUD。

但是此时在从磁盘上读取数据页放入Buffer Pool中的缓存页的时候,必然涉及到一个问题,那就是哪些缓存页是空闲的?

因为默认情况下磁盘上的数据页和缓存页一一对应,都是16K,一个数据页对应一个缓存页。所以必须要知道BP中哪些缓存页是空闲状态。

所以数据库会为BP设计个free链表,双向链表,每个节点就是个空闲缓存页的描述数据块的地址,即只要一个缓存页空闲,那他的描述数据块就会被放入free链表。

刚开始DB启动时,可能所有缓存页都空闲,因为此时可能是个空DB,所以此时所有缓存页的描述数据块,都放入free链表。

image

上图中,这free链表里就是各个缓存页的描述信息块,只要缓存页空闲,对应的描述信息块就会加入free链表,每个节点都会双向链接自己的前后节点,组成一个双向链表。free链表有个基础节点引用链表的头节点和尾节点,存储了链表中有多少个描述数据块的节点,即有多少个空闲缓存页。

free链表占用内存大小

这free链表本就由BP里的描述信息块组成,可认为是每个描述信息块里都有两个指针:

  • free_pre

    指向自己的上一个free链表节点

  • free_next

    指向下一个free链表的节点

通过BP中的描述数据块的free_pre和free_next两个指针,就能将所有描述数据块串成一个free链表,上面只是为了方便画图,所以将描述信息块单独画出来。

对free链表,只有一个基础节点(40K)不属于BP,存放了free链表的头节点地址,尾节点地址,还有free链表当前节点个数。

如何将磁盘上的页读取到BP的缓存页?

先从free链表获取一个描述信息块,就能获取到对应空闲缓存页。

image

就能将磁盘上的数据页读到对应缓存页,同时将相关的描述信息写入缓存页的描述信息块,比如该数据页所属的表空间之类的信息,最后把那描述信息块从free链表中移除:

image

怎知数据页是否被缓存?

执行CRUD时,先看该数据页是否被缓存,若没被缓存就走上面逻辑,从free找个空闲缓存页,从磁盘上读取数据页写入缓存页,写入描述信息,最后从free中移除该描述信息块。

但若数据页已被缓存,就能直接使用。

所以DB还有个数据页缓存哈希表:

  • key:表空间号+数据页号
  • value:缓存页的地址

当要使用一个数据页时,通过“表空间号+数据页号”作为K查这个哈希表:

  • 若无,读取数据页
  • 若有,说明数据页已被缓存

每次读取一个数据页到缓存后,都会在这哈希表写入一个数据,下次若再使用这数据页,就能从哈希表直接读出来,毕竟他经被放入一个缓存页了:

image

你可能感兴趣的:(图解MySQL系列(4)-Buffer Pool中的free链表)