Skip to content

Commit 9e85743

Browse files
committed
Don't include unused space in LOG_NEWPAGE records.
This is the same trick we use when taking a full page image of a buffer passed to XLogInsert.
1 parent 22122c8 commit 9e85743

File tree

11 files changed

+109
-62
lines changed

11 files changed

+109
-62
lines changed

src/backend/access/gin/gininsert.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,10 @@ ginbuildempty(PG_FUNCTION_ARGS)
435435
START_CRIT_SECTION();
436436
GinInitMetabuffer(MetaBuffer);
437437
MarkBufferDirty(MetaBuffer);
438-
log_newpage_buffer(MetaBuffer);
438+
log_newpage_buffer(MetaBuffer, false);
439439
GinInitBuffer(RootBuffer, GIN_LEAF);
440440
MarkBufferDirty(RootBuffer);
441-
log_newpage_buffer(RootBuffer);
441+
log_newpage_buffer(RootBuffer, false);
442442
END_CRIT_SECTION();
443443

444444
/* Unlock and release the buffers. */

src/backend/access/gist/gist.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ gistbuildempty(PG_FUNCTION_ARGS)
8383
START_CRIT_SECTION();
8484
GISTInitBuffer(buffer, F_LEAF);
8585
MarkBufferDirty(buffer);
86-
log_newpage_buffer(buffer);
86+
log_newpage_buffer(buffer, true);
8787
END_CRIT_SECTION();
8888

8989
/* Unlock and release the buffer */

src/backend/access/heap/heapam.c

Lines changed: 83 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6207,16 +6207,22 @@ log_heap_update(Relation reln, Buffer oldbuf,
62076207
* memory and writing them directly to smgr. If you're using buffers, call
62086208
* log_newpage_buffer instead.
62096209
*
6210-
* Note: the NEWPAGE log record is used for both heaps and indexes, so do
6211-
* not do anything that assumes we are touching a heap.
6210+
* If the page follows the standard page layout, with a PageHeader and unused
6211+
* space between pd_lower and pd_upper, set 'page_std' to TRUE. That allows
6212+
* the unused space to be left out from the WAL record, making it smaller.
62126213
*/
62136214
XLogRecPtr
62146215
log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
6215-
Page page)
6216+
Page page, bool page_std)
62166217
{
62176218
xl_heap_newpage xlrec;
62186219
XLogRecPtr recptr;
6219-
XLogRecData rdata[2];
6220+
XLogRecData rdata[3];
6221+
6222+
/*
6223+
* Note: the NEWPAGE log record is used for both heaps and indexes, so do
6224+
* not do anything that assumes we are touching a heap.
6225+
*/
62206226

62216227
/* NO ELOG(ERROR) from here till newpage op is logged */
62226228
START_CRIT_SECTION();
@@ -6225,15 +6231,58 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
62256231
xlrec.forknum = forkNum;
62266232
xlrec.blkno = blkno;
62276233

6234+
if (page_std)
6235+
{
6236+
/* Assume we can omit data between pd_lower and pd_upper */
6237+
uint16 lower = ((PageHeader) page)->pd_lower;
6238+
uint16 upper = ((PageHeader) page)->pd_upper;
6239+
6240+
if (lower >= SizeOfPageHeaderData &&
6241+
upper > lower &&
6242+
upper <= BLCKSZ)
6243+
{
6244+
xlrec.hole_offset = lower;
6245+
xlrec.hole_length = upper - lower;
6246+
}
6247+
else
6248+
{
6249+
/* No "hole" to compress out */
6250+
xlrec.hole_offset = 0;
6251+
xlrec.hole_length = 0;
6252+
}
6253+
}
6254+
else
6255+
{
6256+
/* Not a standard page header, don't try to eliminate "hole" */
6257+
xlrec.hole_offset = 0;
6258+
xlrec.hole_length = 0;
6259+
}
6260+
62286261
rdata[0].data = (char *) &xlrec;
62296262
rdata[0].len = SizeOfHeapNewpage;
62306263
rdata[0].buffer = InvalidBuffer;
62316264
rdata[0].next = &(rdata[1]);
62326265

6233-
rdata[1].data = (char *) page;
6234-
rdata[1].len = BLCKSZ;
6235-
rdata[1].buffer = InvalidBuffer;
6236-
rdata[1].next = NULL;
6266+
if (xlrec.hole_length == 0)
6267+
{
6268+
rdata[1].data = (char *) page;
6269+
rdata[1].len = BLCKSZ;
6270+
rdata[1].buffer = InvalidBuffer;
6271+
rdata[1].next = NULL;
6272+
}
6273+
else
6274+
{
6275+
/* must skip the hole */
6276+
rdata[1].data = (char *) page;
6277+
rdata[1].len = xlrec.hole_offset;
6278+
rdata[1].buffer = InvalidBuffer;
6279+
rdata[1].next = &rdata[2];
6280+
6281+
rdata[2].data = (char *) page + (xlrec.hole_offset + xlrec.hole_length);
6282+
rdata[2].len = BLCKSZ - (xlrec.hole_offset + xlrec.hole_length);
6283+
rdata[2].buffer = InvalidBuffer;
6284+
rdata[2].next = NULL;
6285+
}
62376286

62386287
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
62396288

@@ -6257,44 +6306,24 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
62576306
* Caller should initialize the buffer and mark it dirty before calling this
62586307
* function. This function will set the page LSN and TLI.
62596308
*
6260-
* Note: the NEWPAGE log record is used for both heaps and indexes, so do
6261-
* not do anything that assumes we are touching a heap.
6309+
* If the page follows the standard page layout, with a PageHeader and unused
6310+
* space between pd_lower and pd_upper, set 'page_std' to TRUE. That allows
6311+
* the unused space to be left out from the WAL record, making it smaller.
62626312
*/
62636313
XLogRecPtr
6264-
log_newpage_buffer(Buffer buffer)
6314+
log_newpage_buffer(Buffer buffer, bool page_std)
62656315
{
6266-
xl_heap_newpage xlrec;
6267-
XLogRecPtr recptr;
6268-
XLogRecData rdata[2];
62696316
Page page = BufferGetPage(buffer);
6317+
RelFileNode rnode;
6318+
ForkNumber forkNum;
6319+
BlockNumber blkno;
62706320

6271-
/* We should be in a critical section. */
6321+
/* Shared buffers should be modified in a critical section. */
62726322
Assert(CritSectionCount > 0);
62736323

6274-
BufferGetTag(buffer, &xlrec.node, &xlrec.forknum, &xlrec.blkno);
6275-
6276-
rdata[0].data = (char *) &xlrec;
6277-
rdata[0].len = SizeOfHeapNewpage;
6278-
rdata[0].buffer = InvalidBuffer;
6279-
rdata[0].next = &(rdata[1]);
6280-
6281-
rdata[1].data = page;
6282-
rdata[1].len = BLCKSZ;
6283-
rdata[1].buffer = InvalidBuffer;
6284-
rdata[1].next = NULL;
6285-
6286-
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
6287-
6288-
/*
6289-
* The page may be uninitialized. If so, we can't set the LSN and TLI
6290-
* because that would corrupt the page.
6291-
*/
6292-
if (!PageIsNew(page))
6293-
{
6294-
PageSetLSN(page, recptr);
6295-
}
6324+
BufferGetTag(buffer, &rnode, &forkNum, &blkno);
62966325

6297-
return recptr;
6326+
return log_newpage(&rnode, forkNum, blkno, page, page_std);
62986327
}
62996328

63006329
/*
@@ -6582,12 +6611,15 @@ static void
65826611
heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
65836612
{
65846613
xl_heap_newpage *xlrec = (xl_heap_newpage *) XLogRecGetData(record);
6614+
char *blk = ((char *) xlrec) + sizeof(xl_heap_newpage);
65856615
Buffer buffer;
65866616
Page page;
65876617

65886618
/* Backup blocks are not used in newpage records */
65896619
Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
65906620

6621+
Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ - xlrec->hole_length);
6622+
65916623
/*
65926624
* Note: the NEWPAGE log record is used for both heaps and indexes, so do
65936625
* not do anything that assumes we are touching a heap.
@@ -6598,8 +6630,19 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
65986630
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
65996631
page = (Page) BufferGetPage(buffer);
66006632

6601-
Assert(record->xl_len == SizeOfHeapNewpage + BLCKSZ);
6602-
memcpy(page, (char *) xlrec + SizeOfHeapNewpage, BLCKSZ);
6633+
if (xlrec->hole_length == 0)
6634+
{
6635+
memcpy((char *) page, blk, BLCKSZ);
6636+
}
6637+
else
6638+
{
6639+
memcpy((char *) page, blk, xlrec->hole_offset);
6640+
/* must zero-fill the hole */
6641+
MemSet((char *) page + xlrec->hole_offset, 0, xlrec->hole_length);
6642+
memcpy((char *) page + (xlrec->hole_offset + xlrec->hole_length),
6643+
blk + xlrec->hole_offset,
6644+
BLCKSZ - (xlrec->hole_offset + xlrec->hole_length));
6645+
}
66036646

66046647
/*
66056648
* The page may be uninitialized. If so, we can't set the LSN because that

src/backend/access/heap/rewriteheap.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,8 @@ end_heap_rewrite(RewriteState state)
277277
log_newpage(&state->rs_new_rel->rd_node,
278278
MAIN_FORKNUM,
279279
state->rs_blockno,
280-
state->rs_buffer);
280+
state->rs_buffer,
281+
true);
281282
RelationOpenSmgr(state->rs_new_rel);
282283

283284
PageSetChecksumInplace(state->rs_buffer, state->rs_blockno);
@@ -622,7 +623,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
622623
log_newpage(&state->rs_new_rel->rd_node,
623624
MAIN_FORKNUM,
624625
state->rs_blockno,
625-
page);
626+
page,
627+
true);
626628

627629
/*
628630
* Now write the page. We say isTemp = true even if it's not a

src/backend/access/nbtree/nbtree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ btbuildempty(PG_FUNCTION_ARGS)
222222
(char *) metapage, true);
223223
if (XLogIsNeeded())
224224
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
225-
BTREE_METAPAGE, metapage);
225+
BTREE_METAPAGE, metapage, false);
226226

227227
/*
228228
* An immediate sync is require even if we xlog'd the page, because the

src/backend/access/nbtree/nbtsort.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
274274
if (wstate->btws_use_wal)
275275
{
276276
/* We use the heap NEWPAGE record type for this */
277-
log_newpage(&wstate->index->rd_node, MAIN_FORKNUM, blkno, page);
277+
log_newpage(&wstate->index->rd_node, MAIN_FORKNUM, blkno, page, true);
278278
}
279279

280280
/*

src/backend/access/spgist/spginsert.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ spgbuildempty(PG_FUNCTION_ARGS)
169169
(char *) page, true);
170170
if (XLogIsNeeded())
171171
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
172-
SPGIST_METAPAGE_BLKNO, page);
172+
SPGIST_METAPAGE_BLKNO, page, false);
173173

174174
/* Likewise for the root page. */
175175
SpGistInitPage(page, SPGIST_LEAF);
@@ -179,7 +179,7 @@ spgbuildempty(PG_FUNCTION_ARGS)
179179
(char *) page, true);
180180
if (XLogIsNeeded())
181181
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
182-
SPGIST_ROOT_BLKNO, page);
182+
SPGIST_ROOT_BLKNO, page, true);
183183

184184
/* Likewise for the null-tuples root page. */
185185
SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS);
@@ -189,7 +189,7 @@ spgbuildempty(PG_FUNCTION_ARGS)
189189
(char *) page, true);
190190
if (XLogIsNeeded())
191191
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
192-
SPGIST_NULL_BLKNO, page);
192+
SPGIST_NULL_BLKNO, page, true);
193193

194194
/*
195195
* An immediate sync is required even if we xlog'd the pages, because the

src/backend/commands/tablecmds.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9130,9 +9130,13 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
91309130
src->smgr_rnode.backend,
91319131
forkNum))));
91329132

9133-
/* XLOG stuff */
9133+
/*
9134+
* WAL-log the copied page. Unfortunately we don't know what kind of
9135+
* a page this is, so we have to log the full page including any
9136+
* unused space.
9137+
*/
91349138
if (use_wal)
9135-
log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page);
9139+
log_newpage(&dst->smgr_rnode.node, forkNum, blkno, page, false);
91369140

91379141
PageSetChecksumInplace(page, blkno);
91389142

src/backend/commands/vacuumlazy.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -699,14 +699,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
699699
* which will cause a PANIC. To prevent that, check whether
700700
* the page has been previously WAL-logged, and if not, do that
701701
* now.
702-
*
703-
* XXX: It would be nice to use a logging method supporting
704-
* standard buffers here since log_newpage_buffer() will write
705-
* the full block instead of omitting the hole.
706702
*/
707703
if (RelationNeedsWAL(onerel) &&
708704
PageGetLSN(page) == InvalidXLogRecPtr)
709-
log_newpage_buffer(buf);
705+
log_newpage_buffer(buf, true);
710706

711707
PageSetAllVisible(page);
712708
visibilitymap_set(onerel, blkno, buf, InvalidXLogRecPtr,

src/include/access/heapam_xlog.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,12 @@ typedef struct xl_heap_newpage
198198
RelFileNode node;
199199
ForkNumber forknum;
200200
BlockNumber blkno; /* location of new page */
201-
/* entire page contents follow at end of record */
201+
uint16 hole_offset; /* number of bytes before "hole" */
202+
uint16 hole_length; /* number of bytes in "hole" */
203+
/* entire page contents (minus the hole) follow at end of record */
202204
} xl_heap_newpage;
203205

204-
#define SizeOfHeapNewpage (offsetof(xl_heap_newpage, blkno) + sizeof(BlockNumber))
206+
#define SizeOfHeapNewpage (offsetof(xl_heap_newpage, hole_length) + sizeof(uint16))
205207

206208
/* flags for infobits_set */
207209
#define XLHL_XMAX_IS_MULTI 0x01
@@ -282,7 +284,7 @@ extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
282284
extern XLogRecPtr log_heap_visible(RelFileNode rnode, Buffer heap_buffer,
283285
Buffer vm_buffer, TransactionId cutoff_xid);
284286
extern XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum,
285-
BlockNumber blk, Page page);
286-
extern XLogRecPtr log_newpage_buffer(Buffer buffer);
287+
BlockNumber blk, Page page, bool page_std);
288+
extern XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std);
287289

288290
#endif /* HEAPAM_XLOG_H */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy