aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Davis <jdavis@postgresql.org>2023-10-10 11:01:13 -0700
committerJeff Davis <jdavis@postgresql.org>2023-10-10 11:01:55 -0700
commitb8963e8a28545275c4d3288aa9bf50ce73f537af (patch)
tree6f63dbe5cd307ffe3ec74e93f9f22009864244be
parente943cff33d6bc6db3011a243d9b7ccd1a0472e62 (diff)
downloadpostgresql-b8963e8a28545275c4d3288aa9bf50ce73f537af.tar.gz
postgresql-b8963e8a28545275c4d3288aa9bf50ce73f537af.zip
Fix bug in GenericXLogFinish().
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
-rw-r--r--src/backend/access/transam/generic_xlog.c56
1 files changed, 26 insertions, 30 deletions
diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c
index 6c68191ca62..6e747bf1b1c 100644
--- a/src/backend/access/transam/generic_xlog.c
+++ b/src/backend/access/transam/generic_xlog.c
@@ -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();
}