@@ -6792,7 +6792,7 @@ heap_freeze_execute_prepared(Relation rel, Buffer buffer,
6792
6792
Page page = BufferGetPage (buffer );
6793
6793
6794
6794
Assert (ntuples > 0 );
6795
- Assert (TransactionIdIsValid (FreezeLimit ));
6795
+ Assert (TransactionIdIsNormal (FreezeLimit ));
6796
6796
6797
6797
START_CRIT_SECTION ();
6798
6798
@@ -6815,21 +6815,20 @@ heap_freeze_execute_prepared(Relation rel, Buffer buffer,
6815
6815
int nplans ;
6816
6816
xl_heap_freeze_page xlrec ;
6817
6817
XLogRecPtr recptr ;
6818
- TransactionId latestRemovedXid ;
6818
+ TransactionId snapshotConflictHorizon ;
6819
6819
6820
6820
/* Prepare deduplicated representation for use in WAL record */
6821
6821
nplans = heap_xlog_freeze_plan (tuples , ntuples , plans , offsets );
6822
6822
6823
6823
/*
6824
- * latestRemovedXid describes the latest processed XID, whereas
6825
6824
* FreezeLimit is (approximately) the first XID not frozen by VACUUM.
6826
6825
* Back up caller's FreezeLimit to avoid false conflicts when
6827
6826
* FreezeLimit is precisely equal to VACUUM's OldestXmin cutoff.
6828
6827
*/
6829
- latestRemovedXid = FreezeLimit ;
6830
- TransactionIdRetreat (latestRemovedXid );
6828
+ snapshotConflictHorizon = FreezeLimit ;
6829
+ TransactionIdRetreat (snapshotConflictHorizon );
6831
6830
6832
- xlrec .latestRemovedXid = latestRemovedXid ;
6831
+ xlrec .snapshotConflictHorizon = snapshotConflictHorizon ;
6833
6832
xlrec .nplans = nplans ;
6834
6833
6835
6834
XLogBeginInsert ();
@@ -7401,24 +7400,30 @@ heap_tuple_would_freeze(HeapTupleHeader tuple, TransactionId cutoff_xid,
7401
7400
}
7402
7401
7403
7402
/*
7404
- * If 'tuple' contains any visible XID greater than latestRemovedXid,
7405
- * ratchet forwards latestRemovedXid to the greatest one found.
7406
- * This is used as the basis for generating Hot Standby conflicts, so
7407
- * if a tuple was never visible then removing it should not conflict
7408
- * with queries.
7403
+ * Maintain snapshotConflictHorizon for caller by ratcheting forward its value
7404
+ * using any committed XIDs contained in 'tuple', an obsolescent heap tuple
7405
+ * that caller is in the process of physically removing, e.g. via HOT pruning
7406
+ * or index deletion.
7407
+ *
7408
+ * Caller must initialize its value to InvalidTransactionId, which is
7409
+ * generally interpreted as "definitely no need for a recovery conflict".
7410
+ * Final value must reflect all heap tuples that caller will physically remove
7411
+ * (or remove TID references to) via its ongoing pruning/deletion operation.
7412
+ * ResolveRecoveryConflictWithSnapshot() is passed the final value (taken from
7413
+ * caller's WAL record) by REDO routine when it replays caller's operation.
7409
7414
*/
7410
7415
void
7411
- HeapTupleHeaderAdvanceLatestRemovedXid (HeapTupleHeader tuple ,
7412
- TransactionId * latestRemovedXid )
7416
+ HeapTupleHeaderAdvanceConflictHorizon (HeapTupleHeader tuple ,
7417
+ TransactionId * snapshotConflictHorizon )
7413
7418
{
7414
7419
TransactionId xmin = HeapTupleHeaderGetXmin (tuple );
7415
7420
TransactionId xmax = HeapTupleHeaderGetUpdateXid (tuple );
7416
7421
TransactionId xvac = HeapTupleHeaderGetXvac (tuple );
7417
7422
7418
7423
if (tuple -> t_infomask & HEAP_MOVED )
7419
7424
{
7420
- if (TransactionIdPrecedes (* latestRemovedXid , xvac ))
7421
- * latestRemovedXid = xvac ;
7425
+ if (TransactionIdPrecedes (* snapshotConflictHorizon , xvac ))
7426
+ * snapshotConflictHorizon = xvac ;
7422
7427
}
7423
7428
7424
7429
/*
@@ -7431,11 +7436,9 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
7431
7436
(!HeapTupleHeaderXminInvalid (tuple ) && TransactionIdDidCommit (xmin )))
7432
7437
{
7433
7438
if (xmax != xmin &&
7434
- TransactionIdFollows (xmax , * latestRemovedXid ))
7435
- * latestRemovedXid = xmax ;
7439
+ TransactionIdFollows (xmax , * snapshotConflictHorizon ))
7440
+ * snapshotConflictHorizon = xmax ;
7436
7441
}
7437
-
7438
- /* *latestRemovedXid may still be invalid at end */
7439
7442
}
7440
7443
7441
7444
#ifdef USE_PREFETCH
@@ -7558,7 +7561,7 @@ TransactionId
7558
7561
heap_index_delete_tuples (Relation rel , TM_IndexDeleteOp * delstate )
7559
7562
{
7560
7563
/* Initial assumption is that earlier pruning took care of conflict */
7561
- TransactionId latestRemovedXid = InvalidTransactionId ;
7564
+ TransactionId snapshotConflictHorizon = InvalidTransactionId ;
7562
7565
BlockNumber blkno = InvalidBlockNumber ;
7563
7566
Buffer buf = InvalidBuffer ;
7564
7567
Page page = NULL ;
@@ -7769,8 +7772,8 @@ heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate)
7769
7772
}
7770
7773
7771
7774
/*
7772
- * Maintain latestRemovedXid value for deletion operation as a whole
7773
- * by advancing current value using heap tuple headers. This is
7775
+ * Maintain snapshotConflictHorizon value for deletion operation as a
7776
+ * whole by advancing current value using heap tuple headers. This is
7774
7777
* loosely based on the logic for pruning a HOT chain.
7775
7778
*/
7776
7779
offnum = ItemPointerGetOffsetNumber (htid );
@@ -7805,12 +7808,12 @@ heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate)
7805
7808
* LP_DEAD item. This is okay because the earlier pruning
7806
7809
* operation that made the line pointer LP_DEAD in the first place
7807
7810
* must have considered the original tuple header as part of
7808
- * generating its own latestRemovedXid value.
7811
+ * generating its own snapshotConflictHorizon value.
7809
7812
*
7810
7813
* Relying on XLOG_HEAP2_PRUNE records like this is the same
7811
7814
* strategy that index vacuuming uses in all cases. Index VACUUM
7812
- * WAL records don't even have a latestRemovedXid field of their
7813
- * own for this reason.
7815
+ * WAL records don't even have a snapshotConflictHorizon field of
7816
+ * their own for this reason.
7814
7817
*/
7815
7818
if (!ItemIdIsNormal (lp ))
7816
7819
break ;
@@ -7824,7 +7827,8 @@ heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate)
7824
7827
!TransactionIdEquals (HeapTupleHeaderGetXmin (htup ), priorXmax ))
7825
7828
break ;
7826
7829
7827
- HeapTupleHeaderAdvanceLatestRemovedXid (htup , & latestRemovedXid );
7830
+ HeapTupleHeaderAdvanceConflictHorizon (htup ,
7831
+ & snapshotConflictHorizon );
7828
7832
7829
7833
/*
7830
7834
* If the tuple is not HOT-updated, then we are at the end of this
@@ -7856,7 +7860,7 @@ heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate)
7856
7860
Assert (finalndeltids > 0 || delstate -> bottomup );
7857
7861
delstate -> ndeltids = finalndeltids ;
7858
7862
7859
- return latestRemovedXid ;
7863
+ return snapshotConflictHorizon ;
7860
7864
}
7861
7865
7862
7866
/*
@@ -8232,14 +8236,17 @@ bottomup_sort_and_shrink(TM_IndexDeleteOp *delstate)
8232
8236
* corresponding visibility map block. Both should have already been modified
8233
8237
* and dirtied.
8234
8238
*
8239
+ * snapshotConflictHorizon comes from the largest xmin on the page being
8240
+ * marked all-visible. REDO routine uses it to generate recovery conflicts.
8241
+ *
8235
8242
* If checksums or wal_log_hints are enabled, we may also generate a full-page
8236
8243
* image of heap_buffer. Otherwise, we optimize away the FPI (by specifying
8237
8244
* REGBUF_NO_IMAGE for the heap buffer), in which case the caller should *not*
8238
8245
* update the heap page's LSN.
8239
8246
*/
8240
8247
XLogRecPtr
8241
8248
log_heap_visible (RelFileLocator rlocator , Buffer heap_buffer , Buffer vm_buffer ,
8242
- TransactionId cutoff_xid , uint8 vmflags )
8249
+ TransactionId snapshotConflictHorizon , uint8 vmflags )
8243
8250
{
8244
8251
xl_heap_visible xlrec ;
8245
8252
XLogRecPtr recptr ;
@@ -8248,7 +8255,7 @@ log_heap_visible(RelFileLocator rlocator, Buffer heap_buffer, Buffer vm_buffer,
8248
8255
Assert (BufferIsValid (heap_buffer ));
8249
8256
Assert (BufferIsValid (vm_buffer ));
8250
8257
8251
- xlrec .cutoff_xid = cutoff_xid ;
8258
+ xlrec .snapshotConflictHorizon = snapshotConflictHorizon ;
8252
8259
xlrec .flags = vmflags ;
8253
8260
XLogBeginInsert ();
8254
8261
XLogRegisterData ((char * ) & xlrec , SizeOfHeapVisible );
@@ -8683,7 +8690,8 @@ heap_xlog_prune(XLogReaderState *record)
8683
8690
* no queries running for which the removed tuples are still visible.
8684
8691
*/
8685
8692
if (InHotStandby )
8686
- ResolveRecoveryConflictWithSnapshot (xlrec -> latestRemovedXid , rlocator );
8693
+ ResolveRecoveryConflictWithSnapshot (xlrec -> snapshotConflictHorizon ,
8694
+ rlocator );
8687
8695
8688
8696
/*
8689
8697
* If we have a full-page image, restore it (using a cleanup lock) and
@@ -8851,7 +8859,8 @@ heap_xlog_visible(XLogReaderState *record)
8851
8859
* rather than killing the transaction outright.
8852
8860
*/
8853
8861
if (InHotStandby )
8854
- ResolveRecoveryConflictWithSnapshot (xlrec -> cutoff_xid , rlocator );
8862
+ ResolveRecoveryConflictWithSnapshot (xlrec -> snapshotConflictHorizon ,
8863
+ rlocator );
8855
8864
8856
8865
/*
8857
8866
* Read the heap page, if it still exists. If the heap file has dropped or
@@ -8939,7 +8948,7 @@ heap_xlog_visible(XLogReaderState *record)
8939
8948
visibilitymap_pin (reln , blkno , & vmbuffer );
8940
8949
8941
8950
visibilitymap_set (reln , blkno , InvalidBuffer , lsn , vmbuffer ,
8942
- xlrec -> cutoff_xid , xlrec -> flags );
8951
+ xlrec -> snapshotConflictHorizon , xlrec -> flags );
8943
8952
8944
8953
ReleaseBuffer (vmbuffer );
8945
8954
FreeFakeRelcacheEntry (reln );
@@ -9105,7 +9114,8 @@ heap_xlog_freeze_page(XLogReaderState *record)
9105
9114
RelFileLocator rlocator ;
9106
9115
9107
9116
XLogRecGetBlockTag (record , 0 , & rlocator , NULL , NULL );
9108
- ResolveRecoveryConflictWithSnapshot (xlrec -> latestRemovedXid , rlocator );
9117
+ ResolveRecoveryConflictWithSnapshot (xlrec -> snapshotConflictHorizon ,
9118
+ rlocator );
9109
9119
}
9110
9120
9111
9121
if (XLogReadBufferForRedo (record , 0 , & buffer ) == BLK_NEEDS_REDO )
0 commit comments