Skip to content

Commit 43434ed

Browse files
committed
Back-patch log_newpage_range().
Back-patch a subset of commit 9155580 to v11, v10, 9.6, and 9.5. Include the latest repairs to this function. Use a new XLOG_FPI_MULTI value instead of reusing XLOG_FPI. That way, if an older server reads WAL from this function, that server will PANIC instead of applying just one page of the record. The next commit adds a call to this function. Discussion: https://postgr.es/m/20200304.162919.898938381201316571.horikyota.ntt@gmail.com
1 parent 78a34c6 commit 43434ed

File tree

6 files changed

+113
-9
lines changed

6 files changed

+113
-9
lines changed

src/backend/access/rmgrdesc/xlogdesc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
7878

7979
appendStringInfoString(buf, xlrec->rp_name);
8080
}
81-
else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
81+
else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT ||
82+
info == XLOG_FPI_MULTI)
8283
{
8384
/* no further information to print */
8485
}
@@ -182,6 +183,9 @@ xlog_identify(uint8 info)
182183
case XLOG_FPI_FOR_HINT:
183184
id = "FPI_FOR_HINT";
184185
break;
186+
case XLOG_FPI_MULTI:
187+
id = "FPI_MULTI";
188+
break;
185189
}
186190

187191
return id;

src/backend/access/transam/xlog.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9721,7 +9721,7 @@ xlog_redo(XLogReaderState *record)
97219721

97229722
/* in XLOG rmgr, backup blocks are only used by XLOG_FPI records */
97239723
Assert(info == XLOG_FPI || info == XLOG_FPI_FOR_HINT ||
9724-
!XLogRecHasAnyBlockRefs(record));
9724+
info == XLOG_FPI_MULTI || !XLogRecHasAnyBlockRefs(record));
97259725

97269726
if (info == XLOG_NEXTOID)
97279727
{
@@ -9924,14 +9924,16 @@ xlog_redo(XLogReaderState *record)
99249924
{
99259925
/* nothing to do here */
99269926
}
9927-
else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT)
9927+
else if (info == XLOG_FPI || info == XLOG_FPI_FOR_HINT ||
9928+
info == XLOG_FPI_MULTI)
99289929
{
9929-
Buffer buffer;
9930+
uint8 block_id;
99309931

99319932
/*
99329933
* Full-page image (FPI) records contain nothing else but a backup
9933-
* block. The block reference must include a full-page image -
9934-
* otherwise there would be no point in this record.
9934+
* block (or multiple backup blocks). Every block reference must
9935+
* include a full-page image - otherwise there would be no point in
9936+
* this record.
99359937
*
99369938
* No recovery conflicts are generated by these generic records - if a
99379939
* resource manager needs to generate conflicts, it has to define a
@@ -9943,9 +9945,14 @@ xlog_redo(XLogReaderState *record)
99439945
* XLOG_FPI and XLOG_FPI_FOR_HINT records, they use a different info
99449946
* code just to distinguish them for statistics purposes.
99459947
*/
9946-
if (XLogReadBufferForRedo(record, 0, &buffer) != BLK_RESTORED)
9947-
elog(ERROR, "unexpected XLogReadBufferForRedo result when restoring backup block");
9948-
UnlockReleaseBuffer(buffer);
9948+
for (block_id = 0; block_id <= record->max_block_id; block_id++)
9949+
{
9950+
Buffer buffer;
9951+
9952+
if (XLogReadBufferForRedo(record, block_id, &buffer) != BLK_RESTORED)
9953+
elog(ERROR, "unexpected XLogReadBufferForRedo result when restoring backup block");
9954+
UnlockReleaseBuffer(buffer);
9955+
}
99499956
}
99509957
else if (info == XLOG_BACKUP_END)
99519958
{

src/backend/access/transam/xloginsert.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,94 @@ log_newpage_buffer(Buffer buffer, bool page_std)
10211021
return log_newpage(&rnode, forkNum, blkno, page, page_std);
10221022
}
10231023

1024+
/*
1025+
* WAL-log a range of blocks in a relation.
1026+
*
1027+
* An image of all pages with block numbers 'startblk' <= X < 'endblk' is
1028+
* written to the WAL. If the range is large, this is done in multiple WAL
1029+
* records.
1030+
*
1031+
* If all page follows the standard page layout, with a PageHeader and unused
1032+
* space between pd_lower and pd_upper, set 'page_std' to true. That allows
1033+
* the unused space to be left out from the WAL records, making them smaller.
1034+
*
1035+
* NOTE: This function acquires exclusive-locks on the pages. Typically, this
1036+
* is used on a newly-built relation, and the caller is holding a
1037+
* AccessExclusiveLock on it, so no other backend can be accessing it at the
1038+
* same time. If that's not the case, you must ensure that this does not
1039+
* cause a deadlock through some other means.
1040+
*/
1041+
void
1042+
log_newpage_range(Relation rel, ForkNumber forkNum,
1043+
BlockNumber startblk, BlockNumber endblk,
1044+
bool page_std)
1045+
{
1046+
int flags;
1047+
BlockNumber blkno;
1048+
1049+
flags = REGBUF_FORCE_IMAGE;
1050+
if (page_std)
1051+
flags |= REGBUF_STANDARD;
1052+
1053+
/*
1054+
* Iterate over all the pages in the range. They are collected into
1055+
* batches of XLR_MAX_BLOCK_ID pages, and a single WAL-record is written
1056+
* for each batch.
1057+
*/
1058+
XLogEnsureRecordSpace(XLR_MAX_BLOCK_ID - 1, 0);
1059+
1060+
blkno = startblk;
1061+
while (blkno < endblk)
1062+
{
1063+
Buffer bufpack[XLR_MAX_BLOCK_ID];
1064+
XLogRecPtr recptr;
1065+
int nbufs;
1066+
int i;
1067+
1068+
CHECK_FOR_INTERRUPTS();
1069+
1070+
/* Collect a batch of blocks. */
1071+
nbufs = 0;
1072+
while (nbufs < XLR_MAX_BLOCK_ID && blkno < endblk)
1073+
{
1074+
Buffer buf = ReadBufferExtended(rel, forkNum, blkno,
1075+
RBM_NORMAL, NULL);
1076+
1077+
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
1078+
1079+
/*
1080+
* Completely empty pages are not WAL-logged. Writing a WAL record
1081+
* would change the LSN, and we don't want that. We want the page
1082+
* to stay empty.
1083+
*/
1084+
if (!PageIsNew(BufferGetPage(buf)))
1085+
bufpack[nbufs++] = buf;
1086+
else
1087+
UnlockReleaseBuffer(buf);
1088+
blkno++;
1089+
}
1090+
1091+
/* Write WAL record for this batch. */
1092+
XLogBeginInsert();
1093+
1094+
START_CRIT_SECTION();
1095+
for (i = 0; i < nbufs; i++)
1096+
{
1097+
XLogRegisterBuffer(i, bufpack[i], flags);
1098+
MarkBufferDirty(bufpack[i]);
1099+
}
1100+
1101+
recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI_MULTI);
1102+
1103+
for (i = 0; i < nbufs; i++)
1104+
{
1105+
PageSetLSN(BufferGetPage(bufpack[i]), recptr);
1106+
UnlockReleaseBuffer(bufpack[i]);
1107+
}
1108+
END_CRIT_SECTION();
1109+
}
1110+
}
1111+
10241112
/*
10251113
* Allocate working buffers needed for WAL record construction.
10261114
*/

src/backend/replication/logical/decode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ DecodeXLogOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
195195
case XLOG_FPW_CHANGE:
196196
case XLOG_FPI_FOR_HINT:
197197
case XLOG_FPI:
198+
case XLOG_FPI_MULTI:
198199
break;
199200
default:
200201
elog(ERROR, "unexpected RM_XLOG_ID record type: %u", info);

src/include/access/xloginsert.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "storage/block.h"
1717
#include "storage/buf.h"
1818
#include "storage/relfilenode.h"
19+
#include "utils/relcache.h"
1920

2021
/*
2122
* The minimum size of the WAL construction working area. If you need to
@@ -54,6 +55,8 @@ extern bool XLogCheckBufferNeedsBackup(Buffer buffer);
5455
extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum,
5556
BlockNumber blk, char *page, bool page_std);
5657
extern XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std);
58+
extern void log_newpage_range(Relation rel, ForkNumber forkNum,
59+
BlockNumber startblk, BlockNumber endblk, bool page_std);
5760
extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std);
5861

5962
extern void InitXLogInsert(void);

src/include/catalog/pg_control.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ typedef struct CheckPoint
7676
#define XLOG_END_OF_RECOVERY 0x90
7777
#define XLOG_FPI_FOR_HINT 0xA0
7878
#define XLOG_FPI 0xB0
79+
#define XLOG_FPI_MULTI 0xC0
7980

8081

8182
/*

0 commit comments

Comments
 (0)