@@ -6207,16 +6207,22 @@ log_heap_update(Relation reln, Buffer oldbuf,
6207
6207
* memory and writing them directly to smgr. If you're using buffers, call
6208
6208
* log_newpage_buffer instead.
6209
6209
*
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.
6212
6213
*/
6213
6214
XLogRecPtr
6214
6215
log_newpage (RelFileNode * rnode ,ForkNumber forkNum ,BlockNumber blkno ,
6215
- Page page )
6216
+ Page page , bool page_std )
6216
6217
{
6217
6218
xl_heap_newpage xlrec ;
6218
6219
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
+ */
6220
6226
6221
6227
/* NO ELOG(ERROR) from here till newpage op is logged */
6222
6228
START_CRIT_SECTION ();
@@ -6225,15 +6231,58 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
6225
6231
xlrec .forknum = forkNum ;
6226
6232
xlrec .blkno = blkno ;
6227
6233
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
+
6228
6261
rdata [0 ].data = (char * )& xlrec ;
6229
6262
rdata [0 ].len = SizeOfHeapNewpage ;
6230
6263
rdata [0 ].buffer = InvalidBuffer ;
6231
6264
rdata [0 ].next = & (rdata [1 ]);
6232
6265
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
+ }
6237
6286
6238
6287
recptr = XLogInsert (RM_HEAP_ID ,XLOG_HEAP_NEWPAGE ,rdata );
6239
6288
@@ -6257,44 +6306,24 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
6257
6306
* Caller should initialize the buffer and mark it dirty before calling this
6258
6307
* function. This function will set the page LSN and TLI.
6259
6308
*
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.
6262
6312
*/
6263
6313
XLogRecPtr
6264
- log_newpage_buffer (Buffer buffer )
6314
+ log_newpage_buffer (Buffer buffer , bool page_std )
6265
6315
{
6266
- xl_heap_newpage xlrec ;
6267
- XLogRecPtr recptr ;
6268
- XLogRecData rdata [2 ];
6269
6316
Page page = BufferGetPage (buffer );
6317
+ RelFileNode rnode ;
6318
+ ForkNumber forkNum ;
6319
+ BlockNumber blkno ;
6270
6320
6271
- /*We should be in a critical section. */
6321
+ /*Shared buffers should be modified in a critical section. */
6272
6322
Assert (CritSectionCount > 0 );
6273
6323
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 );
6296
6325
6297
- return recptr ;
6326
+ return log_newpage ( & rnode , forkNum , blkno , page , page_std ) ;
6298
6327
}
6299
6328
6300
6329
/*
@@ -6582,12 +6611,15 @@ static void
6582
6611
heap_xlog_newpage (XLogRecPtr lsn ,XLogRecord * record )
6583
6612
{
6584
6613
xl_heap_newpage * xlrec = (xl_heap_newpage * )XLogRecGetData (record );
6614
+ char * blk = ((char * )xlrec )+ sizeof (xl_heap_newpage );
6585
6615
Buffer buffer ;
6586
6616
Page page ;
6587
6617
6588
6618
/* Backup blocks are not used in newpage records */
6589
6619
Assert (!(record -> xl_info & XLR_BKP_BLOCK_MASK ));
6590
6620
6621
+ Assert (record -> xl_len == SizeOfHeapNewpage + BLCKSZ - xlrec -> hole_length );
6622
+
6591
6623
/*
6592
6624
* Note: the NEWPAGE log record is used for both heaps and indexes, so do
6593
6625
* not do anything that assumes we are touching a heap.
@@ -6598,8 +6630,19 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
6598
6630
LockBuffer (buffer ,BUFFER_LOCK_EXCLUSIVE );
6599
6631
page = (Page )BufferGetPage (buffer );
6600
6632
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
+ }
6603
6646
6604
6647
/*
6605
6648
* The page may be uninitialized. If so, we can't set the LSN because that