aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/xlog.c4
-rw-r--r--src/backend/commands/sequence.c29
2 files changed, 24 insertions, 9 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index cce87a3cd30..b128bfda36d 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 d3739cb0952..1f95abc7147 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