pg_controldata中可以看到这样的lsn表示:
Latest checkpoint location: 2F/F849D720
Prior checkpoint location: 2F/F849D720
Latest checkpoint's REDO location: 2F/F849D6E8
Latest checkpoint's REDO WAL file: 000000010000002F000000F8
pg中的一些控制函数也可以看到类似的表示:
postgres=# select pg_current_wal_lsn();
pg_current_wal_lsn
--------------------
2F/F849D7C8
postgres=# select pg_walfile_name('2F/F849D7C8');
pg_walfile_name
--------------------------
000000010000002F000000F8
pg中的xlog文件命名看起来是另一种形式:
16777216 Mar 15 19:16 000000010000002F000000F8
16777216 Feb 28 15:16 000000010000002F000000F9
16777216 Feb 28 15:16 000000010000002F000000FA
16777216 Feb 28 15:16 000000010000002F000000FB
16777216 Feb 28 15:16 000000010000002F000000FC
16777216 Feb 28 15:16 000000010000002F000000FD
16777216 Feb 28 15:16 000000010000002F000000FE
16777216 Feb 28 15:16 000000010000002F000000FF
16777216 Feb 28 15:16 000000010000003000000000
16777216 Feb 28 15:16 000000010000003000000001
16777216 Feb 28 15:16 000000010000003000000002
16777216 Feb 28 15:16 000000010000003000000003
16777216 Feb 28 15:16 000000010000003000000004
16777216 Feb 28 15:16 000000010000003000000005
16777216 Feb 28 15:18 000000010000003000000006
16777216 Feb 28 15:18 000000010000003000000007
16777216 Feb 28 15:20 000000010000003000000008
16777216 Mar 11 15:18 000000010000003000000009
16777216 Mar 11 15:18 00000001000000300000000A
16777216 Mar 11 15:18 00000001000000300000000B
在代码中可以看到的lsn又是一种表示:
(gdb) p RedoStartLSN
$23 = 206029051624
(gdb) p/x checkPointLoc
$24 = 0x2ff849d720
上述三种形式的关系是什么?
一、文件名含义
000000010000002F000000F8
00000001 0000002F 000000F8
timeline logid segid
二、控制函数查出来的'A/B'形式的lsn含义
2F/F849D7C8
2F F8 49D7C8
logid segid offset
三、pg内部变量含义:就是lsn不带'/'
(gdb) p RedoStartLSN
$23 = 206029051624 = 0x2FF849D6E8
2F F8 49D6E8
logid segid offset
如果需要分析源码,可以从这个堆栈入手
XLogReaderAllocate
ReadCheckpointRecord
record = ReadRecord(xlogreader, RecPtr: 0x2FF849D720) : 读取位置 0x2FF849D720
XLogReadRecord(xlogreader, RecPtr: 0x2FF849D720)
state->currRecPtr = 0x2FF849D720
targetPagePtr = RecPtr - (RecPtr % XLOG_BLCKSZ) : 计算页面ID 0x2FF849C000
targetRecOff = RecPtr % XLOG_BLCKSZ : 计算页内偏移 0x1720
:
读一个8k上来 ReadPageInternal(state, targetPagePtr:0x2FF849C000 , Min(targetRecOff + SizeOfXLogRecord, XLOG_BLCKSZ): 0x1720) :最多读8k出来
XLByteToSeg(pageptr, targetSegNo) : 计算SEG号targetSegNo=0x2ff8
targetPageOff = (pageptr % XLogSegSize) : 计算SEG号内的偏移targetPageOff=0x49c000
targetSegmentPtr = pageptr - targetPageOff : 目标SEG的起始位置
(第一次读:按SEG头的位置读)
state->read_page : 调用钩子
XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *readTLI)
targetPagePtr = 0x2ff8000000
reqLen = 8192
targetRecPtr = 0x2ff849d720
XLByteToSeg(targetPagePtr, targetSegNo) : targetPagePtr = 0x2ff8
targetPageOff = targetPagePtr % XLogSegSize : targetPageOff = 0
(第一个文件或前一个文件已经读完了,开始读下一个文件)
XLByteToSeg(targetPagePtr, readSegNo) : readSegNo = 0x2ff8
WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr)
RecPtr = 0x2ff8002000
randAccess = 1
fetching_ckpt = 1
tliRecPtr = 0x2ff849d720
XLogFileReadAnyTLI(readSegNo: 0x2ff8) : 把指定的XLOG文件的FD读出来
lseek(readFile, (off_t) readOff, SEEK_SET) : 开始读文件
read(readFile, readBuf, XLOG_BLCKSZ)
XLogReaderValidatePageHeader : 检测页面正常
XLogReaderValidatePageHeader : 检测页面正常
(第二次读:按SEG内的位置读)
state->read_page
XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf, TimeLineID *readTLI)
targetPagePtr = 0x2ff849c000
reqLen = 5944
targetRecPtr = 0x2ff849d720
XLogReaderValidatePageHeader : 检测页面正常
************(ReadPageInternal读完了数据在state->readBuf里面)
record = (XLogRecord *) (state->readBuf + RecPtr % XLOG_BLCKSZ) : 读了一个完整的页面,用读取位置0x2ff849d720对8k取余能得到record的位置state->readBuf+0x1720
total_len = record->xl_tot_len;
ReadPageInternal
ValidXLogRecord
(CRC校验)