PostgreSQL源码分析——pg_waldump

PG中有个可以打印WAL日志信息的工具,pg_waldump,对于开发人员来说,掌握该工具是十分有必要的。

用法

具体用法这里不去详解,可见官网pg_waldump文档。

postgres@slpc:~$ pg_waldump --help
pg_waldump decodes and displays PostgreSQL write-ahead logs for debugging.Usage:pg_waldump [OPTION]... [STARTSEG [ENDSEG]]Options:-b, --bkp-details      output detailed information about backup blocks-e, --end=RECPTR       stop reading at WAL location RECPTR-f, --follow           keep retrying after reaching end of WAL-n, --limit=N          number of records to display-p, --path=PATH        directory in which to find log segment files or adirectory with a ./pg_wal that contains such files(default: current directory, ./pg_wal, $PGDATA/pg_wal)-q, --quiet            do not print any output, except for errors-r, --rmgr=RMGR        only show records generated by resource manager RMGR;use --rmgr=list to list valid resource manager names-s, --start=RECPTR     start reading at WAL location RECPTR-t, --timeline=TLI     timeline from which to read log records(default: 1 or the value used in STARTSEG)-V, --version          output version information, then exit-x, --xid=XID          only show records with transaction ID XID-z, --stats[=record]   show statistics instead of records(optionally, show per-record statistics)-?, --help             show this help, then exit

具体的,我们举一个例子:

postgres=# create table t1(a int);
CREATE TABLEpostgres=# select pg_current_wal_lsn();pg_current_wal_lsn 
--------------------0/1696C78
(1 row)
-- 插入一条数据
postgres=# insert into t1 values(1);
INSERT 0 1
postgres=# select pg_current_wal_insert_lsn();pg_current_wal_insert_lsn 
---------------------------0/1696D18
(1 row)
postgres=# select txid_current();txid_current 
--------------735
(1 row)-- 查看WAL日志
postgres@slpc:~/pgsql$ pg_waldump -p pgdata/pg_wal/ -s 0/1696C78 -e 0/1696D18
-- 插入一条数据,堆表, 事务ID 735   
rmgr: Heap        len (rec/tot):     59/    59, tx:        734, lsn: 0/01696C78, prev 0/01696C40, desc: INSERT+INIT off 1 flags 0x00, blkref #0: rel 1663/13010/16384 blk 0 
rmgr: Transaction len (rec/tot):     34/    34, tx:        734, lsn: 0/01696CB8, prev 0/01696C78, desc: COMMIT 2023-09-23 10:58:39.915785 CST
rmgr: Standby     len (rec/tot):     54/    54, tx:          0, lsn: 0/01696CE0, prev 0/01696CB8, desc: RUNNING_XACTS nextXid 735 latestCompletedXid 733 oldestRunningXid 734; 1 xacts: 734-- 设置wal_debug = on
postgres=# set wal_debug = on;
SET
postgres=# select pg_current_wal_lsn();pg_current_wal_lsn 
--------------------0/1696E28
(1 row)postgres=# insert into t1 values(2);
LOG:  INSERT @ 0/1696EC0:  - Heap/INSERT: off 2 flags 0x00
LOG:  INSERT @ 0/1696EE8:  - Transaction/COMMIT: 2023-09-23 11:27:25.399199+08
LOG:  xlog flush request 0/1696EE8; write 0/1696E28; flush 0/1696E28
INSERT 0 1
postgres=# select pg_current_wal_lsn();pg_current_wal_lsn 
--------------------0/1696F20
(1 row)postgres@slpc:~/pgsql$ pg_waldump -p pgdata/pg_wal/ -s 0/1696E28 -e 0/1696F20
rmgr: Heap        len (rec/tot):     54/   150, tx:        736, lsn: 0/01696E28, prev 0/01696DF0, desc: INSERT off 2 flags 0x00, blkref #0: rel 1663/13010/16384 blk 0 FPW
rmgr: Transaction len (rec/tot):     34/    34, tx:        736, lsn: 0/01696EC0, prev 0/01696E28, desc: COMMIT 2023-09-23 11:27:25.399199 CST
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/01696EE8, prev 0/01696EC0, desc: RUNNING_XACTS nextXid 737 latestCompletedXid 736 oldestRunningXid 737
pg_waldump源码分析

pg_waldump的源码比较简单,在src/bin/pg_waldump中, 执行pg_waldump -p pgdata/pg_wal/ -s 0/1696E28 -e 0/1696F20进行调试。

main(int argc, char **argv)
--> XLogReaderAllocate(WalSegSz, waldir,XL_ROUTINE(.page_read = WALDumpReadPage,.segment_open = WALDumpOpenSegment, .segment_close = WALDumpCloseSegment), &private);// 因为我们是读wal日志的一个范围,从起点到终点,所以,这里第1步要做的就是先找到起始的wal日志记录
--> XLogFindNextRecord(xlogreader_state, private.startptr);for (;;){// 开始读取后续WAL日志/* try to read the next record */record = XLogReadRecord(xlogreader_state, &errormsg);/* perform any per-record work */if (!config.quiet){if (config.stats == true)XLogDumpCountRecord(&config, &stats, xlogreader_state);elseXLogDumpDisplayRecord(&config, xlogreader_state);}/* check whether we printed enough */config.already_displayed_records++;if (config.stop_after_records > 0 &&config.already_displayed_records >= config.stop_after_records)break;}
--> XLogReaderFree(xlogreader_state);	

更详细的代码可以查看:

int main(int argc, char **argv)
{uint32		xlogid;uint32		xrecoff;XLogReaderState *xlogreader_state;XLogDumpPrivate private;XLogDumpConfig config;XLogDumpStats stats;XLogRecord *record;XLogRecPtr	first_record;private.timeline = 1;private.startptr = InvalidXLogRecPtr;     // 起点private.endptr = InvalidXLogRecPtr;       // 终点private.endptr_reached = false;while ((option = getopt_long(argc, argv, "be:fn:p:qr:s:t:x:z", long_options, &optindex)) != -1){switch (option){case 'e':if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2){pg_log_error("could not parse end WAL location \"%s\"",optarg);goto bad_argument;}private.endptr = (uint64) xlogid << 32 | xrecoff;break;case 's':if (sscanf(optarg, "%X/%X", &xlogid, &xrecoff) != 2){pg_log_error("could not parse start WAL location \"%s\"",optarg);goto bad_argument;}elseprivate.startptr = (uint64) xlogid << 32 | xrecoff;break;// ...}}// .../* done with argument parsing, do the actual work *//* we have everything we need, start reading */// 初始化XLogReader,分配读取所需的内存空间xlogreader_state = XLogReaderAllocate(WalSegSz, waldir, XL_ROUTINE(.page_read = WALDumpReadPage,.segment_open = WALDumpOpenSegment,.segment_close = WALDumpCloseSegment), &private);/* first find a valid recptr to start from */// 找到第一个lsn >= startptr的有效日志记录first_record = XLogFindNextRecord(xlogreader_state, private.startptr);if (first_record == InvalidXLogRecPtr)fatal_error("could not find a valid record after %X/%X",LSN_FORMAT_ARGS(private.startptr));/** Display a message that we're skipping data if `from` wasn't a pointer* to the start of a record and also wasn't a pointer to the beginning of* a segment (e.g. we were used in file mode).*/if (first_record != private.startptr &&XLogSegmentOffset(private.startptr, WalSegSz) != 0)printf(ngettext("first record is after %X/%X, at %X/%X, skipping over %u byte\n","first record is after %X/%X, at %X/%X, skipping over %u bytes\n",(first_record - private.startptr)),LSN_FORMAT_ARGS(private.startptr),LSN_FORMAT_ARGS(first_record),(uint32) (first_record - private.startptr));for (;;){/* try to read the next record */record = XLogReadRecord(xlogreader_state, &errormsg);if (!record){if (!config.follow || private.endptr_reached)break;else{pg_usleep(1000000L);	/* 1 second */continue;}}/* apply all specified filters */if (config.filter_by_rmgr != -1 &&config.filter_by_rmgr != record->xl_rmid)continue;if (config.filter_by_xid_enabled &&config.filter_by_xid != record->xl_xid)continue;/* perform any per-record work */if (!config.quiet){if (config.stats == true)XLogDumpCountRecord(&config, &stats, xlogreader_state);elseXLogDumpDisplayRecord(&config, xlogreader_state);}/* check whether we printed enough */config.already_displayed_records++;if (config.stop_after_records > 0 &&config.already_displayed_records >= config.stop_after_records)break;}if (config.stats == true && !config.quiet)XLogDumpDisplayStats(&config, &stats);if (errormsg)fatal_error("error in WAL record at %X/%X: %s",LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),errormsg);XLogReaderFree(xlogreader_state);return EXIT_SUCCESS;bad_argument:fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);return EXIT_FAILURE;
}

参考文档:
pg_waldump

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/30623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#.Net筑基-集合知识全解

01、集合基础知识 .Net 中提供了一系列的管理对象集合的类型&#xff0c;数组、可变列表、字典等。从类型安全上集合分为两类&#xff0c;泛型集合 和 非泛型集合&#xff0c;传统的非泛型集合存储为Object&#xff0c;需要类型转。而泛型集合提供了更好的性能、编译时类型安全…

华为数通——ACL

ACL基本介绍 ACL:访问控制列表&#xff0c;通过端口对数据流进行过滤&#xff0c;ACL判别依据是五元组&#xff1a;源IP地址&#xff0c;源端口&#xff0c;目的IP地址&#xff0c;目的端口、协议。&#xff08;ACL工作于OSI模型第三层&#xff0c;是路由器和三层交换机接口的…

SpringBoot的配置文件和YAML文件的语法

1.SpringBoot的有两种格式的全局配置文件&#xff0c;使用任何一个功能都是一样的 注意&#xff1a;SpringBoot的全局配置文件名都是固定的application.xxx ① application.properties&#xff0c; 这个是默认Spring initializr默认自动生成的配置文件&#xff0c;也是我们属…

2024免费数据恢复工具EasyRecovery电脑必备软件

&#x1f389; 数据安全小能手&#xff0c;EasyRecovery最新功能揭秘 &#x1f513; 亲爱的小红书的朋友们&#xff01;你们有没有因为不小心删除了重要文件而焦急万分&#xff1f;或者因为电脑突然崩溃&#xff0c;担心珍贵的资料丢失&#xff1f;别怕&#xff0c;今天我就来给…

HAL-DMA中断空闲接受不定长数据

title: HAL-DMA中断空闲接受不定长数据 tags: STM32HalCubemax 面对无规律长度的数据帧如何处理&#xff1f; 不定长数据接收可以使用每帧数据发送完成后会有一定的空闲时间"帧的时间间隔?" 如果你想每帧都要可以采用dma加空闲中断的方式空闲中断一次就是一帧数据…

while循环或for循环写九九乘法表

print("\n") i1 while i<9:j1while j<i:print(f"{j}*{i}{i*j}\t",end)j1print("\n")i1 print(\n) for i in range(1,10):for j in range(1,10):if j<i:print(f"{i}*{j}{i*j}\t",end)else:breakprint(\n)

岁月长河中的温柔等待

在那个年代&#xff0c;爱情往往像是一条静静流淌的小河&#xff0c;不动声色却又波澜不惊。在一个小村庄里&#xff0c;住着一对中年夫妻&#xff0c;人们叫他们李大叔和赵阿姨。他们的故事&#xff0c;就像是那个时代的缩影&#xff0c;承载着岁月的沧桑与深情的守候。 李大…

【CT】LeetCode手撕—160. 相交链表

目录 题目1- 思路2- 实现⭐160. 相交链表——题解思路 3- ACM 实现 题目 原题连接&#xff1a;160. 相交链表 1- 思路 模式识别&#xff1a;相交链表 ——> 判断是否相交 思路 保证 headA 是最长的那个链表&#xff0c;之后对其开始依次遍历 2- 实现 ⭐160. 相交链表—…

基于振弦采集仪的地下综合管廊工程安全监测技术研究

基于振弦采集仪的地下综合管廊工程安全监测技术研究 地下综合管廊工程是一项重要的城市基础设施工程&#xff0c;承载着城市供水、供电、供热、排水等重要功能。为了确保地下综合管廊工程的安全运行&#xff0c;需要进行有效的安全监测。本文将重点研究基于振弦采集仪的地下综…

【HarmonyOS NEXT】使用RSA非对称密钥分段加解密

加密 调用cryptoFramework.createAsyKeyGenerator、AsyKeyGenerator.generateKeyPair&#xff0c;生成RSA密钥类型为RSA1024、素数个数为2&#xff08;不填默认&#xff09;的非对称密钥对&#xff08;KeyPair&#xff09;。KeyPair对象中包括公钥PubKey、私钥PriKey。 如何生…

【中南林业科技大学校园生存指南】序 | 大学之道

前言 本专栏所有内容来自同学们所提供的建议&#xff0c;已经征得收集者意见在此发布。 由于刚开始做&#xff0c;故后续内容会在积累一定程度时发布&#xff0c;感谢支持。 序 回顾大学四年&#xff0c;我仔细梳理了每一刻&#xff0c;把它们凝结成文字&#xff0c;记录下我…

Socket编程之多进程模型

一、多进程模型概述 基于最初的阻塞网络 I/O &#xff0c;若服务器要为多个客户端提供支持&#xff0c;在较为传统的手段中&#xff0c;多进程模型是常用的选择&#xff0c;即为每个客户端都分配一个进程来处理其请求。 服务器的主进程主要负责对客户连接的监听&#xff0c;一旦…

JSON 对象

JSON 对象 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript编程语言的一个子集,但JSON是独立于语言的文本格式,代码中可以使用各种语言来解析和生成它。JSON格式通常用于数据交换、配置文件以…

vmware 虚拟机保留数据扩展C盘

1&#xff0c;在默认安装系统的时候&#xff0c;VMWARE一般给C盘50G&#xff0c;很多人想着够用了&#xff0c;但是后面慢慢的安装各种大型软件&#xff0c;游戏&#xff0c;才发现&#xff0c;悔时已晚。 2&#xff0c;有很多人虚拟机其实就是拿来游戏多开&#xff0c;但是当…

局域网共享文件夹怎么加密?方法很简单

局域网共享文件夹是企业内部信息、数据传递沟通的重要工具&#xff0c;而为了保护共享文件夹数据安全&#xff0c;我们需要使用专业的加密软件加密保护局域网共享文件夹。下面我们就来了解一下局域网共享文件夹加密方法。 局域网共享文件夹加密 在加密共享文件夹时&#xff0c…

PyCharm新手入门

前言 在之前《Python集成开发工具的选择》一文中介绍了python初学者可以使用Jupyter Notebook&#xff0c;Jupyter Notebook简单易用&#xff0c;可以用来练习代码编写&#xff0c;但是实际生产开发环境使用这个工具是远远不够用的&#xff0c;因为实际软件开发中需要软件调试…

计算机组成原理(Wrong Question)

目录 一、计算机系统概述 *1.1 计算机发展历程 1.2 计算机系统层次结构 1.3 计算机的性能指标 二、 数据的表示和运算 2.1 数制和编码 2.2 运算方法和运算电路 2.3 浮点数的表示与运算 三、存储系统 3.1 存储器概述 3.2 主存储器 3.3 主存储器与CPU的连接 3.4 外部…

面试技巧:正确回答JavaScript中Map和Object的选择问题

在JavaScript的面试中&#xff0c;对于何时使用Map和Object的选择问题&#xff0c;是一个常见的考察点。这两个数据结构都能存储键值对&#xff0c;但它们各有优势和适用场景。本文将深入探讨两者的区别&#xff0c;并通过实际代码示例来指导您如何选择。 基本概念 Map&#…

MFC扩展库BCGControlBar Pro v35.0

LINK : fatal error LNK1104: 无法打开文件“BCGCBPRO2800U140.lib” BCGControlBar v25.0版本 环境VS2015&#xff0c;在运行程序时出现提示错误 &#xff1a;LINK : fatal error LNK1104: 无法打开文件“BCGCBPRO2800U140.lib” 1、需要编译一下BGCControlBar&#xff0c;在…

串口rx + RAM + LCD

REVIEW 昨天摸鱼怪发现高两位的数据写入or读出存在问题&#xff1a; RAM 串口的简单应用-CSDN博客 1. 今日摸鱼任务 UART_RX RAM LCD 来显示一下是 rx or tx 的问题 2. 代码部分 rx_ram_lcd.v module rx_ram_lcd(input clk ,input reset_n ,input uart_rx ,output …