• 8.缓冲区管理器


    目录

    1. 结构

    1.1 缓冲区标签

    1.2 缓冲表

    1.3 缓冲区描述符

    1.4 缓冲池

    2. 锁

    2.1 缓冲表锁bufMappingLock

    2.2 缓冲区描述符相关锁

    3. 页面访问

    3.1 访问缓冲池中的页面

    ​编辑

    3.2 将页面从存储加载到空槽

    4. 其他

    4.1 时钟扫描的页面置换算法

    4.2 环形缓冲区

    4.3 脏页刷盘


    1. 结构

    1.1 缓冲区标签

    tag{(16821,16384,37721),1,3}表示16821号表空间的16384号数据库的37721号表的空闲空间映射(0为关系本体main分支,2位VM分支)的第3页。

    1.2 缓冲表

    缓冲表为散列表,通过散列函数,可根据缓冲区标签tag找到对应的buffer_id,即数据在缓冲池中的槽位号。散列表通过分离链接方法解决冲突。

    1.3 缓冲区描述符

    缓冲区描述符层包括与之相关的缓冲池槽位的元数据信息,包括buffer_id,缓冲区标签tag,当前访问页面的进程数refcount,访问次数usage_count,标志脏位的flags,指向下一个描述符的freeNext(所以缓冲区描述符层也是一个链表),以及context_lock与io_in_progress_lock两个锁,后面会介绍。

    缓冲区描述符有三种状态:

    空:缓冲池槽中无页面,refcount与usage_count均为0。

    钉住:当前页面正在被访问,refcount与usage_count均大于等于1。

    未钉住:存在该页面,但目前没有进程访问,refcount为0,usage大于等于1(因为至少将其载入缓冲池槽的进程使其加了1)。

    其中空缓冲区描述符组成了一个freelist链表。

    1.4 缓冲池

    缓冲池有多个槽位组成,是一个数组,每个槽位为8k,正好可加载一个磁盘页面。

    2. 锁

    该锁为缓冲区管理器同步化的一部分,与SQL语句与操作中的锁无关。

    2.1 缓冲表锁bufMappingLock

    维护缓冲表的锁,分为读取的共享锁与增删的独占锁。

    为了不影响其他事务对缓冲表的读写,提高并发量,pg将散列表划分为16组,每组一个锁,一次锁多个桶。

    2.2 缓冲区描述符相关锁

    内容锁:读取页面时的共享锁以及独占锁,独占锁在以下几种情况下分配:

    1. 增删改元组t_xmin/t_xmax事务
    2. 物理删除元组
    3. 冻结页面中的元组

    IO进行锁

    进程加载、写入页面时分配。

    自旋锁

    检查或更新元数据信息字段时获取,如更新refcount等。9.6版后,使用原子操作替代自旋锁。

    3. 页面访问

    3.1 访问缓冲池中的页面

    通过Tag1与散列函数,找到散列表上的桶,

    获取桶所在区的缓冲表共享锁,在该桶中找到tag1对应的buffer_id1(一个桶中可能有多个buffer_id)。

    钉住buffer_id1的缓冲区描述符,将ref_count与usage_count分别加1.

    释放共享锁,访问buffer_id1的缓冲池槽。

    3.2 将页面从存储加载到空槽

    1.通过Tag1与散列函数,找到散列表上的桶,获取桶所在区的缓冲表共享锁,在该桶中没找到tag1。释放共享锁。

    2.从freelist(空缓冲区描述符链表)中获取空缓冲区描述符,并将其钉住,假设获得的是buffer_id2,以独占模式获取桶所在分区的锁。

    3.创建一条tag=1,buffer_id=2的数据项,插入桶中。

    4.获得排他的IO锁,将数据页面加载到buffer_id=2的缓冲池插槽中,标记vaild为1,释放IO锁。

    5.释放桶所在分区的锁。

    6.访问buffer_id=2的插槽。

    将页面从存储加载到受害者缓冲池槽

    1. 使用时钟扫描算法选择脏页,将脏页刷到磁盘中
    2. 在散列表中加新的tag,删旧的tag,并且将脏页腾出的buffer_id设为新tag对应的id。
    3. 将新数据页面替换缓冲池插槽中的旧数据页面

    4. 其他

    4.1 时钟扫描的页面置换算法

    以时钟的方式扫描缓冲区描述符,跳过被钉住的描述符,对于未被钉住的描述符,如果其usage_count为0,则将其置换出去,若不为0,则将其减1,然后扫描下一个:

    (深色的表示被钉住的) 

    4.2 环形缓冲区

    当需要读写大表时,需要大量置换缓冲池,这会导致之后的缓存命中率降低。所以pg使用额外的环形缓冲区来替代缓冲池加载大表。当有以下情况时,会启用环形缓冲区:

    • 批量读取。当扫描关系读取数据的大小超过缓冲池的四分之一时,环形缓冲区的大小为 256 KB。(256k正好可以加载进二级缓存)
    • 批量写入,当执行下列 SQL 命令时,环形缓冲区大小为 16 MB。

    COPY FROM 命令。

    CREATE TABLE AS 命令。

    CREATE MATERIALIZED VIEW 或 REFRESH MATERIALIZED VIEW 命令。

    ALTER TABLE 命令。

    • 清理过程,当自动清理守护进程执行清理过程时,环形缓冲区大小为 256 KB。分配的环形缓冲区将在使用后被立即释放。

    4.3 脏页刷盘

    除了置换脏页时需要脏页刷盘外,检查点进程会在检查点开始时进行脏页刷盘;

    后台写入进程通过少量多次的脏页刷盘来减少检查点的密集写入,默认为200ms一次,默认最多刷100个页。

  • 相关阅读:
    软考-软件项目活动图详解
    三、git的安装和配置
    java8新特性,Lambda 表达式
    【libuv】与uvgrtrp的_SSIZE_T_定义不同
    css实现水波纹
    爬虫工作者必备:使用爬虫IP轻松获得最强辅助
    node封装mysql
    【kali-Metasploit】Armitage常见问题:sudo权限、连接不到数据库、service not found
    解决 MacOS Sonoma 14 系统下修改用户名无法进入系统的历史Bug
    微信扫一扫 - 实现签到功能 - 思路
  • 原文地址:https://blog.csdn.net/Michaelia_hu/article/details/127804260