summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2015-07-23 01:30:11 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2015-07-23 01:30:11 +0300
commit6ae9a021893b5cd24e1d7e8a1a07854d33af9990 (patch)
tree2ed8d0de97c7cf845f7673d155da05b831d26c6f /src
parentb2efbb71dfb48108d142e954b9e608253ceee91c (diff)
Fix off-by-one error in calculating subtrans/multixact truncation point.
If there were no subtransactions (or multixacts) active, we would calculate the oldestxid == next xid. That's correct, but if next XID happens to be on the next pg_subtrans (pg_multixact) page, the page does not exist yet, and SimpleLruTruncate will produce an "apparent wraparound" warning. The warning is harmless in this case, but looks very alarming to users. Backpatch to all supported versions. Patch and analysis by Thomas Munro.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/multixact.c12
-rw-r--r--src/backend/access/transam/subtrans.c7
2 files changed, 16 insertions, 3 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 77f6d3cb3a9..9b10496d9bd 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -171,6 +171,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
@@ -3076,9 +3078,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 1c8b52b33f8..a9e4d31ce44 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);