PostgreSQL 소스 코드 판독 (106) - WAL \ # 3 (삽입 & WAL - heap insert 함수 \ # 3)
데이터 구조
정적 변수 프로 세 스 의 전역 공유
/*
* 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;
매크로 정의
typedef char* Pointer;//
typedef Pointer Page;//Page
#define XLOG_HEAP_INSERT 0x00
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
* XLOG .
* 64bit, .
*/
typedef uint64 XLogRecPtr;
/*
* Additional macros for access to page headers. (Beware multiple evaluation
* of the arguments!)
*/
#define PageGetLSN(page) \
PageXLogRecPtrGet(((PageHeader) (page))->pd_lsn)
#define PageSetLSN(page, lsn) \
PageXLogRecPtrSet(((PageHeader) (page))->pd_lsn, lsn)
/* Buffer size required to store a compressed version of backup block image */
//
#define PGLZ_MAX_BLCKSZ PGLZ_MAX_OUTPUT(BLCKSZ)
/*
* Fake spinlock implementation using semaphores --- slow and prone
* to fall foul of kernel limits on number of semaphores, so don't use this
* unless you must! The subroutines appear in spin.c.
* —— ,
* , !
* spin.c 。
*/
typedef int slock_t;
XLogCtl XLog 의 모든 공유 메모리 상태 정보
/*
* Total shared-memory state for XLOG.
* XLOG
*/
typedef struct XLogCtlData
{
XLogCtlInsert Insert;//
/* Protected by info_lck: */
//------ info_lck
XLogwrtRqst LogwrtRqst;
//Insert->RedoRecPtr
XLogRecPtr RedoRecPtr; /* a recent copy of Insert->RedoRecPtr */
// checkpoint nextXID & epoch
uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */
TransactionId ckptXid;
// / LSN
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
//slot " " LSN
XLogRecPtr replicationSlotMinLSN; /* oldest LSN needed by any slot */
// / XLOG
XLogSegNo lastRemovedSegNo; /* latest removed/recycled XLOG segment */
/* Fake LSN counter, for unlogged relations. Protected by ulsn_lck. */
//---- " " LSN , . ulsn_lck
XLogRecPtr unloggedLSN;
slock_t ulsn_lck;
/* Time and LSN of last xlog segment switch. Protected by WALWriteLock. */
//---- xlog LSN, WALWriteLock
pg_time_t lastSegSwitchTime;
XLogRecPtr lastSegSwitchLSN;
/*
* Protected by info_lck and WALWriteLock (you must hold either lock to
* read it, but both to update)
* info_lck WALWriteLock
* ( , )
*/
XLogwrtResult LogwrtResult;
/*
* Latest initialized page in the cache (last byte position + 1).
* page( + 1)
*
* To change the identity of a buffer (and InitializedUpTo), you need to
* hold WALBufMappingLock. To change the identity of a buffer that's
* still dirty, the old page needs to be written out first, and for that
* you need WALWriteLock, and you need to ensure that there are no
* in-progress insertions to the page by calling
* WaitXLogInsertionsToFinish().
* ( InitializedUpTo), WALBufMappingLock .
* dirty , page , WALWriteLock ,
* WaitXLogInsertionsToFinish() page
*/
XLogRecPtr InitializedUpTo;
/*
* These values do not change after startup, although the pointed-to pages
* and xlblocks values certainly do. xlblock values are protected by
* WALBufMappingLock.
* , pointed-to pages xlblocks .
* xlblock WALBufMappingLock .
*/
// XLOG pages
char *pages; /* buffers for unwritten XLOG pages */
//ptr-s + XLOG_BLCKSZ
XLogRecPtr *xlblocks; /* 1st byte ptr-s + XLOG_BLCKSZ */
// xlog
int XLogCacheBlck; /* highest allocated xlog buffer index */
/*
* Shared copy of ThisTimeLineID. Does not change after end-of-recovery.
* If we created a new timeline when the system was started up,
* PrevTimeLineID is the old timeline's ID that we forked off from.
* Otherwise it's equal to ThisTimeLineID.
* ThisTimeLineID .
* .
* ,PrevTimeLineID ID.
* ,PrevTimeLineID = ThisTimeLineID
*/
TimeLineID ThisTimeLineID;
TimeLineID PrevTimeLineID;
/*
* SharedRecoveryInProgress indicates if we're still in crash or archive
* recovery. Protected by info_lck.
* SharedRecoveryInProgress , info_lck .
*/
bool SharedRecoveryInProgress;
/*
* SharedHotStandbyActive indicates if we're still in crash or archive
* recovery. Protected by info_lck.
* SharedHotStandbyActive , info_lck .
*/
bool SharedHotStandbyActive;
/*
* WalWriterSleeping indicates whether the WAL writer is currently in
* low-power mode (and hence should be nudged if an async commit occurs).
* Protected by info_lck.
* WalWriterSleeping WAL writer " "
* ( , , ).
* info_lck .
*/
bool WalWriterSleeping;
/*
* recoveryWakeupLatch is used to wake up the startup process to continue
* WAL replay, if it is waiting for WAL to arrive or failover trigger file
* to appear.
* recoveryWakeupLatch WAL arrive failover ,
* WAL .
*
*/
Latch recoveryWakeupLatch;
/*
* During recovery, we keep a copy of the latest checkpoint record here.
* lastCheckPointRecPtr points to start of checkpoint record and
* lastCheckPointEndPtr points to end+1 of checkpoint record. Used by the
* checkpointer when it wants to create a restartpoint.
* , .
* lastCheckPointRecPtr
* lastCheckPointEndPtr +1
* checkpointer .
*
* Protected by info_lck.
* info_lck .
*/
XLogRecPtr lastCheckPointRecPtr;
XLogRecPtr lastCheckPointEndPtr;
CheckPoint lastCheckPoint;
/*
* lastReplayedEndRecPtr points to end+1 of the last record successfully
* replayed. When we're currently replaying a record, ie. in a redo
* function, replayEndRecPtr points to the end+1 of the record being
* replayed, otherwise it's equal to lastReplayedEndRecPtr.
* lastReplayedEndRecPtr + 1 .
* redo , replayEndRecPtr + 1 ,
* replayEndRecPtr = lastReplayedEndRecPtr
*/
XLogRecPtr lastReplayedEndRecPtr;
TimeLineID lastReplayedTLI;
XLogRecPtr replayEndRecPtr;
TimeLineID replayEndTLI;
/* timestamp of last COMMIT/ABORT record replayed (or being replayed) */
// COMMIT/ABORT ( )
TimestampTz recoveryLastXTime;
/*
* timestamp of when we started replaying the current chunk of WAL data,
* only relevant for replication or archive recovery
* WAL chunk ( )
*/
TimestampTz currentChunkStartTime;
/* Are we requested to pause recovery? */
//
bool recoveryPause;
/*
* lastFpwDisableRecPtr points to the start of the last replayed
* XLOG_FPW_CHANGE record that instructs full_page_writes is disabled.
* lastFpwDisableRecPtr XLOG_FPW_CHANGE ( ) .
*/
XLogRecPtr lastFpwDisableRecPtr;
//
slock_t info_lck; /* locks shared variables shown above */
} XLogCtlData;
static XLogCtlData *XLogCtl = NULL;
2. 소스 코드 해독
heap_insert 의 주요 구현 논 리 는 원 그룹 을 더미 에 삽입 하 는 것 입 니 다. WAL (XLog) 을 처리 하 는 부분 이 있 습 니 다. PostgreSQL 소스 코드 해석 (104) - WAL \ # 1 (Insert & WAL - heap insert 함수 \ # 1 참조)
XLogInsert 는 지정 한 RMID 와 info 바이트 가 있 는 XLOG 기록 을 삽입 합 니 다. 이 기록 의 주 체 는 이전에 XLogRegister * 를 통 해 등 록 된 데이터 와 버퍼 참조 입 니 다.
/*
* Insert an XLOG record having the specified RMID and info bytes, with the
* body of the record being the data and buffer references registered earlier
* with XLogRegister* calls.
* RMID info XLOG ,
* XLogRegister* 。
*
* Returns XLOG pointer to end of record (beginning of next record).
* This can be used as LSN for data pages affected by the logged action.
* (LSN is the XLOG point up to which the XLOG must be flushed to disk
* before the data page can be written out. This implements the basic
* WAL rule "write the log before the data".)
* XLOG ( )。
* LSN。
* (LSN XLOG XLOG 。
* WAL :“ ”。)
*/
XLogRecPtr
XLogInsert(RmgrId rmid, uint8 info)
{
XLogRecPtr EndPos;//uint64
/* XLogBeginInsert() must have been called. */
// ,XLogBeginInsert()
if (!begininsert_called)
elog(ERROR, "XLogBeginInsert was not called");
/*
* The caller can set rmgr bits, XLR_SPECIAL_REL_UPDATE and
* XLR_CHECK_CONSISTENCY; the rest are reserved for use by me.
* rmgr :XLR_SPECIAL_REL_UPDATE & XLR_CHECK_CONSISTENCY.
*
*/
if ((info & ~(XLR_RMGR_INFO_MASK |
XLR_SPECIAL_REL_UPDATE |
XLR_CHECK_CONSISTENCY)) != 0)
elog(PANIC, "invalid xlog info mask %02X", info);
TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
/*
* In bootstrap mode, we don't actually log anything but XLOG resources;
* return a phony record pointer.
* bootstrap , XLOG , .
* .
*/
if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID)
{
XLogResetInsertion();
EndPos = SizeOfXLogLongPHD; /* ;start of 1st chkpt record */
return EndPos;
}
do
{
//
XLogRecPtr RedoRecPtr;
bool doPageWrites;
XLogRecPtr fpw_lsn;
XLogRecData *rdt;
/*
* Get values needed to decide whether to do full-page writes. Since
* we don't yet have an insertion lock, these could change under us,
* but XLogInsertRecord will recheck them once it has a lock.
* 。
* , ,
* XLogInsertRecord , 。
*/
GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
&fpw_lsn);
//curinsert_flags uint8
EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags);
} while (EndPos == InvalidXLogRecPtr);
XLogResetInsertion();
return EndPos;
}
XLogInsertRecord 는 이미 구 성 된 데이터 chunks 체인 이 표시 하 는 XLOG 기록 을 삽입 합 니 다.
/*
* Insert an XLOG record represented by an already-constructed chain of data
* chunks. This is a low-level routine; to construct the WAL record header
* and data, use the higher-level routines in xloginsert.c.
* chunks XLOG 。
* ,
* xloginsert.c WAL
*
* If 'fpw_lsn' is valid, it is the oldest LSN among the pages that this
* WAL record applies to, that were not included in the record as full page
* images. If fpw_lsn <= RedoRecPtr, the function does not perform the
* insertion and returns InvalidXLogRecPtr. The caller can then recalculate
* which pages need a full-page image, and retry. If fpw_lsn is invalid, the
* record is always inserted.
* "fpw_lsn" , WAL pages LSN,
* .
* fpw_lsn <= RedoRecPtr, InvalidXLogRecPtr.
* pages full-page image .
* fpw_lsn , .
*
* 'flags' gives more in-depth control on the record being inserted. See
* XLogSetRecordFlags() for details.
* "flags" .
* XLogSetRecordFlags() .
*
* The first XLogRecData in the chain must be for the record header, and its
* data must be MAXALIGNed. XLogInsertRecord fills in the xl_prev and
* xl_crc fields in the header, the rest of the header must already be filled
* by the caller.
* XLogRecData , MAXALIGNed.
* XLogInsertRecord xl_prev xl_crc ,
* .
*
* Returns XLOG pointer to end of record (beginning of next record).
* This can be used as LSN for data pages affected by the logged action.
* (LSN is the XLOG point up to which the XLOG must be flushed to disk
* before the data page can be written out. This implements the basic
* WAL rule "write the log before the data".)
* XLOG , ( ).
* LSN。
* (LSN XLOG XLOG 。
* WAL " ")
*/
XLogRecPtr
XLogInsertRecord(XLogRecData *rdata,
XLogRecPtr fpw_lsn,
uint8 flags)
{
XLogCtlInsert *Insert = &XLogCtl->Insert;//XLOG
pg_crc32c rdata_crc;//uint32
bool inserted;
XLogRecord *rechdr = (XLogRecord *) rdata->data;
uint8 info = rechdr->xl_info & ~XLR_INFO_MASK;
bool isLogSwitch = (rechdr->xl_rmid == RM_XLOG_ID &&
info == XLOG_SWITCH);
XLogRecPtr StartPos;
XLogRecPtr EndPos;
bool prevDoPageWrites = doPageWrites;
/* we assume that all of the record header is in the first chunk */
// chunk
Assert(rdata->len >= SizeOfXLogRecord);
/* cross-check on whether we should be here or not */
//
if (!XLogInsertAllowed())
elog(ERROR, "cannot make new WAL entries during recovery");
/*----------
*
* We have now done all the preparatory work we can without holding a
* lock or modifying shared state. From here on, inserting the new WAL
* record to the shared WAL buffer cache is a two-step process:
* , , 。
* , WAL WAL :
*
* 1. Reserve the right amount of space from the WAL. The current head of
* reserved space is kept in Insert->CurrBytePos, and is protected by
* insertpos_lck.
* 1. WAL . Insert->CurrBytePos ,
* insertpos_lck
*
* 2. Copy the record to the reserved WAL space. This involves finding the
* correct WAL buffer containing the reserved space, and copying the
* record in place. This can be done concurrently in multiple processes.
* 2. WAL . WAL ,
* .
* .
*
* To keep track of which insertions are still in-progress, each concurrent
* inserter acquires an insertion lock. In addition to just indicating that
* an insertion is in progress, the lock tells others how far the inserter
* has progressed. There is a small fixed number of insertion locks,
* determined by NUM_XLOGINSERT_LOCKS. When an inserter crosses a page
* boundary, it updates the value stored in the lock to the how far it has
* inserted, to allow the previous buffer to be flushed.
* , insertion .
* insertion , .
* insertion , NUM_XLOGINSERT_LOCKS .
* page , ,
* .
*
* Holding onto an insertion lock also protects RedoRecPtr and
* fullPageWrites from changing until the insertion is finished.
* RedoRecPtr fullpagewrite 。
*
* Step 2 can usually be done completely in parallel. If the required WAL
* page is not initialized yet, you have to grab WALBufMappingLock to
* initialize it, but the WAL writer tries to do that ahead of insertions
* to avoid that from happening in the critical path.
* 2 。
* WAL , WALBufMappingLock ,
* WAL writer , 。
*
*----------
*/
START_CRIT_SECTION();
if (isLogSwitch)
WALInsertLockAcquireExclusive();
else
WALInsertLockAcquire();
/*
* Check to see if my copy of RedoRecPtr is out of date. If so, may have
* to go back and have the caller recompute everything. This can only
* happen just after a checkpoint, so it's better to be slow in this case
* and fast otherwise.
* RedoRecPtr 。
* , 。
* , , 。
*
* Also check to see if fullPageWrites or forcePageWrites was just turned
* on; if we weren't already doing full-page writes then go back and
* recompute.
* fullpagewrite forcepagewrite;
* , 。
*
* If we aren't doing full-page writes then RedoRecPtr doesn't actually
* affect the contents of the XLOG record, so we'll update our local copy
* but not force a recomputation. (If doPageWrites was just turned off,
* we could recompute the record without full pages, but we choose not to
* bother.)
* , RedoRecPtr XLOG ,
* , 。
* ( doPageWrites , , 。)
*
*/
if (RedoRecPtr != Insert->RedoRecPtr)
{
Assert(RedoRecPtr < Insert->RedoRecPtr);
RedoRecPtr = Insert->RedoRecPtr;
}
doPageWrites = (Insert->fullPageWrites || Insert->forcePageWrites);
if (doPageWrites &&
(!prevDoPageWrites ||
(fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr)))
{
/*
* Oops, some buffer now needs to be backed up that the caller didn't
* back up. Start over.
* , 。
* 。
*/
WALInsertLockRelease();
END_CRIT_SECTION();
return InvalidXLogRecPtr;
}
/*
* Reserve space for the record in the WAL. This also sets the xl_prev
* pointer.
* WAL . xl_prev .
*
*/
if (isLogSwitch)
inserted = ReserveXLogSwitch(&StartPos, &EndPos, &rechdr->xl_prev);
else
{
ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
&rechdr->xl_prev);
inserted = true;
}
if (inserted)
{
/*
* Now that xl_prev has been filled in, calculate CRC of the record
* header.
* xl_prev , CRC
*/
rdata_crc = rechdr->xl_crc;
COMP_CRC32C(rdata_crc, rechdr, offsetof(XLogRecord, xl_crc));
FIN_CRC32C(rdata_crc);
rechdr->xl_crc = rdata_crc;
/*
* All the record data, including the header, is now ready to be
* inserted. Copy the record in the space reserved.
* , , !
* .
*/
CopyXLogRecordToWAL(rechdr->xl_tot_len, isLogSwitch, rdata,
StartPos, EndPos);
/*
* Unless record is flagged as not important, update LSN of last
* important record in the current slot. When holding all locks, just
* update the first one.
* , slot LSN。
* , 。
*/
if ((flags & XLOG_MARK_UNIMPORTANT) == 0)
{
int lockno = holdingAllLocks ? 0 : MyLockNo;
WALInsertLocks[lockno].l.lastImportantAt = StartPos;
}
}
else
{
/*
* This was an xlog-switch record, but the current insert location was
* already exactly at the beginning of a segment, so there was no need
* to do anything.
* xlog-switch , , 。
*/
}
/*
* Done! Let others know that we're finished.
* ! !
*/
WALInsertLockRelease();
MarkCurrentTransactionIdLoggedIfAny();
END_CRIT_SECTION();
/*
* Update shared LogwrtRqst.Write, if we crossed page boundary.
* page , LogwrtRqst.Write
*/
if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
{
SpinLockAcquire(&XLogCtl->info_lck);
/* advance global request to include new block(s) */
// (s)
if (XLogCtl->LogwrtRqst.Write < EndPos)
XLogCtl->LogwrtRqst.Write = EndPos;
/* update local result copy while I have the chance */
// ,
LogwrtResult = XLogCtl->LogwrtResult;
SpinLockRelease(&XLogCtl->info_lck);
}
/*
* If this was an XLOG_SWITCH record, flush the record and the empty
* padding space that fills the rest of the segment, and perform
* end-of-segment actions (eg, notifying archiver).
* XLOG_SWITCH ,
* ,
* ( , )。
*/
if (isLogSwitch)
{
TRACE_POSTGRESQL_WAL_SWITCH();
XLogFlush(EndPos);
/*
* Even though we reserved the rest of the segment for us, which is
* reflected in EndPos, we return a pointer to just the end of the
* xlog-switch record.
* ( EndPos ),
* xlog-switch 。
*/
if (inserted)
{
EndPos = StartPos + SizeOfXLogRecord;
if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
{
uint64 offset = XLogSegmentOffset(EndPos, wal_segment_size);
if (offset == EndPos % XLOG_BLCKSZ)
EndPos += SizeOfXLogLongPHD;
else
EndPos += SizeOfXLogShortPHD;
}
}
}
#ifdef WAL_DEBUG//DEBUG
if (XLOG_DEBUG)
{
static XLogReaderState *debug_reader = NULL;
StringInfoData buf;
StringInfoData recordBuf;
char *errormsg = NULL;
MemoryContext oldCxt;
oldCxt = MemoryContextSwitchTo(walDebugCxt);
initStringInfo(&buf);
appendStringInfo(&buf, "INSERT @ %X/%X: ",
(uint32) (EndPos >> 32), (uint32) EndPos);
/*
* We have to piece together the WAL record data from the XLogRecData
* entries, so that we can pass it to the rm_desc function as one
* contiguous chunk.
*/
initStringInfo(&recordBuf);
for (; rdata != NULL; rdata = rdata->next)
appendBinaryStringInfo(&recordBuf, rdata->data, rdata->len);
if (!debug_reader)
debug_reader = XLogReaderAllocate(wal_segment_size, NULL, NULL);
if (!debug_reader)
{
appendStringInfoString(&buf, "error decoding record: out of memory");
}
else if (!DecodeXLogRecord(debug_reader, (XLogRecord *) recordBuf.data,
&errormsg))
{
appendStringInfo(&buf, "error decoding record: %s",
errormsg ? errormsg : "no error message");
}
else
{
appendStringInfoString(&buf, " - ");
xlog_outdesc(&buf, debug_reader);
}
elog(LOG, "%s", buf.data);
pfree(buf.data);
pfree(recordBuf.data);
MemoryContextSwitchTo(oldCxt);
}
#endif
/*
* Update our global variables
*
*/
ProcLastRecPtr = StartPos;
XactLastRecEnd = EndPos;
return EndPos;
}
3. 추적 분석
테스트 스 크 립 트 는 다음 과 같 습 니 다.
insert into t_wal_partition(c1,c2,c3) VALUES(0,'HASH0','HAHS0');
gdb 시작, 정지점 설정, XLogInsert 진입
(gdb) b XLogInsert
Breakpoint 1 at 0x5652d6: file xloginsert.c, line 420.
(gdb) c
Continuing.
Breakpoint 1, XLogInsert (rmid=10 '
', info=0 '\000') at xloginsert.c:420
420 if (!begininsert_called)
이전 에는 XLogBeginInsert () 가 호출 되 어야 합 니 다.
420 if (!begininsert_called)
(gdb) n
호출 자 는 rmgr 비트 를 설정 해 야 합 니 다: XLRSPECIAL_REL_UPDATE & XLR_CHECK_CONSISTENCY. 나머지 는 여기 서 사용 을 보류 합 니 다.
427 if ((info & ~(XLR_RMGR_INFO_MASK |
(gdb) n
432 TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
순환 에 들어가다
(gdb) n
438 if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID)
(gdb)
457 GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
전체 페이지 기록 을 실행 할 지 여 부 를 결정 하 는 데 필요 한 값 가 져 오기
(gdb) p *RedoRecPtr
$1 = 1166604425
(gdb) p doPageWrites
$2 = false
(gdb) n
459 rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
(gdb) p RedoRecPtr
$3 = 5411227832
(gdb) p doPageWrites
$4 = true
rdt 가 져 오기
(gdb) n
462 EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags);
(gdb) p *rdt
$5 = {next = 0x2a911b8, data = 0x2a8f460 , len = 51}
XLogInsertRecord - > XLogInsertRecord 를 호출 하여 XLogInsertRecord 함수 fpw 에 들 어 갑 니 다.lsn=0, flags=1 '\001'
(gdb) step
XLogInsertRecord (rdata=0xf9cc70 , fpw_lsn=0, flags=1 '\001') at xlog.c:970
970 XLogCtlInsert *Insert = &XLogCtl->Insert;
XLogInsertRecord - > 삽입 관리자 가 져 오기
(gdb) n
973 XLogRecord *rechdr = (XLogRecord *) rdata->data;
(gdb) p *Insert
$6 = {insertpos_lck = 0 '\000', CurrBytePos = 5395369608, PrevBytePos = 5395369552, pad = '\000' ,
RedoRecPtr = 5411227832, forcePageWrites = false, fullPageWrites = true, exclusiveBackupState = EXCLUSIVE_BACKUP_NONE,
nonExclusiveBackups = 0, lastBackupStart = 0, WALInsertLocks = 0x7fa2523d4100}
XLogInsertRecord - > 변수 할당
(gdb) n
974 uint8 info = rechdr->xl_info & ~XLR_INFO_MASK;
(gdb)
975 bool isLogSwitch = (rechdr->xl_rmid == RM_XLOG_ID &&
(gdb)
979 bool prevDoPageWrites = doPageWrites;
(gdb)
982 Assert(rdata->len >= SizeOfXLogRecord);
(gdb)
(gdb) p *rechdr
$7 = {xl_tot_len = 210, xl_xid = 1948, xl_prev = 0, xl_info = 0 '\000', xl_rmid = 10 '
', xl_crc = 3212449170}
(gdb) p info
$8 = 0 '\000'
(gdb) p isLogSwitch
$9 = false
(gdb) p prevDoPageWrites
$10 = true
XLogInsertRecord - > 관련 판단 수행, CRIT 오픈SECTION, WAL 잠 금 삽입 가 져 오기
(gdb) n
985 if (!XLogInsertAllowed())
(gdb)
1020 START_CRIT_SECTION();
(gdb)
1021 if (isLogSwitch)
(gdb)
1024 WALInsertLockAcquire();
(gdb)
1042 if (RedoRecPtr != Insert->RedoRecPtr)
(gdb)
XLogInsertRecord - > 관련 판단 을 실행 하고 doPageWrites 업데이트
(gdb) p RedoRecPtr
$11 = 5411227832
(gdb) p Insert->RedoRecPtr
$12 = 5411227832
(gdb) n
1047 doPageWrites = (Insert->fullPageWrites || Insert->forcePageWrites);
(gdb)
1049 if (doPageWrites &&
(gdb) p doPageWrites
$13 = true
(gdb) n
1050 (!prevDoPageWrites ||
(gdb)
1049 if (doPageWrites &&
XLogInsert Record - > WAL 에 기록 공간 을 예약 합 니 다. xl 을 설정 합 니 다.prev 포인터.
(gdb)
1050 (!prevDoPageWrites ||
(gdb)
1066 if (isLogSwitch)
(gdb)
1070 ReserveXLogInsertLocation(rechdr->xl_tot_len, &StartPos, &EndPos,
(gdb)
1072 inserted = true;
(gdb) p rechdr->xl_tot_len
$14 = 210
(gdb) p StartPos
$15 = 5411228000
(gdb) p EndPos
$16 = 5411228216
(gdb) p *rechdr->xl_prev
Cannot access memory at address 0x14288c928
(gdb) p rechdr->xl_prev
$17 = 5411227944
(gdb)
XLogInsertRecord - > 현재 xlprev 포인터 가 채 워 져 머리 를 기록 하 는 CRC 를 계산 합 니 다.
(gdb) n
1075 if (inserted)
(gdb)
1081 rdata_crc = rechdr->xl_crc;
(gdb)
1082 COMP_CRC32C(rdata_crc, rechdr, offsetof(XLogRecord, xl_crc));
(gdb)
1083 FIN_CRC32C(rdata_crc);
(gdb)
1084 rechdr->xl_crc = rdata_crc;
(gdb)
1090 CopyXLogRecordToWAL(rechdr->xl_tot_len, isLogSwitch, rdata,
(gdb) p rdata_crc
$18 = 2310972234
(gdb) p *rechdr
$19 = {xl_tot_len = 210, xl_xid = 1948, xl_prev = 5411227944, xl_info = 0 '\000', xl_rmid = 10 '
', xl_crc = 2310972234}
(gdb)
XLogInsert Record - > 모든 기록 데이터, 머리 데이터 포함 OK, 삽입 준비!보존 공간 에 복사 하여 기록 합 니 다. 기록 이 중요 하지 않 은 것 으로 표시 되 지 않 는 한 현재 slot 의 마지막 중요 한 기록 인 LSN 을 업데이트 합 니 다.
(gdb) n
1098 if ((flags & XLOG_MARK_UNIMPORTANT) == 0)
(gdb)
1100 int lockno = holdingAllLocks ? 0 : MyLockNo;
(gdb)
(gdb) n
1102 WALInsertLocks[lockno].l.lastImportantAt = StartPos;
(gdb)
1117 WALInsertLockRelease();
XLogInsertRecord - > 모두 완료!다른 삽입 기 에 우리 가 이미 완성 했다 는 것 을 알 게 하 세 요!page 경 계 를 넘 어서 면 공 유 된 LogwrtRqst. Write 변 수 를 업데이트 합 니 다.
(gdb)
1117 WALInsertLockRelease();
(gdb) n
1119 MarkCurrentTransactionIdLoggedIfAny();
(gdb)
1121 END_CRIT_SECTION();
(gdb)
1126 if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ)
(gdb)
1142 if (isLogSwitch)
XLogInsertRecord - > 전역 변 수 를 업데이트 하고 함수 반환
(gdb)
1220 ProcLastRecPtr = StartPos;
(gdb)
1221 XactLastRecEnd = EndPos;
(gdb)
1223 return EndPos;
(gdb)
1224 }
XLogInsert 되 돌리 기, 삽입 초기 화, EndPos 되 돌리 기, 종료
(gdb)
XLogInsert (rmid=10 '
', info=0 '\000') at xloginsert.c:463
463 } while (EndPos == InvalidXLogRecPtr);
(gdb) n
465 XLogResetInsertion();
(gdb)
467 return EndPos;
(gdb)
468 }
(gdb) p EndPos
$20 = 5411228216
(gdb)
$21 = 5411228216
(gdb) n
heap_insert (relation=0x7fa280616228, tup=0x2b15440, cid=0, options=0, bistate=0x0) at heapam.c:2590
2590 PageSetLSN(page, recptr);
(gdb)
DONE!
참고 자료
Write Ahead Logging - WAL PostgreSQL 소스 코드 판독 (4) - 데이터 삽입 \ # 3 (heap insert) PgSQL · 특성 분 석 · 데이터베이스 붕괴 복구 (상) PgSQL · 특성 분 석 · 데이터베이스 붕괴 복구 (하) PgSQL · 특성 분 석 · Write - Ahead Logging 메커니즘 분석 PostgreSQL WAL Buffers, Clog Buffers Deep Dive
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.