Make XLOG_FPI_FOR_HINT records honor full_page_writes setting.
authorFujii Masao <fujii@postgresql.org>
Wed, 21 Jul 2021 02:19:00 +0000 (11:19 +0900)
committerFujii Masao <fujii@postgresql.org>
Wed, 21 Jul 2021 02:19:00 +0000 (11:19 +0900)
Commit 2c03216d83 changed XLOG_FPI_FOR_HINT records so that they always
included full-page images even when full_page_writes was disabled. However,
in this setting, they don't need to do that because hint bit updates don't
need to be protected from torn writes.

Therefore, this commit makes XLOG_FPI_FOR_HINT records honor full_page_writes
setting. That is, XLOG_FPI_FOR_HINT records may include no full-page images
if full_page_writes is disabled, and WAL replay of them does nothing.

Reported-by: Zhang Wenjie
Author: Kyotaro Horiguchi
Reviewed-by: Fujii Masao
Discussion: https://postgr.es/m/tencent_60F11973A111EED97A8596FFECC4A91ED405@qq.com

src/backend/access/transam/xlog.c
src/backend/access/transam/xloginsert.c

index 2ee951513928839252a8175e7d920cd3a9f135a3..3479402272bf801844188c6065ddf0de5e6c45b8 100644 (file)
@@ -10148,7 +10148,10 @@ xlog_redo(XLogReaderState *record)
        uint8           info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
        XLogRecPtr      lsn = record->EndRecPtr;
 
-       /* in XLOG rmgr, backup blocks are only used by XLOG_FPI records */
+       /*
+        * In XLOG rmgr, backup blocks are only used by XLOG_FPI and
+        * XLOG_FPI_FOR_HINT records.
+        */
        Assert(info == XLOG_FPI || info == XLOG_FPI_FOR_HINT ||
                   !XLogRecHasAnyBlockRefs(record));
 
@@ -10356,25 +10359,32 @@ xlog_redo(XLogReaderState *record)
        else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
        {
                /*
-                * Full-page image (FPI) records contain nothing else but a backup
-                * block (or multiple backup blocks). Every block reference must
-                * include a full-page image - otherwise there would be no point in
-                * this record.
+                * XLOG_FPI records contain nothing else but one or more block
+                * references. Every block reference must include a full-page image
+                * even if full_page_writes was disabled when the record was generated
+                * - otherwise there would be no point in this record.
+                *
+                * XLOG_FPI_FOR_HINT records are generated when a page needs to be
+                * WAL-logged because of a hint bit update. They are only generated
+                * when checksums and/or wal_log_hints are enabled. They may include
+                * no full-page images if full_page_writes was disabled when they were
+                * generated. In this case there is nothing to do here.
                 *
                 * No recovery conflicts are generated by these generic records - if a
                 * resource manager needs to generate conflicts, it has to define a
                 * separate WAL record type and redo routine.
-                *
-                * XLOG_FPI_FOR_HINT records are generated when a page needs to be
-                * WAL- logged because of a hint bit update. They are only generated
-                * when checksums are enabled. There is no difference in handling
-                * XLOG_FPI and XLOG_FPI_FOR_HINT records, they use a different info
-                * code just to distinguish them for statistics purposes.
                 */
                for (uint8 block_id = 0; block_id <= record->max_block_id; block_id++)
                {
                        Buffer          buffer;
 
+                       if (!XLogRecHasBlockImage(record, block_id))
+                       {
+                               if (info == XLOG_FPI)
+                                       elog(ERROR, "XLOG_FPI record did not contain a full-page image");
+                               continue;
+                       }
+
                        if (XLogReadBufferForRedo(record, block_id, &buffer) != BLK_RESTORED)
                                elog(ERROR, "unexpected XLogReadBufferForRedo result when restoring backup block");
                        UnlockReleaseBuffer(buffer);
index 3d2c9c3e8cf529279e0c6e40949b331a1ae7a346..e596a0470a9775ffa63d3171d8889a1a9a0ca1ed 100644 (file)
@@ -287,8 +287,6 @@ XLogRegisterBlock(uint8 block_id, RelFileNode *rnode, ForkNumber forknum,
 {
        registered_buffer *regbuf;
 
-       /* This is currently only used to WAL-log a full-page image of a page */
-       Assert(flags & REGBUF_FORCE_IMAGE);
        Assert(begininsert_called);
 
        if (block_id >= max_registered_block_id)
@@ -995,7 +993,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
 
        if (lsn <= RedoRecPtr)
        {
-               int                     flags;
+               int                     flags = 0;
                PGAlignedBlock copied_buffer;
                char       *origdata = (char *) BufferGetBlock(buffer);
                RelFileNode rnode;
@@ -1022,7 +1020,6 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
 
                XLogBeginInsert();
 
-               flags = REGBUF_FORCE_IMAGE;
                if (buffer_std)
                        flags |= REGBUF_STANDARD;