shmemvariablecache-replay.patch
text/x-patch
Filename: shmemvariablecache-replay.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/access/transam/multixact.c | 0 | 0 |
| src/backend/access/transam/twophase.c | 0 | 0 |
| src/backend/access/transam/xlog.c | 0 | 0 |
| src/backend/storage/ipc/procarray.c | 0 | 0 |
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 454ca310f339db34a4cc352899fea1d663abf93b..0f4cea124d7436380c730203e6cfd1518bc5d3b2 100644
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
*************** CheckPointMultiXact(void)
*** 1655,1662 ****
* Set the next-to-be-assigned MultiXactId and offset
*
* This is used when we can determine the correct next ID/offset exactly
! * from a checkpoint record. We need no locking since it is only called
! * during bootstrap and XLog replay.
*/
void
MultiXactSetNextMXact(MultiXactId nextMulti,
--- 1655,1663 ----
* Set the next-to-be-assigned MultiXactId and offset
*
* This is used when we can determine the correct next ID/offset exactly
! * from a checkpoint record. Although this is only called during bootstrap
! * and XLog replay, we take the lock in case any hot-standby backends are
! * examining the values.
*/
void
MultiXactSetNextMXact(MultiXactId nextMulti,
*************** MultiXactSetNextMXact(MultiXactId nextMu
*** 1664,1671 ****
--- 1665,1674 ----
{
debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
nextMulti, nextMultiOffset);
+ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
MultiXactState->nextMXact = nextMulti;
MultiXactState->nextOffset = nextMultiOffset;
+ LWLockRelease(MultiXactGenLock);
}
/*
*************** MultiXactSetNextMXact(MultiXactId nextMu
*** 1674,1685 ****
*
* This is used when we can determine minimum safe values from an XLog
* record (either an on-line checkpoint or an mxact creation log entry).
! * We need no locking since it is only called during XLog replay.
*/
void
MultiXactAdvanceNextMXact(MultiXactId minMulti,
MultiXactOffset minMultiOffset)
{
if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
{
debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
--- 1677,1690 ----
*
* This is used when we can determine minimum safe values from an XLog
* record (either an on-line checkpoint or an mxact creation log entry).
! * Although this is only called during XLog replay, we take the lock in case
! * any hot-standby backends are examining the values.
*/
void
MultiXactAdvanceNextMXact(MultiXactId minMulti,
MultiXactOffset minMultiOffset)
{
+ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
{
debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
*************** MultiXactAdvanceNextMXact(MultiXactId mi
*** 1691,1696 ****
--- 1696,1702 ----
minMultiOffset);
MultiXactState->nextOffset = minMultiOffset;
}
+ LWLockRelease(MultiXactGenLock);
}
/*
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 6e84cd0a21671486693e7f94d5fda8efdedf4bb4..3d08e92d3a747cc9426206dc0623ff390f18b09c 100644
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
*************** PrescanPreparedTransactions(TransactionI
*** 1715,1720 ****
--- 1715,1724 ----
/*
* Examine subtransaction XIDs ... they should all follow main
* XID, and they may force us to advance nextXid.
+ *
+ * We don't expect anyone else to modify nextXid, hence we don't
+ * need to hold a lock while examining it. We still acquire the
+ * lock to modify it, though.
*/
subxids = (TransactionId *)
(buf + MAXALIGN(sizeof(TwoPhaseFileHeader)));
*************** PrescanPreparedTransactions(TransactionI
*** 1726,1733 ****
--- 1730,1739 ----
if (TransactionIdFollowsOrEquals(subxid,
ShmemVariableCache->nextXid))
{
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->nextXid = subxid;
TransactionIdAdvance(ShmemVariableCache->nextXid);
+ LWLockRelease(XidGenLock);
}
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b128bfda36dbf00c0ef49a34bd2d48d6cdf42218..5e59c1ab1967a0516ef5e240286c36cab9ae2570 100644
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
*************** StartupXLOG(void)
*** 6625,6636 ****
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
! /* nextXid must be beyond record's xid */
if (TransactionIdFollowsOrEquals(record->xl_xid,
ShmemVariableCache->nextXid))
{
ShmemVariableCache->nextXid = record->xl_xid;
TransactionIdAdvance(ShmemVariableCache->nextXid);
}
/*
--- 6625,6644 ----
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
! /*
! * ShmemVariableCache->nextXid must be beyond record's xid.
! *
! * We don't expect anyone else to modify nextXid, hence we
! * don't need to hold a lock while examining it. We still
! * acquire the lock to modify it, though.
! */
if (TransactionIdFollowsOrEquals(record->xl_xid,
ShmemVariableCache->nextXid))
{
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->nextXid = record->xl_xid;
TransactionIdAdvance(ShmemVariableCache->nextXid);
+ LWLockRelease(XidGenLock);
}
/*
*************** StartupXLOG(void)
*** 6656,6661 ****
--- 6664,6670 ----
TransactionIdIsValid(record->xl_xid))
RecordKnownAssignedTransactionIds(record->xl_xid);
+ /* Now apply the WAL record itself */
RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);
/* Pop the error context stack */
*************** StartupXLOG(void)
*** 6971,6978 ****
--- 6980,6989 ----
XLogCtl->ckptXid = ControlFile->checkPointCopy.nextXid;
/* also initialize latestCompletedXid, to nextXid - 1 */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
ShmemVariableCache->latestCompletedXid = ShmemVariableCache->nextXid;
TransactionIdRetreat(ShmemVariableCache->latestCompletedXid);
+ LWLockRelease(ProcArrayLock);
/*
* Start up the commit log and subtrans, if not already done for
*************** xlog_redo(XLogRecPtr lsn, XLogRecord *re
*** 8547,8558 ****
{
Oid nextOid;
memcpy(&nextOid, XLogRecGetData(record), sizeof(Oid));
! if (ShmemVariableCache->nextOid < nextOid)
! {
! ShmemVariableCache->nextOid = nextOid;
! ShmemVariableCache->oidCount = 0;
! }
}
else if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
--- 8558,8575 ----
{
Oid nextOid;
+ /*
+ * We used to try to take the maximum of ShmemVariableCache->nextOid
+ * and the recorded nextOid, but that fails if the OID counter wraps
+ * around. Since no OID allocation should be happening during replay
+ * anyway, better to just believe the record exactly. We still take
+ * OidGenLock while setting the variable, just in case.
+ */
memcpy(&nextOid, XLogRecGetData(record), sizeof(Oid));
! LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
! ShmemVariableCache->nextOid = nextOid;
! ShmemVariableCache->oidCount = 0;
! LWLockRelease(OidGenLock);
}
else if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
*************** xlog_redo(XLogRecPtr lsn, XLogRecord *re
*** 8560,8568 ****
--- 8577,8589 ----
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
/* In a SHUTDOWN checkpoint, believe the counters exactly */
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->nextXid = checkPoint.nextXid;
+ LWLockRelease(XidGenLock);
+ LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->nextOid = checkPoint.nextOid;
ShmemVariableCache->oidCount = 0;
+ LWLockRelease(OidGenLock);
MultiXactSetNextMXact(checkPoint.nextMulti,
checkPoint.nextMultiOffset);
SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
*************** xlog_redo(XLogRecPtr lsn, XLogRecord *re
*** 8575,8581 ****
if (InArchiveRecovery &&
!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
! ereport(ERROR,
(errmsg("online backup was canceled, recovery cannot continue")));
/*
--- 8596,8602 ----
if (InArchiveRecovery &&
!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
! ereport(PANIC,
(errmsg("online backup was canceled, recovery cannot continue")));
/*
*************** xlog_redo(XLogRecPtr lsn, XLogRecord *re
*** 8641,8655 ****
CheckPoint checkPoint;
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
! /* In an ONLINE checkpoint, treat the counters like NEXTOID */
if (TransactionIdPrecedes(ShmemVariableCache->nextXid,
checkPoint.nextXid))
ShmemVariableCache->nextXid = checkPoint.nextXid;
! if (ShmemVariableCache->nextOid < checkPoint.nextOid)
! {
! ShmemVariableCache->nextOid = checkPoint.nextOid;
! ShmemVariableCache->oidCount = 0;
! }
MultiXactAdvanceNextMXact(checkPoint.nextMulti,
checkPoint.nextMultiOffset);
if (TransactionIdPrecedes(ShmemVariableCache->oldestXid,
--- 8662,8678 ----
CheckPoint checkPoint;
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
! /* In an ONLINE checkpoint, treat the XID counter as a minimum */
! LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
if (TransactionIdPrecedes(ShmemVariableCache->nextXid,
checkPoint.nextXid))
ShmemVariableCache->nextXid = checkPoint.nextXid;
! LWLockRelease(XidGenLock);
! /* ... but still treat OID counter as exact */
! LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
! ShmemVariableCache->nextOid = checkPoint.nextOid;
! ShmemVariableCache->oidCount = 0;
! LWLockRelease(OidGenLock);
MultiXactAdvanceNextMXact(checkPoint.nextMulti,
checkPoint.nextMultiOffset);
if (TransactionIdPrecedes(ShmemVariableCache->oldestXid,
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 8bda474bc712938ce8619e5ba715c12e7ba45deb..09b7311e7bcd82fbdc16d62ffcd8f3214193ab50 100644
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
*************** ProcArrayApplyRecoveryInfo(RunningTransa
*** 654,670 ****
running->latestCompletedXid))
ShmemVariableCache->latestCompletedXid = running->latestCompletedXid;
! /* nextXid must be beyond any observed xid */
nextXid = latestObservedXid;
TransactionIdAdvance(nextXid);
if (TransactionIdFollows(nextXid, ShmemVariableCache->nextXid))
ShmemVariableCache->nextXid = nextXid;
- Assert(TransactionIdIsNormal(ShmemVariableCache->latestCompletedXid));
Assert(TransactionIdIsValid(ShmemVariableCache->nextXid));
- LWLockRelease(ProcArrayLock);
-
KnownAssignedXidsDisplay(trace_recovery(DEBUG3));
if (standbyState == STANDBY_SNAPSHOT_READY)
elog(trace_recovery(DEBUG1), "recovery snapshots are now enabled");
--- 654,681 ----
running->latestCompletedXid))
ShmemVariableCache->latestCompletedXid = running->latestCompletedXid;
! Assert(TransactionIdIsNormal(ShmemVariableCache->latestCompletedXid));
!
! LWLockRelease(ProcArrayLock);
!
! /*
! * ShmemVariableCache->nextXid must be beyond any observed xid.
! *
! * We don't expect anyone else to modify nextXid, hence we don't need to
! * hold a lock while examining it. We still acquire the lock to modify
! * it, though.
! */
nextXid = latestObservedXid;
TransactionIdAdvance(nextXid);
if (TransactionIdFollows(nextXid, ShmemVariableCache->nextXid))
+ {
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->nextXid = nextXid;
+ LWLockRelease(XidGenLock);
+ }
Assert(TransactionIdIsValid(ShmemVariableCache->nextXid));
KnownAssignedXidsDisplay(trace_recovery(DEBUG3));
if (standbyState == STANDBY_SNAPSHOT_READY)
elog(trace_recovery(DEBUG1), "recovery snapshots are now enabled");
*************** GetOldestActiveTransactionId(void)
*** 1690,1695 ****
--- 1701,1713 ----
LWLockAcquire(ProcArrayLock, LW_SHARED);
+ /*
+ * It's okay to read nextXid without acquiring XidGenLock because (1) we
+ * assume TransactionIds can be read atomically and (2) we don't care if
+ * we get a slightly stale value. It can't be very stale anyway, because
+ * the LWLockAcquire above will have done any necessary memory
+ * interlocking.
+ */
oldestRunningXid = ShmemVariableCache->nextXid;
/*
*************** RecordKnownAssignedTransactionIds(Transa
*** 2609,2615 ****
--- 2627,2635 ----
/* ShmemVariableCache->nextXid must be beyond any observed xid */
next_expected_xid = latestObservedXid;
TransactionIdAdvance(next_expected_xid);
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
ShmemVariableCache->nextXid = next_expected_xid;
+ LWLockRelease(XidGenLock);
}
}