diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c index f0436859957..5988486ecb7 100644 --- a/src/backend/access/heap/visibilitymap.c +++ b/src/backend/access/heap/visibilitymap.c @@ -473,6 +473,9 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) LockBuffer(mapBuffer, BUFFER_LOCK_EXCLUSIVE); + /* NO EREPORT(ERROR) from here till changes are logged */ + START_CRIT_SECTION(); + /* Clear out the unwanted bytes. */ MemSet(&map[truncByte + 1], 0, MAPSIZE - (truncByte + 1)); @@ -488,7 +491,20 @@ visibilitymap_truncate(Relation rel, BlockNumber nheapblocks) */ map[truncByte] &= (1 << truncBit) - 1; + /* + * Truncation of a relation is WAL-logged at a higher-level, and we + * will be called at WAL replay. But if checksums are enabled, we need + * to still write a WAL record to protect against a torn page, if the + * page is flushed to disk before the truncation WAL record. We cannot + * use MarkBufferDirtyHint here, because that will not dirty the page + * during recovery. + */ MarkBufferDirty(mapBuffer); + if (!InRecovery && RelationNeedsWAL(rel) && DataChecksumsEnabled()) + log_newpage_buffer(mapBuffer); + + END_CRIT_SECTION(); + UnlockReleaseBuffer(mapBuffer); } else diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 4845f93a598..f68d004b146 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -23,6 +23,7 @@ */ #include "postgres.h" +#include "access/heapam_xlog.h" #include "access/htup_details.h" #include "access/xlogutils.h" #include "miscadmin.h" @@ -285,8 +286,26 @@ FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks) if (!BufferIsValid(buf)) return; /* nothing to do; the FSM was already smaller */ LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); + + /* NO EREPORT(ERROR) from here till changes are logged */ + START_CRIT_SECTION(); + fsm_truncate_avail(BufferGetPage(buf), first_removed_slot); - MarkBufferDirtyHint(buf, false); + + /* + * Truncation of a relation is WAL-logged at a higher-level, and we + * will be called at WAL replay. But if checksums are enabled, we need + * to still write a WAL record to protect against a torn page, if the + * page is flushed to disk before the truncation WAL record. We cannot + * use MarkBufferDirtyHint here, because that will not dirty the page + * during recovery. + */ + MarkBufferDirty(buf); + if (!InRecovery && RelationNeedsWAL(rel) && DataChecksumsEnabled()) + log_newpage_buffer(buf); + + END_CRIT_SECTION(); + UnlockReleaseBuffer(buf); new_nfsmblocks = fsm_logical_to_physical(first_removed_address) + 1;