Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f21bb9c

Browse files
Refactor inCommit flag into generic delayChkpt flag.
Rename PGXACT->inCommit flag into delayChkpt flag, and generalise comments to allow use in other situations, such as the forthcoming potential use in checksum patch. Replace wait loop to look for VXIDs with delayChkpt set. No user visible changes, not behaviour changes at present. Simon Riggs, reviewed and rebased by Jeff Davis
1 parent 7a76499 commit f21bb9c

File tree

7 files changed

+89
-73
lines changed

7 files changed

+89
-73
lines changed

src/backend/access/transam/twophase.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
318318
proc->lxid = (LocalTransactionId) xid;
319319
pgxact->xid = xid;
320320
pgxact->xmin = InvalidTransactionId;
321-
pgxact->inCommit = false;
321+
pgxact->delayChkpt = false;
322322
pgxact->vacuumFlags = 0;
323323
proc->pid = 0;
324324
proc->backendId = InvalidBackendId;
@@ -1034,18 +1034,18 @@ EndPrepare(GlobalTransaction gxact)
10341034
* odds of a PANIC actually occurring should be very tiny given that we
10351035
* were able to write the bogus CRC above.
10361036
*
1037-
* We have to set inCommit here, too; otherwise a checkpoint starting
1037+
* We have to set delayChkpt here, too; otherwise a checkpoint starting
10381038
* immediately after the WAL record is inserted could complete without
10391039
* fsync'ing our state file. (This is essentially the same kind of race
10401040
* condition as the COMMIT-to-clog-write case that RecordTransactionCommit
1041-
* uses inCommit for; see notes there.)
1041+
* uses delayChkpt for; see notes there.)
10421042
*
10431043
* We save the PREPARE record's location in the gxact for later use by
10441044
* CheckPointTwoPhase.
10451045
*/
10461046
START_CRIT_SECTION();
10471047

1048-
MyPgXact->inCommit = true;
1048+
MyPgXact->delayChkpt = true;
10491049

10501050
gxact->prepare_lsn = XLogInsert(RM_XACT_ID, XLOG_XACT_PREPARE,
10511051
records.head);
@@ -1086,7 +1086,7 @@ EndPrepare(GlobalTransaction gxact)
10861086
* checkpoint starting after this will certainly see the gxact as a
10871087
* candidate for fsyncing.
10881088
*/
1089-
MyPgXact->inCommit = false;
1089+
MyPgXact->delayChkpt = false;
10901090

10911091
END_CRIT_SECTION();
10921092

@@ -1972,7 +1972,7 @@ RecoverPreparedTransactions(void)
19721972
* RecordTransactionCommitPrepared
19731973
*
19741974
* This is basically the same as RecordTransactionCommit: in particular,
1975-
* we must set the inCommit flag to avoid a race condition.
1975+
* we must set the delayChkpt flag to avoid a race condition.
19761976
*
19771977
* We know the transaction made at least one XLOG entry (its PREPARE),
19781978
* so it is never possible to optimize out the commit record.
@@ -1995,7 +1995,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
19951995
START_CRIT_SECTION();
19961996

19971997
/* See notes in RecordTransactionCommit */
1998-
MyPgXact->inCommit = true;
1998+
MyPgXact->delayChkpt = true;
19991999

20002000
/* Emit the XLOG commit record */
20012001
xlrec.xid = xid;
@@ -2053,7 +2053,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
20532053
TransactionIdCommitTree(xid, nchildren, children);
20542054

20552055
/* Checkpoint can proceed now */
2056-
MyPgXact->inCommit = false;
2056+
MyPgXact->delayChkpt = false;
20572057

20582058
END_CRIT_SECTION();
20592059

src/backend/access/transam/xact.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,13 +1001,13 @@ RecordTransactionCommit(void)
10011001
* RecordTransactionAbort. That's because loss of a transaction abort
10021002
* is noncritical; the presumption would be that it aborted, anyway.
10031003
*
1004-
* It's safe to change the inCommit flag of our own backend without
1004+
* It's safe to change the delayChkpt flag of our own backend without
10051005
* holding the ProcArrayLock, since we're the only one modifying it.
1006-
* This makes checkpoint's determination of which xacts are inCommit a
1006+
* This makes checkpoint's determination of which xacts are delayChkpt a
10071007
* bit fuzzy, but it doesn't matter.
10081008
*/
10091009
START_CRIT_SECTION();
1010-
MyPgXact->inCommit = true;
1010+
MyPgXact->delayChkpt = true;
10111011

10121012
SetCurrentTransactionStopTimestamp();
10131013

@@ -1160,7 +1160,7 @@ RecordTransactionCommit(void)
11601160
*/
11611161
if (markXidCommitted)
11621162
{
1163-
MyPgXact->inCommit = false;
1163+
MyPgXact->delayChkpt = false;
11641164
END_CRIT_SECTION();
11651165
}
11661166

src/backend/access/transam/xlog.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6884,8 +6884,8 @@ CreateCheckPoint(int flags)
68846884
XLogRecData rdata;
68856885
uint32 freespace;
68866886
XLogSegNo _logSegNo;
6887-
TransactionId *inCommitXids;
6888-
int nInCommit;
6887+
VirtualTransactionId *vxids;
6888+
int nvxids;
68896889

68906890
/*
68916891
* An end-of-recovery checkpoint is really a shutdown checkpoint, just
@@ -7056,9 +7056,14 @@ CreateCheckPoint(int flags)
70567056
TRACE_POSTGRESQL_CHECKPOINT_START(flags);
70577057

70587058
/*
7059-
* Before flushing data, we must wait for any transactions that are
7060-
* currently in their commit critical sections. If an xact inserted its
7061-
* commit record into XLOG just before the REDO point, then a crash
7059+
* In some cases there are groups of actions that must all occur on
7060+
* one side or the other of a checkpoint record. Before flushing the
7061+
* checkpoint record we must explicitly wait for any backend currently
7062+
* performing those groups of actions.
7063+
*
7064+
* One example is end of transaction, so we must wait for any transactions
7065+
* that are currently in commit critical sections. If an xact inserted
7066+
* its commit record into XLOG just before the REDO point, then a crash
70627067
* restart from the REDO point would not replay that record, which means
70637068
* that our flushing had better include the xact's update of pg_clog. So
70647069
* we wait till he's out of his commit critical section before proceeding.
@@ -7073,21 +7078,24 @@ CreateCheckPoint(int flags)
70737078
* protected by different locks, but again that seems best on grounds of
70747079
* minimizing lock contention.)
70757080
*
7076-
* A transaction that has not yet set inCommit when we look cannot be at
7081+
* A transaction that has not yet set delayChkpt when we look cannot be at
70777082
* risk, since he's not inserted his commit record yet; and one that's
70787083
* already cleared it is not at risk either, since he's done fixing clog
70797084
* and we will correctly flush the update below. So we cannot miss any
70807085
* xacts we need to wait for.
70817086
*/
7082-
nInCommit = GetTransactionsInCommit(&inCommitXids);
7083-
if (nInCommit > 0)
7087+
vxids = GetVirtualXIDsDelayingChkpt(&nvxids);
7088+
if (nvxids > 0)
70847089
{
7090+
uint nwaits = 0;
7091+
70857092
do
70867093
{
70877094
pg_usleep(10000L); /* wait for 10 msec */
7088-
} while (HaveTransactionsInCommit(inCommitXids, nInCommit));
7095+
nwaits++;
7096+
} while (HaveVirtualXIDsDelayingChkpt(vxids, nvxids));
70897097
}
7090-
pfree(inCommitXids);
7098+
pfree(vxids);
70917099

70927100
/*
70937101
* Get the other info we need for the checkpoint record.

src/backend/storage/ipc/procarray.c

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
400400
pgxact->xmin = InvalidTransactionId;
401401
/* must be cleared with xid/xmin: */
402402
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
403-
pgxact->inCommit = false; /* be sure this is cleared in abort */
403+
pgxact->delayChkpt = false; /* be sure this is cleared in abort */
404404
proc->recoveryConflictPending = false;
405405

406406
/* Clear the subtransaction-XID cache too while holding the lock */
@@ -427,7 +427,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
427427
pgxact->xmin = InvalidTransactionId;
428428
/* must be cleared with xid/xmin: */
429429
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
430-
pgxact->inCommit = false; /* be sure this is cleared in abort */
430+
pgxact->delayChkpt = false; /* be sure this is cleared in abort */
431431
proc->recoveryConflictPending = false;
432432

433433
Assert(pgxact->nxids == 0);
@@ -462,7 +462,7 @@ ProcArrayClearTransaction(PGPROC *proc)
462462

463463
/* redundant, but just in case */
464464
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
465-
pgxact->inCommit = false;
465+
pgxact->delayChkpt = false;
466466

467467
/* Clear the subtransaction-XID cache too */
468468
pgxact->nxids = 0;
@@ -1778,96 +1778,103 @@ GetOldestActiveTransactionId(void)
17781778
}
17791779

17801780
/*
1781-
* GetTransactionsInCommit -- Get the XIDs of transactions that are committing
1781+
* GetVirtualXIDsDelayingChkpt -- Get the VXIDs of transactions that are
1782+
* delaying checkpoint because they have critical actions in progress.
17821783
*
1783-
* Constructs an array of XIDs of transactions that are currently in commit
1784-
* critical sections, as shown by having inCommit set in their PGXACT entries.
1784+
* Constructs an array of VXIDs of transactions that are currently in commit
1785+
* critical sections, as shown by having delayChkpt set in their PGXACT.
17851786
*
1786-
* *xids_p is set to a palloc'd array that should be freed by the caller.
1787-
* The return value is the number of valid entries.
1787+
* Returns a palloc'd array that should be freed by the caller.
1788+
* *nvxids is the number of valid entries.
17881789
*
1789-
* Note that because backends set or clear inCommit without holding any lock,
1790+
* Note that because backends set or clear delayChkpt without holding any lock,
17901791
* the result is somewhat indeterminate, but we don't really care. Even in
17911792
* a multiprocessor with delayed writes to shared memory, it should be certain
1792-
* that setting of inCommit will propagate to shared memory when the backend
1793-
* takes the WALInsertLock, so we cannot fail to see an xact as inCommit if
1793+
* that setting of delayChkpt will propagate to shared memory when the backend
1794+
* takes a lock, so we cannot fail to see an virtual xact as delayChkpt if
17941795
* it's already inserted its commit record. Whether it takes a little while
1795-
* for clearing of inCommit to propagate is unimportant for correctness.
1796+
* for clearing of delayChkpt to propagate is unimportant for correctness.
17961797
*/
1797-
int
1798-
GetTransactionsInCommit(TransactionId **xids_p)
1798+
VirtualTransactionId *
1799+
GetVirtualXIDsDelayingChkpt(int *nvxids)
17991800
{
1801+
VirtualTransactionId *vxids;
18001802
ProcArrayStruct *arrayP = procArray;
1801-
TransactionId *xids;
1802-
int nxids;
1803+
int count = 0;
18031804
int index;
18041805

1805-
xids = (TransactionId *) palloc(arrayP->maxProcs * sizeof(TransactionId));
1806-
nxids = 0;
1806+
/* allocate what's certainly enough result space */
1807+
vxids = (VirtualTransactionId *)
1808+
palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
18071809

18081810
LWLockAcquire(ProcArrayLock, LW_SHARED);
18091811

18101812
for (index = 0; index < arrayP->numProcs; index++)
18111813
{
1812-
int pgprocno = arrayP->pgprocnos[index];
1813-
volatile PGXACT *pgxact = &allPgXact[pgprocno];
1814-
TransactionId pxid;
1814+
int pgprocno = arrayP->pgprocnos[index];
1815+
volatile PGPROC *proc = &allProcs[pgprocno];
1816+
volatile PGXACT *pgxact = &allPgXact[pgprocno];
18151817

1816-
/* Fetch xid just once - see GetNewTransactionId */
1817-
pxid = pgxact->xid;
1818+
if (pgxact->delayChkpt)
1819+
{
1820+
VirtualTransactionId vxid;
18181821

1819-
if (pgxact->inCommit && TransactionIdIsValid(pxid))
1820-
xids[nxids++] = pxid;
1822+
GET_VXID_FROM_PGPROC(vxid, *proc);
1823+
if (VirtualTransactionIdIsValid(vxid))
1824+
vxids[count++] = vxid;
1825+
}
18211826
}
18221827

18231828
LWLockRelease(ProcArrayLock);
18241829

1825-
*xids_p = xids;
1826-
return nxids;
1830+
*nvxids = count;
1831+
return vxids;
18271832
}
18281833

18291834
/*
1830-
* HaveTransactionsInCommit -- Are any of the specified XIDs in commit?
1835+
* HaveVirtualXIDsDelayingChkpt -- Are any of the specified VXIDs delaying?
18311836
*
1832-
* This is used with the results of GetTransactionsInCommit to see if any
1833-
* of the specified XIDs are still in their commit critical sections.
1837+
* This is used with the results of GetVirtualXIDsDelayingChkpt to see if any
1838+
* of the specified VXIDs are still in critical sections of code.
18341839
*
1835-
* Note: this is O(N^2) in the number of xacts that are/were in commit, but
1840+
* Note: this is O(N^2) in the number of vxacts that are/were delaying, but
18361841
* those numbers should be small enough for it not to be a problem.
18371842
*/
18381843
bool
1839-
HaveTransactionsInCommit(TransactionId *xids, int nxids)
1844+
HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids)
18401845
{
18411846
bool result = false;
18421847
ProcArrayStruct *arrayP = procArray;
18431848
int index;
18441849

18451850
LWLockAcquire(ProcArrayLock, LW_SHARED);
18461851

1847-
for (index = 0; index < arrayP->numProcs; index++)
1852+
while (VirtualTransactionIdIsValid(*vxids))
18481853
{
1849-
int pgprocno = arrayP->pgprocnos[index];
1850-
volatile PGXACT *pgxact = &allPgXact[pgprocno];
1851-
TransactionId pxid;
1852-
1853-
/* Fetch xid just once - see GetNewTransactionId */
1854-
pxid = pgxact->xid;
1855-
1856-
if (pgxact->inCommit && TransactionIdIsValid(pxid))
1854+
for (index = 0; index < arrayP->numProcs; index++)
18571855
{
1858-
int i;
1856+
int pgprocno = arrayP->pgprocnos[index];
1857+
volatile PGPROC *proc = &allProcs[pgprocno];
1858+
volatile PGXACT *pgxact = &allPgXact[pgprocno];
1859+
VirtualTransactionId vxid;
18591860

1860-
for (i = 0; i < nxids; i++)
1861+
GET_VXID_FROM_PGPROC(vxid, *proc);
1862+
if (VirtualTransactionIdIsValid(vxid))
18611863
{
1862-
if (xids[i] == pxid)
1864+
if (VirtualTransactionIdEquals(vxid, *vxids) &&
1865+
pgxact->delayChkpt)
18631866
{
18641867
result = true;
18651868
break;
18661869
}
18671870
}
1868-
if (result)
1869-
break;
18701871
}
1872+
1873+
if (result)
1874+
break;
1875+
1876+
/* The virtual transaction is gone now, wait for the next one */
1877+
vxids++;
18711878
}
18721879

18731880
LWLockRelease(ProcArrayLock);

src/backend/storage/lmgr/proc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ InitProcess(void)
350350
MyProc->backendId = InvalidBackendId;
351351
MyProc->databaseId = InvalidOid;
352352
MyProc->roleId = InvalidOid;
353-
MyPgXact->inCommit = false;
353+
MyPgXact->delayChkpt = false;
354354
MyPgXact->vacuumFlags = 0;
355355
/* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
356356
if (IsAutoVacuumWorkerProcess())
@@ -516,7 +516,7 @@ InitAuxiliaryProcess(void)
516516
MyProc->backendId = InvalidBackendId;
517517
MyProc->databaseId = InvalidOid;
518518
MyProc->roleId = InvalidOid;
519-
MyPgXact->inCommit = false;
519+
MyPgXact->delayChkpt = false;
520520
MyPgXact->vacuumFlags = 0;
521521
MyProc->lwWaiting = false;
522522
MyProc->lwWaitMode = 0;

src/include/storage/proc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ typedef struct PGXACT
168168

169169
uint8 vacuumFlags; /* vacuum-related flags, see above */
170170
bool overflowed;
171-
bool inCommit; /* true if within commit critical section */
171+
bool delayChkpt; /* true if this proc delays checkpoint start */
172+
/* previously called InCommit */
172173

173174
uint8 nxids;
174175
} PGXACT;

src/include/storage/procarray.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ extern bool TransactionIdIsActive(TransactionId xid);
5252
extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
5353
extern TransactionId GetOldestActiveTransactionId(void);
5454

55-
extern int GetTransactionsInCommit(TransactionId **xids_p);
56-
extern bool HaveTransactionsInCommit(TransactionId *xids, int nxids);
55+
extern VirtualTransactionId *GetVirtualXIDsDelayingChkpt(int *nvxids);
56+
extern bool HaveVirtualXIDsDelayingChkpt(VirtualTransactionId *vxids, int nvxids);
5757

5858
extern PGPROC *BackendPidGetProc(int pid);
5959
extern int BackendXidGetPid(TransactionId xid);

0 commit comments

Comments
 (0)