千家信息网

XLOG段文件跳号现象分析

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,一、原理当执行promote 时,我们经常看到的结果是:生成一个新 XLOG 文件,名称为:时间线加 1 ,段文件名为之前的段文件号。那么做这个动作的时机是什么时候呢?是否只有这一种现象,会不会有其他
千家信息网最后更新 2026年10月31日XLOG段文件跳号现象分析

一、原理

当执行promote 时,我们经常看到的结果是:生成一个新 XLOG 文件,名称为:时间线加 1 ,段文件名为之前的段文件号。那么做这个动作的时机是什么时候呢?是否只有这一种现象,会不会有其他现象?先透露下,当执行 promote 动作前,最后一个 XLOG 日志是 SWITCH 时,段文件号会加 1 。下面我们对其流程做详细分析,并通过 gdb 理解其原理。

做这个动作的函数是 exitArchiveRecovery , 调用时机为startup 进程退出的时刻,见堆栈:

Breakpoint 1, exitArchiveRecovery (endTLI=1, endOfLog=23053968) at xlog.c:54755475  InArchiveRecovery = false;(gdb) bt#0  exitArchiveRecovery (endTLI=1, endOfLog=23053968) at xlog.c:5475#1  0x0815fc4b in StartupXLOG () at xlog.c:7460#2  0x083dbc56 in StartupProcessMain () at startup.c:207#3  0x08173cbf in AuxiliaryProcessMain (argc=2, argv=0xbfa8a2f4) at bootstrap.c:451#4  0x083dab93 in StartChildProcess (type=StartupProcess) at postmaster.c:5386#5  0x083d5d86 in PostmasterMain (argc=1, argv=0xa22e7e8) at postmaster.c:1369#6  0x0831c76c in main (argc=1, argv=0xa22e7e8) at main.c:228

具体代码行为恢复完成之后:

StartupXLOG-> 读取 checkpoint-> 恢复 ->exitArchiveRecovery : EndOfLog 为当前回放日志最后的位置, EndOfLogTLI 为当前退出时回放日志的时间线。当 data 目录下有 standby.signal 文件即该机器是备时 ArchiveRecoveryRequested 为 TRUE 。

exitArchiveRecovery 函数调用流程如下:首先通过 endOfLog 即回放最后的位置计算出段文件日志号: endLogSegNo= (endOfLog - 1) / (wal_segment_size) ; startLogSegNo= endOfLog / (wal_segment_size) 。如果 endLogSegNo 等于 startLogSegNo ,表示回放位置为文件中间位置,在调用 XLogFileCopy 生成一个新文件,并将上个 XLOG 文件内容拷贝到新文件中;段文件号相同,时间线加 1 。如果 endLogSegNo 不等于 startLogSegNo ,即回放位置正好是文件大小的末尾处,或者正好是 SWITCH 这个日志,那么调用 XLogFileInit 函数进行初始化文件:

XlogFileCopy 函数调用:调用 XLogFilePath 函数获取源 XLOG 文件名, OpenTransientFile 打开该文件,创建并打开一个临时 XLOG 文件 pg_wal/xlogtemp.pid , pid 为 startup 进程的 ID 号。 sizeof(buffer) 为一页大小 8192 字节,从源文件每次 read 一页数据并将之 write 到 xlogtemp 文件,最后一页数据如果不够 8192 字节,则有多少读取多少并写入文件。当文件拷贝完成后,执行一次 sync 。最后调用 InstallXLogFileSegment 将文件重命名。

InstallXLogFileSegment 函数: XlogFileCopy 调用时, find_free 为 false ,直接将文件重命名为时间线加 1 的文件名; XLogFileInit 调用时为 TRUE ,将段文件号加 1 后(注意这里不是加 1 ,是因为正好是文件末尾,求得的是下一个段文件号,只是现象上看是加 1 ),重命名为时间线加 1 的文件,会先 stat 下这个文件,该流程返回值是 2 即该文件不存在,所以不会再将 segno 加 1 ,直接跳过虚框内的步骤,进入重命名流程 durable_like_or_rename 。

XLogFileInit 函数的调用:首先获取新文件的文件名,即时间线加 1 ,段文件名为原文件名,本次 exitArchiveRecovery 函数的调用流程中, use_existent 为 TRUE 所以会视图打开该文件。当然因为该文件不存在所以打开失败。然后创建并打开一个临时文件 xlogtemp.pid ,将该文件全部清 0 ,最后 sync 。之后调用 InstallXLogFileSegment 函数重命名。最后打开新文件以供之后使用。

二、GDB跟踪-lsn位置在xlog文件中间

1 、进入第一个断点,即函数入口

Breakpoint 1, exitArchiveRecovery (endTLI=1, endOfLog=23053968) at xlog.c:54755475  InArchiveRecovery = false;(gdb) bt#0  exitArchiveRecovery (endTLI=1, endOfLog=23053968) at xlog.c:5475#1  0x0815fc4b in StartupXLOG () at xlog.c:7460#2  0x083dbc56 in StartupProcessMain () at startup.c:207#3  0x08173cbf in AuxiliaryProcessMain (argc=2, argv=0xbfa8a2f4) at bootstrap.c:451#4  0x083dab93 in StartChildProcess (type=StartupProcess) at postmaster.c:5386#5  0x083d5d86 in PostmasterMain (argc=1, argv=0xa22e7e8) at postmaster.c:1369#6  0x0831c76c in main (argc=1, argv=0xa22e7e8) at main.c:228

2 、接着计算出段文件号,这两个值相等,即执行 promote 时, lsn 最后位置在文件中间。

5507  if (endLogSegNo == startLogSegNo)(gdb) 5517       XLogSegmentOffset(endOfLog, wal_segment_size));(gdb) p endLogSegNo$1 = 1(gdb) p startLogSegNo$2 = 1

3 、 lsn 在文件中间,调用 XlogFileCopy , upto 为 lsn 在最后文件的偏移

XLogFileCopy (destsegno=1, srcTLI=1, srcsegno=1, upto=6276752) at xlog.c:34053405  XLogFilePath(path, srcTLI, srcsegno, wal_segment_size);(gdb) p 23053968%(16*1024*1024)$3 = 6276752

4 、打开原文件 00000001 0000000000000001 ,以及临时文件 xlogtemp.29683

3406  srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY);(gdb) p path$4 = "pg_wal/00000001", '0' , "1", '\000' , "\b\221\250\277gmE\b\004\005ĥ\000\000\000\001\030\221\250\277\bnE\b\004\005ĥ\000\000\000\001X\221\250\277$\207E\b\004\005ĥ\000\000\000\001", '\000' "\270, \004\246X\221\250\277\000\000\000\000\000\000\000 \000\270\004\000\000\000\000\000\000\000\000\000\n\000\000\000\000\270\004\246\270\221\250\277dd\025\b\000\005ĥ\352\320a\b\341\n\000\000~\016b\b\000\000\000"(gdb) n(gdb) p tmppath$5 = "pg_wal/xlogtemp.29683", '\000' (gdb) n3420  fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);

5 、循环进行拷贝,一次拷贝一页 8192 字节

3429  for (nbytes = 0; nbytes < wal_segment_size; nbytes += sizeof(buffer))(gdb) p sizeof(buffer)$6 = 8192(gdb) n3433   nread = upto - nbytes;(gdb) 3439   if (nread < sizeof(buffer))(gdb) p nread$7 = 6276752(gdb) p 6276752/8192$8 = 766

6 、 InstallXLogFileSegment 函数重命名, path 为 000000020000000000000001

Breakpoint 2, InstallXLogFileSegment (segno=0xbfa86968, tmppath=0xbfa88974 "pg_wal/xlogtemp.29683", find_free=false, max_segno=0, use_lock=false) at xlog.c:35453545  XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size); (gdb) p path$10 = "pg_wal/00000002", '0' , "1\000 \212\022\251\322\"[\000\000\000\000\000\277 `\b\204\211\250\277\347e\250\277\005\000\000\000\003\000\000\000 NҬ\003\000\000\000\002\000\000\000\005\000\000\000;\000\000\000\000\000\000\000\030f\250\277\206\032`\b\000\000\000\000\350h\250\277\350h\250\277\350h\250\277\240.{\262d\000\000\000\363s\000\000\000\000\000\000\240\020[\264\003\000\000\000\000\000\000\000\003\000\000\000\240\362:\266\003\000\000\000\220\251t\267\003\000\000\000\240\324\032\270\003\000\000\000\220\213T\271\003\000\000\000 \361\003\272\003\000\000\000\020\250=\273\003\000\000\000 \323\343\273\322\"[29683\000\000\000\000\n", '\000' , "\001\000\000\000\373\333y\b\005\000\000\000\000\000\000\000\001\000\000\000\270\240\250\277\310h\250\277\225\017`\b\363s\000\000\000\000\000\000d", '\000' "\350"...(gdb) n

7 、将临时文件重命名为 000000020000000000000001

3579  if (durable_link_or_rename(tmppath, path, LOG) != 0)(gdb) p path$11 = "pg_wal/00000002", '0' , "1\000 \212\022\251\322\"[\000\000\000\000\000\277 `\b\204\211\250\277\347e\250\277\005\000\000\000\003\000\000\000 NҬ\003\000\000\000\002\000\000\000\005\000\000\000;\000\000\000\000\000\000\000\030f\250\277\206\032`\b\000\000\000\000\350h\250\277\350h\250\277\350h\250\277\240.{\262d\000\000\000\363s\000\000\000\000\000\000\240\020[\264\003\000\000\000\000\000\000\000\003\000\000\000\240\362:\266\003\000\000\000\220\251t\267\003\000\000\000\240\324\032\270\003\000\000\000\220\213T\271\003\000\000\000 \361\003\272\003\000\000\000\020\250=\273\003\000\000\000 \323\343\273\322\"[29683\000\000\000\000\n", '\000' , "\001\000\000\000\373\333y\b\005\000\000\000\000\000\000\000\001\000\000\000\270\240\250\277\310h\250\277\225\017`\b\363s\000\000\000\000\000\000d", '\000' "\350"...(gdb) n

三、GDB跟踪-lsn位置在xlog文件尾或最后一个为SWITCH

1 、 lsn 位于文件尾,调用函数 XLogFileInit

Breakpoint 3, exitArchiveRecovery (endTLI=3, endOfLog=50331648) at xlog.c:54755475  InArchiveRecovery = false;(gdb) n5480  UpdateMinRecoveryPoint(InvalidXLogRecPtr, true);(gdb) 5486  if (readFile >= 0)(gdb) 5488   close(readFile);(gdb) 5489   readFile = -1;(gdb) 5498  XLByteToPrevSeg(endOfLog, endLogSegNo, wal_segment_size);(gdb) 5499  XLByteToSeg(endOfLog, startLogSegNo, wal_segment_size);(gdb) 5507  if (endLogSegNo == startLogSegNo)(gdb) 5525   bool  use_existent = true;(gdb) 5528   fd = XLogFileInit(startLogSegNo, &use_existent, true);(gdb)

2 、 path 为 000000040000000000000003, 该文件不存在

Breakpoint 2, XLogFileInit (logsegno=3, use_existent=0xbfbd366f, use_lock=true) at xlog.c:32163216  XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size);(gdb) n3221  if (*use_existent)(gdb) p path$1 = "pg_wal/00000004", '0' , "3\000\000\000\000\000\346!`\bX6\275\277\060\000\000\000\a\000\000\000\030\333\177\t\364\257`\000\270\331\177\t\000\000\000\000\a\000\000\000\000\224M\000\000\000\000\000h3\275\277: `\b4\000\000\000\330\065\275\277\330\065\275\277\000\000\000\000h3\275\277L\274M\000\004\000\000\000\000\000\000\000?\000\000\000\a\000\000\000\b3\275\277\206\032`\b\000\000\000\000\330\065\275\277\330\065\275\277\330\065\275\277\373\210}\tX\025w\b\004\000\000\000\000\000\000\000\177\323a\bX\000\000\000\000\000\000\000\b", '\000' , "\b\000\000\000\000\000\000\000\060", '\000' , "recovering 00000\322\"[\000\000\270\004\246\277 `\b`6\275\277\360\253a\b\b", '\000' ...(gdb) n3223   fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method));(gdb) 3224   if (fd < 0)(gdb) 3226    if (errno != ENOENT)(gdb) p fd$2 = -1(gdb) p errno$3 = 2

3 、创建并打开临时文件,将 zbuffer.data 清 0 ,然后一页一页的将文件清 0

3243  snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());(gdb)3245  unlink(tmppath);(gdb)3248  fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);(gdb)3249  if (fd < 0)(gdb)3254  memset(zbuffer.data, 0, XLOG_BLCKSZ);(gdb) p fd$4 = 33269   for (nbytes = 0; nbytes < wal_segment_size; nbytes += XLOG_BLCKSZ)(gdb)3271    errno = 0;(gdb)3272    if (write(fd, zbuffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)

4 、进入 InstallXLogFileSegment 函数, 000000040000000000000003 文件 stat 失败,调用 durable_link_or_rename 重命名。

InstallXLogFileSegment (segno=0xbfbd0de0, tmppath=0xbfbd2de8 "pg_wal/xlogtemp.31765", find_free=true, max_segno=45, use_lock=true) at xlog.c:35503550  if (use_lock)(gdb) n3551   LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);(gdb)3553  if (!find_free)(gdb)3561   while (stat(path, &stat_buf) == 0)(gdb) p path$5 = "pg_wal/00000004", '0' , "3\000 \212\022\251\322\"[\000\000\000\000\000\277 `\b\370-\275\277W\n\275\277\005\000\000\000\003\000\000\000 NҬ\003\000\000\000\003\000\000\000\005\000\000\000;\000\000\000\000\000\000\000\210\n\275\277\206\032`\b\000\000\000\000X\r\275\277X\r\275\277X\r\275\277\240.{\262d\000\000\000\025|\000\000\000\000\000\000\240\020[\264\003\000\000\000\000\000\000\000\003\000\000\000\240\362:\266\003\000\000\000\220\251t\267\003\000\000\000\240\324\032\270\003\000\000\000\220\213T\271\003\000\000\000 \361\003\272\003\000\000\000\020\250=\273\003\000\000\000 \323\343\273\322\"[31765\000\000\000\000\n", '\000' , "\001\000\000\000\373\333y\b\005\000\000\000\000\000\000\000\003\000\000\000(E\275\277\070\r\275\277\225\017`\b\025|\000\000\000\000\000\000"...(gdb) n3579  if (durable_link_or_rename(tmppath, path, LOG) != 0)(gdb) p errno$6 = 2
文件 函数 位置 时间 日志 流程 拷贝 文件名 现象 动作 字节 原理 大小 数据 时机 末尾 进程 并将 生成 跟踪 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 小米移动互联网科技园 互联网金融科技创新 米客互联网科技 互联网科技公司介绍 安控科技rtu产品工业互联网 云创客互联网科技公司 中盈科技互联网信息有限公司 天速互联网络科技有限公司 恒银科技与互联网金融 以后互联网后是啥科技 湖南诚度互联网科技有限公司 世界互联网科技公司市值排名 湖南一路畅行互联网科技 广州新华互联网科技学校电竞方面 银行科技岗属于互联网吗 启辰互联网科技 杭州披云加互联网科技有限公司 广州百诚互联网科技有限公司官网 互联网的黑科技实验室 利用互联网等科技手段 互联网科技有限公司 智网互联网科技 成都狮子座互联网科技 小米互联网科技园设置 互联网系的金融科技公司 成都铂石互联网科技做什么的 厦门比较好的科技互联网公司 乌鲁木齐新华智原互联网科技学校 众安科技工业互联网合作 青岛易易互联网科技
0