postgresql源码学习(59)—— 磁盘管理器 SMGR
一、 定义及作用
PostgreSQL 的磁盘管理器(Storage Manager,简称 SMGR)是数据库系统中负责管理底层存储的核心模块。磁盘管理器并非直接操作磁盘上的文件,而是通过VFD(虚拟文件描述符,将在后续学习)实现。
-
抽象存储层,解耦存储逻辑:
SMGR 提供了一层抽象接口,屏蔽了不同存储类型(如表、索引、TOAST 表等)的底层细节,使上层模块(如执行器、缓冲池)无需关心具体的存储实现。 -
管理文件操作:
SMGR 负责文件的创建、删除、扩展、截断等操作,确保数据文件能够高效地存储和访问。 -
支持多种存储类型:
PostgreSQL 支持多种存储类型(如堆表、索引、TOAST 表等),SMGR 通过统一的接口管理这些存储类型。 -
与缓冲池交互:
SMGR 与缓冲池(Buffer Manager)紧密协作,确保数据页能够正确地加载到内存中。 -
提高可扩展性:
通过 SMGR 的抽象接口,PostgreSQL 可以更容易地支持新的存储类型或存储引擎(如列存储、外部表等)。
二、 核心数据结构
src/include/storage/smgr.h SMGR 的头文件,定义了存储管理器的接口和数据结构。
SMgrRelation:SMGR的核心数据结构,主要作用是:
- 管理文件句柄:缓存关系的文件句柄,避免频繁打开和关闭文件。
- 支持多分支(Fork):PostgreSQL 中的表或索引可能包含多个分支(如主数据分支、TOAST 分支等),SMgrRelationData 支持管理这些分支的文件。
- 缓存文件大小:记录每个分支的最后一个已知大小,用于优化文件扩展操作。
- 支持临时关系:通过 smgr_owner 指针区分临时关系和持久关系,临时关系在事务结束时自动释放
/** smgr.c 维护了一个 SMgrRelation 对象表,这些对象本质上是缓存的文件句柄。* SMgrRelation 通过 smgropen() 创建(如果尚未存在),并通过 smgrclose() 销毁。* 注意,这些操作并不涉及 I/O,它们只是创建或销毁哈希表条目。* (但 smgrclose() 可能会释放相关资源,例如操作系统级别的文件描述符。)** 一个 SMgrRelation 可能有一个“所有者”,这只是从其他地方指向它的指针;* 如果 SMgrRelation 被关闭,smgr.c 会清除此指针。* 我们使用此机制来避免从 relcache 到 smgr 的悬空指针,而无需让 smgr 显式感知 relcache。* 每个 SMgrRelation 只能有一个“所有者”指针,但这已经足够。** 没有“所有者”的 SMgrRelation 被认为是临时的,并在事务结束时被删除。*/typedef struct SMgrRelationData
{/* rnode 是哈希表查找键,因此必须放在第一位! */RelFileNodeBackend smgr_rnode; /* 表的物理标识符 *//* 指向所有者指针的指针,如果没有则为 NULL */struct SMgrRelationData **smgr_owner;/** 以下字段在缓存刷新事件时重置为 InvalidBlockNumber,* 并记录每个分支的最后一个已知大小。* 此信息目前仅在恢复期间可靠,因为分支扩展没有缓存失效机制。*/BlockNumber smgr_targblock; /* 当前插入目标块 */BlockNumber smgr_cached_nblocks[MAX_FORKNUM + 1]; /* 每个分支的最后一个已知大小 *//* 未来可能会在此处添加其他公共字段 *//** 以下字段是 smgr.c 及其子模块私有的。* 不要从其他地方修改它们。*/int smgr_which; /* 存储管理器选择器 *//** 用于 md.c;每个分支的打开段数量(md_num_open_segs)* 和段本身(md_seg_fds)。*/int md_num_open_segs[MAX_FORKNUM + 1];struct _MdfdVec *md_seg_fds[MAX_FORKNUM + 1];/* 如果没有所有者,则链接到所有无所有者 SMgrRelations 的链表中 */dlist_node node;
} SMgrRelationData;typedef SMgrRelationData *SMgrRelation;
三、 核心函数
1. smgrinit(void)
-
作用:初始化存储管理器模块。
-
说明:在 PostgreSQL 启动时调用,用于初始化 SMGR 的全局状态(如哈希表、锁等)。
2. smgropen(RelFileNode rnode, BackendId backend)
-
作用:打开一个关系的存储管理器(
SMgrRelation)。 -
参数:
-
rnode:关系的物理标识符(RelFileNode)。 -
backend:后端 ID,用于区分不同后端进程。
-
-
返回值:返回一个
SMgrRelation对象,表示关系的存储管理器。
3. smgrexists(SMgrRelation reln, ForkNumber forknum)
-
作用:检查指定分叉(Fork)的文件是否存在。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号(如主数据分叉、TOAST 分叉等)。
-
-
返回值:如果文件存在,返回
true;否则返回false。
4. smgrsetowner(SMgrRelation *owner, SMgrRelation reln)
-
作用:设置关系的所有者。
-
参数:
-
owner:指向所有者指针的指针。 -
reln:关系的存储管理器。
-
-
说明:用于将
reln的所有者设置为owner,避免悬空指针问题。
5. smgrclearowner(SMgrRelation *owner, SMgrRelation reln)
-
作用:清除关系的所有者。
-
参数:
-
owner:指向所有者指针的指针。 -
reln:关系的存储管理器。
-
-
说明:用于清除
reln的所有者,通常在关系关闭时调用。
6. smgrclose(SMgrRelation reln)
-
作用:关闭一个关系的存储管理器。
-
参数:
-
reln:关系的存储管理器。
-
-
说明:释放与
reln相关的资源(如文件描述符),并将其从哈希表中移除。
7. smgrcloseall(void)
-
作用:关闭所有关系的存储管理器。
-
说明:在事务结束时调用,用于清理所有临时关系的存储管理器。
8. smgrclosenode(RelFileNodeBackend rnode)
-
作用:关闭指定关系的存储管理器。
-
参数:
-
rnode:关系的物理标识符。
-
-
说明:根据
rnode查找并关闭对应的存储管理器。
9. smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
-
作用:创建一个新的分叉文件。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。 -
isRedo:是否在恢复期间调用。
-
-
说明:用于创建表或索引的分叉文件(如主数据文件、TOAST 文件等)。
10. smgrdosyncall(SMgrRelation *rels, int nrels)
-
作用:同步所有指定关系的文件到磁盘。
-
参数:
-
rels:存储管理器数组。 -
nrels:数组长度。
-
-
说明:确保所有修改过的文件数据被写入磁盘。
11. smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo)
-
作用:删除所有指定关系的文件。
-
参数:
-
rels:存储管理器数组。 -
nrels:数组长度。 -
isRedo:是否在恢复期间调用。
-
-
说明:用于删除表或索引的分叉文件。
12. smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
-
作用:扩展指定分叉的文件,并写入数据。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。 -
blocknum:要写入的块号。 -
buffer:要写入的数据。 -
skipFsync:是否跳过同步到磁盘。
-
-
说明:用于扩展文件并写入数据块。
13. smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
-
作用:预取指定分叉的数据块。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。 -
blocknum:要预取的块号。
-
-
返回值:如果预取成功,返回
true;否则返回false。
14. smgrread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer)
-
作用:从指定分叉的文件中读取数据块。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。 -
blocknum:要读取的块号。 -
buffer:存储读取数据的缓冲区。
-
-
说明:用于从文件中读取数据块到内存。
15. smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
-
作用:将数据块写入指定分叉的文件。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。 -
blocknum:要写入的块号。 -
buffer:要写入的数据。 -
skipFsync:是否跳过同步到磁盘。
-
-
说明:用于将数据块写入文件。
16. smgrwriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks)
-
作用:将指定范围内的数据块写回磁盘。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。 -
blocknum:起始块号。 -
nblocks:要写回的块数。
-
-
说明:用于批量写回数据块,优化 I/O 性能。
17. smgrnblocks(SMgrRelation reln, ForkNumber forknum)
-
作用:获取指定分叉的文件大小(块数)。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。
-
-
返回值:文件的大小(块数)。
18. smgrnblocks_cached(SMgrRelation reln, ForkNumber forknum)
-
作用:获取指定分叉的文件大小(块数),使用缓存值。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。
-
-
返回值:文件的大小(块数)。
-
说明:与
smgrnblocks类似,但使用缓存值以提高性能。
19. smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
-
作用:截断指定分叉的文件到指定大小。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号数组。 -
nforks:分叉数量。 -
nblocks:每个分叉的目标大小(块数)。
-
-
说明:用于截断文件,释放多余的空间。
20. smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
-
作用:立即同步指定分叉的文件到磁盘。
-
参数:
-
reln:关系的存储管理器。 -
forknum:分叉编号。
-
-
说明:确保文件的修改被立即写入磁盘。
21. AtEOXact_SMgr(void)
-
作用:在事务结束时清理存储管理器。
-
说明:用于释放临时关系的存储管理器,清理缓存等。
参考:《PostgreSQL 数据库内核分析》
相关文章:
postgresql源码学习(59)—— 磁盘管理器 SMGR
一、 定义及作用 PostgreSQL 的磁盘管理器(Storage Manager,简称 SMGR)是数据库系统中负责管理底层存储的核心模块。磁盘管理器并非直接操作磁盘上的文件,而是通过VFD(虚拟文件描述符,将在后续学习…...
Spring Boot(8)深入理解 @Autowired 注解:使用场景与实战示例
搞个引言 在 Spring 框架的开发中,依赖注入(Dependency Injection,简称 DI)是它的一个核心特性,它能够让代码更加模块化、可测试,并且易于维护。而 Autowired 注解作为 Spring 实现依赖注入的关键工具&…...
UE_C++ —— Structs
目录 一,实现一个UStruct 二,Struct Specifiers 三,最佳做法与技巧 结构体(Struct)是一种帮助组织和操作相关属性的数据结构;在引擎中,结构体会被引擎反射系统识别为 UStruct,但不…...
ArcGISPro 新建shp+数据结构
import arcpy# 设置工作空间和 Shapefile 存放路径 shp_path r"C:\path\to\your\folder\PolygonZY.shp" # Shapefile 存放路径 fields [("CHBH", "TEXT", 20),("ZCMC", "TEXT", 100),("ZCLX", "TEXT"…...
DeepSeek教unity------MessagePack-06
无类型 Typeless 无类型的 API 类似于 BinaryFormatter,因为它会将类型信息嵌入到数据块中,所以在调用 API 时不需要显式指定类型。 MessagePackSerializer.Typeless 是 Serialize/Deserialize<object>(TypelessContractlessStandardResolver.In…...
2.【BUUCTF】bestphp‘s revenge
进入题目页面如下 进行代码审计 <?php // 1. 高亮显示当前PHP文件的源代码,方便开发者查看代码内容,在生产环境中不应使用此函数,可能会导致代码泄露。 highlight_file(__FILE__);// 2. 定义变量 $b ,其值为字符串 implode &…...
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-23- 操作鼠标拖拽 - 番外篇(详细教程)
拉票 亲爱的小伙伴们或者童鞋们,喜欢宏哥文章的,请动动你们发财小手,给我投投票票 。 祝2025小伙伴们工作顺利,家庭和睦,心想事成,财源滚滚! 我的票还有7票,互票的朋友私信给我。 投…...
Netty源码解析之异步处理(二):盛赞Promise中的集合设计
前言 在阅读Netty源码的过程中,我越来越相信一句话:“Netty的源码非常好,质量极高,是Java中质量最高的开源项目之一”。如果认真研究,会有一种遍地黄金的感觉。 本篇文件我将记录一下鄙人在Promise的实现类DefaultPr…...
NetworkX布局算法:nx.spring_layout
诸神缄默不语-个人CSDN博文目录 官方文档:https://networkx.org/documentation/stable/reference/generated/networkx.drawing.layout.spring_layout.html 和nx.fruchterman_reingold_layout()等价。 这个函数主要是为了在可视化NetworkX图时设置节点分布布局的&…...
Navicat导入海量Excel数据到数据库(简易介绍)
目录 前言正文 前言 此处主要作为科普帖进行记录 原先Java处理海量数据的导入时,由于接口超时,数据处理不过来,后续转为Navicat Navicat 是一款功能强大的数据库管理工具,支持多种数据库系统(如 MySQL、PostgreSQL、…...
LeetCodehot100 力扣热题100 二叉树展开为链表
代码思路 目标: 将二叉树展平(flatten)为一个单链表。展平后的链表应该按照前序遍历的顺序排列节点,即: • 节点的左子树指针设置为 nullptr。 • 节点的右子树指针指向下一个节点。 代码注释及思路 class Solution…...
2.14学习总结
#include <stdio.h> #include <stdlib.h> #include <math.h>#define MAX_N 32767// 二分查找最接近目标值的元素 int binarySearch(int* arr, int left, int right, int target) {while (left < right) {int mid left (right - left) / 2;if (arr[mid] …...
在WPS中通过JavaScript宏(JSA)调用本地DeepSeek API优化文档教程
既然我们已经在本地部署了DeepSeek,肯定希望能够利用本地的模型对自己软件开发、办公文档进行优化使用,接下来就先在WPS中通过JavaScript宏(JSA)调用本地DeepSeek API优化文档的教程奉上。 前提: (1)已经部署好了DeepSeek,可以看我的文章:个人windows电脑上安装DeepSe…...
zola + github page,用 workflows 部署
之前的Zola都是本地build之后,再push到github上,这种方式很明显的弊端就是只能在本地编辑,而不能通过github编辑,再pull到本地,缺乏了灵活性。因此将zola用workflows来部署。 repo地址:https://github.com/…...
【科技革命】颠覆性力量与社会伦理的再平衡
目录 2025年科技革命:颠覆性力量与社会伦理的再平衡目录技术突破全景图认知智能的范式转移量子霸权实现路径生物编程技术革命能源结构重构工程 产业生态链重构医疗健康新范式教育系统智能进化金融基础设施变革制造范式革命 科技伦理与文明演进 2025年科技革命&#…...
UIView 与 CALayer 的联系和区别
今天说一下UIView 与 CALayer 一、UIView 和 CALayer 的关系 在 iOS 开发中,UIView 是用户界面的基础,它负责处理用户交互和绘制内容,而 CALayer 是 UIView 内部用于显示内容的核心图层(Layer)。每个 UIView 内部都有…...
Jenkins 新建配置 Freestyle project 任务 六
Jenkins 新建配置 Freestyle project 任务 六 一、新建任务 在 Jenkins 界面 点击 New Item 点击 Apply 点击 Save 回到任务主界面 二、General 点击左侧 Configure Description:任务描述 勾选 Discard old builds Discard old builds:控制何时…...
深入解析A2DP v1.4协议:蓝牙高质量音频传输的技术与实现
1. A2DP概述 A2DP(Advanced Audio Distribution Profile)是一种高质量音频流媒体协议,旨在实现高质量音频内容的分发,通常用于通过蓝牙设备传输音频数据,例如将音乐从便携式播放器传输到耳机或扬声器。与传统的蓝牙语…...
mybatis-plus逆向code generator pgsql实践
mybatis-plus逆向code generator pgsql实践 环境准备重要工具的版本供参考pom依赖待逆向的SQL 配置文件CodeGenerator配置类配置类说明 环境准备 重要工具的版本 jdk1.8.0_131springboot 2.7.6mybatis-plus 3.5.7pgsql 14.15 供参考pom依赖 <?xml version"1.0&quo…...
Android Studio:RxBus结合ICompositeSubscription使用
我现在想用 RxBus 来发布和订阅事件,同时使用 ICompositeSubscription 来管理订阅。跟前一个博客的区别在于,事件流的产生方式不同,更加得全面。 目标 使用 RxBus 发布事件。使用 ICompositeSubscription 来管理订阅。在 Activity 中创建订…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
