@@ -92,9 +92,11 @@ typedef struct BtreeCheckState
9292 BufferAccessStrategy checkstrategy ;
9393
9494 /*
95- * Info for uniqueness checking. Fill these fields once per index check.
95+ * Info for uniqueness checking. Fill this field and the one below once
96+ * per index check.
9697 */
9798 IndexInfo * indexinfo ;
99+ /* Table scan snapshot for heapallindexed and checkunique */
98100 Snapshot snapshot ;
99101
100102 /*
@@ -382,7 +384,6 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
382384 BTMetaPageData * metad ;
383385 uint32 previouslevel ;
384386 BtreeLevel current ;
385- Snapshot snapshot = SnapshotAny ;
386387
387388 if (!readonly )
388389 elog (DEBUG1 , "verifying consistency of tree structure for index \"%s\"" ,
@@ -433,54 +434,46 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
433434 state -> heaptuplespresent = 0 ;
434435
435436 /*
436- * Register our own snapshot in !readonly case , rather than asking
437+ * Register our own snapshot for heapallindexed , rather than asking
437438 * table_index_build_scan() to do this for us later. This needs to
438439 * happen before index fingerprinting begins, so we can later be
439440 * certain that index fingerprinting should have reached all tuples
440441 * returned by table_index_build_scan().
441442 */
442- if (!state -> readonly )
443- {
444- snapshot = RegisterSnapshot (GetTransactionSnapshot ());
443+ state -> snapshot = RegisterSnapshot (GetTransactionSnapshot ());
445444
446- /*
447- * GetTransactionSnapshot() always acquires a new MVCC snapshot in
448- * READ COMMITTED mode. A new snapshot is guaranteed to have all
449- * the entries it requires in the index.
450- *
451- * We must defend against the possibility that an old xact
452- * snapshot was returned at higher isolation levels when that
453- * snapshot is not safe for index scans of the target index. This
454- * is possible when the snapshot sees tuples that are before the
455- * index's indcheckxmin horizon. Throwing an error here should be
456- * very rare. It doesn't seem worth using a secondary snapshot to
457- * avoid this.
458- */
459- if (IsolationUsesXactSnapshot () && rel -> rd_index -> indcheckxmin &&
460- !TransactionIdPrecedes (HeapTupleHeaderGetXmin (rel -> rd_indextuple -> t_data ),
461- snapshot -> xmin ))
462- ereport (ERROR ,
463- (errcode (ERRCODE_T_R_SERIALIZATION_FAILURE ),
464- errmsg ("index \"%s\" cannot be verified using transaction snapshot" ,
465- RelationGetRelationName (rel ))));
466- }
445+ /*
446+ * GetTransactionSnapshot() always acquires a new MVCC snapshot in
447+ * READ COMMITTED mode. A new snapshot is guaranteed to have all the
448+ * entries it requires in the index.
449+ *
450+ * We must defend against the possibility that an old xact snapshot
451+ * was returned at higher isolation levels when that snapshot is not
452+ * safe for index scans of the target index. This is possible when
453+ * the snapshot sees tuples that are before the index's indcheckxmin
454+ * horizon. Throwing an error here should be very rare. It doesn't
455+ * seem worth using a secondary snapshot to avoid this.
456+ */
457+ if (IsolationUsesXactSnapshot () && rel -> rd_index -> indcheckxmin &&
458+ !TransactionIdPrecedes (HeapTupleHeaderGetXmin (rel -> rd_indextuple -> t_data ),
459+ state -> snapshot -> xmin ))
460+ ereport (ERROR ,
461+ errcode (ERRCODE_T_R_SERIALIZATION_FAILURE ),
462+ errmsg ("index \"%s\" cannot be verified using transaction snapshot" ,
463+ RelationGetRelationName (rel )));
467464 }
468465
469466 /*
470- * We need a snapshot to check the uniqueness of the index. For better
471- * performance take it once per index check. If snapshot already taken
472- * reuse it .
467+ * We need a snapshot to check the uniqueness of the index. For better
468+ * performance, take it once per index check. If one was already taken
469+ * above, use that .
473470 */
474471 if (state -> checkunique )
475472 {
476473 state -> indexinfo = BuildIndexInfo (state -> rel );
477- if (state -> indexinfo -> ii_Unique )
478- {
479- if (snapshot != SnapshotAny )
480- state -> snapshot = snapshot ;
481- else
482- state -> snapshot = RegisterSnapshot (GetTransactionSnapshot ());
483- }
474+
475+ if (state -> indexinfo -> ii_Unique && state -> snapshot == InvalidSnapshot )
476+ state -> snapshot = RegisterSnapshot (GetTransactionSnapshot ());
484477 }
485478
486479 Assert (!state -> rootdescend || state -> readonly );
@@ -555,30 +548,28 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
555548 /*
556549 * Create our own scan for table_index_build_scan(), rather than
557550 * getting it to do so for us. This is required so that we can
558- * actually use the MVCC snapshot registered earlier in !readonly
559- * case.
551+ * actually use the MVCC snapshot registered earlier.
560552 *
561553 * Note that table_index_build_scan() calls heap_endscan() for us.
562554 */
563555 scan = table_beginscan_strat (state -> heaprel , /* relation */
564- snapshot , /* snapshot */
556+ state -> snapshot , /* snapshot */
565557 0 , /* number of keys */
566558 NULL , /* scan key */
567559 true, /* buffer access strategy OK */
568560 true); /* syncscan OK? */
569561
570562 /*
571563 * Scan will behave as the first scan of a CREATE INDEX CONCURRENTLY
572- * behaves in !readonly case .
564+ * behaves.
573565 *
574566 * It's okay that we don't actually use the same lock strength for the
575- * heap relation as any other ii_Concurrent caller would in !readonly
576- * case. We have no reason to care about a concurrent VACUUM
577- * operation, since there isn't going to be a second scan of the heap
578- * that needs to be sure that there was no concurrent recycling of
579- * TIDs.
567+ * heap relation as any other ii_Concurrent caller would. We have no
568+ * reason to care about a concurrent VACUUM operation, since there
569+ * isn't going to be a second scan of the heap that needs to be sure
570+ * that there was no concurrent recycling of TIDs.
580571 */
581- indexinfo -> ii_Concurrent = ! state -> readonly ;
572+ indexinfo -> ii_Concurrent = true ;
582573
583574 /*
584575 * Don't wait for uncommitted tuple xact commit/abort when index is a
@@ -602,14 +593,11 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
602593 state -> heaptuplespresent , RelationGetRelationName (heaprel ),
603594 100.0 * bloom_prop_bits_set (state -> filter ))));
604595
605- if (snapshot != SnapshotAny )
606- UnregisterSnapshot (snapshot );
607-
608596 bloom_free (state -> filter );
609597 }
610598
611599 /* Be tidy: */
612- if (snapshot == SnapshotAny && state -> snapshot != InvalidSnapshot )
600+ if (state -> snapshot != InvalidSnapshot )
613601 UnregisterSnapshot (state -> snapshot );
614602 MemoryContextDelete (state -> targetcontext );
615603}
@@ -721,7 +709,7 @@ bt_check_level_from_leftmost(BtreeCheckState *state, BtreeLevel level)
721709 errmsg ("block %u is not leftmost in index \"%s\"" ,
722710 current , RelationGetRelationName (state -> rel ))));
723711
724- if (level .istruerootlevel && !P_ISROOT (opaque ))
712+ if (level .istruerootlevel && ( !P_ISROOT (opaque ) && ! P_INCOMPLETE_SPLIT ( opaque ) ))
725713 ereport (ERROR ,
726714 (errcode (ERRCODE_INDEX_CORRUPTED ),
727715 errmsg ("block %u is not true root in index \"%s\"" ,
@@ -2270,7 +2258,7 @@ bt_child_highkey_check(BtreeCheckState *state,
22702258 * If we visit page with high key, check that it is equal to the
22712259 * target key next to corresponding downlink.
22722260 */
2273- if (!rightsplit && !P_RIGHTMOST (opaque ))
2261+ if (!rightsplit && !P_RIGHTMOST (opaque ) && ! P_ISHALFDEAD ( opaque ) )
22742262 {
22752263 BTPageOpaque topaque ;
22762264 IndexTuple highkey ;
0 commit comments