@@ -3536,8 +3536,9 @@ IndexCheckExclusion(Relation heapRelation,
35363536 * insert their new tuples into it. At the same moment we clear "indisready" for
35373537 * auxiliary index, since it is no more required to be updated.
35383538 *
3539- * We then take a new reference snapshot, any tuples that are valid according
3540- * to this snap, but are not in the index, must be added to the index.
3539+ * We then take a new snapshot, any tuples that are valid according
3540+ * to this snap, but are not in the index, must be added to the index. In
3541+ * order to propagate xmin we reset that snapshot every few so often.
35413542 * (Any tuples committed live after the snap will be inserted into the
35423543 * index by their originating transaction. Any tuples committed dead before
35433544 * the snap need not be indexed, because we will wait out all transactions
@@ -3550,7 +3551,7 @@ IndexCheckExclusion(Relation heapRelation,
35503551 * TIDs of both auxiliary and target indexes, and doing a "merge join" against
35513552 * the TID lists to see which tuples from auxiliary index are missing from the
35523553 * target index. Thus we will ensure that all tuples valid according to the
3553- * reference snapshot are in the index. Notice we need to do bulkdelete in the
3554+ * latest snapshot are in the index. Notice we need to do bulkdelete in the
35543555 * particular order: auxiliary first, target last.
35553556 *
35563557 * Building a unique index this way is tricky: we might try to insert a
@@ -3571,13 +3572,14 @@ IndexCheckExclusion(Relation heapRelation,
35713572 *
35723573 * Also, some actions to concurrent drop the auxiliary index are performed.
35733574 */
3574- void
3575- validate_index (Oid heapId , Oid indexId , Oid auxIndexId , Snapshot snapshot )
3575+ TransactionId
3576+ validate_index (Oid heapId , Oid indexId , Oid auxIndexId )
35763577{
35773578 Relation heapRelation ,
35783579 indexRelation ,
35793580 auxIndexRelation ;
35803581 IndexInfo * indexInfo ;
3582+ TransactionId limitXmin ;
35813583 IndexVacuumInfo ivinfo , auxivinfo ;
35823584 ValidateIndexState state , auxState ;
35833585 Oid save_userid ;
@@ -3627,8 +3629,12 @@ validate_index(Oid heapId, Oid indexId, Oid auxIndexId, Snapshot snapshot)
36273629 * Fetch info needed for index_insert. (You might think this should be
36283630 * passed in from DefineIndex, but its copy is long gone due to having
36293631 * been built in a previous transaction.)
3632+ *
3633+ * We might need snapshot for index expressions or predicates.
36303634 */
3635+ PushActiveSnapshot (GetTransactionSnapshot ());
36313636 indexInfo = BuildIndexInfo (indexRelation );
3637+ PopActiveSnapshot ();
36323638
36333639 /* mark build is concurrent just for consistency */
36343640 indexInfo -> ii_Concurrent = true;
@@ -3664,6 +3670,9 @@ validate_index(Oid heapId, Oid indexId, Oid auxIndexId, Snapshot snapshot)
36643670 NULL , TUPLESORT_NONE );
36653671 auxState .htups = auxState .itups = auxState .tups_inserted = 0 ;
36663672
3673+ /* tuplesort_begin_datum may require catalog snapshot */
3674+ InvalidateCatalogSnapshot ();
3675+
36673676 (void ) index_bulk_delete (& auxivinfo , NULL ,
36683677 validate_index_callback , & auxState );
36693678 /* If aux index is empty, merge may be skipped */
@@ -3698,6 +3707,9 @@ validate_index(Oid heapId, Oid indexId, Oid auxIndexId, Snapshot snapshot)
36983707 NULL , TUPLESORT_NONE );
36993708 state .htups = state .itups = state .tups_inserted = 0 ;
37003709
3710+ /* tuplesort_begin_datum may require catalog snapshot */
3711+ InvalidateCatalogSnapshot ();
3712+
37013713 /* ambulkdelete updates progress metrics */
37023714 (void ) index_bulk_delete (& ivinfo , NULL ,
37033715 validate_index_callback , & state );
@@ -3717,19 +3729,24 @@ validate_index(Oid heapId, Oid indexId, Oid auxIndexId, Snapshot snapshot)
37173729 pgstat_progress_update_multi_param (3 , progress_index , progress_vals );
37183730 }
37193731 tuplesort_performsort (state .tuplesort );
3732+ /* tuplesort_performsort may require catalog snapshot */
3733+ InvalidateCatalogSnapshot ();
3734+
37203735 tuplesort_performsort (auxState .tuplesort );
3736+ /* tuplesort_performsort may require catalog snapshot */
3737+ InvalidateCatalogSnapshot ();
3738+ Assert (!TransactionIdIsValid (MyProc -> xmin ));
37213739
37223740 /*
37233741 * Now merge both indexes
37243742 */
37253743 pgstat_progress_update_param (PROGRESS_CREATEIDX_PHASE ,
37263744 PROGRESS_CREATEIDX_PHASE_VALIDATE_IDXMERGE );
3727- table_index_validate_scan (heapRelation ,
3728- indexRelation ,
3729- indexInfo ,
3730- snapshot ,
3731- & state ,
3732- & auxState );
3745+ limitXmin = table_index_validate_scan (heapRelation ,
3746+ indexRelation ,
3747+ indexInfo ,
3748+ & state ,
3749+ & auxState );
37333750
37343751 /* Tuple sort closed by table_index_validate_scan */
37353752 Assert (state .tuplesort == NULL && auxState .tuplesort == NULL );
@@ -3752,6 +3769,9 @@ validate_index(Oid heapId, Oid indexId, Oid auxIndexId, Snapshot snapshot)
37523769 index_close (auxIndexRelation , NoLock );
37533770 index_close (indexRelation , NoLock );
37543771 table_close (heapRelation , NoLock );
3772+
3773+ Assert (!TransactionIdIsValid (MyProc -> xmin ));
3774+ return limitXmin ;
37553775}
37563776
37573777/*
0 commit comments