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:01:13 +0000 (11:01 -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 6c68191ca6241a05fe6fc9bd8d5afbabe1dec9bd..6e747bf1b1c5e7d752962e591501abdf9a0f94a5 100644 (file)
@@ -347,6 +347,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];
@@ -359,41 +363,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);
                        }
@@ -402,7 +399,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];
@@ -410,7 +407,6 @@ GenericXLogFinish(GenericXLogState *state)
                        if (BufferIsInvalid(pageData->buffer))
                                continue;
                        PageSetLSN(BufferGetPage(pageData->buffer), lsn);
-                       MarkBufferDirty(pageData->buffer);
                }
                END_CRIT_SECTION();
        }