diff --git a/src/backend/access/transam/generic_xlog.c b/src/backend/access/transam/generic_xlog.c index 072838a5e7a82eecd1fd6cec0d044b6fa621bbe5..e07bd836d2ef5c2163a62344abb6ae93d0089d92 100644 --- a/src/backend/access/transam/generic_xlog.c +++ b/src/backend/access/transam/generic_xlog.c @@ -338,17 +338,31 @@ GenericXLogFinish(GenericXLogState *state) { PageData *pageData = &state->pages[i]; Page page; + PageHeader pageHeader; if (BufferIsInvalid(pageData->buffer)) continue; page = BufferGetPage(pageData->buffer, NULL, NULL, BGP_NO_SNAPSHOT_TEST); + pageHeader = (PageHeader) pageData->image; if (pageData->fullImage) { - /* A full page image does not require anything special */ - memcpy(page, pageData->image, BLCKSZ); + /* + * 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); } @@ -359,7 +373,15 @@ GenericXLogFinish(GenericXLogState *state) * associated with this page. */ computeDelta(pageData, page, (Page) pageData->image); - memcpy(page, pageData->image, BLCKSZ); + + /* 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); } @@ -395,6 +417,7 @@ GenericXLogFinish(GenericXLogState *state) BGP_NO_SNAPSHOT_TEST), pageData->image, BLCKSZ); + /* We don't worry about zeroing the "hole" in this case */ MarkBufferDirty(pageData->buffer); } END_CRIT_SECTION(); @@ -473,6 +496,7 @@ generic_redo(XLogReaderState *record) if (action == BLK_NEEDS_REDO) { Page page; + PageHeader pageHeader; char *blockDelta; Size blockDeltaSize; @@ -481,6 +505,16 @@ generic_redo(XLogReaderState *record) blockDelta = XLogRecGetBlockData(record, block_id, &blockDeltaSize); applyPageRedo(page, blockDelta, blockDeltaSize); + /* + * Since the delta contains no information about what's in the + * "hole" between pd_lower and pd_upper, set that to zero to + * ensure we produce the same page state that application of the + * logged action by GenericXLogFinish did. + */ + pageHeader = (PageHeader) page; + memset(page + pageHeader->pd_lower, 0, + pageHeader->pd_upper - pageHeader->pd_lower); + PageSetLSN(page, lsn); MarkBufferDirty(buffers[block_id]); }