50
50
typedef struct
51
51
{
52
52
Buffer buffer ;/* registered buffer */
53
- bool fullImage ;/*are we taking a full image of thispage? */
53
+ int flags ;/*flags for thisbuffer */
54
54
int deltaLen ;/* space consumed in delta field */
55
55
char image [BLCKSZ ];/* copy of page image for modification */
56
56
char delta [MAX_DELTA_SIZE ];/* delta between page images */
@@ -280,9 +280,11 @@ GenericXLogStart(Relation relation)
280
280
* is what the caller should modify.
281
281
*
282
282
* 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.)
283
285
*/
284
286
Page
285
- GenericXLogRegister (GenericXLogState * state ,Buffer buffer ,bool isNew )
287
+ GenericXLogRegisterBuffer (GenericXLogState * state ,Buffer buffer ,int flags )
286
288
{
287
289
int block_id ;
288
290
@@ -295,7 +297,7 @@ GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
295
297
{
296
298
/* Empty slot, so use it (there cannot be a match later) */
297
299
page -> buffer = buffer ;
298
- page -> fullImage = isNew ;
300
+ page -> flags = flags ;
299
301
memcpy (page -> image ,
300
302
BufferGetPage (buffer ,NULL ,NULL ,BGP_NO_SNAPSHOT_TEST ),
301
303
BLCKSZ );
@@ -338,17 +340,31 @@ GenericXLogFinish(GenericXLogState *state)
338
340
{
339
341
PageData * pageData = & state -> pages [i ];
340
342
Page page ;
343
+ PageHeader pageHeader ;
341
344
342
345
if (BufferIsInvalid (pageData -> buffer ))
343
346
continue ;
344
347
345
348
page = BufferGetPage (pageData -> buffer ,NULL ,NULL ,
346
349
BGP_NO_SNAPSHOT_TEST );
350
+ pageHeader = (PageHeader )pageData -> image ;
347
351
348
- if (pageData -> fullImage )
352
+ if (pageData -> flags & GENERIC_XLOG_FULL_IMAGE )
349
353
{
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
+
352
368
XLogRegisterBuffer (i ,pageData -> buffer ,
353
369
REGBUF_FORCE_IMAGE |REGBUF_STANDARD );
354
370
}
@@ -359,7 +375,15 @@ GenericXLogFinish(GenericXLogState *state)
359
375
* associated with this page.
360
376
*/
361
377
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
+
363
387
XLogRegisterBuffer (i ,pageData -> buffer ,REGBUF_STANDARD );
364
388
XLogRegisterBufData (i ,pageData -> delta ,pageData -> deltaLen );
365
389
}
@@ -395,6 +419,7 @@ GenericXLogFinish(GenericXLogState *state)
395
419
BGP_NO_SNAPSHOT_TEST ),
396
420
pageData -> image ,
397
421
BLCKSZ );
422
+ /* We don't worry about zeroing the "hole" in this case */
398
423
MarkBufferDirty (pageData -> buffer );
399
424
}
400
425
END_CRIT_SECTION ();
@@ -473,6 +498,7 @@ generic_redo(XLogReaderState *record)
473
498
if (action == BLK_NEEDS_REDO )
474
499
{
475
500
Page page ;
501
+ PageHeader pageHeader ;
476
502
char * blockDelta ;
477
503
Size blockDeltaSize ;
478
504
@@ -481,6 +507,16 @@ generic_redo(XLogReaderState *record)
481
507
blockDelta = XLogRecGetBlockData (record ,block_id ,& blockDeltaSize );
482
508
applyPageRedo (page ,blockDelta ,blockDeltaSize );
483
509
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
+
484
520
PageSetLSN (page ,lsn );
485
521
MarkBufferDirty (buffers [block_id ]);
486
522
}