@@ -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{
62176218xl_heap_newpage xlrec ;
62186219XLogRecPtr 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 */
62226228START_CRIT_SECTION ();
@@ -6225,15 +6231,58 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
62256231xlrec .forknum = forkNum ;
62266232xlrec .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+
62286261rdata [0 ].data = (char * )& xlrec ;
62296262rdata [0 ].len = SizeOfHeapNewpage ;
62306263rdata [0 ].buffer = InvalidBuffer ;
62316264rdata [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
62386287recptr = 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 ];
62696316Page 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. */
62726322Assert (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{
65846613xl_heap_newpage * xlrec = (xl_heap_newpage * )XLogRecGetData (record );
6614+ char * blk = ((char * )xlrec )+ sizeof (xl_heap_newpage );
65856615Buffer buffer ;
65866616Page page ;
65876617
65886618/* Backup blocks are not used in newpage records */
65896619Assert (!(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)
65986630LockBuffer (buffer ,BUFFER_LOCK_EXCLUSIVE );
65996631page = (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