@@ -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 */
62136214XLogRecPtr
62146215log_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 */
62636313XLogRecPtr
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
65826611heap_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
0 commit comments