postgresql集羣方案hot standby初級測試(四)——xlog詳細解釋header

xlog日誌header部分詳解

前些天,做了些實驗,也確實能夠證明手動同步xlog數據是可行性的,爲了更深入的研究,我覺得研究下xlog的源碼,並且打開xlog的二進制文件,讀一讀它裏面的內容。


本文來自:http://blog.csdn.net/lengzijian/article/details/7836402


首先來看下xlog日誌的結構圖:


從上到下觀察下:

xlog日誌文件命名:

文件名 = 時間線 + 日誌文件號(logid) + 段號(segmented)

        分爲三部分,每個部分由8個16進制字符組成,時間線由1開始,日誌文件號和段號由0開始,所以在系統中第一個事務日誌文件名爲:000000010000000000000000

 

       一個xlog文件日誌備有256個段組成,每個段大小爲16M,當最近的文件名有000000010000000000000000變爲000000010000000100000000時,實際增加了256個段文件,但是邏輯上只增加了一個xlog日誌文件。

 

每一個段文件又分爲很多頁面,每個一面的大小爲一個塊的大小:

include/pg_config.h:

#defineXLOG_BLCKSZ 8192        //塊大小

//頁面個數 = 16M / 8192bit = 2048

 

對於每一個日誌頁面,需要在器頭部寫一個頭部信息XLogPageHeaderData,數據結構如下:

include/access/xlog_internal.h

 

typedef struct XLogPageHeaderData

{

    uint16          xlp_magic;              /* 校驗位 */                                                                                                 

    uint16          xlp_info;               /* 標誌位 */

    TimeLineID      xlp_tli;                /* 頁面第一條記錄的時間序列 */

    XLogRecPtr      xlp_pageaddr;           /* XLOG 頁面首地址 */

} XLogPageHeaderData;


其中標誌位xlp_info只使用最低兩位“01”或者“10”或者11:

“01”表明該頁的第一個XLOG記錄着上一個頁的最後一個XLOG記錄,這樣的記錄會接在一個XLogContRecord結構體之後;

“10”表明該頁的頭部是一個長頭部,既該頁是XLOG段文件的首頁;


這樣頭部標誌位會有三種狀態:

/* 如果記錄跨越兩個頁面,這隻該標誌位到新的頁面 */

#define XLP_FIRST_IS_CONTRECORD         0x0001                                                                                   

/*這裏就是之前說過的表示該頁是xlog段文件的首頁 */

#define XLP_LONG_HEADER                         0x0002

/* 表示既是首頁也是contrecore*/

#define XLP_ALL_FLAGS                                0x0003


長頭部結構體如下:

typedef struct XLogLongPageHeaderData                                                                                                      

{

        XLogPageHeaderData std;         /* 頭部信息 */

        uint64          xlp_sysid;              /* pg_control中的系統標識符 */

        uint32          xlp_seg_size;     /* 校驗位,段的尺寸*/

        uint32          xlp_xlog_blcksz;        /* 校驗位,塊的尺寸 */

} XLogLongPageHeaderData;

 

        要注意的地方,對於一條很長的xlog日誌,當頁面沒有足夠的空間存儲時,postgreseql允許把多餘的數據存儲到下一個頁面,即同一條日誌寫到了兩個文件檔中。一種數據除外,頭部數據是不允許存到兩個頁面當中的。

        當出現一條日誌存放到兩個頁面時,需要用XLogContRecord來記錄該頁除了本頁面存儲的內容外,剩餘的存儲數據信息:

typedef struct XLogContRecord                                                                                                                       

{

        uint32          xl_rem_len;             /* 記錄中剩餘信息的總長度*/

} XLogContRecord;

 

        使用xlogdump(之後做一篇詳細介紹xlogdump的文章)工具來觀察下頁面頭信息(也可以觀察源碼xlogdump.c文件的readXLogPage函數),之後詳細講解xlogdump用法:

打印信息如下:

[page:0, xlp_info:3, xlp_tli:1, xlp_pageaddr:0/4C000000] XLP_FIRST_IS_CONTRECORD XLP_LONG_HEADER

 #第一頁

函數方法爲:

static bool                                                                                                                                                             

readXLogPage(void)

{

         size_t nread = read(logFd, pageBuffer, XLOG_BLCKSZ);

 

         if (nread == XLOG_BLCKSZ)

         {

                   logPageOff += XLOG_BLCKSZ;

                   if (((XLogPageHeader) pageBuffer)->xlp_magic != XLOG_PAGE_MAGIC)

                   {

                            printf("Bogus page magic number %04X at offset %X\n",

                                        ((XLogPageHeader) pageBuffer)->xlp_magic, logPageOff);

                   }

 

                   /*

                    * FIXME: check xlp_magic here.

                    */

                   if (!enable_stats)

                   {

                            printf("[page:%d, xlp_info:%d, xlp_tli:%d, xlp_pageaddr:%X/%X] ",

                                   logPageOff / XLOG_BLCKSZ,

                                   ((XLogPageHeader) pageBuffer)->xlp_info,

                                   ((XLogPageHeader) pageBuffer)->xlp_tli,

                                   ((XLogPageHeader) pageBuffer)->xlp_pageaddr.xlogid,

                                   ((XLogPageHeader) pageBuffer)->xlp_pageaddr.xrecoff);

                           

                            if ( (((XLogPageHeader)pageBuffer)->xlp_info & XLP_FIRST_IS_CONTRECORD) )

                                     printf("XLP_FIRST_IS_CONTRECORD ");

                            if ((((XLogPageHeader)pageBuffer)->xlp_info & XLP_LONG_HEADER) )

                                     printf("XLP_LONG_HEADER ");

#if PG_VERSION_NUM >= 90200

                            if ((((XLogPageHeader)pageBuffer)->xlp_info & XLP_BKP_REMOVABLE) )

                                     printf("XLP_BKP_REMOVABLE ");

#endif

                           

                            printf("\n");

                   }

 

                   return true;

         }

         if (nread != 0)

         {

                   fprintf(stderr, "Partial page of %d bytes ignored\n",

                            (int) nread);

         }

         return false;

}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章