diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 516a89f..1f01725 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -173,6 +173,8 @@ #define MULTIXACT_MEMBER_DANGER_THRESHOLD \ (MaxMultiXactOffset - MaxMultiXactOffset / 4) +#define PreviousMultiXactId(xid) \ + ((xid) == FirstMultiXactId ? MaxMultiXactId : (xid) - 1) /* * Links to shared-memory data structures for MultiXact control @@ -3014,9 +3016,15 @@ TruncateMultiXact(void) SlruScanDirectory(MultiXactMemberCtl, SlruScanDirCbRemoveMembers, &range); - /* Now we can truncate MultiXactOffset */ + /* + * Now we can truncate MultiXactOffset. 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. + */ SimpleLruTruncate(MultiXactOffsetCtl, - MultiXactIdToOffsetPage(oldestMXact)); + MultiXactIdToOffsetPage(PreviousMultiXactId(oldestMXact))); /* diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c index 4bc24d9..48b7b98 100644 --- a/src/backend/access/transam/subtrans.c +++ b/src/backend/access/transam/subtrans.c @@ -340,9 +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. */ - cutoffPage = TransactionIdToPage(oldestXact); + cutoffPage = TransactionIdToPage(PreviousTransactionId(oldestXact)); SimpleLruTruncate(SubTransCtl, cutoffPage); } diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 96b3fac..2ca90bb 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -43,6 +43,8 @@ #define TransactionIdEquals(id1, id2) ((id1) == (id2)) #define TransactionIdStore(xid, dest) (*(dest) = (xid)) #define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId) +#define PreviousTransactionId(xid) \ + ((xid) == FirstNormalTransactionId ? MaxTransactionId : (xid) - 1) /* advance a transaction ID variable, handling wraparound correctly */ #define TransactionIdAdvance(dest) \