上一篇文章講了下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工具的使用和部分源碼分析。