diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index cce87a3cd30280a0b4f6a2cb68cb73a56a1e3d86..b128bfda36dbf00c0ef49a34bd2d48d6cdf42218 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -3716,9 +3716,9 @@ RestoreBkpBlocks(XLogRecPtr lsn, XLogRecord *record, bool cleanup) } else { - /* must zero-fill the hole */ - MemSet((char *) page, 0, BLCKSZ); memcpy((char *) page, blk, bkpb.hole_offset); + /* must zero-fill the hole */ + MemSet((char *) page + bkpb.hole_offset, 0, bkpb.hole_length); memcpy((char *) page + (bkpb.hole_offset + bkpb.hole_length), blk + bkpb.hole_offset, BLCKSZ - (bkpb.hole_offset + bkpb.hole_length)); diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index d3739cb0952fe3c09e7e36c70bd0d9289cc4c999..1f95abc7147863c2dba9252fc827c1cc3b8f733a 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1521,6 +1521,7 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record) uint8 info = record->xl_info & ~XLR_INFO_MASK; Buffer buffer; Page page; + Page localpage; char *item; Size itemsz; xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record); @@ -1536,23 +1537,37 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record) Assert(BufferIsValid(buffer)); page = (Page) BufferGetPage(buffer); - /* Always reinit the page and reinstall the magic number */ - /* See comments in DefineSequence */ - PageInit((Page) page, BufferGetPageSize(buffer), sizeof(sequence_magic)); - sm = (sequence_magic *) PageGetSpecialPointer(page); + /* + * We must always reinit the page and reinstall the magic number (see + * comments in fill_seq_with_data). However, since this WAL record type + * is also used for updating sequences, it's possible that a hot-standby + * backend is examining the page concurrently; so we mustn't transiently + * trash the buffer. The solution is to build the correct new page + * contents in local workspace and then memcpy into the buffer. Then + * only bytes that are supposed to change will change, even transiently. + * We must palloc the local page for alignment reasons. + */ + localpage = (Page) palloc(BufferGetPageSize(buffer)); + + PageInit(localpage, BufferGetPageSize(buffer), sizeof(sequence_magic)); + sm = (sequence_magic *) PageGetSpecialPointer(localpage); sm->magic = SEQ_MAGIC; item = (char *) xlrec + sizeof(xl_seq_rec); itemsz = record->xl_len - sizeof(xl_seq_rec); itemsz = MAXALIGN(itemsz); - if (PageAddItem(page, (Item) item, itemsz, + if (PageAddItem(localpage, (Item) item, itemsz, FirstOffsetNumber, false, false) == InvalidOffsetNumber) elog(PANIC, "seq_redo: failed to add item to page"); - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); + PageSetLSN(localpage, lsn); + PageSetTLI(localpage, ThisTimeLineID); + + memcpy(page, localpage, BufferGetPageSize(buffer)); MarkBufferDirty(buffer); UnlockReleaseBuffer(buffer); + + pfree(localpage); } void