diff options
author | Jeff Davis <jdavis@postgresql.org> | 2023-10-10 11:01:13 -0700 |
---|---|---|
committer | Jeff Davis <jdavis@postgresql.org> | 2023-10-10 11:01:55 -0700 |
commit | b8963e8a28545275c4d3288aa9bf50ce73f537af (patch) | |
tree | 6f63dbe5cd307ffe3ec74e93f9f22009864244be | |
parent | e943cff33d6bc6db3011a243d9b7ccd1a0472e62 (diff) | |
download | postgresql-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.c | 56 |
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(); } |