一、WAL日志概述

pg中wal子系统的存在是为了故障恢复,它也被用于基于时间点的恢复、基于日志搬迁的Hot-standby复制。以下想描述一点wal日志的设计理念。
wal日志的一个基本假设是日志条目必须先于它所描述的数据变化页面持久化到稳定存储(如硬盘)。这确保重放日志到它的末端将使数据库可以重新达到一致性状态(不存在部分执行的事务)。为了达到这一点,每一个数据页面(堆或索引页面)被标记上了影响本页面的最新xlog记录的LSN号。
LSN号,全称Log sequence number, 实际上代表wal文件位置。
在wal重放时,可以核对页面的LSN来确定本条xlog记录是否已经被重放(如果页面LSN>日志条目的位置,则该条日志已被重放)。

二、事务日志与WAL段文件

xlog详细记录了服务进程对数据库的操作过程。xlog日志文件在内存中按页存放,每个页面大小为8kb,每个页面都有一个头部,头部信息之后才是xlog日志记录。

每个xlog文件都有一个ID,但事实上它被分成一个个固定大小(默认16MB,initdb时可由–wal-segsize指定)的XLOG段文件来存放。xlog文件号和段文件号可以用来唯一确定这个段文件。确定日志文件内一个日志记录的地址时,只需用一个XLOG文件号和日志记录在该文件内的偏移量即可。

三、xlog文件初始化

initdb初始化data时,在函数bootstrap_template1中初始化template1模板库时,通过popen调用postgres程序中的AuxiliaryProcessMain,AuxiliaryProcessMain中调用BootStrapXLOG函数完成XLOG段文件初始化工作。

四、xlog文件名

initdb生成xlog文件时,用以下宏生成文件名,

#define XLogFilePath(path, tli, logSegNo)    \snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli,              \(uint32) ((logSegNo) / XLogSegmentsPerXLogId),             \(uint32) ((logSegNo) % XLogSegmentsPerXLogId))
#define XLOG_SEG_SIZE (16 * 1024 * 1024)
#define XLogSegmentsPerXLogId   (UINT64CONST(0x100000000) / XLOG_SEG_SIZE)

note: XLogSegmentsPerXlogId值为256,XLOG_SEG_SIZE为段大小16MB
宏中变量:
path: 代表文件名
tli:代表时间线,初始时间线为1
logSegNo:代表段号,初始值为1

以上值代入宏,经snprint格式化后,path值为:
pg_xlog路径+时间线+(uint32)段号/256+段号%256 --%08X代表按8位16进制数显示
结果即:
pg_xlog/+00000001+00000000+00000001
Note: 此处,可以看出段文件名最后两位最大值为256,转为16进制则段文件名的最后8位最大为000000FF.

五、xlog存储结构

每一个XLOG文件有一个ID,事实上一个逻辑上的xlog文件物理上被分割为一个个固定大小的段(默认16MB)来保存。xlog文件号和段号可以唯一确定这个段文件。确定日志文件内的一个日志记录的地址时,只需用xlog文件号和日志记录在该文件内的偏移量即可。

对于每一个Xlog文件第一个段的第一个页面是一个长头部(Long Header),一个xlog文件头部是不是长头部,可以由其头部XLogPageHeaderData的标志位xlp_info确定出来,如果是长头部,则:
XLogPageHeader page;
page->xlp_info = XLP_LONG_HEADER;

1)xlog日志页面头部信息
xlog日志文件分为许多的逻辑段,每一个段文件又分成许多个页面,每一个页面大小为一个块的大小。对于每一个日志页面,需要在其头部写一个头部信息XLogPageHeaderData,其结构如下:

/** Each page of XLOG file has a header like this:*/
#define XLOG_PAGE_MAGIC 0xD093  /* can be used as WAL version indicator */typedef struct XLogPageHeaderData
{uint16     xlp_magic;      /* magic value for correctness checks */uint16      xlp_info;       /* flag bits, see below */TimeLineID    xlp_tli;        /* TimeLineID of first record on page */XLogRecPtr  xlp_pageaddr;   /* XLOG address of this page *//** When there is not enough space on current page for whole record, we* continue on the next page.  xlp_rem_len is the number of bytes* remaining from a previous page.** Note that xl_rem_len includes backup-block data; that is, it tracks* xl_tot_len not xl_len in the initial header.  Also note that the* continuation data isn't necessarily aligned.*/uint32      xlp_rem_len;    /* total len of remaining data for record */
} XLogPageHeaderData;#define SizeOfXLogShortPHD MAXALIGN(sizeof(XLogPageHeaderData))typedef XLogPageHeaderData *XLogPageHeader;

如果一个页面是一个逻辑段文件的第一个页面,那么在页面头部信息标志位会设置XLP_LONG_HEADER标记,那么将在原页面头部信息的基础上使用一个长的XLOG页面头部XLogLongPageHeaderData,其结构如下:

/** When the XLP_LONG_HEADER flag is set, we store additional fields in the* page header.  (This is ordinarily done just in the first page of an* XLOG file.)    The additional fields serve to identify the file accurately.*/
typedef struct XLogLongPageHeaderData
{XLogPageHeaderData std;        /* standard header fields */uint64      xlp_sysid;      /* system identifier from pg_control */uint32       xlp_seg_size;   /* just as a cross-check */uint32       xlp_xlog_blcksz;    /* just as a cross-check */
} XLogLongPageHeaderData;#define SizeOfXLogLongPHD  MAXALIGN(sizeof(XLogLongPageHeaderData))typedef XLogLongPageHeaderData *XLogLongPageHeader;

2)xlog日志记录结构信息
XLOG Record由两部分组成,第一部分是XLOG Record的头部信息,大小固定(24 Bytes),对应的结构体是XLogRecord;第二部分是XLOG Record data。
xlog记录存储格局:
Fixed-size header (XLogRecord struct)
XLogRecordBlockHeader struct
XLogRecordBlockHeader struct

XLogRecordDataHeader[Short|Long] struct
block data
block data

main data

XLOG Record按存储的数据内容来划分,大体可以分为三类:

Record for backup block:存储full-write-page的block,这种类型Record是为了解决page部分写的问题。在checkpoint完成后第一次修改数据page,在记录此变更写入事务日志文件时整页写入(需设置参数full_page_write,默认为打开);

Record for tuple data block:存储page中的tuple变更,使用这种类型的Record记录;

Record for Checkpoint:在checkpoint发生时,在事务日志文件中记录checkpoint信息。

XLogRecord记录了Xlog记录的相关控制信息,

typedef struct XLogRecord
{uint32     xl_tot_len;     /* total len of entire record */TransactionId xl_xid;       /* xact id */XLogRecPtr xl_prev;        /* ptr to previous record in log */uint8        xl_info;        /* flag bits, see below */RmgrId        xl_rmid;        /* resource manager for this record *//* 2 bytes of padding here, initialize to zero */pg_crc32c    xl_crc;         /* CRC for this record *//* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */} XLogRecord;

xl_tot_len //整条记录总长度
xl_xid //事务ID
xl_prev //在日志中的前一条记录
xl_info //信息标志位
xl_rmid //资源管理器ID

其中,xl_info被资源管理器使用,表示该日志是哪种类型的日志,其取值如下:

/* XLOG info values for XLOG rmgr */
#define XLOG_CHECKPOINT_SHUTDOWN        0x00
#define XLOG_CHECKPOINT_ONLINE          0x10
#define XLOG_NOOP                       0x20
#define XLOG_NEXTOID                    0x30
#define XLOG_SWITCH                     0x40
#define XLOG_BACKUP_END                 0x50
#define XLOG_PARAMETER_CHANGE           0x60
#define XLOG_RESTORE_POINT              0x70
#define XLOG_FPW_CHANGE                 0x80
#define XLOG_END_OF_RECOVERY            0x90
#define XLOG_FPI_FOR_HINT               0xA0
#define XLOG_FPI                        0xB0

其中,xl_rmid资源管理器的取值如下:

/* symbol name, textual name, redo, desc, identify, startup, cleanup */
PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
PG_RMGR(RM_BRIN_ID, "BRIN", brin_redo, brin_desc, brin_identify, NULL, NULL)
PG_RMGR(RM_COMMIT_TS_ID, "CommitTs", commit_ts_redo, commit_ts_desc, commit_ts_identify, NULL, NULL)
PG_RMGR(RM_REPLORIGIN_ID, "ReplicationOrigin", replorigin_redo, replorigin_desc, replorigin_identify, NULL, NULL)
PG_RMGR(RM_GENERIC_ID, "Generic", generic_redo, generic_desc, generic_identify, NULL, NULL)
PG_RMGR(RM_LOGICALMSG_ID, "LogicalMessage", logicalmsg_redo, logicalmsg_desc, logicalmsg_identify, NULL, NULL)

下列出其中较重要几种资源管理器ID含义:
RM_XLOG_ID:该条日志记录的是一个检查点信息
RM_XACT_ID:该条日志记录的是一个事务的提交或终止信息
RM_CLOG_ID:该条日志记录的是CLOG中某一页的初始化
RM_HEAP_ID:该条日志记录的是对堆中元组进行修改的信息

XLOG Record data

XLOG Record data是存储实际数据的地方,由以下几部分组成:

0…N个XLogRecordBlockHeader,每一个XLogRecordBlockHeader对应一个block data;

XLogRecordDataHeader[Short|Long],如数据大小<256 Bytes,则使用Short格式,否则使用Long格式;

block data:full-write-page data和tuple data。对于full-write-page data,如启用了压缩,则数据压缩存储,压缩后该page相关的元数据存储在XLogRecordBlockCompressHeader中;

main data: checkpoint等日志数据.

。。。
细节内容有点多,本篇先写到这里

PostgreSQL 9.6源码解析之XLOG生成相关推荐

  1. PostgreSQL 9.6源码解析之XLOG生成(二)xlog文件内部结构

    xlog段文件结构 数据目录下的pg_xlog目录(pg9.6上版本)下,产生wal日志文件段(如000000010000000000000001),每一个wal段的page的构成如下图. 页头 wa ...

  2. postgresql snapshot快照源码解析, 快照内容生成规则, 可见性是这样判断的

    postgresql snapshot快照源码解读 ​专栏内容:postgresql内核源码分析 个人主页:我的主页 座右铭:天行健,君子以自强不息:地势坤,君子以厚德载物. 概述 本文主要介绍数据库 ...

  3. SharingSphere 源码解析 -- 真实SQL生成探索

    SharingSphere 源码解析 – 真实SQL生成探索 简介 在上一篇文章中,我们探索了ShardingSphere JDBC Mybatis示例执行的一个大致的过程,找到了SQL处理的关键节点 ...

  4. Flink 源码解析2--JobGraph的生成

    上一节介绍了StreamGraph的生成,这个实际上只对应 Flink 作业在逻辑上的执行计划图.Flink 会进一步对 StreamGraph 进行转换,得到另一个执行计划图,即JobGraph.然 ...

  5. Flink 源码解析1--StreamGraph的生成

    1. 先来简单看一下入门的WordCount程序 1.首先数据源会产生随机的数字数据流(0-10内的数字)形式,然后通过flink的transformation将数据进行单词计数,再print输出 / ...

  6. 腾讯mars xlog源码解析

    前言   之前由于公司发展需要,app网络请求日志始终没有一个良好的分析手段,故公司成立了apm项目小组,通过AOP编程获取app网络请求日志并上报到服务端,然后通过网页多维度分析用户网络请求数据,类 ...

  7. sharding-jdbc源码解析之sql解析

    2019独角兽企业重金招聘Python工程师标准>>> 说在前面 本文转自"天河聊技术"微信公众号 本次介绍的是sharding-jdbc的源码解析部分的sql解 ...

  8. 2022-10-24 ClickHouse 源码解析-查询引擎经典理论

    ClickHouse 源码解析: 综述 ClickHouse 源码解析: MergeTree Write-Path ClickHouse 源码解析: MergeTree Read-Path Click ...

  9. loraserver 源码解析 (六) lora-app-server

    目录 下载源码 升级 npm 安装一些必要的依赖库 pq_trgm extension run 调用 handleDataDownPayloads 开启一个Goroutine  G1 run再调用 s ...

最新文章

  1. python编程问题---第一次
  2. apache nginx 性能简单对比测试
  3. 【转载】栈溢出原理及实现
  4. MCGS与PLC通讯不上
  5. sigmoid函数_常用的激活(激励)函数——深度学习笔记(建议收藏)
  6. Python面试题大全(一):基础知识学习
  7. “21天好习惯”第一期-18
  8. [AppScan深入浅出]修复漏洞:会话标识未更新
  9. 【备忘】老罗Android开发视频教程[共9大知识点] 下载
  10. 赤峰中考计算机考试软件,2017赤峰中考信息技术与实验操作考试实施细则
  11. PP点点通介绍与下载
  12. ie内核出现问题的解决方法
  13. 好用的在线HTTP接口测试 - HTTP GET/POST模拟请求测试工具-ApiPost
  14. 最新计算机java毕业设计题目选题推荐2023
  15. python zipfile 压缩文件夹的方法
  16. 产业分析:短视频平台研究报告
  17. What is XMP
  18. 一文轻松看透AQS的核心设计思想
  19. Mac/Linux 安装 Go 详解
  20. python数据字典ppt_Python3自动生成MySQL数据字典的markdown文本的实现

热门文章

  1. 分布式架构-ZK客户端工具Curator框架分布式锁及基本使用
  2. 在IDEA中集成Jenkins插件 解决Missing or bad crumb data异常
  3. 路由器上DNS的设置
  4. Python 字符串前加f,r,u,b的含义
  5. win10 RTX30系列显卡 安装tensorflow-gpu 1.15
  6. word中鼠标没有反应,可以动但是点哪都没反应
  7. Java开发环境及其特点
  8. 一本纯属个人的兴趣的书籍即将在未来面世
  9. 计算机桌面文件保存位置是哪里,电脑微信接收文件存放位置在哪?怎么更改文件存放位置...
  10. 新手建站详细步骤(图文教程)