前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Postgresql中lsn的三种记录形式与相关代码

Postgresql中lsn的三种记录形式与相关代码

作者头像
mingjie
发布2022-05-12 11:10:10
8990
发布2022-05-12 11:10:10
举报
文章被收录于专栏:Postgresql源码分析

lsn三种形式

pg_controldata中可以看到这样的lsn表示:

代码语言:javascript
复制
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中的一些控制函数也可以看到类似的表示:

代码语言:javascript
复制
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文件命名看起来是另一种形式:

代码语言:javascript
复制
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又是一种表示:

代码语言:javascript
复制
(gdb) p RedoStartLSN
$23 = 206029051624
(gdb) p/x checkPointLoc
$24 = 0x2ff849d720

上述三种形式的关系是什么?

解析

代码语言:javascript
复制
一、文件名含义
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
  1. 后两种是等价的。
  2. xlog文件名是把lsn最后6个16进制省略了,也就是一个16MB的文件中可以保存省略的偏移量offset。
  3. offset范围:0x000000 - 0xFFFFFF = 16777215 = 16MB 所以16MB的文件的每个字节都可以通过offset索引到。
  4. 所以在代码调试时,看到lsn的变量,可以使用p/x打印值,就可以和xlog文件或外部函数查询到的值对比了。

show me the code

如果需要分析源码,可以从这个堆栈入手

代码语言:javascript
复制
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校验)
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • lsn三种形式
  • 解析
  • show me the code
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档