aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/multixact.c13
-rw-r--r--src/backend/access/transam/subtrans.c7
2 files changed, 16 insertions, 4 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 377d0842bdd..1933a87d656 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
@@ -3057,10 +3059,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)));
/*
* Now, and only now, we can advance the stop point for multixact members.
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 4bc24d9bbcb..6b709823227 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);