summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/heap/heapam.c52
1 files changed, 40 insertions, 12 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 72395a50b8..b8bfe23a82 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8172,7 +8172,7 @@ heap_xlog_cleanup_info(XLogReaderState *record)
}
/*
- * Handles HEAP2_CLEAN record type
+ * Handles XLOG_HEAP2_CLEAN record type
*/
static void
heap_xlog_clean(XLogReaderState *record)
@@ -8180,7 +8180,6 @@ heap_xlog_clean(XLogReaderState *record)
XLogRecPtr lsn = record->EndRecPtr;
xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record);
Buffer buffer;
- Size freespace = 0;
RelFileNode rnode;
BlockNumber blkno;
XLogRedoAction action;
@@ -8232,8 +8231,6 @@ heap_xlog_clean(XLogReaderState *record)
nowdead, ndead,
nowunused, nunused);
- freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
-
/*
* Note: we don't worry about updating the page's prunability hints.
* At worst this will cause an extra prune cycle to occur soon.
@@ -8242,18 +8239,24 @@ heap_xlog_clean(XLogReaderState *record)
PageSetLSN(page, lsn);
MarkBufferDirty(buffer);
}
+
if (BufferIsValid(buffer))
+ {
+ Size freespace = PageGetHeapFreeSpace(BufferGetPage(buffer));
+
UnlockReleaseBuffer(buffer);
- /*
- * Update the FSM as well.
- *
- * XXX: Don't do this if the page was restored from full page image. We
- * don't bother to update the FSM in that case, it doesn't need to be
- * totally accurate anyway.
- */
- if (action == BLK_NEEDS_REDO)
+ /*
+ * After cleaning records from a page, it's useful to update the FSM
+ * about it, as it may cause the page become target for insertions
+ * later even if vacuum decides not to visit it (which is possible if
+ * gets marked all-visible.)
+ *
+ * Do this regardless of a full-page image being applied, since the
+ * FSM data is not in the page anyway.
+ */
XLogRecordPageWithFreeSpace(rnode, blkno, freespace);
+ }
}
/*
@@ -8326,9 +8329,34 @@ heap_xlog_visible(XLogReaderState *record)
* wal_log_hints enabled.)
*/
}
+
if (BufferIsValid(buffer))
+ {
+ Size space = PageGetFreeSpace(BufferGetPage(buffer));
+
UnlockReleaseBuffer(buffer);
+ /*
+ * Since FSM is not WAL-logged and only updated heuristically, it
+ * easily becomes stale in standbys. If the standby is later promoted
+ * and runs VACUUM, it will skip updating individual free space
+ * figures for pages that became all-visible (or all-frozen, depending
+ * on the vacuum mode,) which is troublesome when FreeSpaceMapVacuum
+ * propagates too optimistic free space values to upper FSM layers;
+ * later inserters try to use such pages only to find out that they
+ * are unusable. This can cause long stalls when there are many such
+ * pages.
+ *
+ * Forestall those problems by updating FSM's idea about a page that
+ * is becoming all-visible or all-frozen.
+ *
+ * Do this regardless of a full-page image being applied, since the
+ * FSM data is not in the page anyway.
+ */
+ if (xlrec->flags & VISIBILITYMAP_VALID_BITS)
+ XLogRecordPageWithFreeSpace(rnode, blkno, space);
+ }
+
/*
* Even if we skipped the heap page update due to the LSN interlock, it's
* still safe to update the visibility map. Any WAL record that clears