5050typedef struct
5151{
5252 Buffer buffer ; /* registered buffer */
53- bool fullImage ; /* are we taking a full image of this page? */
53+ int flags ; /* flags for this buffer */
5454 int deltaLen ; /* space consumed in delta field */
5555 char image [BLCKSZ ]; /* copy of page image for modification */
5656 char delta [MAX_DELTA_SIZE ]; /* delta between page images */
@@ -280,9 +280,11 @@ GenericXLogStart(Relation relation)
280280 * is what the caller should modify.
281281 *
282282 * If the buffer is already registered, just return its existing entry.
283+ * (It's not very clear what to do with the flags in such a case, but
284+ * for now we stay with the original flags.)
283285 */
284286Page
285- GenericXLogRegister (GenericXLogState * state , Buffer buffer , bool isNew )
287+ GenericXLogRegisterBuffer (GenericXLogState * state , Buffer buffer , int flags )
286288{
287289 int block_id ;
288290
@@ -295,7 +297,7 @@ GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
295297 {
296298 /* Empty slot, so use it (there cannot be a match later) */
297299 page -> buffer = buffer ;
298- page -> fullImage = isNew ;
300+ page -> flags = flags ;
299301 memcpy (page -> image ,
300302 BufferGetPage (buffer , NULL , NULL , BGP_NO_SNAPSHOT_TEST ),
301303 BLCKSZ );
@@ -338,17 +340,31 @@ GenericXLogFinish(GenericXLogState *state)
338340 {
339341 PageData * pageData = & state -> pages [i ];
340342 Page page ;
343+ PageHeader pageHeader ;
341344
342345 if (BufferIsInvalid (pageData -> buffer ))
343346 continue ;
344347
345348 page = BufferGetPage (pageData -> buffer , NULL , NULL ,
346349 BGP_NO_SNAPSHOT_TEST );
350+ pageHeader = (PageHeader ) pageData -> image ;
347351
348- if (pageData -> fullImage )
352+ if (pageData -> flags & GENERIC_XLOG_FULL_IMAGE )
349353 {
350- /* A full page image does not require anything special */
351- memcpy (page , pageData -> image , BLCKSZ );
354+ /*
355+ * A full-page image does not require us to supply any xlog
356+ * data. Just apply the image, being careful to zero the
357+ * "hole" between pd_lower and pd_upper in order to avoid
358+ * divergence between actual page state and what replay would
359+ * produce.
360+ */
361+ memcpy (page , pageData -> image , pageHeader -> pd_lower );
362+ memset (page + pageHeader -> pd_lower , 0 ,
363+ pageHeader -> pd_upper - pageHeader -> pd_lower );
364+ memcpy (page + pageHeader -> pd_upper ,
365+ pageData -> image + pageHeader -> pd_upper ,
366+ BLCKSZ - pageHeader -> pd_upper );
367+
352368 XLogRegisterBuffer (i , pageData -> buffer ,
353369 REGBUF_FORCE_IMAGE | REGBUF_STANDARD );
354370 }
@@ -359,7 +375,15 @@ GenericXLogFinish(GenericXLogState *state)
359375 * associated with this page.
360376 */
361377 computeDelta (pageData , page , (Page ) pageData -> image );
362- memcpy (page , pageData -> image , BLCKSZ );
378+
379+ /* Apply the image, with zeroed "hole" as above */
380+ memcpy (page , pageData -> image , pageHeader -> pd_lower );
381+ memset (page + pageHeader -> pd_lower , 0 ,
382+ pageHeader -> pd_upper - pageHeader -> pd_lower );
383+ memcpy (page + pageHeader -> pd_upper ,
384+ pageData -> image + pageHeader -> pd_upper ,
385+ BLCKSZ - pageHeader -> pd_upper );
386+
363387 XLogRegisterBuffer (i , pageData -> buffer , REGBUF_STANDARD );
364388 XLogRegisterBufData (i , pageData -> delta , pageData -> deltaLen );
365389 }
@@ -395,6 +419,7 @@ GenericXLogFinish(GenericXLogState *state)
395419 BGP_NO_SNAPSHOT_TEST ),
396420 pageData -> image ,
397421 BLCKSZ );
422+ /* We don't worry about zeroing the "hole" in this case */
398423 MarkBufferDirty (pageData -> buffer );
399424 }
400425 END_CRIT_SECTION ();
@@ -473,6 +498,7 @@ generic_redo(XLogReaderState *record)
473498 if (action == BLK_NEEDS_REDO )
474499 {
475500 Page page ;
501+ PageHeader pageHeader ;
476502 char * blockDelta ;
477503 Size blockDeltaSize ;
478504
@@ -481,6 +507,16 @@ generic_redo(XLogReaderState *record)
481507 blockDelta = XLogRecGetBlockData (record , block_id , & blockDeltaSize );
482508 applyPageRedo (page , blockDelta , blockDeltaSize );
483509
510+ /*
511+ * Since the delta contains no information about what's in the
512+ * "hole" between pd_lower and pd_upper, set that to zero to
513+ * ensure we produce the same page state that application of the
514+ * logged action by GenericXLogFinish did.
515+ */
516+ pageHeader = (PageHeader ) page ;
517+ memset (page + pageHeader -> pd_lower , 0 ,
518+ pageHeader -> pd_upper - pageHeader -> pd_lower );
519+
484520 PageSetLSN (page , lsn );
485521 MarkBufferDirty (buffers [block_id ]);
486522 }
0 commit comments