openGauss内核求索——缓冲区管理器

2024年 4月 23日 72.2k 0

1.基本原理

缓冲管理器:主要是管理共享内和持久存储之间的数据传输,并可能对 DBMS 的性能产生重大影响。

缓冲区管理器、持久存储和后端进程之间的关系如下图所示:

2.缓冲区管理器结构

缓冲区管理器包括一个缓冲区表、缓冲区描述符和缓冲池。

缓冲区描述符:保存着页面的元数据,对应的页面则保存在缓冲池的槽位中。

缓冲池:缓冲池存储数据文件的页,如表的页面。缓冲池是一个数组,每个插槽存储数据文件的一页。缓冲池数组的索引称为buffer_id。

相关函数:BufferDesc *BufferAlloc

2.1 缓冲区标签

数据库为所有数据文件的每个页面分配一个唯一的标记,即缓冲区标签。

缓冲区标签由关系文件节点、关系分支编号和页面块号

    typedef struct buftag {
       RelFileNode rnode; * physical relation identifier */
       ForkNumber forkNum;
       BlockNumber blockNum; * blknum relative to begin of reln */
    } BufferTag;

    (1)关系文件节点用于定位页面所属的关系,包含了表空间、数据库和表的oid。例如:(表空间,数据库, 表) -> (1663, 16384, 37721)

    (2)关系分支编号用于定位关系文件的具体分支文件,一个关系可能有三种分支,分别是关系主体(main分支,编号为0)、空闲空间映射( fsm分支,编号为1)及可见性映射(vm分支,编号为2)

    (3)页面块号则在具体分支文件中指明相应页面的偏移量,即页面号

    例如,{(1663, 16384, 37721), 0, 7} 标签表示,在某个表空间(oid=1663)中,某个数据库(oid=16384)的某张表(oid=37721)的 0 号分支( 0代表关系表本体)的第 7 号页面。再比如,缓冲区标签 {(1663, 16384, 37721), 1, 3} 表示该表空闲空间映射文件的三号页面。关系本体 main 分支编号为0,空闲空间映射 fsm 分支编号为1。

    2.2 缓冲区表

    缓冲区表:一个散列表(hash 表),存储着页面的buffer_tag与缓冲区描述符的 buffer_id 之间的映射关系。

    缓冲表在逻辑上可分为三部分: 散列函数、散列桶槽、数据项

    散列函数:hashquickany

    散列桶槽:key值

    数据项: (页面的 buffer_tag,包含页面元数据的描述符的 buffer_id)

       Notes

    为了避免哈希函数的冲突,缓冲表采用了使用链表的分离链接方法来解决冲突。当数据项被映射至同一个桶槽时,该方法会将数据项(包括两个值,即页面的 buffer_tag 和包含页面元数据的描述符的 buffer_id)保存在一个链表中。例如,数据项 (Tag_A,id=1)表示在 buffer_id=1 对应的缓冲区描述符中,存储着页面 Tag_A 的元数据

    页面简单访问流程:根据后端进程发送的请求,创建目标页面的 buffer_tag,然后将 buffer_tag 通过内置的散列函数映射到哈希桶槽,并分配 buffer_id, 即目标页面在缓冲池数组中存储的槽位的序号。

    2.3缓冲区描述符

    缓冲区描述符:保存着页面的元数据,对应的页面则保存在缓冲池的槽位中。缓冲区描述符的结构由BufferDesc结构定义。

    2.3.1 缓冲区描述符结构体

    结构体BufferDesc定义如下:

      typedef struct BufferDesc {  
        BufferTag tag; * ID of page contained in buffer */

       /* state of the tag, containing flags, refcount and usagecount */
       pg_atomic_uint64 state;

       int buf_id;   * buffer's index number (from 0) */

       ThreadId wait_backend_pid; * backend PID of pin-count waiter */

       LWLock* io_in_progress_lock; * to wait for I/O to complete */
       LWLock* content_lock;       * to lock access to buffer contents */  
       
        BufferDescExtra *extra;  
       
      #ifdef USE_ASSERT_CHECKING  
        volatile uint64 lsn_dirty;  
      #endif  
      } BufferDesc;

      参数说明:

      tag:保存着目标页面的buffer_tag(2.1 缓冲区标签),缓冲区标签中对应的页面存储在相应的缓冲池槽中。

      buffer_id:标识了缓冲区描述符,相当于对应缓冲池槽的buffer_id。

      context_lock:轻量级锁,用于控制对相关页面的访问。

      io_in_progress_lock: 轻量级锁,用于控制对相关页面的访问。

      state: 用于保存相应页面的状态,主要状态如下:

        /*
        * Flags for buffer descriptors
        *
        * Note: TAG_VALID essentially means that there is a buffer hashtable
        * entry associated with the buffer's tag.
        */
        #define BM_IN_MIGRATE (1U tag.rnode.relNode,
                              buf->tag.blockNum, buf->tag.forkNum)));
               SimpleMarkBufDirty(buf);
               *oldFlags |= BM_DIRTY;
               *needGetLock = true;
           }

        5.相关系统对象

        5.1 参数

        shared_buffers

        5.2 函数或视图

        (1)系统函数pg_buffercache_pages

          select count(*) from pg_buffercache_pages();

          观测参数:bufferid, relfilenode, bucketid, storage_type, reltablespace, reldatabase, relforknumber, relblocknumber, isdirty, isvalid, usage_count, pinning_backends

          (2)系统函数local_candidate_stat

            select count(*) from local_candidate_stat;

            观测参数:node_name, candidate_slots, get_buf_from_list, get_buf_clock_sweep, seg_candidate_slots, seg_get_buf_from_list, seg_get_buf_clock_sweep

               本文借鉴博客

            https://blog.csdn.net/hmxz2nn/article/details/118526453

            自旋锁技术博客:https://zhuanlan.zhihu.com/p/659527782

            相关文章

            Oracle如何使用授予和撤销权限的语法和示例
            Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
            下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
            社区版oceanbase安装
            Oracle 导出CSV工具-sqluldr2
            ETL数据集成丨快速将MySQL数据迁移至Doris数据库

            发布评论