penGauss内核求索 缓冲区管理器

2024年 5月 19日 62.9k 0

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

Table of Contents

  • openGauss内核求索 ---- 缓冲区管理器
    • 1.基本原理
    • 2.缓冲区管理器结构
      • 2.1 缓冲区标签
      • 2.2 缓冲区表
      • 2.3缓冲区描述符
        • 2.3.1 缓冲区描述符结构体
        • 2.3.2 缓冲区描述符初始状态
      • 2.4 缓冲池
        • 2.4.1 缓冲池结构
        • 2.4.2 buffer候选队列
      • 2.5 缓冲区相关的锁
        • 2.5.1 缓冲表锁
        • 2.5.2 缓冲区描述符相关的锁
    • 3.缓冲区管理器的工作原理
      • 3.1 访问存储在缓冲池中的页面
      • 3.2 将页面从存储加载到空槽
      • 3.3 将页面从存储加载到受害者缓冲池槽
    • 4. 相关函数解析
        • 4.1 函数BufferAlloc
      • 4.1 函数StrategyGetBuffer
      • 4.2 函数PageCheckIfCanEliminate
    • 5.相关系统对象
      • 5.1 参数
      • 5.2 函数或视图

1.基本原理

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

缓冲区管理器、持久存储和后端进程之间的关系如下图所示:
penGauss内核求索 ---- 缓冲区管理器-1

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 的元数据
penGauss内核求索 ---- 缓冲区管理器-2

页面简单访问流程:根据后端进程发送的请求,创建目标页面的 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.dbNode, buf->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

  1. 系统函数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

author: 丑丑的老太婆(unique woman)

相关文章

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

发布评论