@@ -913,7 +913,9 @@ static void VerifyOverwriteContrecord(xl_overwrite_contrecord *xlrec,
913
913
XLogReaderState * state );
914
914
static int LocalSetXLogInsertAllowed (void );
915
915
static void CreateEndOfRecoveryRecord (void );
916
- static XLogRecPtr CreateOverwriteContrecordRecord (XLogRecPtr aborted_lsn );
916
+ static XLogRecPtr CreateOverwriteContrecordRecord (XLogRecPtr aborted_lsn ,
917
+ XLogRecPtr missingContrecPtr ,
918
+ TimeLineID newTLI );
917
919
static void CheckPointGuts (XLogRecPtr checkPointRedo , int flags );
918
920
static void KeepLogSeg (XLogRecPtr recptr , XLogSegNo * logSegNo );
919
921
static XLogRecPtr XLogGetReplicationSlotMinimumLSN (void );
@@ -2295,18 +2297,6 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
2295
2297
if (!Insert -> forcePageWrites )
2296
2298
NewPage -> xlp_info |= XLP_BKP_REMOVABLE ;
2297
2299
2298
- /*
2299
- * If a record was found to be broken at the end of recovery, and
2300
- * we're going to write on the page where its first contrecord was
2301
- * lost, set the XLP_FIRST_IS_OVERWRITE_CONTRECORD flag on the page
2302
- * header. See CreateOverwriteContrecordRecord().
2303
- */
2304
- if (missingContrecPtr == NewPageBeginPtr )
2305
- {
2306
- NewPage -> xlp_info |= XLP_FIRST_IS_OVERWRITE_CONTRECORD ;
2307
- missingContrecPtr = InvalidXLogRecPtr ;
2308
- }
2309
-
2310
2300
/*
2311
2301
* If first page of an XLOG segment file, make it a long header.
2312
2302
*/
@@ -8149,7 +8139,7 @@ StartupXLOG(void)
8149
8139
if (!XLogRecPtrIsInvalid (abortedRecPtr ))
8150
8140
{
8151
8141
Assert (!XLogRecPtrIsInvalid (missingContrecPtr ));
8152
- CreateOverwriteContrecordRecord (abortedRecPtr );
8142
+ CreateOverwriteContrecordRecord (abortedRecPtr , missingContrecPtr , newTLI );
8153
8143
abortedRecPtr = InvalidXLogRecPtr ;
8154
8144
missingContrecPtr = InvalidXLogRecPtr ;
8155
8145
}
@@ -9530,27 +9520,70 @@ CreateEndOfRecoveryRecord(void)
9530
9520
* skip the record it was reading, and pass back the LSN of the skipped
9531
9521
* record, so that its caller can verify (on "replay" of that record) that the
9532
9522
* XLOG_OVERWRITE_CONTRECORD matches what was effectively overwritten.
9523
+ *
9524
+ * 'aborted_lsn' is the beginning position of the record that was incomplete.
9525
+ * It is included in the WAL record. 'pagePtr' and 'newTLI' point to the
9526
+ * beginning of the XLOG page where the record is to be inserted. They must
9527
+ * match the current WAL insert position, they're passed here just so that we
9528
+ * can verify that.
9533
9529
*/
9534
9530
static XLogRecPtr
9535
- CreateOverwriteContrecordRecord (XLogRecPtr aborted_lsn )
9531
+ CreateOverwriteContrecordRecord (XLogRecPtr aborted_lsn , XLogRecPtr pagePtr ,
9532
+ TimeLineID newTLI )
9536
9533
{
9537
9534
xl_overwrite_contrecord xlrec ;
9538
9535
XLogRecPtr recptr ;
9536
+ XLogPageHeader pagehdr ;
9537
+ XLogRecPtr startPos ;
9539
9538
9540
- /* sanity check */
9539
+ /* sanity checks */
9541
9540
if (!RecoveryInProgress ())
9542
9541
elog (ERROR , "can only be used at end of recovery" );
9543
-
9544
- xlrec .overwritten_lsn = aborted_lsn ;
9545
- xlrec .overwrite_time = GetCurrentTimestamp ();
9542
+ if (pagePtr % XLOG_BLCKSZ != 0 )
9543
+ elog (ERROR , "invalid position for missing continuation record %X/%X" ,
9544
+ LSN_FORMAT_ARGS (pagePtr ));
9545
+
9546
+ /* The current WAL insert position should be right after the page header */
9547
+ startPos = pagePtr ;
9548
+ if (XLogSegmentOffset (startPos , wal_segment_size ) == 0 )
9549
+ startPos += SizeOfXLogLongPHD ;
9550
+ else
9551
+ startPos += SizeOfXLogShortPHD ;
9552
+ recptr = GetXLogInsertRecPtr ();
9553
+ if (recptr != startPos )
9554
+ elog (ERROR , "invalid WAL insert position %X/%X for OVERWRITE_CONTRECORD" ,
9555
+ LSN_FORMAT_ARGS (recptr ));
9546
9556
9547
9557
START_CRIT_SECTION ();
9548
9558
9559
+ /*
9560
+ * Initialize the XLOG page header (by GetXLogBuffer), and set the
9561
+ * XLP_FIRST_IS_OVERWRITE_CONTRECORD flag.
9562
+ *
9563
+ * No other backend is allowed to write WAL yet, so acquiring the WAL
9564
+ * insertion lock is just pro forma.
9565
+ */
9566
+ WALInsertLockAcquire ();
9567
+ pagehdr = (XLogPageHeader ) GetXLogBuffer (pagePtr , newTLI );
9568
+ pagehdr -> xlp_info |= XLP_FIRST_IS_OVERWRITE_CONTRECORD ;
9569
+ WALInsertLockRelease ();
9570
+
9571
+ /*
9572
+ * Insert the XLOG_OVERWRITE_CONTRECORD record as the first record on the
9573
+ * page. We know it becomes the first record, because no other backend is
9574
+ * allowed to write WAL yet.
9575
+ */
9549
9576
XLogBeginInsert ();
9577
+ xlrec .overwritten_lsn = aborted_lsn ;
9578
+ xlrec .overwrite_time = GetCurrentTimestamp ();
9550
9579
XLogRegisterData ((char * ) & xlrec , sizeof (xl_overwrite_contrecord ));
9551
-
9552
9580
recptr = XLogInsert (RM_XLOG_ID , XLOG_OVERWRITE_CONTRECORD );
9553
9581
9582
+ /* check that the record was inserted to the right place */
9583
+ if (ProcLastRecPtr != startPos )
9584
+ elog (ERROR , "OVERWRITE_CONTRECORD was inserted to unexpected position %X/%X" ,
9585
+ LSN_FORMAT_ARGS (ProcLastRecPtr ));
9586
+
9554
9587
XLogFlush (recptr );
9555
9588
9556
9589
END_CRIT_SECTION ();
0 commit comments