您好,登錄后才能下訂單哦!
本節重點跟蹤分析了XLogRecordAssemble函數中對FPW(full-page-write)的處理過程。
全局靜態變量
XLogRecordAssemble使用的全局變量包括hdr_rdt/hdr_scratch/rdatas等.
/* flags for the in-progress insertion */
//用于插入過程中的標記信息
static uint8 curinsert_flags = 0;
/*
* These are used to hold the record header while constructing a record.
* 'hdr_scratch' is not a plain variable, but is palloc'd at initialization,
* because we want it to be MAXALIGNed and padding bytes zeroed.
* 在構建XLOG Record時通常會存儲記錄的頭部信息.
* 'hdr_scratch'并不是一個普通(plain)變量,而是在初始化時通過palloc初始化,
* 因為我們希望該變量已經是MAXALIGNed并且已被0x00填充.
*
* For simplicity, it's allocated large enough to hold the headers for any
* WAL record.
* 簡單起見,該變量預先會分配足夠大的空間用于存儲所有WAL Record的頭部信息.
*/
static XLogRecData hdr_rdt;
static char *hdr_scratch = NULL;
#define SizeOfXlogOrigin (sizeof(RepOriginId) + sizeof(char))
#define HEADER_SCRATCH_SIZE \
(SizeOfXLogRecord + \
MaxSizeOfXLogRecordBlockHeader * (XLR_MAX_BLOCK_ID + 1) + \
SizeOfXLogRecordDataHeaderLong + SizeOfXlogOrigin)
/*
* An array of XLogRecData structs, to hold registered data.
* XLogRecData結構體數組,存儲已注冊的數據.
*/
static XLogRecData *rdatas;
static int num_rdatas; /* entries currently used */
//已分配的空間大小
static int max_rdatas; /* allocated size */
//是否調用XLogBeginInsert函數
static bool begininsert_called = false;
static XLogCtlData *XLogCtl = NULL;
/* flags for the in-progress insertion */
static uint8 curinsert_flags = 0;
/*
* A chain of XLogRecDatas to hold the "main data" of a WAL record, registered
* with XLogRegisterData(...).
* 存儲WAL Record "main data"的XLogRecDatas數據鏈
*/
static XLogRecData *mainrdata_head;
static XLogRecData *mainrdata_last = (XLogRecData *) &mainrdata_head;
//鏈中某個位置的mainrdata大小
static uint32 mainrdata_len; /* total # of bytes in chain */
/*
* ProcLastRecPtr points to the start of the last XLOG record inserted by the
* current backend. It is updated for all inserts. XactLastRecEnd points to
* end+1 of the last record, and is reset when we end a top-level transaction,
* or start a new one; so it can be used to tell if the current transaction has
* created any XLOG records.
* ProcLastRecPtr指向當前后端插入的最后一條XLOG記錄的開頭。
* 它針對所有插入進行更新。
* XactLastRecEnd指向最后一條記錄的末尾位置 + 1,
* 并在結束頂級事務或啟動新事務時重置;
* 因此,它可以用來判斷當前事務是否創建了任何XLOG記錄。
*
* While in parallel mode, this may not be fully up to date. When committing,
* a transaction can assume this covers all xlog records written either by the
* user backend or by any parallel worker which was present at any point during
* the transaction. But when aborting, or when still in parallel mode, other
* parallel backends may have written WAL records at later LSNs than the value
* stored here. The parallel leader advances its own copy, when necessary,
* in WaitForParallelWorkersToFinish.
* 在并行模式下,這可能不是完全是最新的。
* 在提交時,事務可以假定覆蓋了用戶后臺進程或在事務期間出現的并行worker進程的所有xlog記錄。
* 但是,當中止時,或者仍然處于并行模式時,其他并行后臺進程可能在較晚的LSNs中寫入了WAL記錄,
* 而不是存儲在這里的值。
* 當需要時,并行處理進程的leader在WaitForParallelWorkersToFinish中會推進自己的副本。
*/
XLogRecPtr ProcLastRecPtr = InvalidXLogRecPtr;
XLogRecPtr XactLastRecEnd = InvalidXLogRecPtr;
XLogRecPtr XactLastCommitEnd = InvalidXLogRecPtr;
/* For WALInsertLockAcquire/Release functions */
//用于WALInsertLockAcquire/Release函數
static int MyLockNo = 0;
static bool holdingAllLocks = false;
宏定義
XLogRegisterBuffer函數使用的flags
/* flags for XLogRegisterBuffer */
//XLogRegisterBuffer函數使用的flags
#define REGBUF_FORCE_IMAGE 0x01 /* 強制執行full-page-write;force a full-page image */
#define REGBUF_NO_IMAGE 0x02 /* 不需要FPI;don't take a full-page image */
#define REGBUF_WILL_INIT (0x04 | 0x02) /* 在回放時重新初始化page(表示NO_IMAGE);
* page will be re-initialized at
* replay (implies NO_IMAGE) */
#define REGBUF_STANDARD 0x08 /* 標準的page layout(數據在pd_lower和pd_upper之間的數據會被跳過)
* page follows "standard" page layout,
* (data between pd_lower and pd_upper
* will be skipped) */
#define REGBUF_KEEP_DATA 0x10 /* include data even if a full-page image
* is taken */
/*
* Flag bits for the record being inserted, set using XLogSetRecordFlags().
*/
#define XLOG_INCLUDE_ORIGIN 0x01 /* include the replication origin */
#define XLOG_MARK_UNIMPORTANT 0x02 /* record not important for durability */
XLogRecData
xloginsert.c中的函數構造一個XLogRecData結構體鏈用于標識最后的WAL記錄
/*
* The functions in xloginsert.c construct a chain of XLogRecData structs
* to represent the final WAL record.
* xloginsert.c中的函數構造一個XLogRecData結構體鏈用于標識最后的WAL記錄
*/
typedef struct XLogRecData
{
//鏈中的下一個結構體,如無則為NULL
struct XLogRecData *next; /* next struct in chain, or NULL */
//rmgr數據的起始地址
char *data; /* start of rmgr data to include */
//rmgr數據大小
uint32 len; /* length of rmgr data to include */
} XLogRecData;
registered_buffer
對于每一個使用XLogRegisterBuffer注冊的每個數據塊,填充到registered_buffer結構體中
/*
* For each block reference registered with XLogRegisterBuffer, we fill in
* a registered_buffer struct.
* 對于每一個使用XLogRegisterBuffer注冊的每個數據塊,
* 填充到registered_buffer結構體中
*/
typedef struct
{
//slot是否在使用?
bool in_use; /* is this slot in use? */
//REGBUF_* 相關標記
uint8 flags; /* REGBUF_* flags */
//定義關系和數據庫的標識符
RelFileNode rnode; /* identifies the relation and block */
//fork進程編號
ForkNumber forkno;
//塊編號
BlockNumber block;
//頁內容
Page page; /* page content */
//rdata鏈中的數據總大小
uint32 rdata_len; /* total length of data in rdata chain */
//使用該數據塊注冊的數據鏈頭
XLogRecData *rdata_head; /* head of the chain of data registered with
* this block */
//使用該數據塊注冊的數據鏈尾
XLogRecData *rdata_tail; /* last entry in the chain, or &rdata_head if
* empty */
//臨時rdatas數據引用,用于存儲XLogRecordAssemble()中使用的備份塊數據
XLogRecData bkp_rdatas[2]; /* temporary rdatas used to hold references to
* backup block data in XLogRecordAssemble() */
/* buffer to store a compressed version of backup block image */
//用于存儲壓縮版本的備份塊鏡像的緩存
char compressed_page[PGLZ_MAX_BLCKSZ];
} registered_buffer;
//registered_buffer指針(全局變量)
static registered_buffer *registered_buffers;
//已分配的大小
static int max_registered_buffers; /* allocated size */
//最大塊號 + 1(當前注冊塊)
static int max_registered_block_id = 0; /* highest block_id + 1 currently
* registered */
rmid(Resource Manager ID)的定義
0 XLOG
1 Transaction
2 Storage
3 CLOG
4 Database
5 Tablespace
6 MultiXact
7 RelMap
8 Standby
9 Heap2
10 Heap
11 Btree
12 Hash
13 Gin
14 Gist
15 Sequence
16 SPGist
XLogRecordAssemble函數從已注冊的數據和緩沖區中組裝XLOG record到XLogRecData鏈中,組裝完成后可以使用XLogInsertRecord()函數插入到WAL buffer中.
詳見上一小節
場景二:在數據表中插入第n條記錄
測試腳本如下:
testdb=# drop table t_wal_normal;
DROP TABLE
testdb=# create table t_wal_normal(c1 int not null,c2 varchar(40),c3 varchar(40));
CREATE TABLE
testdb=# insert into t_wal_normal(c1,c2,c3) select i,'C2-'||i,'C3-'||i from generate_series(1,8191) as i;
INSERT 0 8191
testdb=# select pg_size_pretty(pg_relation_size('t_wal_normal'));
pg_size_pretty
----------------
424 kB
(1 row)
testdb=# checkpoint;
CHECKPOINT
testdb=# insert into t_wal_normal(c1,c2,c3) VALUES(8192,'C2-8192','C3-8192');
設置斷點,進入XLogRecordAssemble
(gdb) b XLogRecordAssemble
Breakpoint 1 at 0x565411: file xloginsert.c, line 488.
(gdb) c
Continuing.
Breakpoint 1, XLogRecordAssemble (rmid=10 '\n', info=0 '\000', RedoRecPtr=5509173376, doPageWrites=true,
fpw_lsn=0x7ffd7eb51408) at xloginsert.c:488
488 uint32 total_len = 0;
輸入參數:
rmid=10即0x0A --> Heap
info=0 '\000'
RedoRecPtr=5509173376,十六進制值為0x00000001485F5080
doPageWrites=true,需要full-page-write
fpw_lsn=0x7ffd7eb51408(fpw是full-page-write的簡稱,注意該變量仍未賦值)
接下來是變量賦值.
hdr_scratch的定義為:static char *hdr_scratch = NULL;
hdr_rdt的定義為:static XLogRecData hdr_rdt;
(gdb) n
491 registered_buffer *prev_regbuf = NULL;
(gdb)
494 char *scratch = hdr_scratch;
(gdb)
502 rechdr = (XLogRecord *) scratch;
(gdb)
503 scratch += SizeOfXLogRecord;
(gdb) p *(XLogRecord *)rechdr
$1 = {xl_tot_len = 0, xl_xid = 0, xl_prev = 0, xl_info = 0 '\000', xl_rmid = 0 '\000', xl_crc = 0}
(gdb) p hdr_scratch
$2 = 0x1f6a4c0 ""
(gdb)
配置hdr_rdt(用于存儲header信息)
(gdb) n
505 hdr_rdt.next = NULL;
(gdb)
506 rdt_datas_last = &hdr_rdt;
(gdb) n
507 hdr_rdt.data = hdr_scratch;
(gdb)
515 if (wal_consistency_checking[rmid])
full-page-write's LSN初始化
(gdb) n
523 *fpw_lsn = InvalidXLogRecPtr;
(gdb)
524 for (block_id = 0; block_id < max_registered_block_id; block_id++)
(gdb) p max_registered_block_id
$7 = 1
開始循環,獲取regbuf.
regbuf是使用
(gdb) n
526 registered_buffer *regbuf = ®istered_buffers[block_id];
(gdb)
531 XLogRecordBlockCompressHeader cbimg = {0};
(gdb)
533 bool is_compressed = false;
(gdb) p *regbuf
$3 = {in_use = true, flags = 8 '\b', rnode = {spcNode = 1663, dbNode = 16402, relNode = 25271}, forkno = MAIN_FORKNUM,
block = 52, page = 0x7f391f91b380 "\001", rdata_len = 26, rdata_head = 0x1f6a2c0, rdata_tail = 0x1f6a2d8, bkp_rdatas = {{
next = 0x0, data = 0x0, len = 0}, {next = 0x0, data = 0x0, len = 0}}, compressed_page = '\000' <repeats 8195 times>}
(gdb)
################
testdb=# select oid,relname,reltablespace from pg_class where relfilenode = 25271;
oid | relname | reltablespace
-------+--------------+---------------
25271 | t_wal_normal | 0
(1 row)
##############
注意:
在內存中,main data已由函數XLogRegisterData注冊,由mainrdata_head和mainrdata_last指針維護,本例中,填充了xl_heap_insert結構體.
block data由XLogRegisterBuffer初始化,通過XLogRegisterBufData注冊(填充)數據,分別是xl_heap_header結構體和實際數據(實質上是char *指針,最終填充的數據,由組裝器確定).
1.main data
(gdb) p *mainrdata_head
$4 = {next = 0x0, data = 0x7ffd7eb51480 "\r", len = 3}
(gdb) p *(xl_heap_insert *)regbuf->rdata_head->data
$8 = {offnum = 3, flags = 2 '\002'}
(gdb)
2.block data -> xl_heap_header
(gdb) p *regbuf->rdata_head
$6 = {next = 0x1f6a2d8, data = 0x7ffd7eb51470 "\003", len = 5}
(gdb) p *(xl_heap_header *)regbuf->rdata_head->data
$7 = {t_infomask2 = 3, t_infomask = 2050, t_hoff = 24 '\030'}
(gdb)
3.block data -> tuple data
(gdb) p *regbuf->rdata_head->next
$9 = {next = 0x0, data = 0x1feb07f "", len = 21}
查看地址0x1feb07f開始的21個字節數據,指向實際的數據.
第一個字段:首字節0 '\000'是類型標識符(INT,注:未最終確認),后續4個字節是32bit整型0x00002000,即整數8192.
第二個字段:首字節 17 '\021'是類型標識符(VARCHAR,注:未最終確認),后續是實際數據,即C2-8192
第三個字段:與第二個字段類似(C3-8192)
(gdb) x/21bc 0x1feb07f
0x1feb07f: 0 '\000' 0 '\000' 32 ' ' 0 '\000' 0 '\000' 17 '\021' 67 'C' 50 '2'
0x1feb087: 45 '-' 56 '8' 49 '1' 57 '9' 50 '2' 17 '\021' 67 'C' 51 '3'
0x1feb08f: 45 '-' 56 '8' 49 '1' 57 '9' 50 '2'
(gdb)
4.block data -> backup block image
這部分內容由XLogRecordAssemble()函數填充.
繼續執行后續邏輯,regbuf->flags=0x08表示REGBUF_STANDARD(標準的page layout)
(gdb) n
536 if (!regbuf->in_use)
(gdb)
540 if (regbuf->flags & REGBUF_FORCE_IMAGE)
(gdb) p regbuf->flags
$10 = 8 '\b'
doPageWrites = T,需要執行full-page-write.
page_lsn = 5509173336,十六進制值為0x00000001485F5058,邏輯ID為0x00000001,物理ID為0x00000048,segment file文文件名稱為00000001 00000001 00000048(時間線為0x00000001),文件內偏移為0x5F5058.
(gdb) n
542 else if (regbuf->flags & REGBUF_NO_IMAGE)
(gdb)
544 else if (!doPageWrites)
(gdb)
553 XLogRecPtr page_lsn = PageGetLSN(regbuf->page);
(gdb)
555 needs_backup = (page_lsn <= RedoRecPtr);
(gdb) p page_lsn
$11 = 5510687552
(gdb) p RedoRecPtr
$12 = 5510687592
需要執行full-page-write
(gdb) n
556 if (!needs_backup)
(gdb) p needs_backup
$20 = true
(gdb)
判斷是否需要tuple data(needs_data標記)
(gdb) n
564 if (regbuf->rdata_len == 0)
(gdb) n
566 else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0)
(gdb)
569 needs_data = !needs_backup;
(gdb)
571 bkpb.id = block_id;
(gdb) p needs_data
$14 = false
(gdb)
配置BlockHeader
(gdb) n
572 bkpb.fork_flags = regbuf->forkno;
(gdb)
573 bkpb.data_length = 0;
(gdb)
575 if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT)
(gdb)
582 include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
(gdb)
584 if (include_image)
(gdb) p bkpb
$15 = {id = 0 '\000', fork_flags = 0 '\000', data_length = 0}
(gdb) p include_image
$16 = true
(gdb)
要求包含塊鏡像(FPI),獲取相應的page(64bit的指針)
(gdb) n
586 Page page = regbuf->page;
(gdb)
587 uint16 compressed_len = 0;
(gdb)
593 if (regbuf->flags & REGBUF_STANDARD)
(gdb) p page
$17 = (Page) 0x7f391f91b380 "\001"
查看page內容
(gdb) x/8192bx 0x7f391f91b380
0x7f391f91b380: 0x01 0x00 0x00 0x00 0x40 0x6b 0x76 0x48
0x7f391f91b388: 0x00 0x00 0x00 0x00 0x4c 0x00 0x90 0x1d
0x7f391f91b390: 0x00 0x20 0x04 0x20 0x00 0x00 0x00 0x00
0x7f391f91b398: 0xd0 0x9f 0x58 0x00 0xa0 0x9f 0x58 0x00
0x7f391f91b3a0: 0x70 0x9f 0x58 0x00 0x40 0x9f 0x58 0x00
0x7f391f91b3a8: 0x10 0x9f 0x58 0x00 0xe0 0x9e 0x58 0x00
0x7f391f91b3b0: 0xb0 0x9e 0x58 0x00 0x80 0x9e 0x58 0x00
0x7f391f91b3b8: 0x50 0x9e 0x58 0x00 0x20 0x9e 0x58 0x00
0x7f391f91b3c0: 0xf0 0x9d 0x58 0x00 0xc0 0x9d 0x58 0x00
0x7f391f91b3c8: 0x90 0x9d 0x58 0x00 0x00 0x00 0x00 0x00
0x7f391f91b3d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7f391f91b3d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7f391f91b3e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 --> 頭部數據
...
0x7f391f91d330: 0x02 0x00 0x03 0x00 0x02 0x09 0x18 0x00
0x7f391f91d338: 0xf5 0x1f 0x00 0x00 0x11 0x43 0x32 0x2d
0x7f391f91d340: 0x38 0x31 0x38 0x31 0x11 0x43 0x33 0x2d
0x7f391f91d348: 0x38 0x31 0x38 0x31 0x00 0x00 0x00 0x00
0x7f391f91d350: 0xe7 0x07 0x00 0x00 0x00 0x00 0x00 0x00
0x7f391f91d358: 0x00 0x00 0x00 0x00 0x00 0x00 0x34 0x00
0x7f391f91d360: 0x01 0x00 0x03 0x00 0x02 0x09 0x18 0x00
0x7f391f91d368: 0xf4 0x1f 0x00 0x00 0x11 0x43 0x32 0x2d
0x7f391f91d370: 0x38 0x31 0x38 0x30 0x11 0x43 0x33 0x2d
0x7f391f91d378: 0x38 0x31 0x38 0x30 0x00 0x00 0x00 0x00 --> 部分尾部數據
換用字符格式查看0x7f391f91d330開始的數據
(gdb) x/80bc 0x7f391f91d330
0x7f391f91d330: 2 '\002' 0 '\000' 3 '\003' 0 '\000' 2 '\002' 9 '\t' 24 '\030' 0 '\000'
0x7f391f91d338: -11 '\365' 31 '\037' 0 '\000' 0 '\000' 17 '\021' 67 'C' 50 '2' 45 '-'
0x7f391f91d340: 56 '8' 49 '1' 56 '8' 49 '1' 17 '\021' 67 'C' 51 '3' 45 '-'
0x7f391f91d348: 56 '8' 49 '1' 56 '8' 49 '1' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7f391f91d350: -25 '\347' 7 '\a' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
0x7f391f91d358: 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 0 '\000' 52 '4' 0 '\000'
0x7f391f91d360: 1 '\001' 0 '\000' 3 '\003' 0 '\000' 2 '\002' 9 '\t' 24 '\030' 0 '\000'
0x7f391f91d368: -12 '\364' 31 '\037' 0 '\000' 0 '\000' 17 '\021' 67 'C' 50 '2' 45 '-'
0x7f391f91d370: 56 '8' 49 '1' 56 '8' 48 '0' 17 '\021' 67 'C' 51 '3' 45 '-'
0x7f391f91d378: 56 '8' 49 '1' 56 '8' 48 '0' 0 '\000' 0 '\000' 0 '\000' 0 '\000'
(gdb)
標準塊(REGBUF_STANDARD),獲取lower&upper,并設置hole信息
(gdb) n
596 uint16 lower = ((PageHeader) page)->pd_lower;
(gdb)
597 uint16 upper = ((PageHeader) page)->pd_upper;
(gdb)
599 if (lower >= SizeOfPageHeaderData &&
(gdb) p lower
$18 = 76
(gdb) p upper
$19 = 7568
(gdb) n
600 upper > lower &&
(gdb)
603 bimg.hole_offset = lower;
(gdb)
604 cbimg.hole_length = upper - lower;
(gdb) n
623 if (wal_compression)
(gdb) p bimg
$22 = {length = 49648, hole_offset = 76, bimg_info = 0 '\000'}
(gdb) p cbimg
$23 = {hole_length = 7492}
(gdb)
沒有啟用壓縮,則不嘗試壓縮block
(gdb) p wal_compression
$24 = false
(gdb)
設置標記BKPBLOCK_HAS_IMAGE
(gdb) n
636 bkpb.fork_flags |= BKPBLOCK_HAS_IMAGE;
(gdb)
641 rdt_datas_last->next = ®buf->bkp_rdatas[0];
(gdb)
設置相關信息
(gdb)
641 rdt_datas_last->next = ®buf->bkp_rdatas[0];
(gdb) n
642 rdt_datas_last = rdt_datas_last->next;
(gdb)
644 bimg.bimg_info = (cbimg.hole_length == 0) ? 0 : BKPIMAGE_HAS_HOLE;
(gdb)
652 if (needs_backup)
設置標記BKPIMAGE_APPLY
(gdb) n
653 bimg.bimg_info |= BKPIMAGE_APPLY;
(gdb)
655 if (is_compressed)
(gdb) p bimg
$26 = {length = 49648, hole_offset = 76, bimg_info = 5 '\005'}
沒有壓縮存儲,設置相關信息
(gdb) p is_compressed
$27 = false
(gdb) n
665 bimg.length = BLCKSZ - cbimg.hole_length;
(gdb)
667 if (cbimg.hole_length == 0)
(gdb)
(gdb) p bimg
$28 = {length = 700, hole_offset = 76, bimg_info = 5 '\005'}
設置rdt_datas_last變量,構建hdr_rdt鏈表,分別指向hole前面部分hole后面部分
675 rdt_datas_last->data = page;
(gdb)
676 rdt_datas_last->len = bimg.hole_offset;
(gdb)
678 rdt_datas_last->next = ®buf->bkp_rdatas[1];
(gdb)
679 rdt_datas_last = rdt_datas_last->next;
(gdb)
682 page + (bimg.hole_offset + cbimg.hole_length);
(gdb)
681 rdt_datas_last->data =
(gdb)
684 BLCKSZ - (bimg.hole_offset + cbimg.hole_length);
(gdb)
683 rdt_datas_last->len =
(gdb)
688 total_len += bimg.length;
查看hdr_rdt相關信息
(gdb) p hdr_rdt
$31 = {next = 0x1f6c218, data = 0x1f6a4c0 "", len = 0}
(gdb) p *hdr_rdt->next
$34 = {next = 0x1f6c230, data = 0x7f391f91b380 "\001", len = 76}
(gdb) p *hdr_rdt->next->next
$35 = {next = 0x0, data = 0x7f391f91d110 "\351\a", len = 624}
(gdb)
設置大小
(gdb) n
691 if (needs_data)
(gdb) p total_len
$36 = 700
(gdb)
不需要處理tuple data,不是同一個REL
(gdb) p needs_data
$37 = false
(gdb)
(gdb) n
705 if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode))
(gdb) p prev_regbuf
$38 = (registered_buffer *) 0x0
(gdb) n
711 samerel = false;
(gdb)
712 prev_regbuf = regbuf;
(gdb)
拷貝頭部信息到scratch緩沖區中
(gdb)
715 memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);
(gdb)
716 scratch += SizeOfXLogRecordBlockHeader;
(gdb)
包含FPI,追加SizeOfXLogRecordBlockImageHeader
(gdb) n
717 if (include_image)
(gdb)
719 memcpy(scratch, &bimg, SizeOfXLogRecordBlockImageHeader);
(gdb)
720 scratch += SizeOfXLogRecordBlockImageHeader;
(gdb)
721 if (cbimg.hole_length != 0 && is_compressed)
(gdb)
728 if (!samerel)
(gdb)
不是同一個REL,追加RelFileNode
728 if (!samerel)
(gdb)
730 memcpy(scratch, ®buf->rnode, sizeof(RelFileNode));
(gdb)
731 scratch += sizeof(RelFileNode);
(gdb)
后跟blocknumber
733 memcpy(scratch, ®buf->block, sizeof(BlockNumber));
(gdb)
734 scratch += sizeof(BlockNumber);
繼續下一個block
(gdb)
524 for (block_id = 0; block_id < max_registered_block_id; block_id++)
(gdb)
已處理完畢,接下來,是XLOG Record origin(不需要)
(gdb) n
738 if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
(gdb)
739 replorigin_session_origin != InvalidRepOriginId)
(gdb)
738 if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
(gdb)
747 if (mainrdata_len > 0)
(gdb)
接下來是main data,使用XLR_BLOCK_ID_DATA_SHORT格式
(gdb) n
749 if (mainrdata_len > 255)
(gdb)
757 *(scratch++) = (char) XLR_BLOCK_ID_DATA_SHORT;
(gdb) p mainrdata_len
$39 = 3
(gdb)
調整rdt_datas_last變量信息,調整總大小
(gdb) n
758 *(scratch++) = (uint8) mainrdata_len;
(gdb)
760 rdt_datas_last->next = mainrdata_head;
(gdb)
761 rdt_datas_last = mainrdata_last;
(gdb)
762 total_len += mainrdata_len;
(gdb)
764 rdt_datas_last->next = NULL;
(gdb) p total_len
$40 = 703
(gdb)
調整hdr_rdt信息
(gdb) n
766 hdr_rdt.len = (scratch - hdr_scratch);
(gdb)
767 total_len += hdr_rdt.len;
(gdb)
777 INIT_CRC32C(rdata_crc);
(gdb) p hdr_rdt
$41 = {next = 0x1f6c218, data = 0x1f6a4c0 "", len = 51}
(gdb) p total_len
$42 = 754
(gdb)
計算CRC
(gdb)
779 for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb)
780 COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
(gdb)
779 for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb)
780 COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
(gdb)
779 for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb)
780 COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
(gdb)
779 for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb)
787 rechdr->xl_xid = GetCurrentTransactionIdIfAny();
(gdb)
填充記錄頭部信息的其他域字段.
(gdb) n
788 rechdr->xl_tot_len = total_len;
(gdb)
789 rechdr->xl_info = info;
(gdb)
790 rechdr->xl_rmid = rmid;
(gdb)
791 rechdr->xl_prev = InvalidXLogRecPtr;
(gdb)
792 rechdr->xl_crc = rdata_crc;
(gdb)
794 return &hdr_rdt;
(gdb) p *(XLogRecord *)rechdr
$43 = {xl_tot_len = 754, xl_xid = 2025, xl_prev = 0, xl_info = 0 '\000', xl_rmid = 10 '\n', xl_crc = 1615792998}
(gdb)
返回hdr_rdt
(gdb) n
795 }
(gdb)
XLogInsert (rmid=10 '\n', info=0 '\000') at xloginsert.c:462
462 EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags);
(gdb)
(gdb) p *rdt
$44 = {next = 0x1f6c218, data = 0x1f6a4c0 "\362\002", len = 51}
(gdb) p fpw_lsn
$45 = 0
(gdb) p curinsert_flags
$46 = 1 '\001'
(gdb)
DONE!
Write Ahead Logging — WAL
PostgreSQL 源碼解讀(4)- 插入數據#3(heap_insert)
PostgreSQL 事務日志WAL結構淺析
PostgreSQL 源碼解讀(110)- WAL#6(Insert&WAL - XLogRecordAssemble記錄組裝函數)
PG Source Code
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。