
▲ 初阶篇
文章平均质量分 82
此专栏将主要讲解PG数据库内核体系架构、源码安装、内存上下文实现原理、存储管理(内存、外层)、VFD实现机制、libpq原理、PG客户端认证、后端进程创建原理、postmaster创建、共享内存、锁、IPC等等。通过本专栏的系统学习,能让你快速上手PG,并掌握PG内核的实现原理,成为一名优秀的DBA
优惠券已抵扣
余额抵扣
还需支付
¥119.90
¥299.90
购买须知?
本专栏为图文内容,最终完结不会低于15篇文章。
订阅专栏,享有专栏所有文章阅读权限。
本专栏为虚拟商品,基于网络商品和虚拟商品的性质和特征,专栏一经购买无正当理由不予退款,不支持升级,敬请谅解。
内核之道
某大厂资深技术专家,精通PostgreSQL内核、专注于『NVR、AI超脑、智能应用服务器、Postgres内核』开发
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
【0294】Postgres内核 dynahash 之 hash_search 实现原理(1)
注意:扩展表失败不是致命错误,它只是意味着我们必须在比我们想要的更高的填充因子下运行。但是,如果我们使用palloc分配器,那么无论如何它都会在内存不足时抛出错误,因此我们必须在修改表之前执行此操作。(1)如果参数action是插入(HASH_ENTER),需检查是否到了拆分桶(bucket)的时间。附: 这里的枚举值定义,以及Postgres内核中的dynahash实现, 与glibc库源码中“的元素的指针(如果有),如果没有找到匹配项则返回NULL。的情况下是需要的,但是对于返回值来说是多余的。原创 2024-07-05 19:26:26 · 516 阅读 · 0 评论 -
【0269】揭晓Postgres内核 procArray、MyProc、ProcGlobal 三者间的微妙关系
在一文中,讲解了pg内核初始化ProcGlobalPROC_HDR)的过程,以及ProcGlobal的作用;而在一文中,讲解了初始化procArray)的过程。pg内核中,三个全局指针变量(procArray、MyProc、ProcGlobal)彼此间有着复杂的关联和依赖,而这层关系较为复杂、微妙。本文的主旨是通过源码结合图文的方式,彻底搞清楚它们之间的关联、管理。带着这几个疑问与思考,开始正式本文内容。原创 2024-02-28 12:38:22 · 330 阅读 · 0 评论 -
【0137】【libpq】向postmaster发送 startup packet 数据包(7)
在【0136】【libpq】startup packet应用机制及构建过程(6)一文,介绍了libpq是如何与postmaster进行通信的。它将首先构造一个startup packet数据包,然后发送给postmaster中的postgres后端进程;postgres在接收到libpq发送过来的startup packet之后,会进行相应的系列的初始化操作。然后并发送相关的数据给libpq(这个具体实现与细节将在【0138】中讲解)。原创 2022-10-31 11:23:38 · 633 阅读 · 0 评论 -
【0000】PostgreSQL V17.4 内核源码剖析专栏(2017 ~ 2025.05.15 更新)
本专栏将会持续更新,直到将PostgreSQL V13.2源码涉及的所有原理、技术剖析完成为止。每一篇文章都是经过多次的源码阅读 + 调试,得以验证之后才梳理成文章形式。最终该专栏的文章数量应该在一万篇或以下,这也是文章序号从【0000】开始的缘故。通过本专栏的学习,能够让你掌握PostgreSQL数据库中的每个技术背后,底层的实现原理。原创 2022-12-13 15:01:01 · 5569 阅读 · 10 评论 -
【0175】Postgres内核 使用 context_freelists[] 彻底释放 MemoryContext 中分配的所有内存(8 - 2)
在上一篇文件中讲解了如何删除PG内核中某个指定内存上下文(MemoryContex)指针变量所分配的内存空间过程。通过指定内存上下文(context)中的set->blocks中的next指针变量一直遍历的方式,便可实现该内存上下文中所有已申请的block的内存空间删除,以及该context本身所占用的block的内存空间删除。本文将从PG内核源码实现角度出发,介绍另外一种删除context中所有已分配内存空间的方式,那就是借助“数组中这两个元素的具体作用分别是什么。中的两个元素,其默认值均初始化为。原创 2023-02-12 16:23:30 · 864 阅读 · 0 评论 -
【0407】Postgres内核 Condition variables (ConditionVariable)设计机制 ①
要在条件变量上进入sleep状态,一个进程应当使用一个循环,该循环首先检查条件,如果条件满足则退出循环,随后调用 ConditionVariableSleep。与轻量级锁(LWLock)的等待不同,对条件变量的等待是可以被中断的。在我们的实现中,条件变量使进程进入可中断睡眠状态(所以在条件满足之前能够被取消),并且内部不使用指针(因而在分布式共享内存(DSM)中使用是安全的)。这保证能唤醒在调用之时处于该条件变量上睡眠状态的所有进程,但是在调用中途将自身添加到列表中的进程通常不会被唤醒。原创 2025-02-19 20:11:35 · 157 阅读 · 0 评论 -
【0400】解决Ubuntu系统上源码安装Postgres,报错:chown: invalid user: ‘postgres:postgres’
【代码】【0400】Ubuntu系统上源码安装Postgres,报错:chown: invalid group: ‘postgres:postgres’原创 2025-02-06 16:48:22 · 180 阅读 · 0 评论 -
【0399】Source Insight 4.0 中文乱码问题(已解决)
SourceInsight 4.0 工具打开 Postgres内核源码时候,添加中文注释,发现乱码了。如下图所示:期间也尝试过调整文件的(不同)编码,但问题仍然存在。直到最近调整 SourceInsight 4.0工具的界面某些配置时候,不经意间,反勾选的某些配置参数,解决了该问题。原创 2025-01-23 10:47:58 · 1499 阅读 · 0 评论 -
【0397】Postgres内核 checkpoint process ⑦ 获取 delaying checkpoint VXIDs(delayChkpt)
顶级事务(Top-level transactions)通过由 PGPROC 字段 backendId 和 lxid 组成的 VirtualTransactionIDs 来标识。对于已准备的事务,LocalTransactionId 是一个普通的XID。这些在短期内保证唯一,但在数据库重启或 XID 滚转后会被重新使用;因此,它们永远不应被存储在磁盘上。请注意,不能假定结构体 VirtualTransactionId 可以作为一个整体进行原子赋值。然而,类型。原创 2025-01-21 12:39:53 · 304 阅读 · 0 评论 -
【0395】Postgres内核 checkpoint process ⑤ 于 procArray 获取 xid
函数 GetOldestActiveTransactionId() 获取 procArray 中的 xid。procArray 是一个 ProcArrayStruct 类型的全局指针变量,定义于 procarray.c 源文件中。与 GetSnapshotData 类似,但仅返回 oldestActiveXid。我们包含所有已分配 TransactionId 的 PGXACT,甚至包括 VACUUM 进程。我们会查看所有数据库,不过无需包含 WALSender,因为这不会对热备冲突产生影响。原创 2025-01-20 14:32:41 · 230 阅读 · 0 评论 -
【0383】Postgres内核(replication slot)根据给定 FunctionCallInfo fcinfo, 获取返回的 datatype 类别 ( 2 )
Postgres内核 SQL functions(pg_create_physical_replication_slot)实现物理复制槽创建过程,涉及的内容比较多,所以将其底层实现拆分四篇文章进行讲解。这部分内容涉及到 Postgres内核初始化 Backend process 过程中初始化的 系统表有关系。关于 Postgres内核 SysCache 系列相关知识点,后面会用专门的文章进行深入分析。这部分内容由函数 get_call_result_type() 实现。原创 2025-01-07 15:49:16 · 85 阅读 · 0 评论 -
【0381】Postgres内核 replication slot shared memory 初始化
Postgres内核中 ReplicationSlotsShmemSize() 函数用于计算 replication slot (ReplicationSlotsShmemInit)所需的共享内存空间。$PGDATA/postgresql.conf 配置文件中的 max_replication_slots 默认值10,表明当前 Postgres内核中 replication slot 的最大数量。该函数没有出入参, 也无返回值。add_size() 計算值。原创 2025-01-03 15:21:06 · 122 阅读 · 0 评论 -
【0378】Postgres内核 replication slot management (复制槽管理)
复制槽(Replication slots)用于保存源自此集群的复制流(replication streams)的状态信息。复制槽需要是永久性的(以便支持重启)、崩溃安全的,并且可以在备用服务器上分配(以支持级联设置)。对于在会话结束时消失的槽位,“TEMPORARY”是合适的选择。被标记为 “PERSISTENT(持久)” 的槽位具有防崩溃特性,在释放时不会被丢弃。ReplicationSlotPersistency 枚举类型代表着 “复制槽(replication slots)在释放或崩溃时的表现。原创 2024-12-31 19:09:05 · 208 阅读 · 0 评论 -
【0376】Postgres内核 分配 last safe MultiXactId( 14 )
函数 SetMultiXactIdLimit() 在 postmaster 初始化 startup process 中, 在已经读取到 XLOG record 的情况下, 通过 checkPoint.oldestMulti 完成当前 Postgres数据库环境中, 最后一个安全的 MultiXactId 的分配过程。函数原型如下:, Oid, boolis_startup。原创 2024-12-24 15:52:39 · 287 阅读 · 0 评论 -
【0375】Postgres内核 XLOG 之 设置下一个待分配 MultiXactId 和 offset ( 13 )
Postgres内核在读取到 XLOG record 之后,接着设置下一个待分配的 MultiXactId 及偏移量(offset)当我们能够确切地从checkpoint record确定正确的下一个 ID/offset 时,会使用此操作。尽管这仅在 bootstrap 和 XLog 重放(XLog replay)期间被调用,但我们会采取锁定操作,以防任何热备后端正在检查这些值。原创 2024-12-23 19:56:45 · 123 阅读 · 0 评论 -
【0372】Postgres内核 multi transaction log 管理器 (multixact)
pg_multixact 管理器是一个类似于 pg_xact 的管理器,其为每个 MultiXactId 存储一个 MultiXactMember 数组。它是共享行锁实现的基础部分。每个 MultiXactMember 由一个 TransactionId 和一组标志位构成。此名称有一定的历史背景:最初,一个 MultiXactId 由不止一个 TransactionId 组成(除极少数特殊情况外),故而称为“multi”。然而,如今存在仅包含单个 Xid 的 MultiXactId 是完全合理的。原创 2024-12-20 14:04:45 · 162 阅读 · 0 评论 -
【0370】Posgres内核 LRU buffering 机制
LRU是Postgres内核 “用于事务状态日志文件的简单 LRU 缓冲机制 ”。我们采用一种简单的最近最少使用(least-recently-used)方案来管理页面缓冲区池(pool of page buffers)。在通常情况下,我们预计写入流量主要会出现在最新的页面(以及页面转换后不久的前一个页面)上。读取流量可能会触及更大范围的页面,但无论如何,使用数量相当少的页面缓冲区应该就足够了。所以,我们仅通过简单的线性搜索来查找缓冲区;不需要哈希表或任何复杂的东西。原创 2024-12-19 18:08:52 · 402 阅读 · 0 评论 -
【0361】Postgres内核 page_read 读取所请求数据长度(至少 short page header)( 6 )
上一篇文章中的 XLogPageRead() 执行完成后,回到了 ReadPageInternal() 函数。这里需要对 读取到的单个XLOG page 长度进行校验,因为理论上,读取到的页面至少需要包含。首先,读取所请求的数据长度,不过至少要读取一个 short 的页头部信息,从而我们能够对其予以验证。从前面文章可知,这里读取到的 readLen 是 8192字节,值得注意的是,这里回再次调用函数 XLogReaderValidatePageHeader() 对。原创 2024-12-07 11:47:32 · 177 阅读 · 0 评论 -
【0360】Postgres内核 检验 WAL page header ( 5 - 1)
上一篇文章中,检查了 WAL page头中的相关信息, 如 页头魔幻字(xlp_magic)、页头标志位(xlp_info)、当页标志位是 XLP_LONG_HEADER时, 交叉检查 system_identifier、xlp_seg_size 和 xlp_xlog_blcksz 等。原创 2024-12-07 11:24:11 · 279 阅读 · 0 评论 -
【0359】Postgres内核 检验 WAL page header ( 5 )
这或许看似没有必要,因为 XLogReadRecord() 无论如何都会验证页面头部,且会将失败向上传递至 ReadRecord() ,而 ReadRecord() 会重试。我们会从本地 WAL 段读取第一个页面,但在读取第二个页面时, 我们会读取到这个错误的、已回收的 WAL 段。倘若我们在此处未处理这种情况,我们将永远无法恢复,因为 ReadRecord() 会重试从开头读取整个记录。(2)当然,这仅能捕获页面头部的错误,这是在 WAL 段被回收的情况下会发生的情况。原创 2024-12-06 20:40:53 · 225 阅读 · 0 评论 -
【0358】Postgres内核 读取请求的 XLOG page (4)
接下来通过 pg_pread() 函数读取 WAL page 数据。就从 readFile 文件句柄的 偏移量为0(readOff)处 读取长度 8192字节(readLen)。的处理, 当前 readFile 指向待读取 XLOG WAL 的页。在此刻,我们已打开正确的段,并且倘若我们正在进行流传输,我们便知晓所请求的记录就在其中。pg_pread() 函数实现比较简单,对于 linux 平台,主要调用了 lseek() 和 read() 两个库函数。由于pg_pread() 函数读取到的数据长度。原创 2024-12-06 20:19:54 · 491 阅读 · 0 评论 -
【0357】Postgres内核 set_ps_display 更新 ps status 实现
相关文件:set_ps_display() 函数声明于 ps_status.h,实现于 ps_status.c 源文件中。它接受一个参数 activity 字符串, 用于显示当前进程正在执行的指示。原创 2024-12-06 11:55:42 · 60 阅读 · 0 评论 -
【0354】Postgres内核 XLOG文件每个 page 头部信息
在中讲解了 Postgres内核中 XLOG 文件的布局;通过该文章的学习,知道位于磁盘上 $PGDATA/pg_wal 目录下 类似 “000000010000000A00000002” 规则命令的文件的组成结构。本文将继续在此基础上更深入一层地去学习 XLOG文件内部结构, 细化到该文件中的每一个页(page)。原创 2024-12-03 12:36:09 · 114 阅读 · 0 评论 -
【0353】Postgres内核 walreceiver 进程 shared memory 申请与初始化 ( 2 )
均通过Postgres内核中 CreateSharedMemoryAndSemaphores () 去间接调用相关函数(比如此处的 “分配并初始化与walreceiver相关的共享内存”是通过调用函数 WalRcvShmemInit() )来完成共享内存的申请与初始化功能。下面将围绕这三步讲解Postgres内核中 walreceiver 的共享内存申请、初始化等操作原理。(2) walreceiver 共享内存申请,申请结果判断处理。(1) 计算 walreceiver 待申请共享内存大小。原创 2024-12-02 12:40:25 · 135 阅读 · 0 评论 -
【0352】Postgres内核 walreceiver 进程实现机制(1)
WAL 接收器进程(walreceiver)自 PostgreSQL 9.0 起成为新增内容。它是备用服务器(standby server )中的进程,在流式复制过程中负责从主服务器接收 XLOG 记录(XLOG records)。原创 2024-12-02 12:14:41 · 235 阅读 · 0 评论 -
【0351】Postgres内核 Open WAL segment(包含 WAL 位置 ‘RecPtr’)(2 - 4)
如果在从流中读取 WAL 时关闭 standby mode ,我们将切换至 XLOG_FROM_ARCHIVE 并重置 lastSourceFailed,以强制从归档或 pg_wal 获取文件(例如,在恢复结束时所需的时间线历史文件)。在经过前面的若干个函数调用、逻辑处理后, 最终来到了函数 WaitForWALToBecomeAvailable() ,该函数的主要功能是 “打开包含 WAL 位置“RecPtr”的 WAL 段。在此情况下,“tliRecPtr”是我们感兴趣的 WAL 记录的位置。原创 2024-11-29 16:20:16 · 286 阅读 · 0 评论 -
【0348】Postgres内核 XLOG record 整体布局
中曾文章描述过 Postgres内核中 XLOG record文件的整体布局情况, 了解 XLOG record 布局, 对后面的XLOG 读、写等原理的学习有非常重要的帮助。(1)XLOG record 整体布局、及其对应示意图。(2)SizeOfXLogRecord 宏意味着什么。原创 2024-11-28 18:29:28 · 153 阅读 · 0 评论 -
【0347】Postgres内核 startup XLOG 之 核实 pg_wal 、 pg_wal/archive_status (1)
postmaster 守护进程在真正进入 ServerLoop() 前,会调用 StartChildProcess() 函数启动 postmaster 辅助进程如:bgwriter、walwriter、walreceiver、bootstrapper 和 checkpointer 等。这里首先初始化的第一个辅助进程是 StartupProcess。该进程的主入口是 StartupProcessMain() 函数。在该函数内部执行最重要、最为复杂的一个功能是: StartupXLOG()。原创 2024-11-28 14:13:23 · 403 阅读 · 0 评论 -
【0345】Postgres内核 向 Postgres process 发送信号 (SendProcSignal)(4)
在中讲解了 Postgres内核从 Proc Signal 移除进程的过程。本文则分享 ProcSignal 中的另外一个功能, 即向 ProcSignal 中指定进程发送一个信号。这里信号发送分为两种场景:(1)用户指定的 backendId 有效(2)用户指定的 backendId 无效此过程由函数 SendProcSignal() 实现。函数原型:pidreasonbackendIdtips。原创 2024-11-26 11:26:38 · 545 阅读 · 0 评论 -
【0344】Postgres内核 将 process 从 ProcSignal 机制中移除 (3)
在一文中讲解了 Posgres内核 ProcSignal机制相关。主要是以下几点:(1)Postgres内核向 OS 申请指定数量大小的 共享内存空间,及初始化过程(2)Postgres内核如何通过 ProcSignalInit() 完成 ProcSignal (procsignal array)中注册当前进程。原创 2024-11-25 15:40:55 · 483 阅读 · 0 评论 -
【0342】Postgres内核 分配并初始化 Proc Signal 共享内存 (1)
Postgres内核在启动postmaster守护进程时候, 会通过函数 ProcSignalShmemInit() 去为 Proc Signal 分配并初始化指定大小的共享内存空间。整个调用链路如下。原创 2024-11-23 17:03:18 · 297 阅读 · 0 评论 -
【0343】Postgres内核 Proc Signal 机制例程( 2 )
Postgres内核中 procsignal.h、procsignal.c两个文件中完成了 Postgres内核进程间信号通信机制的例程声明和源码实现。原创 2024-11-23 15:35:43 · 156 阅读 · 0 评论 -
【0330】 Postgres内核之 relation cache entry contents
数据类型是 一个关系表缓存项的内容。该结构定义于rel.h头文件中。原创 2024-09-18 12:38:39 · 186 阅读 · 0 评论 -
【0327】Postgres内核之 VACUUM (FULL) 通过 namespace 查找 relations OID (17 - 1)
1. 查找 relations OID原创 2024-09-09 19:27:38 · 123 阅读 · 0 评论 -
【0324】Postgres内核 Shared Buffer Access Rules (共享缓冲区访问规则)说明
共享磁盘缓冲区有两套独立的访问控制机制:引用计数(a/k/a pin计数)和缓冲区内容锁。(实际上,还有第三级访问控制:在访问任何属于某个关系表的页面之前,必须持有该关系表的适当类型的锁。这里不讨论关系级锁。在对缓冲区做任何操作之前,必须“对缓冲区pin”(即增加其引用计数,未pin的缓冲区随时可能被回收并用于其他页面,因此对其进行操作是不安全的。通常,通过获得pin,通过释放pin。对于单个后端进程来说,同时pin一个页面多次是完全正常的;缓冲区管理器高效地处理这种情况。长时间持有pin。原创 2024-09-07 09:44:23 · 398 阅读 · 0 评论 -
【0312】VACUUM (FULL)命令 之 选择 portal output format(7)
由于portal(VACUUM FULL)不需要返回tuples,因此什么也不需要做,即不需要去初始化输出格式。在前面(PortalStart()函数,请阅读。的输出格式代码,主要由函数PortalSetResultFormat()完成。该函数定义于pquery.c源文件。)初始化了portal->tupDesc = NULL。所以这里直接return。其他目标类型目前不需要它。根据Bind消息约定,目的地读取的portal,必须在。Postgres内核中选择。原创 2024-08-16 11:20:33 · 111 阅读 · 0 评论 -
【0311】Postgres内核之 communication destinations(DestReceiver 、CommandDest、dest.h/dest.c)作用
带着这个问题,让我们开始本文的正文内容。Postgres内核 每当后端执行返回元组的查询时,结果都必须去某个地方。比如:stdout只有当我们运行一个standalone backend(没有postmaster)并将结果返回给交互式用户时,stdout才是目的地。当我们运行带有前端的后端并且前端执行PQexec()或PQfn()时,远程进程是目的地。在这种情况下,结果通过backend/libpq中的函数发送到前端。DestNoneDestNone是系统内部执行查询时的目的地。原创 2024-08-15 16:10:47 · 504 阅读 · 0 评论 -
【0310】VACUUM 命令 之 start portal(6)
在上一篇文章中,讲解了Postgres内核通过函数PortalDefineQuery()将原始SQL文本、原创 2024-08-14 18:53:06 · 278 阅读 · 0 评论 -
【0309】VACUUM 命令 之 建立 portal query(5)
函数PortalDefineQuery()建立portal查询的简单子例程。从PG 8.4开始,调用者必须提供一个源文本字符串;它不再被允许传递NULL。(如果你真的没有源文本,你可以传递一个常量字符串,也许是"(query not available)"。当且仅当原始查询字符串(重写之前)为空字符串时,commandTag应为NULL。另外,传递的commandTag必须是一个指向常量字符串的指针,因为它不会被复制。如果提供了cplan。原创 2024-08-12 18:46:18 · 393 阅读 · 0 评论 -
【0308】VACUUM 命令 之 Create unnamed portal (执行查询)(4)
Postgres内核在依次完成了 原始解析树转查询树、查询树进行重写、重写后的查询树执行计划后,接下来回到exec_simple_query()函数中,通过调用CreatePortal()来创建未命名的portal来运行查询。如果已经存在这样一个portal,则默默地删除它。Portal是一个指向PortalData 类型的指针,通过typedef命令声明。原创 2024-08-12 15:16:14 · 154 阅读 · 0 评论