PostgreSQL 소스 코드 판독 (110) - WAL \ # 6 (Insert & WAL - XLogRe...
데이터 구조
전역 정적 변수 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 */
2. 소스 코드 해독
XLogRecordAssemble 함 수 는 등 록 된 데이터 와 버퍼 에서 XLOG record 를 XLogRecData 체인 에 조립 하고 조립 이 완료 되면 XLogInsertRecord () 함 수 를 WAL buffer 에 삽입 할 수 있 습 니 다.
/*
* Assemble a WAL record from the registered data and buffers into an
* XLogRecData chain, ready for insertion with XLogInsertRecord().
* XLOG record XLogRecData ,
* XLogInsertRecord() .
*
* The record header fields are filled in, except for the xl_prev field. The
* calculated CRC does not include the record header yet.
* xl_prev ,XLOG Record header .
* CRC header .
*
* If there are any registered buffers, and a full-page image was not taken
* of all of them, *fpw_lsn is set to the lowest LSN among such pages. This
* signals that the assembled record is only good for insertion on the
* assumption that the RedoRecPtr and doPageWrites values were up-to-date.
* , full-page-image ,
* *fpw_lsn LSN.
* RedoRecPtr doPageWrites ,
* XLOG Record OK .
*/
static XLogRecData *
XLogRecordAssemble(RmgrId rmid, uint8 info,
XLogRecPtr RedoRecPtr, bool doPageWrites,
XLogRecPtr *fpw_lsn)
{
XLogRecData *rdt;//XLogRecData
uint32 total_len = 0;//XLOG Record
int block_id;// ID
pg_crc32c rdata_crc;//CRC
registered_buffer *prev_regbuf = NULL;// buffer
XLogRecData *rdt_datas_last;//
XLogRecord *rechdr;//
char *scratch = hdr_scratch;
/*
* Note: this function can be called multiple times for the same record.
* All the modifications we do to the rdata chains below must handle that.
* XLOG Record, .
* rdata .
*/
/* The record begins with the fixed-size header */
//XLOG Record .
rechdr = (XLogRecord *) scratch;
scratch += SizeOfXLogRecord;//
hdr_rdt.next = NULL;//hdr_rdt --> static XLogRecData hdr_rdt;
rdt_datas_last = &hdr_rdt;//
hdr_rdt.data = hdr_scratch;//rmgr
/*
* Enforce consistency checks for this record if user is looking for it.
* Do this before at the beginning of this routine to give the possibility
* for callers of XLogInsert() to pass XLR_CHECK_CONSISTENCY directly for
* a record.
* , .
* , XLogInsert()
* XLR_CHECK_CONSISTENCY XLOG Record.
*/
if (wal_consistency_checking[rmid])
info |= XLR_CHECK_CONSISTENCY;
/*
* Make an rdata chain containing all the data portions of all block
* references. This includes the data for full-page images. Also append
* the headers for the block references in the scratch buffer.
* rdata . FPI .
* , scratch .
*/
*fpw_lsn = InvalidXLogRecPtr;//
for (block_id = 0; block_id < max_registered_block_id; block_id++)// block
{
registered_buffer *regbuf = ®istered_buffers[block_id];// block_id
bool needs_backup;// backup block
bool needs_data;// data
XLogRecordBlockHeader bkpb;//XLogRecordBlockHeader
XLogRecordBlockImageHeader bimg;//XLogRecordBlockImageHeader
XLogRecordBlockCompressHeader cbimg = {0};//
bool samerel;// rel?
bool is_compressed = false;//
bool include_image;// FPI
if (!regbuf->in_use)// ,
continue;
/* Determine if this block needs to be backed up */
// block backup
if (regbuf->flags & REGBUF_FORCE_IMAGE)
needs_backup = true;// FPI
else if (regbuf->flags & REGBUF_NO_IMAGE)
needs_backup = false;// IMAGE
else if (!doPageWrites)
needs_backup = false;//doPageWrites F
else//doPageWrites = T
{
/*
* We assume page LSN is first data on *every* page that can be
* passed to XLogInsert, whether it has the standard page layout
* or not.
* page page layout,
* page page LSN,
*
*/
XLogRecPtr page_lsn = PageGetLSN(regbuf->page);// LSN
needs_backup = (page_lsn <= RedoRecPtr);// backup
if (!needs_backup)//
{
if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn)
*fpw_lsn = page_lsn;// LSN
}
}
/* Determine if the buffer data needs to included */
// buffer data
if (regbuf->rdata_len == 0)//
needs_data = false;
else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0)// data
needs_data = true;
else
needs_data = !needs_backup;//needs_backup
//BlockHeader
bkpb.id = block_id;// ID
bkpb.fork_flags = regbuf->forkno;//forkno
bkpb.data_length = 0;//
if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT)
bkpb.fork_flags |= BKPBLOCK_WILL_INIT;//
/*
* If needs_backup is true or WAL checking is enabled for current
* resource manager, log a full-page write for the current block.
* needs_backup T, RM WAL ,
* block full-page-write
*/
// backup
include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
if (include_image)
{
//
Page page = regbuf->page;// page
uint16 compressed_len = 0;//
/*
* The page needs to be backed up, so calculate its hole length
* and offset.
* page ,
*/
if (regbuf->flags & REGBUF_STANDARD)
{
// REGBUF
/* Assume we can omit data between pd_lower and pd_upper */
// pd_lower pd_upper
uint16 lower = ((PageHeader) page)->pd_lower;// lower
uint16 upper = ((PageHeader) page)->pd_upper;// upper
if (lower >= SizeOfPageHeaderData &&
upper > lower &&
upper <= BLCKSZ)
{
//lower Page && upper lower && upper
bimg.hole_offset = lower;
cbimg.hole_length = upper - lower;
}
else
{
/* No "hole" to remove */
//
bimg.hole_offset = 0;
cbimg.hole_length = 0;
}
}
else
{
// REGBUF
/* Not a standard page header, don't try to eliminate "hole" */
// page header, "hole"
bimg.hole_offset = 0;
cbimg.hole_length = 0;
}
/*
* Try to compress a block image if wal_compression is enabled
* wal_compression ,
*/
if (wal_compression)
{
is_compressed =
XLogCompressBackupBlock(page, bimg.hole_offset,
cbimg.hole_length,
regbuf->compressed_page,
&compressed_len);// XLogCompressBackupBlock
}
/*
* Fill in the remaining fields in the XLogRecordBlockHeader
* struct
* XLogRecordBlockHeader
*/
bkpb.fork_flags |= BKPBLOCK_HAS_IMAGE;
/*
* Construct XLogRecData entries for the page content.
* page XLogRecData
*/
rdt_datas_last->next = ®buf->bkp_rdatas[0];
rdt_datas_last = rdt_datas_last->next;
//
bimg.bimg_info = (cbimg.hole_length == 0) ? 0 : BKPIMAGE_HAS_HOLE;
/*
* If WAL consistency checking is enabled for the resource manager
* of this WAL record, a full-page image is included in the record
* for the block modified. During redo, the full-page is replayed
* only if BKPIMAGE_APPLY is set.
* WAL , block XLOG Record FPI.
* redo , BKPIMAGE_APPLY full-page .
*/
if (needs_backup)
bimg.bimg_info |= BKPIMAGE_APPLY;//
if (is_compressed)// ?
{
bimg.length = compressed_len;//
bimg.bimg_info |= BKPIMAGE_IS_COMPRESSED;//
rdt_datas_last->data = regbuf->compressed_page;// registered_buffer
rdt_datas_last->len = compressed_len;//
}
else
{
//
//image
bimg.length = BLCKSZ - cbimg.hole_length;
if (cbimg.hole_length == 0)
{
rdt_datas_last->data = page;// page
rdt_datas_last->len = BLCKSZ;// block size
}
else
{
/* must skip the hole */
// hole
rdt_datas_last->data = page;//
rdt_datas_last->len = bimg.hole_offset;// hole
rdt_datas_last->next = ®buf->bkp_rdatas[1];// 2
rdt_datas_last = rdt_datas_last->next;//
rdt_datas_last->data =
page + (bimg.hole_offset + cbimg.hole_length);//
rdt_datas_last->len =
BLCKSZ - (bimg.hole_offset + cbimg.hole_length);//
}
}
total_len += bimg.length;//
}
if (needs_data)//
{
/*
* Link the caller-supplied rdata chain for this buffer to the
* overall list.
* rdata
*/
bkpb.fork_flags |= BKPBLOCK_HAS_DATA;//
bkpb.data_length = regbuf->rdata_len;//
total_len += regbuf->rdata_len;//
rdt_datas_last->next = regbuf->rdata_head;//
rdt_datas_last = regbuf->rdata_tail;
}
// regbuf RefFileNode( / /block )
if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode))
{
samerel = true;//
bkpb.fork_flags |= BKPBLOCK_SAME_REL;// REL
}
else
samerel = false;
prev_regbuf = regbuf;// regbuf
/* Ok, copy the header to the scratch buffer */
// OK, scratch
memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);
scratch += SizeOfXLogRecordBlockHeader;//
if (include_image)
{
// FPI, SizeOfXLogRecordBlockImageHeader
memcpy(scratch, &bimg, SizeOfXLogRecordBlockImageHeader);
scratch += SizeOfXLogRecordBlockImageHeader;//
if (cbimg.hole_length != 0 && is_compressed)
{
// , SizeOfXLogRecordBlockCompressHeader
memcpy(scratch, &cbimg,
SizeOfXLogRecordBlockCompressHeader);
scratch += SizeOfXLogRecordBlockCompressHeader;//
}
}
if (!samerel)
{
// REL, RelFileNode
memcpy(scratch, ®buf->rnode, sizeof(RelFileNode));
scratch += sizeof(RelFileNode);//
}
// BlockNumber
memcpy(scratch, ®buf->block, sizeof(BlockNumber));
scratch += sizeof(BlockNumber);//
}
/* followed by the record's origin, if any */
// , XLOG Record origin
if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
replorigin_session_origin != InvalidRepOriginId)
{
//
*(scratch++) = (char) XLR_BLOCK_ID_ORIGIN;
memcpy(scratch, &replorigin_session_origin, sizeof(replorigin_session_origin));
scratch += sizeof(replorigin_session_origin);
}
/* followed by main data, if any */
// main data
if (mainrdata_len > 0)//main data > 0
{
if (mainrdata_len > 255)// 255, Long
{
*(scratch++) = (char) XLR_BLOCK_ID_DATA_LONG;
memcpy(scratch, &mainrdata_len, sizeof(uint32));
scratch += sizeof(uint32);
}
else// Short
{
*(scratch++) = (char) XLR_BLOCK_ID_DATA_SHORT;
*(scratch++) = (uint8) mainrdata_len;
}
rdt_datas_last->next = mainrdata_head;
rdt_datas_last = mainrdata_last;
total_len += mainrdata_len;
}
rdt_datas_last->next = NULL;
hdr_rdt.len = (scratch - hdr_scratch);//
total_len += hdr_rdt.len;//
/*
* Calculate CRC of the data
* CRC
*
* Note that the record header isn't added into the CRC initially since we
* don't know the prev-link yet. Thus, the CRC will represent the CRC of
* the whole record in the order: rdata, then backup blocks, then record
* header.
* prev-link , CRC .
* ,CRC CRC: rdata, backup blocks, record header。
*/
INIT_CRC32C(rdata_crc);
COMP_CRC32C(rdata_crc, hdr_scratch + SizeOfXLogRecord, hdr_rdt.len - SizeOfXLogRecord);
for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
COMP_CRC32C(rdata_crc, rdt->data, rdt->len);
/*
* Fill in the fields in the record header. Prev-link is filled in later,
* once we know where in the WAL the record will be inserted. The CRC does
* not include the record header yet.
* .
* Prev-link .
* CRC .
*/
rechdr->xl_xid = GetCurrentTransactionIdIfAny();
rechdr->xl_tot_len = total_len;
rechdr->xl_info = info;
rechdr->xl_rmid = rmid;
rechdr->xl_prev = InvalidXLogRecPtr;
rechdr->xl_crc = rdata_crc;
return &hdr_rdt;
}
3. 추적 분석
장면 1: 데 이 터 를 제거 한 후 checkpoint 를 실행 한 후 첫 번 째 테스트 스 크 립 트 를 다음 과 같이 삽입 합 니 다.
testdb=# truncate table t_wal_partition;
TRUNCATE TABLE
testdb=# checkpoint;
CHECKPOINT
testdb=# insert into t_wal_partition(c1,c2,c3) VALUES(1,'checkpoint','checkpoint');
정지점 설정, XLogRecordAssemble 진입
(gdb) b XLogRecordAssemble
Breakpoint 1 at 0x565411: file xloginsert.c, line 488.
(gdb) c
Continuing.
Breakpoint 1, XLogRecordAssemble (rmid=10 '
', info=128 '\200', RedoRecPtr=5507633240, doPageWrites=true,
fpw_lsn=0x7fff05cfe378) at xloginsert.c:488
488 uint32 total_len = 0;
입력 매개 변수: rmid = 10 즉 0x0A -- > Heap RedoRecPtr = 5507633240 doPageWrites = true, full - page - write fpw 필요lsn = 0x7fff05cfe 378 다음은 변수 할당 입 니 다. 그 중에서 hdrscratch 의 정의: static char * hdrscratch = NULL; hdr_rdt 의 정의: static XLogRecData hdrrdt;
(gdb) n
491 registered_buffer *prev_regbuf = NULL;
(gdb)
494 char *scratch = hdr_scratch;
(gdb)
502 rechdr = (XLogRecord *) scratch;
(gdb)
503 scratch += SizeOfXLogRecord;
(gdb)
XLOG Record 의 머리 정보
(gdb) p *(XLogRecord *)rechdr
$11 = {xl_tot_len = 114, xl_xid = 1997, xl_prev = 5507669824, xl_info = 128 '\200', xl_rmid = 1 '\001', xl_crc = 3794462175}
scratch 포인터 가 Header 다음 주 소 를 가리 키 고 있 습 니 다.
(gdb) p hdr_scratch
$12 = 0x18a24c0 "r"
전역 변수 hdrrdt 할당
505 hdr_rdt.next = NULL;
(gdb)
506 rdt_datas_last = &hdr_rdt;
(gdb)
507 hdr_rdt.data = hdr_scratch;
(gdb) p hdr_rdt
$5 = {next = 0x0, data = 0x18a24c0 "r", len = 26}
(gdb) p *(XLogRecord *)hdr_rdt.data
$7 = {xl_tot_len = 114, xl_xid = 1997, xl_prev = 5507669824, xl_info = 128 '\200', xl_rmid = 1 '\001', xl_crc = 3794462175}
일치 성 검 사 를 실행 하지 않 음
(gdb) n
515 if (wal_consistency_checking[rmid])
(gdb)
523 *fpw_lsn = InvalidXLogRecPtr;
(gdb)
fpw 초기 화lsn, 순환 을 시작 합 니 다. 등 록 된 block id 는 1 개 입 니 다.
(gdb) n
524 for (block_id = 0; block_id < max_registered_block_id; block_id++)
(gdb) p max_registered_block_id
$13 = 1
등 록 된 buffer 를 가 져 옵 니 다. 그 중: rnode - > RelFilenode 구조 체, spcNode - > 표 공간 / dbNode - > 데이터베이스 / relNode - > 관계 Block - > 블록 ID page - > 데이터 페이지 포인터 (char *) rdatalen - > rdata 체인 의 데이터 총 크기 rdatahead - > 이 데이터 블록 으로 등 록 된 데이터 체인 헤드 rdatatail - > 이 데이터 블록 으로 등 록 된 데이터 체인 꼬리 bkprdatas - > 임시 rdatas 데이터 인용, XLogRecordAssemble () 에서 사용 하 는 백업 블록 데 이 터 를 저장 하 는 데 사 용 됩 니 다. bkprdatas 는 block image, bkp 를 조립 하 는 데 사 용 됩 니 다.rdatas [0] 남 은 공간 (hole) 전 데이터 저장, bkprdatas [1] 남 은 공간 후의 데 이 터 를 저장 합 니 다.
(gdb) n
526 registered_buffer *regbuf = ®istered_buffers[block_id];
(gdb)
531 XLogRecordBlockCompressHeader cbimg = {0};
(gdb) p *regbuf
$14 = {in_use = true, flags = 14 '\016', rnode = {spcNode = 1663, dbNode = 16402, relNode = 25258}, forkno = MAIN_FORKNUM,
block = 0, page = 0x7fb8539e7380 "", rdata_len = 32, rdata_head = 0x18a22c0, rdata_tail = 0x18a22d8, bkp_rdatas = {{
next = 0x18a4230, data = 0x7fb85390f380 "\001", len = 252}, {next = 0x18a22a8, data = 0x7fb85390fe28 "\315\a",
len = 5464}}, compressed_page = '\000' }
메모: 메모리 에 main data 는 함수 XLogRegisterData 에 등록 되 어 있 으 며, mainradahead 와 mainradalast 포인터 유지 보수, 이 예 에서 xl 를 채 웠 습 니 다.heap_insert 구조 체. block data 는 XLogRegisterBuffer 에서 초기 화 되 었 고 XLogRegisterBufData 로 데 이 터 를 채 웠 습 니 다. 이 예 에서 XLogRegisterBufData 를 통 해 두 번 의 데 이 터 를 등 록 했 습 니 다. 첫 번 째 는 xl 입 니 다.heap_header 구조 체, 두 번 째 는 실제 데이터 (실질 적 으로 데이터 포인터 일 뿐 최종 적 으로 어떤 데이터 가 필요 한 지 조립 기 에서 확인) 입 니 다.
(gdb) p *mainrdata_head
$18 = {next = 0x18a22c0, data = 0x7fff05cfe3f0 "\001", len = 3}
(gdb) p *(xl_heap_insert *)mainrdata_head->data
$20 = {offnum = 1, flags = 0 '\000'}
(gdb) p *regbuf->rdata_head
$32 = {next = 0x18a22d8, data = 0x7fff05cfe3e0 "\003", len = 5}
(gdb) p *(xl_heap_header *)regbuf->rdata_head->data
$28 = {t_infomask2 = 3, t_infomask = 2050, t_hoff = 24 '\030'}
(gdb) p *regbuf->rdata_head->next
$34 = {next = 0x18a22f0, data = 0x18edaef "", len = 27}
주소 0x18edaef 이후 27 개의 바이트 (tuple data) 를 문자 형식 으로 표시 합 니 다.
(gdb) x/27bc 0x18edaef
0x18edaef: 0 '\000' 1 '\001' 0 '\000' 0 '\000' 0 '\000' 23 '\027' 99 'c' 104 'h'
0x18edaf7: 101 'e' 99 'c' 107 'k' 112 'p' 111 'o' 105 'i' 110 'n' 116 't'
0x18edaff: 23 '\027' 99 'c' 104 'h' 101 'e' 99 'c' 107 'k' 112 'p' 111 'o'
0x18edb07: 105 'i' 110 'n' 116 't'
이 기록 은 첫 번 째 기록 이기 때문에 full - page - image 를 실행 할 필요 가 없습니다.
(gdb) n
533 bool is_compressed = false;
(gdb)
536 if (!regbuf->in_use)
(gdb)
540 if (regbuf->flags & REGBUF_FORCE_IMAGE)
(gdb) p regbuf->flags
$36 = 14 '\016'
(gdb) n
542 else if (regbuf->flags & REGBUF_NO_IMAGE)
(gdb)
543 needs_backup = false;
needs_data 는 T 이 며, 트 랜 잭 션 로그 에 tuple data 만 기록 합 니 다.
(gdb) n
564 if (regbuf->rdata_len == 0)
(gdb) p regbuf->rdata_len
$37 = 32
(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
$38 = true
XLogRecordBlockHeader 필드 값 을 설정 합 니 다. page 의 첫 번 째 tuple 은 BKPBLOCK 로 표 시 됩 니 다.WILL_INIT
(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) n
576 bkpb.fork_flags |= BKPBLOCK_WILL_INIT;
(gdb)
582 include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
(gdb) p bkpb
$40 = {id = 0 '\000', fork_flags = 64 '@', data_length = 0}
(gdb)
FPI 를 실행 할 필요 가 없습니다.
(gdb) p info
$41 = 128 '\200'
(gdb) n
584 if (include_image)
(gdb) p include_image
$42 = false
(gdb)
데이터 포함 필요
(gdb) n
691 if (needs_data)
(gdb)
697 bkpb.fork_flags |= BKPBLOCK_HAS_DATA;
(gdb)
698 bkpb.data_length = regbuf->rdata_len;
(gdb)
699 total_len += regbuf->rdata_len;
(gdb)
701 rdt_datas_last->next = regbuf->rdata_head;
(gdb)
702 rdt_datas_last = regbuf->rdata_tail;
(gdb) p bkpb
$43 = {id = 0 '\000', fork_flags = 96 '`', data_length = 32}
(gdb) p total_len
$44 = 32
(gdb) p *rdt_datas_last
$45 = {next = 0x18a22c0, data = 0x18a24c0 "r", len = 26}
OK, 머리 정 보 를 scratch 버퍼 에 복사
(gdb) n
705 if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode))
(gdb) p prev_regbuf
$46 = (registered_buffer *) 0x0
(gdb) n
711 samerel = false;
(gdb)
712 prev_regbuf = regbuf;
(gdb)
715 memcpy(scratch, &bkpb, SizeOfXLogRecordBlockHeader);
뒤에 RefFileNode + BlockNumber.
(gdb)
716 scratch += SizeOfXLogRecordBlockHeader;
(gdb)
717 if (include_image)
(gdb)
728 if (!samerel)
(gdb)
730 memcpy(scratch, ®buf->rnode, sizeof(RelFileNode));
(gdb)
731 scratch += sizeof(RelFileNode);
(gdb)
733 memcpy(scratch, ®buf->block, sizeof(BlockNumber));
(gdb)
734 scratch += sizeof(BlockNumber);
(gdb)
524 for (block_id = 0; block_id < max_registered_block_id; block_id++)
순환 을 끝내다
524 for (block_id = 0; block_id < max_registered_block_id; block_id++)
(gdb)
다음은 replorginsession_origin (실제 필요 하지 않 음)
738 if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
(gdb) p curinsert_flags
$47 = 1 '\001'
(gdb)
$48 = 1 '\001'
(gdb) n
739 replorigin_session_origin != InvalidRepOriginId)
(gdb)
738 if ((curinsert_flags & XLOG_INCLUDE_ORIGIN) &&
다음은 main data.
(gdb)
747 if (mainrdata_len > 0)
(gdb)
749 if (mainrdata_len > 255)
(gdb)
757 *(scratch++) = (char) XLR_BLOCK_ID_DATA_SHORT;
(gdb)
(gdb)
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)
766 hdr_rdt.len = (scratch - hdr_scratch);
(gdb) p scratch
$49 = 0x18a24ee ""
(gdb) p hdr_scratch
$50 = 0x18a24c0 "r"
(gdb) p hdr_rdt.len
$51 = 26
(gdb) p total_len
$52 = 35
(gdb)
(gdb) n
767 total_len += hdr_rdt.len;
(gdb)
계산 CRC
(gdb)
777 INIT_CRC32C(rdata_crc);
(gdb)
778 COMP_CRC32C(rdata_crc, hdr_scratch + SizeOfXLogRecord, hdr_rdt.len - SizeOfXLogRecord);
(gdb)
779 for (rdt = hdr_rdt.next; rdt != NULL; rdt = rdt->next)
(gdb) n
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) 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)
795 }
(gdb) p rechdr
$62 = (XLogRecord *) 0x18a24c0
(gdb) p *rechdr
$63 = {xl_tot_len = 81, xl_xid = 1998, xl_prev = 0, xl_info = 128 '\200', xl_rmid = 10 '
', xl_crc = 1852971194}
(gdb)
full - page - write 장면 후속 재 분석
참고 자료
Write Ahead Logging - WAL PostgreSQL 소스 코드 판독 (4) - 데이터 삽입 \ # 3 (heap insert) PostgreSQL 트 랜 잭 션 로그 WAL 구조 분석 PG 소스 코드
"ITPUB 블 로그" 에서 왔 습 니 다. 링크:http://blog.itpub.net/6906/viewspace-2374772/전재 가 필요 하 다 면 출처 를 밝 혀 주 십시오. 그렇지 않 으 면 법 적 책임 을 추궁 할 것 입 니 다.
다음으로 전송:http://blog.itpub.net/6906/viewspace-2374772/
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.