溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

XLOG段文件跳號(hào)現(xiàn)象分析

發(fā)布時(shí)間:2020-08-16 15:16:16 來(lái)源:ITPUB博客 閱讀:128 作者:yzs87 欄目:關(guān)系型數(shù)據(jù)庫(kù)

一、原理

當(dāng)執(zhí)行promote 時(shí),我們經(jīng)??吹降慕Y(jié)果是:生成一個(gè)新 XLOG 文件,名稱為:時(shí)間線加 1 ,段文件名為之前的段文件號(hào)。那么做這個(gè)動(dòng)作的時(shí)機(jī)是什么時(shí)候呢?是否只有這一種現(xiàn)象,會(huì)不會(huì)有其他現(xiàn)象?先透露下,當(dāng)執(zhí)行 promote 動(dòng)作前,最后一個(gè) XLOG 日志是 SWITCH 時(shí),段文件號(hào)會(huì)加 1 。下面我們對(duì)其流程做詳細(xì)分析,并通過(guò) gdb 理解其原理。

     做這個(gè)動(dòng)作的函數(shù)是 exitArchiveRecovery 調(diào)用時(shí)機(jī)為startup 進(jìn)程退出的時(shí)刻,見(jiàn)堆棧:

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

具體代碼行為恢復(fù)完成之后:

StartupXLOG-> 讀取 checkpoint-> 恢復(fù) ->exitArchiveRecovery EndOfLog 為當(dāng)前回放日志最后的位置, EndOfLogTLI 為當(dāng)前退出時(shí)回放日志的時(shí)間線。當(dāng) data 目錄下有 standby.signal 文件即該機(jī)器是備時(shí) ArchiveRecoveryRequested TRUE 。

XLOG段文件跳號(hào)現(xiàn)象分析

exitArchiveRecovery 函數(shù)調(diào)用流程如下:首先通過(guò) endOfLog 即回放最后的位置計(jì)算出段文件日志號(hào): endLogSegNo= (endOfLog - 1) / (wal_segment_size) ; startLogSegNo= endOfLog / (wal_segment_size) 。如果 endLogSegNo 等于 startLogSegNo ,表示回放位置為文件中間位置,在調(diào)用 XLogFileCopy 生成一個(gè)新文件,并將上個(gè) XLOG 文件內(nèi)容拷貝到新文件中;段文件號(hào)相同,時(shí)間線加 1 。如果 endLogSegNo 不等于 startLogSegNo ,即回放位置正好是文件大小的末尾處,或者正好是 SWITCH 這個(gè)日志,那么調(diào)用 XLogFileInit 函數(shù)進(jìn)行初始化文件:

XLOG段文件跳號(hào)現(xiàn)象分析

XlogFileCopy 函數(shù)調(diào)用:調(diào)用 XLogFilePath 函數(shù)獲取源 XLOG 文件名, OpenTransientFile 打開(kāi)該文件,創(chuàng)建并打開(kāi)一個(gè)臨時(shí) XLOG 文件 pg_wal/xlogtemp.pid , pid startup 進(jìn)程的 ID 號(hào)。 sizeof(buffer) 為一頁(yè)大小 8192 字節(jié),從源文件每次 read 一頁(yè)數(shù)據(jù)并將之 write xlogtemp 文件,最后一頁(yè)數(shù)據(jù)如果不夠 8192 字節(jié),則有多少讀取多少并寫入文件。當(dāng)文件拷貝完成后,執(zhí)行一次 sync 。最后調(diào)用 InstallXLogFileSegment 將文件重命名。

XLOG段文件跳號(hào)現(xiàn)象分析

InstallXLogFileSegment 函數(shù): XlogFileCopy 調(diào)用時(shí), find_free false ,直接將文件重命名為時(shí)間線加 1 的文件名; XLogFileInit 調(diào)用時(shí)為 TRUE ,將段文件號(hào)加 1 后(注意這里不是加 1 ,是因?yàn)檎檬俏募┪?,求得的是下一個(gè)段文件號(hào),只是現(xiàn)象上看是加 1 ),重命名為時(shí)間線加 1 的文件,會(huì)先 stat 下這個(gè)文件,該流程返回值是 2 即該文件不存在,所以不會(huì)再將 segno 1 ,直接跳過(guò)虛框內(nèi)的步驟,進(jìn)入重命名流程 durable_like_or_rename 。

XLOG段文件跳號(hào)現(xiàn)象分析

XLogFileInit 函數(shù)的調(diào)用:首先獲取新文件的文件名,即時(shí)間線加 1 ,段文件名為原文件名,本次 exitArchiveRecovery 函數(shù)的調(diào)用流程中, use_existent TRUE 所以會(huì)視圖打開(kāi)該文件。當(dāng)然因?yàn)樵撐募淮嬖谒源蜷_(kāi)失敗。然后創(chuàng)建并打開(kāi)一個(gè)臨時(shí)文件 xlogtemp.pid ,將該文件全部清 0 ,最后 sync 。之后調(diào)用 InstallXLogFileSegment 函數(shù)重命名。最后打開(kāi)新文件以供之后使用。

XLOG段文件跳號(hào)現(xiàn)象分析

二、GDB跟蹤-lsn位置在xlog文件中間

1 、進(jìn)入第一個(gè)斷點(diǎn),即函數(shù)入口

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

2 、接著計(jì)算出段文件號(hào),這兩個(gè)值相等,即執(zhí)行 promote 時(shí), lsn 最后位置在文件中間。

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

3 、 lsn 在文件中間,調(diào)用 XlogFileCopy , upto lsn 在最后文件的偏移

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

4 、打開(kāi)原文件 00000001 0000000000000001 ,以及臨時(shí)文件 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) n
3420  fd = OpenTransientFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);

5 、循環(huán)進(jìn)行拷貝,一次拷貝一頁(yè) 8192 字節(jié)

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

6 、 InstallXLogFileSegment 函數(shù)重命名, 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:3545
3545  XLogFilePath(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 、將臨時(shí)文件重命名為 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文件尾或最后一個(gè)為SWITCH

1 lsn 位于文件尾,調(diào)用函數(shù) XLogFileInit

Breakpoint 3, exitArchiveRecovery (endTLI=3, endOfLog=50331648) at xlog.c:5475
5475  InArchiveRecovery = false;
(gdb) n
5480  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:3216
3216  XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size);
(gdb) n
3221  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\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' <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) n
3223   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 、創(chuàng)建并打開(kāi)臨時(shí)文件,將 zbuffer.data 0 ,然后一頁(yè)一頁(yè)的將文件清 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 = 3
3269   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 、進(jìn)入 InstallXLogFileSegment 函數(shù), 000000040000000000000003 文件 stat 失敗,調(diào)用 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
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI