{
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);
}
* 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);
}
BGP_NO_SNAPSHOT_TEST),
pageData->image,
BLCKSZ);
+ /* We don't worry about zeroing the "hole" in this case */
MarkBufferDirty(pageData->buffer);
}
END_CRIT_SECTION();
if (action == BLK_NEEDS_REDO)
{
Page page;
+ PageHeader pageHeader;
char *blockDelta;
Size blockDeltaSize;
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]);
}