一、原理

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

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

Breakpoint 1, exitArchiveRecovery (endTLI=1, endOfLog=23053968) at xlog.c:5475
5475        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、打开原文件000000010000000000000001,以及临时文件xlogtemp.29683

3406 srcfd = OpenTransientFile(path, O_RDONLY | PG_BINARY);(gdb) p path$4 = "pg_wal/00000001", '0' <repeats 15 times>, "1", '\000' <repeats 869 times>, "\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' <repeats 13 times>"\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' <repeats 1002 times>(gdb) nfd = 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:3545XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size);(gdb) p path$10 = "pg_wal/00000002", '0' <repeats 15 times>, "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' <repeats 15 times>, "\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' <repeats 27 times>"\350"...(gdb) n

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

3579 if (durable_link_or_rename(tmppath, path, LOG) != 0)(gdb) p path$11 = "pg_wal/00000002", '0' <repeats 15 times>, "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' <repeats 15 times>, "\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' <repeats 27 times>"\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' <repeats 15 times>, "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\000h2\275\277: `\b4\000\000\000\330\065\275\277\330\065\275\277\000\000\000\000h2\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' <repeats 19 times>, "\b\000\000\000\000\000\000\000\060", '\000' <repeats 11 times>, "recovering 00000\322\"[\000\000\270\004\246\277 `\b`6\275\277\360\253a\b\b", '\000' <repeats 11 times>...(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)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:3550
3550 if (use_lock)
(gdb) n
3551 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' <repeats 15 times>, "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' <repeats 15 times>, "\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) n
3579 if (durable_link_or_rename(tmppath, path, LOG) != 0)
(gdb) p errno
$6 = 2

XLOG段文件跳号现象分析相关推荐

  1. oracle主键从键怎么看,分析Oracle主键的跳号现象

    从做Jforum项目以来,以来遇到一个很明显的现象,就是每个表的主键都出现跳号现象.具体表现在:当一次操作若干条数据时,自动增 从做Jforum项目以来,以来遇到一个很明显的现象,就是每个表的主键都出 ...

  2. oracle序列无缓存,oracle 序列跳号现象

    从做Jforum项目以来,遇到一个很明显的现象,就是每个表的主键都出现跳号现象.具体表现在:当一次操作若干条数据时,自动增长的sequence序列总是从200的倍数开始增加,这次操作完成后,无论这时c ...

  3. SAP 凭证跳号分析

    首先SAP在表TNRO:Definition of number range objects将会为各种object定义number range的属性 在此表中有这么几个字段.OBJECT: 坛 -- ...

  4. 如何查看linux系统下的各种日志文件 linux 系统日志的分析大全

    如何查看linux系统下的各种日志文件 linux 系统日志的分析大全 日志分类: 1. 连接时间的日志 连接时间日志一般由/var/log/wtmp和/var/run/utmp这两个文件记录,不过这 ...

  5. 同时插入同一行记录,产生阻塞的处理分析(4号锁分析之Unique key的约束)

    之前有个客户提出,在insert的时候被hang住了,碰到这样的问题很可能是锁的问题.对于这样的问题我一般就会想到几个常用的视图:v$lock/v$transaction/v$session/v$sq ...

  6. PE文件和COFF文件格式分析——节信息

    在<PE文件和COFF文件格式分析--签名.COFF文件头和可选文件头3>中,我们看到一些区块的信息都有偏移指向.而我们本文讨论的节信息是没有任何偏移指向的,所以它是紧跟在可选文件头后面的 ...

  7. (8)JMP FAR段间跳转

    一.回顾 在前面的课程中我们学习了MOV和LES等修改段寄存器的指令,当时老师说过,CS寄存器比较特殊,不能用MOV和"LCS"进行修改,原因是CS和EIP共同决定下一条指令的地址 ...

  8. oracle获取序列跳号,Oracle sequence跳号知多少

    Sequence是oracle中的一个非常常用的功能,开发经常会频繁使用.但是在生产环境中经常有应用反馈通过sequence生成的自增主键会出现不连续跳号的现象,而且是几十个几十个地跳,为了弄清楚se ...

  9. java ee ide 假死_Eclipse编辑jsp、js文件时卡死现象的解决办法汇总

    使用Eclipse编辑jsp.js文件时,经常出现卡死现象,在网上百度了N次,经过N次优化调整后,卡死现象逐步好转,具体那个方法起到作用,不太好讲.将所有用过的方法罗列如下: 1.取消验证 windo ...

最新文章

  1. php防止网站被镜像,网站被等恶意镜像的解决、反制措施详细教程
  2. 动态内存管理和智能指针 2.0 -- shared_ptr
  3. 如何基于消息中间件实现分布式事务?万字长文给你答案!!
  4. angularjs组件间通讯_详解Angular2组件之间如何通信
  5. redhat和ubuntu上部署本地源
  6. python 字符串大小写转换 其它不变_python字符串大小写如何转换
  7. linux block的含义,Block Prefetching含义
  8. 使用Python 正则匹配两个特定字符之间的字符方法
  9. 【快速入门ORM框架之Dapper】大牛勿进系列
  10. 真快!iOS 15.4支持戴口罩解锁了:苹果终于满足iPhone用户需求
  11. 地址null一个简单的第三人称汽车驾驶系统
  12. JSTL核心标签库详解
  13. 去除DataTable重得记录(net 2.0,不支持Linq)
  14. 电赛练习之旋转倒立摆PID调节
  15. 【编译原理】实验二 词法分析程序
  16. 小程序创建搜索记录,获取搜索记录,删除搜索历史
  17. 框架表示法表示台式计算机,框架表示法,frame representation,音标,读音,翻译,英文例句,英语词典...
  18. 《AngularJS深度剖析与最佳实践》简介
  19. 北京住房公积金提取(取消)指南
  20. c语言cfile用法,MFC CFile类读写文件详解

热门文章

  1. FZOJ--2221-- RunningMan 福建第六届省赛
  2. QT定时器QTimer
  3. Java List数据量大, 需要分片批次操作
  4. HTML5期末大作业:动漫网站设计——动漫电影《你的名字》(7页) HTML+CSS+JavaScript 学生DW网页设计作业成品 html网页设计期末大作业_网页设计平时作业
  5. Unity Network 使用小结
  6. JAVA淮安市教育局职业教研室技能竞赛计算机毕业设计Mybatis+系统+数据库+调试部署
  7. TCP/IP概述和详解--一篇就够
  8. 对照地图看历史剧,学习历史地理
  9. 【渝粤题库】陕西师范大学210012 幼儿园舞蹈教育
  10. VR体验馆推荐重庆也可以体验虚拟现实游戏