Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix theoretical torn page hazard.
authorJeff Davis <jdavis@postgresql.org>
Thu, 10 Nov 2022 22:46:30 +0000 (14:46 -0800)
committerJeff Davis <jdavis@postgresql.org>
Fri, 11 Nov 2022 20:46:44 +0000 (12:46 -0800)
The original report was concerned with a possible inconsistency
between the heap and the visibility map, which I was unable to
confirm. The concern has been retracted.

However, there did seem to be a torn page hazard when using
checksums. By not setting the heap page LSN during redo, the
protections of minRecoveryPoint were bypassed. Fixed, along with a
misleading comment.

It may have been impossible to hit this problem in practice, because
it would require a page tear between the checksum and the flags, so I
am marking this as a theoretical risk. But, as discussed, it did
violate expectations about the page LSN, so it may have other
consequences.

Backpatch to all supported versions.

Reported-by: Konstantin Knizhnik
Reviewed-by: Konstantin Knizhnik
Discussion: https://postgr.es/m/fed17dac-8cb8-4f5b-d462-1bb4908c029e@garret.ru
Backpatch-through: 11

src/backend/access/heap/heapam.c

index dc90660fe3c8df2e925e240adcd2fa8303922463..6aecc143e7b2d6b75b5d1e351ce642d678542d7f 100644 (file)
@@ -7997,8 +7997,7 @@ heap_xlog_visible(XLogReaderState *record)
        /*
         * We don't bump the LSN of the heap page when setting the visibility
         * map bit (unless checksums or wal_hint_bits is enabled, in which
-        * case we must), because that would generate an unworkable volume of
-        * full-page writes.  This exposes us to torn page hazards, but since
+        * case we must). This exposes us to torn page hazards, but since
         * we're not inspecting the existing page contents in any way, we
         * don't care.
         *
@@ -8012,6 +8011,9 @@ heap_xlog_visible(XLogReaderState *record)
 
        PageSetAllVisible(page);
 
+       if (XLogHintBitIsNeeded())
+           PageSetLSN(page, lsn);
+
        MarkBufferDirty(buffer);
    }
    else if (action == BLK_RESTORED)