概述
內(nèi)核提供cbm(changed block map)功能,對(duì)外提供數(shù)據(jù)頁(yè)面的修改情況,并向提供外部接口,根據(jù)cbm信息可直接獲取兩次備份之間發(fā)生對(duì)于數(shù)據(jù)文件(行存、列存)的增量修改信息,并備份。
實(shí)現(xiàn)原理:
數(shù)據(jù)庫(kù)所有的增量修改都會(huì)記錄在xlog中,通過(guò)cbm writer常駐線程,持續(xù)解析新增xlog,識(shí)別并記錄下哪些數(shù)據(jù)頁(yè)面被修改。
CBM writer
在startup線程剛啟動(dòng)時(shí),其根據(jù)已經(jīng)解析出來(lái)的cbm文件,來(lái)決定cbm writer開始解析的起始lsn位置。然后,每次執(zhí)行到checkpoint末尾時(shí),會(huì)設(shè)置cbm writer線程的latch。cbm writer線程一直在一個(gè)死循環(huán)中等待latch被設(shè)置,然后進(jìn)行一輪日志解析。
強(qiáng)制初始化邏輯

獲取解析范圍
上一次結(jié)束的位置就是開始的位置。
結(jié)束位置,要么是最近的checkpoint重做點(diǎn)位置,要么是強(qiáng)制刷新的CBM位置。
關(guān)鍵結(jié)構(gòu)
Hash表

CbmPageHeader
typedef struct cbmpageheader {
pg_crc32c pageCrc;
bool isLastBlock;
uint8 pageType;
XLogRecPtr pageStartLsn;
XLogRecPtr pageEndLsn;
RelFileNode rNode;
ForkNumber forkNum;
BlockNumber firstBlkNo;
BlockNumber truncBlkNo;
} CbmPageHeader;
解析過(guò)程
插入hash表
按page讀取xlog
對(duì)page里所有修改的block進(jìn)行遍歷
按照這個(gè)順序找到自己在hash表中的位置插入,HashEntry -> segEntry -> pageEntry
刷盤
獲取一個(gè)HashEntry上的所有page
按照f(shuō)irstBlkNo從小到大進(jìn)行排序
刷入磁盤文件
CBM文件
cbm文件保存在data目錄的pg_cbm文件夾下,命名方式為:pg_xlog_seqnum_startlsn_endlsn.cbm。
其中,seqnum表示這是第幾個(gè)cbm文件,當(dāng)一個(gè)cbm文件的大小超過(guò)128M時(shí),將會(huì)切換到下一個(gè)cbm文件,并將seqnum加1,。startlsn為本cbm文件內(nèi)容對(duì)應(yīng)xlog記錄的起始lsn,endlsn為本cbm文件切換時(shí)最后一次解析的截止lsn。若一個(gè)cbm文件還沒(méi)有切換,那么endlsn為0。
cbm文件中一個(gè)page是512個(gè)字節(jié)。其中頭文件56個(gè)字節(jié)(已經(jīng)字節(jié)對(duì)齊)??捎米止?jié)為456個(gè)字節(jié),每個(gè)字節(jié)可以表示8個(gè)block的變更,那么一個(gè)page就可以表示3648個(gè)變更的block。1G文件,用4個(gè)page就可以完全表示所有變更的block。

增量備份
首先用pg_cbm_tracked_location函數(shù)獲取已經(jīng)track的cbm的LSN號(hào)作為end LSN,獲取父?jìng)浞莸膕tart LSN作為start LSN。(?為啥不是stop)
然后調(diào)用pg_cbm_get_changed_block(start_LSN, end_LSN)可以獲取文件路徑,改變的block數(shù)量,和block no列表。
pg_cbm_get_changed_block操作首先讀取所有cbm文件,選擇LSN在范圍內(nèi)的page(通過(guò)pageHeader)。
然后將這些page組成上面一樣的Hash(組成hash的過(guò)程其實(shí)也就在進(jìn)行合并),最后再把這些整個(gè)hash轉(zhuǎn)為一個(gè)數(shù)組返回。