PostgreSQL的存储系统二:REDOLOG文件存储结构

本文详细介绍了PostgreSQL的REDOLOG(XLOG)文件存储结构,包括文件命名规则、默认大小、存储格式及关键结构如PageHeaderData、XLogRecord等。通过对XLogLongPageHeaderData和XLogPageHeaderData的解析,揭示了XLOG文件头和页头信息。同时,讲解了XLogRecord的组成部分和不同类型的资源管理器数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Pg XLOG文件(常说的REDOLOG)名字的命名方法是在XLogFileName宏里定义的,分别由时间线ID、日志ID、段ID的八位16进制数依次构成。例如00000001000000010000008F。

#define XLogFileName(fname,tli, log, seg)    \

    snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg)

不同的段ID对应不同的物理XLOG日志文件,日志ID是逻辑概念,有多个物理XLOG日志文件组成。

Pg XLOG文件(常说的REDOLOG)的大小初始值是在configure.in和configure文件里设置的,默认大小是16M。大小设置形式如下

wal_segsize=16

XLOG_SEG_SIZE (${wal_segsize} * 1024 * 1024)=16M

这个XLOG_SEG_SIZE是XLOG日志文件的段大小,就是一个物理的日志文件的大小。一个逻辑的XLOG日志文件大小是4Gb。

 

Pg XLOG文件的存储格式大致如下:

<PageHeaderData>

<XLogRecord>

<rmgr-specific data>

<BkpBlock>

<XLogRecData>里面包括<CheckPoint>等

<BkpBlock>

<XLogRecData>

<BkpBlock>

<XLogRecData>

……

 

1

先看<PageHeaderData>,这个根据不同情况对应XLogLongPageHeaderDataXLogPageHeaderData结构。XLOG文件头用XLogLongPageHeaderData结构和一些合适场合,XLogPageHeaderData用在文件里的页面头。结构XLogLongPageHeaderData的第一个成员是结构XLogPageHeaderData。下面是这两个结构定义:

 

typedefstruct XLogLongPageHeaderData

{

    XLogPageHeaderDatastd;     /*页头结构*/

    uint64     xlp_sysid;    /* 控制文件pg_control里的系统标识符*/

    uint32     xlp_seg_size; /* XLOG文件大小 */

    uint32     xlp_xlog_blcksz/* XLOG文件页面大小 */

} XLogLongPageHeaderData;

 

XLOG文件里的页面头结构

typedefstruct XLogPageHeaderData

{

    uint16     xlp_magic;    /* WAL版本指示器 */

    uint16     xlp_info;     /* flag bits, see below */

    TimeLineIDxlp_tli;      /* 本页第一个记录的时间线*/

    XLogRecPtrxlp_pageaddr; /* 本页XLOG位置*/

} XLogPageHeaderData;

    XLOG文件里的页面头结构XLogPageHeaderData的成员xlp_magic表示WAL版本号。成员xlp_tli表示本页第一个记录的时间线,成员xlp_pageaddr表示本页的XLOG位置。成员xlp_info表示紧跟页头的记录是否是跨页记录的一部分,或者该页头结构XLogPageHeaderData是否在文件头结构XLogLongPageHeaderData里。其值定义见下面:

当记录跨页时,在后面的页头里设置标志

#defineXLP_FIRST_IS_CONTRECORD    0x0001

这个指明是长页头(多用于文件第一页)

#define XLP_LONG_HEADER            0x0002

在xlp_info中定义的所有标志位(用于头的有效性检查)

#define XLP_ALL_FLAGS              0x0003

如果成员xlp_info的值是XLP_FIRST_IS_CONTRECORD,表示页头后面跟的是一个跨页结构的一部分。

XLOG文件头结构XLogLongPageHeaderData的成员xlp_seg_size表示XLOG文件大小,默认是16M。在configure.in和configure文件里设置形式如下

wal_segsize=16

XLOG_SEG_SIZE (${wal_segsize} * 1024 * 1024)=16M

成员xlp_xlog_blcksz表示文件里的页面大小,默认是8k。

 

2

    <XLogRecord>根据情况不同,可能是XLogRecord或XLogContRecord结构,只有在上一个页面最后一个记录是跨页的情况下,页面头的记录前面才用XLogContRecord结构,表示该记录不是一个新记录,而是上一个记录的一部分。XLogRecord结构代表一个新的XLOG/REDOLOG记录,其后跟着实际的XLOG数据,XLogRecord结构定义如下:

typedefstruct XLogRecord

{

    pg_crc32   xl_crc;           /* 该记录的CRC */

    XLogRecPtrxl_prev;      /* xlog里前一个XLogRecord的指针*/

    TransactionIdxl_xid;       /* 该记录事务ID */

    uint32     xl_tot_len;       /* 整个记录长度 */

    uint32     xl_len;           /* XLOG资源管理器数据长度 */

    uint8      xl_info;      /* 标志位 */

    RmgrId     xl_rmid;      /* 本记录的资源管理器ID */

} XLogRecord;

XLOG资源管理器时,其成员xl_info值可以是:

#define XLOG_CHECKPOINT_SHUTDOWN       0x00

#defineXLOG_CHECKPOINT_ONLINE         0x10

#define XLOG_NOOP                  0x20

#define XLOG_NEXTOID               0x30

#define XLOG_SWITCH                    0x40

#define XLOG_BACKUP_END                0x50

#defineXLOG_PARAMETER_CHANGE          0x60

#define XLOG_RESTORE_POINT             0x70

 

XACT资源管理器时,其成员xl_info高4位储存如下信息:

#define XLOG_XACT_COMMIT        0x00

#define XLOG_XACT_PREPARE          0x10

#define XLOG_XACT_ABORT            0x20

#defineXLOG_XACT_COMMIT_PREPARED  0x30

#defineXLOG_XACT_ABORT_PREPARED   0x40

#defineXLOG_XACT_ASSIGNMENT       0x50

 

XLOG仅使用xl_info的低4位,高4为由资源管理器rmgr使用

#define XLR_INFO_MASK           0x0F

 

如果用XLOG记录备份任一磁盘块(数据文件块吧),用其成员xl_info标志位记录,支持每个XLOG记录3个磁盘块的备份,使用xl_info标志的低1、2、3位

#define XLR_BKP_BLOCK_1         XLR_SET_BKP_BLOCK(0) /* 0x08 */

#define XLR_BKP_BLOCK_2         XLR_SET_BKP_BLOCK(1) /* 0x04 */

#define XLR_BKP_BLOCK_3         XLR_SET_BKP_BLOCK(2) /* 0x02 */

 

如果已备份块能从XLOG的压缩版本中被安全删除,设置Xl_info的0位(这就是,备份它们仅是为了防止写部分页(partial-page-write)问题,并且不保证PITR恢复的一致性)。压缩算法将需要从这些块中解析出数据以创建一个相同的非全页XLOG记录。

#define XLR_BKP_REMOVABLE       0x01

 

成员xl_rmid记录资源管理器ID,就是资源种类ID,资源管理器的资源种类包括如下16种(不包含最后一个RM_MAX_ID,这个只是记录最大资源种类数):

#define RM_XLOG_ID              0

#define RM_XACT_ID              1

#define RM_SMGR_ID              2

#define RM_CLOG_ID              3

#define RM_DBASE_ID             4

#define RM_TBLSPC_ID        5

#define RM_MULTIXACT_ID         6

#define RM_RELMAP_ID        7

#define RM_STANDBY_ID           8

#define RM_HEAP2_ID             9

#define RM_HEAP_ID              10

#define RM_BTREE_ID             11

#define RM_HASH_ID              12

#define RM_GIN_ID           13

#define RM_GIST_ID              14

#define RM_SEQ_ID           15

#define RM_MAX_ID           RM_SEQ_ID

    当页头记录是跨页记录的一部分时,在XLogLongPageHeaderData结构的后面跟着XLogContRecord结构。原则XLogRecord记录头从不被分到多个页,如果页尾空间小于SizeOfXLogRecord,就弃之不用,直接使用下一个页面。如果在一个记录在一个页面没写完,在下一个页头的XLogLongPageHeaderData结构后面用XLogContRecord结构,此时XLogLongPageHeaderData结构的成员xlp_info的值是XLP_FIRST_IS_CONTRECORD

typedefstruct XLogContRecord

{

    uint32     xl_rem_len;       /* 记录剩余数据总长度 */

} XLogContRecord;

 

 

3

<rmgr-specificdata>可能是事务状态定义等,例如结构xl_xact_commit、xl_xact_abort等

 

typedefstruct xl_xact_commit

{

    TimestampTzxact_time;      /* 提交时间 */

    uint32     xinfo;        /* 信息位 */

    int        nrels;        /* 关系文件数 */

    int        nsubxacts;    /* 子事务XID */

    int        nmsgs;        /* 共享失效信息数 */

    Oid        dbId;         /* 数据库ID */

    Oid        tsId;         /* 数据库表空间ID */

    /* 提交时要drop的关系文件节点数组*/

    RelFileNodexnodes[1];      /* 变长数组 */

    /* 后面跟已提交子事务ID数组 */

    /* 后面跟共享失效消息数组*/

} xl_xact_commit;

 

typedefstruct xl_xact_abort

{

    TimestampTzxact_time;      /* 退出时间 */

    int        nrels;        /* 关系文件节点数 */

    int        nsubxacts;    /* 子事务XID */

    /* 退出时要drop的关系文件节点数组 */

    RelFileNodexnodes[1];      /*变长数组*/

    /* 后面跟以退出的子事务XID数组 */

} xl_xact_abort;

 

4

<BkpBlock>表示BkpBlock结构,是跟在XLOG记录XLogRecord后面的备份块头信息。XLOG代码知道PG数据页面中间常常包含一个无用的“洞”(“hole”——未使用的空间),其只包含值是0的字节。如果这个洞的长度大于0(hole_length >0),实际的跟在结构BkpBlock后面的块数据量是BLCKSZ -hole_length个字节

typedefstruct BkpBlock

{

    RelFileNodenode;        /* 包含该块的关系文件 */

    ForkNumberfork;         /* 关系分支 */

    BlockNumberblock;          /* 块数 */

    uint16     hole_offset/* "hole"前字节数 */

    uint16     hole_length/* "hole"的字节数 */

 

    /* 实际的块数据跟在结构后面 */

} BkpBlock;

 

5

<XLogRecData>表示XLogRecData结构。要写入XLOG日志文件的资源管理器数据,由一或多个XLogRecData结构定义。

typedefstruct XLogRecData

{

    char      *data;         /* 资源管理器包含数据的开始 */

    uint32     len;          /* 资源管理器包含数据的长度 */

    Buffer     buffer;       /* 有相应数据的buffer,如果有的话 */

    bool       buffer_std;   /* buffer是否有标准pd_lower/pd_upper */

    struct XLogRecData *next;   /* 链里的下一个结构 */

} XLogRecData;

pd_lower页面开始位置与未分配空间开头的字节偏移,pd_upper与未分配空间结尾的字节偏移,LSN:最后修改这个页面的 xlog 记录最后一个字节后面第一个字节。

 

XLogRecData结构里记录各种数据库操作数据,其中典型的,数据是一个检查点(CheckPoint struct)。根据XLogRecord的成员xl_rmid是否等于RM_XLOG_ID以及的成员xl_info是否等于XLOG_CHECKPOINT_SHUTDOWN或XLOG_CHECKPOINT_ONLINE来判定数据是检查点。检查点的定义见下面。

 

typedefstruct CheckPoint

{

    XLogRecPtrredo;         /*开始创建一个检查点时下一个XLOG记录的位置*/

    TimeLineIDThisTimeLineID; /*当前时间线*/

    uint32     nextXidEpoch; /*下一个事务ID的高排序位 */

    TransactionIdnextXid;      /* 下一个空闲事务ID */

    Oid        nextOid;      /* 下一个空闲OID */

    MultiXactIdnextMulti;      /* 下一个空闲多事务ID */

    MultiXactOffsetnextMultiOffset;   /* next free MultiXact offset */

    TransactionIdoldestXid; /* cluster-wide minimum datfrozenxid */

    Oid        oldestXidDB/* database with minimum datfrozenxid*/

    pg_time_t  time;         /* 检查点时间戳 */

 

    /*

仍在运行的最早的事务IDXID)。只有在从一个在线检查点初始化热备模式时才需要,以使在GUC参数wal_levelhot_standby时我们不用为在线检查点计算运行最早的XID。否则设置为常量InvalidTransactionId

     */

    TransactionIdoldestActiveXid;

} CheckPoint;


------------

转载请著明出处,来自博客:
blog.youkuaiyun.com/beiigang
beigang.iteye.com


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值