Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitea42cc1

Browse files
committed
Track the oldest XID that can be safely looked up in CLOG.
This provides infrastructure for looking up arbitrary, user-suppliedXIDs without a risk of scary-looking failures from within the clogmodule. Normally, the oldest XID that can be safely looked up in CLOGis the same as the oldest XID that can reused without causingwraparound, and the latter is already tracked. However, whiletruncation is in progress, the values are different, so we mustkeep track of them separately.Craig Ringer, reviewed by Simon Riggs and by me.Discussion:http://postgr.es/m/CAMsr+YHQiWNEi0daCTboS40T+V5s_+dst3PYv_8v2wNVH+Xx4g@mail.gmail.com
1 parent50c956a commitea42cc1

File tree

11 files changed

+102
-18
lines changed

11 files changed

+102
-18
lines changed

‎doc/src/sgml/monitoring.sgml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,10 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
10171017
<entry><literal>OldSnapshotTimeMapLock</></entry>
10181018
<entry>Waiting to read or update old snapshot control information.</entry>
10191019
</row>
1020+
<row>
1021+
<entry><literal>CLogTruncationLock</></entry>
1022+
<entry>Waiting to truncate the transaction log or waiting for transaction log truncation to finish.</entry>
1023+
</row>
10201024
<row>
10211025
<entry><literal>clog</></entry>
10221026
<entry>Waiting for I/O on a clog (transaction status) buffer.</entry>

‎src/backend/access/rmgrdesc/clogdesc.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,20 @@ clog_desc(StringInfo buf, XLogReaderState *record)
2323
char*rec=XLogRecGetData(record);
2424
uint8info=XLogRecGetInfo(record)& ~XLR_INFO_MASK;
2525

26-
if (info==CLOG_ZEROPAGE||info==CLOG_TRUNCATE)
26+
if (info==CLOG_ZEROPAGE)
2727
{
2828
intpageno;
2929

3030
memcpy(&pageno,rec,sizeof(int));
31-
appendStringInfo(buf,"%d",pageno);
31+
appendStringInfo(buf,"page %d",pageno);
32+
}
33+
elseif (info==CLOG_TRUNCATE)
34+
{
35+
xl_clog_truncatexlrec;
36+
37+
memcpy(&xlrec,rec,sizeof(xl_clog_truncate));
38+
appendStringInfo(buf,"page %d; oldestXact %u",
39+
xlrec.pageno,xlrec.oldestXact);
3240
}
3341
}
3442

‎src/backend/access/transam/clog.c

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ static SlruCtlData ClogCtlData;
8383
staticintZeroCLOGPage(intpageno,boolwriteXlog);
8484
staticboolCLOGPagePrecedes(intpage1,intpage2);
8585
staticvoidWriteZeroPageXlogRec(intpageno);
86-
staticvoidWriteTruncateXlogRec(intpageno);
86+
staticvoidWriteTruncateXlogRec(intpageno,TransactionIdoldestXact,
87+
OidoldestXidDb);
8788
staticvoidTransactionIdSetPageStatus(TransactionIdxid,intnsubxids,
8889
TransactionId*subxids,XidStatusstatus,
8990
XLogRecPtrlsn,intpageno);
@@ -640,7 +641,7 @@ ExtendCLOG(TransactionId newestXact)
640641
* the XLOG flush unless we have confirmed that there is a removable segment.
641642
*/
642643
void
643-
TruncateCLOG(TransactionIdoldestXact)
644+
TruncateCLOG(TransactionIdoldestXact,Oidoldestxid_datoid)
644645
{
645646
intcutoffPage;
646647

@@ -654,8 +655,26 @@ TruncateCLOG(TransactionId oldestXact)
654655
if (!SlruScanDirectory(ClogCtl,SlruScanDirCbReportPresence,&cutoffPage))
655656
return;/* nothing to remove */
656657

657-
/* Write XLOG record and flush XLOG to disk */
658-
WriteTruncateXlogRec(cutoffPage);
658+
/*
659+
* Advance oldestClogXid before truncating clog, so concurrent xact status
660+
* lookups can ensure they don't attempt to access truncated-away clog.
661+
*
662+
* It's only necessary to do this if we will actually truncate away clog
663+
* pages.
664+
*/
665+
AdvanceOldestClogXid(oldestXact);
666+
667+
/* vac_truncate_clog already advanced oldestXid */
668+
Assert(TransactionIdPrecedesOrEquals(oldestXact,
669+
ShmemVariableCache->oldestXid));
670+
671+
/*
672+
* Write XLOG record and flush XLOG to disk. We record the oldest xid we're
673+
* keeping information about here so we can ensure that it's always ahead
674+
* of clog truncation in case we crash, and so a standby finds out the new
675+
* valid xid before the next checkpoint.
676+
*/
677+
WriteTruncateXlogRec(cutoffPage,oldestXact,oldestxid_datoid);
659678

660679
/* Now we can remove the old CLOG segment(s) */
661680
SimpleLruTruncate(ClogCtl,cutoffPage);
@@ -704,12 +723,17 @@ WriteZeroPageXlogRec(int pageno)
704723
* in TruncateCLOG().
705724
*/
706725
staticvoid
707-
WriteTruncateXlogRec(intpageno)
726+
WriteTruncateXlogRec(intpageno,TransactionIdoldestXact,OidoldestXactDb)
708727
{
709728
XLogRecPtrrecptr;
729+
xl_clog_truncatexlrec;
730+
731+
xlrec.pageno=pageno;
732+
xlrec.oldestXact=oldestXact;
733+
xlrec.oldestXactDb=oldestXactDb;
710734

711735
XLogBeginInsert();
712-
XLogRegisterData((char*) (&pageno),sizeof(int));
736+
XLogRegisterData((char*) (&xlrec),sizeof(xl_clog_truncate));
713737
recptr=XLogInsert(RM_CLOG_ID,CLOG_TRUNCATE);
714738
XLogFlush(recptr);
715739
}
@@ -742,17 +766,19 @@ clog_redo(XLogReaderState *record)
742766
}
743767
elseif (info==CLOG_TRUNCATE)
744768
{
745-
intpageno;
769+
xl_clog_truncatexlrec;
746770

747-
memcpy(&pageno,XLogRecGetData(record),sizeof(int));
771+
memcpy(&xlrec,XLogRecGetData(record),sizeof(xl_clog_truncate));
748772

749773
/*
750774
* During XLOG replay, latest_page_number isn't set up yet; insert a
751775
* suitable value to bypass the sanity test in SimpleLruTruncate.
752776
*/
753-
ClogCtl->shared->latest_page_number=pageno;
777+
ClogCtl->shared->latest_page_number=xlrec.pageno;
778+
779+
AdvanceOldestClogXid(xlrec.oldestXact);
754780

755-
SimpleLruTruncate(ClogCtl,pageno);
781+
SimpleLruTruncate(ClogCtl,xlrec.pageno);
756782
}
757783
else
758784
elog(PANIC,"clog_redo: unknown op code %u",info);

‎src/backend/access/transam/transam.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ TransactionLogFetch(TransactionId transactionId)
119119
*True iff transaction associated with the identifier did commit.
120120
*
121121
* Note:
122-
*Assumes transaction identifier is valid.
122+
*Assumes transaction identifier is valid and exists in clog.
123123
*/
124124
bool/* true if given transaction committed */
125125
TransactionIdDidCommit(TransactionIdtransactionId)
@@ -175,7 +175,7 @@ TransactionIdDidCommit(TransactionId transactionId)
175175
*True iff transaction associated with the identifier did abort.
176176
*
177177
* Note:
178-
*Assumes transaction identifier is valid.
178+
*Assumes transaction identifier is valid and exists in clog.
179179
*/
180180
bool/* true if given transaction aborted */
181181
TransactionIdDidAbort(TransactionIdtransactionId)

‎src/backend/access/transam/varsup.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,28 @@ ReadNewTransactionId(void)
259259
}
260260

261261
/*
262-
* Determine the last safe XID to allocate given the currently oldest
262+
* Advance the cluster-wide value for the oldest valid clog entry.
263+
*
264+
* We must acquire CLogTruncationLock to advance the oldestClogXid. It's not
265+
* necessary to hold the lock during the actual clog truncation, only when we
266+
* advance the limit, as code looking up arbitrary xids is required to hold
267+
* CLogTruncationLock from when it tests oldestClogXid through to when it
268+
* completes the clog lookup.
269+
*/
270+
void
271+
AdvanceOldestClogXid(TransactionIdoldest_datfrozenxid)
272+
{
273+
LWLockAcquire(CLogTruncationLock,LW_EXCLUSIVE);
274+
if (TransactionIdPrecedes(ShmemVariableCache->oldestClogXid,
275+
oldest_datfrozenxid))
276+
{
277+
ShmemVariableCache->oldestClogXid=oldest_datfrozenxid;
278+
}
279+
LWLockRelease(CLogTruncationLock);
280+
}
281+
282+
/*
283+
* Determine the last safe XID to allocate using the currently oldest
263284
* datfrozenxid (ie, the oldest XID that might exist in any database
264285
* of our cluster), and the OID of the (or a) database with that value.
265286
*/

‎src/backend/access/transam/xlog.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5016,6 +5016,7 @@ BootStrapXLOG(void)
50165016
ShmemVariableCache->nextOid=checkPoint.nextOid;
50175017
ShmemVariableCache->oidCount=0;
50185018
MultiXactSetNextMXact(checkPoint.nextMulti,checkPoint.nextMultiOffset);
5019+
AdvanceOldestClogXid(checkPoint.oldestXid);
50195020
SetTransactionIdLimit(checkPoint.oldestXid,checkPoint.oldestXidDB);
50205021
SetMultiXactIdLimit(checkPoint.oldestMulti,checkPoint.oldestMultiDB, true);
50215022
SetCommitTsLimit(InvalidTransactionId,InvalidTransactionId);
@@ -6622,6 +6623,7 @@ StartupXLOG(void)
66226623
ShmemVariableCache->nextOid=checkPoint.nextOid;
66236624
ShmemVariableCache->oidCount=0;
66246625
MultiXactSetNextMXact(checkPoint.nextMulti,checkPoint.nextMultiOffset);
6626+
AdvanceOldestClogXid(checkPoint.oldestXid);
66256627
SetTransactionIdLimit(checkPoint.oldestXid,checkPoint.oldestXidDB);
66266628
SetMultiXactIdLimit(checkPoint.oldestMulti,checkPoint.oldestMultiDB, true);
66276629
SetCommitTsLimit(checkPoint.oldestCommitTsXid,
@@ -8687,6 +8689,11 @@ CreateCheckPoint(int flags)
86878689

86888690
/*
86898691
* Get the other info we need for the checkpoint record.
8692+
*
8693+
* We don't need to save oldestClogXid in the checkpoint, it only matters
8694+
* for the short period in which clog is being truncated, and if we crash
8695+
* during that we'll redo the clog truncation and fix up oldestClogXid
8696+
* there.
86908697
*/
86918698
LWLockAcquire(XidGenLock,LW_SHARED);
86928699
checkPoint.nextXid=ShmemVariableCache->nextXid;
@@ -9616,6 +9623,10 @@ xlog_redo(XLogReaderState *record)
96169623

96179624
MultiXactAdvanceOldest(checkPoint.oldestMulti,
96189625
checkPoint.oldestMultiDB);
9626+
/*
9627+
* No need to set oldestClogXid here as well; it'll be set when we
9628+
* redo an xl_clog_truncate if it changed since initialization.
9629+
*/
96199630
SetTransactionIdLimit(checkPoint.oldestXid,checkPoint.oldestXidDB);
96209631

96219632
/*

‎src/backend/commands/vacuum.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ vac_truncate_clog(TransactionId frozenXID,
11941194
/*
11951195
* Truncate CLOG, multixact and CommitTs to the oldest computed value.
11961196
*/
1197-
TruncateCLOG(frozenXID);
1197+
TruncateCLOG(frozenXID,oldestxid_datoid);
11981198
TruncateCommitTs(frozenXID);
11991199
TruncateMultiXact(minMulti,minmulti_datoid);
12001200

‎src/backend/storage/lmgr/lwlocknames.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ MultiXactTruncationLock41
4949
OldSnapshotTimeMapLock42
5050
BackendRandomLock43
5151
LogicalRepWorkerLock44
52+
CLogTruncationLock45

‎src/include/access/clog.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ typedef int XidStatus;
2828
#defineTRANSACTION_STATUS_ABORTED0x02
2929
#defineTRANSACTION_STATUS_SUB_COMMITTED0x03
3030

31+
typedefstructxl_clog_truncate
32+
{
33+
intpageno;
34+
TransactionIdoldestXact;
35+
OidoldestXactDb;
36+
}xl_clog_truncate;
3137

3238
externvoidTransactionIdSetTreeStatus(TransactionIdxid,intnsubxids,
3339
TransactionId*subxids,XidStatusstatus,XLogRecPtrlsn);
@@ -42,7 +48,7 @@ extern void TrimCLOG(void);
4248
externvoidShutdownCLOG(void);
4349
externvoidCheckPointCLOG(void);
4450
externvoidExtendCLOG(TransactionIdnewestXact);
45-
externvoidTruncateCLOG(TransactionIdoldestXact);
51+
externvoidTruncateCLOG(TransactionIdoldestXact,Oidoldestxid_datoid);
4652

4753
/* XLOG stuff */
4854
#defineCLOG_ZEROPAGE0x00

‎src/include/access/transam.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ typedef struct VariableCacheData
134134
*/
135135
TransactionIdlatestCompletedXid;/* newest XID that has committed or
136136
* aborted */
137+
138+
/*
139+
* These fields are protected by CLogTruncationLock
140+
*/
141+
TransactionIdoldestClogXid;/* oldest it's safe to look up in clog */
142+
137143
}VariableCacheData;
138144

139145
typedefVariableCacheData*VariableCache;
@@ -173,6 +179,7 @@ extern TransactionId GetNewTransactionId(bool isSubXact);
173179
externTransactionIdReadNewTransactionId(void);
174180
externvoidSetTransactionIdLimit(TransactionIdoldest_datfrozenxid,
175181
Oidoldest_datoid);
182+
externvoidAdvanceOldestClogXid(TransactionIdoldest_datfrozenxid);
176183
externboolForceTransactionIdLimitUpdate(void);
177184
externOidGetNewObjectId(void);
178185

‎src/include/access/xlog_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
/*
3232
* Each page of XLOG file has a header like this:
3333
*/
34-
#defineXLOG_PAGE_MAGIC0xD096/* can be used as WAL version indicator */
34+
#defineXLOG_PAGE_MAGIC0xD097/* can be used as WAL version indicator */
3535

3636
typedefstructXLogPageHeaderData
3737
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp