MULTIXACT日志管理器
MULTIXACT日志管理器
模块概述
MULTIXACT(Multi-Transaction,组合事务)日志是PostgreSQL为适配多版本并发控制(MVCC) 下的行共享锁场景设计的核心模块:当同一个数据元组关联多个事务ID(XID)时,为简化锁的统一操作,PostgreSQL将这些XID组合映射为一个唯一的MultiXactID,MULTIXACT日志管理器负责维护这种“多XID→单MultiXactID”的映射关系。
该模块与CLOG、SUBTRANS日志的核心共性是基于SLRU(Simple LRU)缓冲池 实现内存管理;核心差异是MULTIXACT需同时维护“偏移量+成员”两类信息,因此使用两个独立的SLRU缓冲池 分别管理,且日志需持久化(与SUBTRANS不同)、需与XLOG交互(保证崩溃恢复)。
1. 核心数据结构与日志定位规则
1.1 MultiXactID的映射关系
MultiXactID是“多XID→单ID”的映射标识,需存储两类核心信息来关联XID集合(还原原文档图7-10的核心逻辑):
Offset(偏移量):标记XID数组中该MultiXactID对应的起始位置;nMembers(成员数量):标记该MultiXactID关联的XID总数。
1.2 核心数据结构定义
(1)MultiXactStateData:MultiXactID分配管理结构
该结构用于维护MultiXactID的全局分配状态,修正原文档格式错误后的完整定义:
// 数据结构7.25 MultiXactStateData
typedef struct MultiXactStateData
{
MultiXactId nextMXact; // 下一个可分配的MultiXactID
MultiXactOffset nextOffset; // 下一个MultiXactID对应的起始偏移量
MultiXactId lastTruncationPoint;// 上一次清理(截断)的位置
MultiXactId perBackendXactIds[1];// MultiXactID队列起始位置
} MultiXactStateData;
(2)mXactCacheEnt:MultiXactID本地缓存结构
该结构定义操作MultiXactID的统一接口,用于本地缓存“MultiXactID→XID集合”的映射关系,修正格式错误后的完整定义:
// 数据结构7.26 mXactCacheEnt
typedef struct mXactCacheEnt
{
struct mXactCacheEnt *next; // 缓存链表下一个节点
MultiXactId multi; // 组合事务ID
int nxids; // 关联的XID数量
TransactionId xids[1]; // 关联的XID数组(柔性数组)
} mXactCacheEnt;
1.3 存储路径与定位规则
(1)存储路径
MULTIXACT日志文件存储于 PGDATA/pg_multixact 目录下,包含两个子目录,分工明确:
members:存储MultiXactID关联的XID成员列表;offsets:存储MultiXactID对应的偏移量(Offset)和成员数(nMembers)。
(2)定位宏定义(修正原文档语法/拼写错误)
通过MultiXactID可计算其在offsets目录的存储位置,通过偏移量可计算其在members目录的存储位置,核心宏定义如下:
| 宏定义 | 功能 | 修正后完整定义 |
|---|---|---|
MultiXactIdToOffsetPage(xid) |
根据MultiXactID计算其在offsets目录的页面号 | `#define MultiXactIdToOffsetPage(xid) \ |
| ((xid) / (MultiXactOffset)MULTIXACT_OFFSETS_PER_PAGE)` | ||
MultiXactIdToOffsetEntry(xid) |
根据MultiXactID计算其在offsets页面内的偏移 | `#define MultiXactIdToOffsetEntry(xid) \ |
| ((xid) % (MultiXactOffset)MULTIXACT_OFFSETS_PER_PAGE)` | ||
MXOffsetToMemberPage(xid) |
根据偏移量计算其在members目录的页面号 | `#define MXOffsetToMemberPage(xid) \ |
| ((xid) / (TransactionId)MULTIXACT_MEMBERS_PER_PAGE)` | ||
MXOffsetToMemberEntry(xid) |
根据偏移量计算其在members页面内的偏移 | `#define MXOffsetToMemberEntry(xid) \ |
| ((xid) & (TransactionId)MULTIXACT_MEMBERS_PER_PAGE)` |
1.4 缓冲池控制结构
MULTIXACT日志管理器使用两个独立的SLRU缓冲池 管理日志(区别于CLOG/SUBTRANS的单缓冲池),均为Postmaster启动后注册的全局共享内存对象:
MultiXactOffsetCtl:管理offsets目录的日志页面(偏移量+成员数);MultiXactMemberCtl:管理members目录的日志页面(XID成员列表);
两个缓冲池协同维护全局MultiXactID的内存映射,保证多进程并发访问的一致性。
2. 核心操作说明
MULTIXACT日志管理器的核心操作包括MultiXactID的生命周期管理(创建/扩增)、日志系统的启停/检查点等,其中启停/检查点需同时操作两个SLRU缓冲池,核心操作如下:
2.1 MultiXactID创建(MultiXactIdCreate)
功能:将多个XID组合为一个MultiXactID,返回该标识以统一管理行共享锁相关操作。
核心流程:
- 本地缓存检查:在当前进程的
MXactCache中查询该XID组合是否已生成过MultiXactID,若存在则直接返回; - 分配新ID:调用
GetNewMultiXactId从共享内存的MultiXactState中获取新的MultiXactID,并更新nextMXact(下一个可分配ID)和nextOffset(下一个起始偏移量); - 记录XLOG:向XLOG写入操作日志,记录本次分配的MultiXactID、关联的XID链表及XID数量(保证崩溃后可恢复);
- 更新缓存并返回:将“MultiXactID→XID集合”的映射关系更新到本地
MXactCache,返回新生成的MultiXactID。
2.2 MultiXactID扩增(MultiXactIdExpand)
功能:向已有MultiXactID关联的XID队列中新增一个XID,实现MultiXactID的扩容。
核心流程:
- 查找关联信息:通过MultiXactID找到其对应的XID队列和XID数量;
- 边界校验1:若该MultiXactID无关联XID成员,直接创建仅包含新增XID的MultiXactID并返回;
- 边界校验2:若新增XID已存在于当前XID队列中,直接返回原MultiXactID;
- 扩容并重建:取出该MultiXactID对应的XID链表,将新增XID追加至链表末尾,调用
MultiXactIdCreate生成新的MultiXactID并返回。
2.3 运行状态检测(MultiXactIdIsRunning)
功能:判断一个MultiXactID是否处于“运行中”状态,用于行锁有效性校验。
核心逻辑:遍历该MultiXactID关联的所有XID,若任意一个XID属于当前事务或正在运行,则判定该MultiXactID处于运行中。
2.4 日志系统启动(StartupMultiXact)
触发时机:Postmaster启动时,通过StartupXlog间接调用。
核心功能:初始化MultiXactOffsetCtl和MultiXactMemberCtl两个SLRU缓冲池,为MultiXactID管理提供基础内存环境。
2.5 日志系统关闭(ShutdownMultiXact)
功能:安全关闭MULTIXACT日志系统。
核心逻辑:调用SimpleLruFlush将MultiXactOffsetCtl和MultiXactMemberCtl两个缓冲池中的所有脏页刷盘,保证日志数据持久化。
2.6 检查点操作(CheckPointMultiXact)
触发时机:数据库执行检查点时调用。
核心功能:将两个SLRU缓冲池的脏页刷盘;与“关闭操作”的核心差异是:刷盘过程中允许其他进程向缓冲池写入日志(保证检查点期间系统可用性)。
总结
- 核心定位:MULTIXACT日志管理器通过“双SLRU缓冲池”维护“多XID→单MultiXactID”的映射关系,解决MVCC下行共享锁的多XID统一操作问题;
- 核心特性:需与XLOG交互保证持久化,支持MultiXactID的创建/扩增,检测运行状态时需遍历关联的所有XID;
- 操作关键:启停/检查点需同时操作“偏移量+成员”两个SLRU缓冲池,检查点刷盘时允许并发写操作(区别于关闭操作)。
更多推荐
所有评论(0)