diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/transam/multixact.c | 14 | ||||
-rw-r--r-- | src/backend/access/transam/subtrans.c | 7 |
2 files changed, 16 insertions, 5 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index b90c110dcad..5182b4acb53 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -90,6 +90,8 @@ #define MXOffsetToMemberEntry(xid) \ ((xid) % (TransactionId) MULTIXACT_MEMBERS_PER_PAGE) +#define PreviousMultiXactId(xid) \ + ((xid) == FirstMultiXactId ? MaxMultiXactId : (xid) - 1) /* * Links to shared-memory data structures for MultiXact control @@ -1902,17 +1904,21 @@ TruncateMultiXact(void) } /* - * The cutoff point is the start of the segment containing oldestMXact. We - * pass the *page* containing oldestMXact to SimpleLruTruncate. + * The cutoff point is the start of the segment containing oldestMXact. + * We step back one multixact to avoid passing a cutoff page that hasn't + * been created yet in the rare case that oldestMXact would be the first + * item on a page and oldestMXact == nextMXact. In that case, if we + * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound + * detection. */ - cutoffPage = MultiXactIdToOffsetPage(oldestMXact); + cutoffPage = MultiXactIdToOffsetPage(PreviousMultiXactId(oldestMXact)); SimpleLruTruncate(MultiXactOffsetCtl, cutoffPage); /* * Also truncate MultiXactMember at the previously determined offset. */ - cutoffPage = MXOffsetToMemberPage(oldestOffset); + cutoffPage = MXOffsetToMemberPage(oldestOffset - 1); SimpleLruTruncate(MultiXactMemberCtl, cutoffPage); diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c index c6fa2419c63..39e0f10866f 100644 --- a/src/backend/access/transam/subtrans.c +++ b/src/backend/access/transam/subtrans.c @@ -340,8 +340,13 @@ TruncateSUBTRANS(TransactionId oldestXact) /* * The cutoff point is the start of the segment containing oldestXact. We - * pass the *page* containing oldestXact to SimpleLruTruncate. + * pass the *page* containing oldestXact to SimpleLruTruncate. We step + * back one transaction to avoid passing a cutoff page that hasn't been + * created yet in the rare case that oldestXact would be the first item on + * a page and oldestXact == next XID. In that case, if we didn't subtract + * one, we'd trigger SimpleLruTruncate's wraparound detection. */ + TransactionIdRetreat(oldestXact); cutoffPage = TransactionIdToPage(oldestXact); SimpleLruTruncate(SubTransCtl, cutoffPage); |