Fix bug in GenericXLogFinish().
authorJeff Davis <jdavis@postgresql.org>
Tue, 10 Oct 2023 18:01:13 +0000 (11:01 -0700)
committerJeff Davis <jdavis@postgresql.org>
Tue, 10 Oct 2023 18:03:03 +0000 (11:03 -0700)
Mark the buffers dirty before writing WAL.

Discussion: https://postgr.es/m/25104133-7df8-cae3-b9a2-1c0aaa1c094a@iki.fi
Reviewed-by: Heikki Linnakangas
Backpatch-through: 11

src/backend/access/transam/generic_xlog.c

index 5164a1c2f30dbbae3e12999ce676aa7a0411ddd8..d84d3bc231ad7a49251b4bfca6104079483aeb6d 100644 (file)
@@ -342,6 +342,10 @@ GenericXLogFinish(GenericXLogState *state)
 
        START_CRIT_SECTION();
 
+       /*
+        * Compute deltas if necessary, write changes to buffers, mark
+        * buffers dirty, and register changes.
+        */
        for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
        {
            PageData   *pageData = &state->pages[i];
@@ -354,41 +358,34 @@ GenericXLogFinish(GenericXLogState *state)
            page = BufferGetPage(pageData->buffer);
            pageHeader = (PageHeader) pageData->image;
 
+           /*
+            * Compute delta while we still have both the unmodified page and
+            * the new image. Not needed if we are logging the full image.
+            */
+           if (!(pageData->flags & GENERIC_XLOG_FULL_IMAGE))
+               computeDelta(pageData, page, (Page) pageData->image);
+
+           /*
+            * Apply the image, being careful to zero the "hole" between
+            * pd_lower and pd_upper in order to avoid divergence between
+            * actual page state and what replay would produce.
+            */
+           memcpy(page, pageData->image, pageHeader->pd_lower);
+           memset(page + pageHeader->pd_lower, 0,
+                  pageHeader->pd_upper - pageHeader->pd_lower);
+           memcpy(page + pageHeader->pd_upper,
+                  pageData->image + pageHeader->pd_upper,
+                  BLCKSZ - pageHeader->pd_upper);
+
+           MarkBufferDirty(pageData->buffer);
+
            if (pageData->flags & GENERIC_XLOG_FULL_IMAGE)
            {
-               /*
-                * A full-page image does not require us to supply any xlog
-                * data.  Just apply the image, being careful to zero the
-                * "hole" between pd_lower and pd_upper in order to avoid
-                * divergence between actual page state and what replay would
-                * produce.
-                */
-               memcpy(page, pageData->image, pageHeader->pd_lower);
-               memset(page + pageHeader->pd_lower, 0,
-                      pageHeader->pd_upper - pageHeader->pd_lower);
-               memcpy(page + pageHeader->pd_upper,
-                      pageData->image + pageHeader->pd_upper,
-                      BLCKSZ - pageHeader->pd_upper);
-
                XLogRegisterBuffer(i, pageData->buffer,
                                   REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
            }
            else
            {
-               /*
-                * In normal mode, calculate delta and write it as xlog data
-                * associated with this page.
-                */
-               computeDelta(pageData, page, (Page) pageData->image);
-
-               /* Apply the image, with zeroed "hole" as above */
-               memcpy(page, pageData->image, pageHeader->pd_lower);
-               memset(page + pageHeader->pd_lower, 0,
-                      pageHeader->pd_upper - pageHeader->pd_lower);
-               memcpy(page + pageHeader->pd_upper,
-                      pageData->image + pageHeader->pd_upper,
-                      BLCKSZ - pageHeader->pd_upper);
-
                XLogRegisterBuffer(i, pageData->buffer, REGBUF_STANDARD);
                XLogRegisterBufData(i, pageData->delta, pageData->deltaLen);
            }
@@ -397,7 +394,7 @@ GenericXLogFinish(GenericXLogState *state)
        /* Insert xlog record */
        lsn = XLogInsert(RM_GENERIC_ID, 0);
 
-       /* Set LSN and mark buffers dirty */
+       /* Set LSN */
        for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
        {
            PageData   *pageData = &state->pages[i];
@@ -405,7 +402,6 @@ GenericXLogFinish(GenericXLogState *state)
            if (BufferIsInvalid(pageData->buffer))
                continue;
            PageSetLSN(BufferGetPage(pageData->buffer), lsn);
-           MarkBufferDirty(pageData->buffer);
        }
        END_CRIT_SECTION();
    }