上一篇文章講了下xlog的頭部,今天詳細講解下record部分,希望這兩篇文章對研究postgresql的xlog的同學有所幫助:
本文來自:http://blog.csdn.net/lengzijian/article/details/7840332
首先看下XLOG日誌記錄結構:
XLogRecord記錄了XLOG的相關控制信息,數據結構如下:
typedef struct XLogRecord { pg_crc32 xl_crc; /* 本條記錄的CRC校驗碼 */ XLogRecPtr xl_prev; /* 日誌的前一條記錄 */ TransactionId xl_xid; /* 事務ID */ uint32 xl_tot_len; /* 整條記錄的總長度*/ uint32 xl_len; /* 組員管理器的數據長度*/ uint8 xl_info; /* 信息標誌位 */ RmgrId xl_rmid; /* 資源管理器IDtypedef uint8 RmgrId;*/ } XLogRecord; |
其中,資源管理器ID主要用於日誌系統中,數據庫系統把各種需要記錄日誌的數據分類,分配給他們對應的資源管理號,系統在回覆或者讀取日誌記錄時,能夠很方便地知道該日誌記錄的元數據屬於哪一類,結合信息標誌位(xl_info)信息,就能知道數據庫對元數據做的是那種操作。共有16中資源(有幾項還不清楚是做什麼用的):
#define RM_XLOG_ID 0 該條日誌記錄的是一個檢查點信息。 #define RM_XACT_ID 1 該條日誌記錄的是一個事物的提交或者終止信息 #define RM_SMGR_ID 2 #define RM_CLOG_ID 3 CLOG中某一頁的初始化 #define RM_DBASE_ID 4 #define RM_TBLSPC_ID 5 #define RM_MULTIXACT_ID 6 #define RM_RELMAP_ID 7 #define RM_STANDBY_ID 8 #define RM_HEAP2_ID 9 #define RM_HEAP_ID 10 該條日誌記錄的是對隊中元組進行修改的信息 #define RM_BTREE_ID 11 該條日誌記錄的是對BTree進行修改 #define RM_HASH_ID 12 #define RM_GIN_ID 13 #define RM_GIST_ID 14 #define RM_SEQ_ID 15 |
信息標誌位(xl_info)的高四位由資源管理器使用,表示該日誌是哪種類型的日誌,低四位表示對應的塊是否需要備份,對於高四位,信息有如下幾種:
/* include/access/xact.h * XLOG allows to store some information in high 4 bits of log * record xl_info field */ #define XLOG_XACT_COMMIT 0x00 //事務提交 #define XLOG_XACT_PREPARE 0x10 //預備 #define XLOG_XACT_ABORT 0x20 //事務取消 #define XLOG_XACT_COMMIT_PREPARED 0x30 //準備提交事務 #define XLOG_XACT_ABORT_PREPARED 0x40 //準備取消事務 #define XLOG_XACT_ASSIGNMENT 0x50 //不詳。。。(之後補充)
/*include/access/htup.h * WAL record definitions for heapam.c's WAL operations * XLOG allows to store some information in high 4 bitsof log * record xl_info field. We use 3 for opcode and one for init bit. */ #define XLOG_HEAP_INSERT 0x00 //插入元組日誌 #define XLOG_HEAP_DELETE 0x10 //刪除元組日誌 #define XLOG_HEAP_UPDATE 0x20 //更新元組日誌
細心的同學會發現,下面的元組操作和上面的事務操作的編碼(0x00)重複了,不要忘記之前我們說過,要通過xl_rmid字段來判斷屬於何種操作:先判斷屬於那種操作,在做具體的操作內容。 |
低四位中只用了三位,具體如下(可以看到最後一位沒有用到):
/*include/access/xlog.h * If we backed up any disk blocks with the XLOG record, we use flag bits in * xl_info to signal it. We support backup of up to 3 disk blocks per XLOG * record. */ #define XLR_BKP_BLOCK_MASK 0x0E /* all info bits used for bkp blocks */ #define XLR_MAX_BKP_BLOCKS 3 #define XLR_SET_BKP_BLOCK(iblk) (0x08 >> (iblk)) #define XLR_BKP_BLOCK_1 XLR_SET_BKP_BLOCK(0) /* 0x08 */ #define XLR_BKP_BLOCK_2 XLR_SET_BKP_BLOCK(1) /* 0x04 */ #define XLR_BKP_BLOCK_3 XLR_SET_BKP_BLOCK(2) /* 0x02 */ |
日誌記錄數據信息:
rmgr data 數據被XLogInsert()函數寫入,有一個或多個XlogRecData數據結構組成,當有多個XLogRecData結構體時有兩種情況:1.源數據沒有在內存上物理相鄰;2.數據在多個緩衝區中被指定。
如果buffer有效,那麼XLOG將會檢查buffer是否必須備份(即,是否該buffer自最後一次checkpoint以來,第一次被更改)。如果是這樣,那麼整個頁面內容會被附加到XLOG日誌中,同時,XLOG在標誌位xl_info中設置XLR_BKP_BLOCK_X位。注:當buffer備份後,我們不能夠通過XLogRecData結構體插入數據到XLOG記錄中,因爲我們假定他已經在buffer中了,因此rmgr的redo操作必須注意XLR_BKP_BLOCK_X的值,以便指導XLOG記錄中到底存的是什麼。
如果buffer有效,調用者必須設置buffer_std(緩衝區存儲標準),來表明頁面是否用標準pd_lower/pd_upper頭字段。
日誌記錄中的數據信息存儲在結構XlogRecData中(結構體如下):
typedef struct XLogRecData { char *data; /* 資源管理器數據 */ uint32 len; /* 資源管理器數據的長度 */ Buffer buffer; /* 該數據涉及的緩衝區*/ bool buffer_std; /* 緩衝區存儲標準 */ struct XLogRecData *next; /* 下一個節點指針 */ } XLogRecData; |
這裏保存了所有操作信息,在閱讀了xlogdump源碼之後發現,讀取xlog記錄不需要XLogRecData結構體,例如讀取插入操作時,只需要調用xl_heap_insert結構體就可以取出數據。
例如執行了一次insert,用xlogdump可以讀出下面的代碼(同樣的updata、delete以及事務操作commit和abort都在改數據內):
INSERT: 2 row(s) found in the table `t_user'. //有兩個字段在表“t_user”中 INSERT: column 0, name userid, type 1043, value '14541'//包括字段名,字段類型,字段的值都會在數據中取出,如果想了解具體細節可以看xlogdump的源碼。 INSERT: column 1, name name, type 1043, value 'lengzijian' |
XLOG記錄中的備份數據塊的頭部信息保存在BkpBlock中,數據結構如下:
typedef struct BkpBlock { RelFileNode node; /* 表節點*/ ForkNumber fork; /* 關係分支*/ BlockNumber block; /* 塊數 */ uint16 hole_offset; /* "hole"偏移值 */ uint16 hole_length; /* "hole"長度 */ /* 實際的塊數據在結構體之後 */ } BkpBlock; |
在用xlogdump工具時,發現一個問題,就是更新或插入時,有時不能夠打印出statements,例如:
lengzijian-----------record->xl_len[21]/SizeOfHeapUpdate:[28]/SizeOfHeapHeader:[5] //這裏我打印出他的判斷信息,由於(21 – 28 – 5)的無符號型大於MaxHeapTupleSize //所以退出,沒有打印出statements. [cur:0/4C6F0960, xid:5215584, rmid:10(Heap), len/tot_len:21/2781, info:9, prev:0/4C6F0910] insert: s/d/r:pg_default/lengzijian/t_user blk/off:758/61 header: none
[cur:0/4C6F0960, xid:5215584, rmid:10(Heap), len/tot_len:21/2781, info:9, prev:0/4C6F0910] bkpblock[1]: s/d/r:pg_default/lengzijian/t_user blk:758 hole_off/len:268/5484 //根據如上分析:是由於已經把數據備份到bkpblock[1]中,通過觀察日誌也可以看到,在之後,xlogdump把bkpblock也打印出來,說明xl_info的後低四位被設置了。 |
下一篇講解xlogdump工具的使用和部分源碼分析。