@@ -335,7 +335,7 @@ index_rescan(IndexScanDesc scan,
335
335
scan -> xs_cbuf = InvalidBuffer ;
336
336
}
337
337
338
- scan -> xs_next_hot = InvalidOffsetNumber ;
338
+ scan -> xs_continue_hot = false ;
339
339
340
340
scan -> kill_prior_tuple = false; /* for safety */
341
341
@@ -417,7 +417,7 @@ index_restrpos(IndexScanDesc scan)
417
417
SCAN_CHECKS ;
418
418
GET_SCAN_PROCEDURE (amrestrpos );
419
419
420
- scan -> xs_next_hot = InvalidOffsetNumber ;
420
+ scan -> xs_continue_hot = false ;
421
421
422
422
scan -> kill_prior_tuple = false; /* for safety */
423
423
@@ -443,26 +443,18 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
443
443
HeapTuple heapTuple = & scan -> xs_ctup ;
444
444
ItemPointer tid = & heapTuple -> t_self ;
445
445
FmgrInfo * procedure ;
446
+ bool all_dead = false;
446
447
447
448
SCAN_CHECKS ;
448
449
GET_SCAN_PROCEDURE (amgettuple );
449
450
450
451
Assert (TransactionIdIsValid (RecentGlobalXmin ));
451
452
452
- /*
453
- * We always reset xs_hot_dead; if we are here then either we are just
454
- * starting the scan, or we previously returned a visible tuple, and in
455
- * either case it's inappropriate to kill the prior index entry.
456
- */
457
- scan -> xs_hot_dead = false;
458
-
459
453
for (;;)
460
454
{
461
- OffsetNumber offnum ;
462
- bool at_chain_start ;
463
- Page dp ;
455
+ bool got_heap_tuple ;
464
456
465
- if (scan -> xs_next_hot != InvalidOffsetNumber )
457
+ if (scan -> xs_continue_hot )
466
458
{
467
459
/*
468
460
* We are resuming scan of a HOT chain after having returned an
@@ -471,10 +463,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
471
463
Assert (BufferIsValid (scan -> xs_cbuf ));
472
464
Assert (ItemPointerGetBlockNumber (tid ) ==
473
465
BufferGetBlockNumber (scan -> xs_cbuf ));
474
- Assert (TransactionIdIsValid (scan -> xs_prev_xmax ));
475
- offnum = scan -> xs_next_hot ;
476
- at_chain_start = false;
477
- scan -> xs_next_hot = InvalidOffsetNumber ;
478
466
}
479
467
else
480
468
{
@@ -488,7 +476,7 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
488
476
* comments in RelationGetIndexScan().
489
477
*/
490
478
if (!scan -> xactStartedInRecovery )
491
- scan -> kill_prior_tuple = scan -> xs_hot_dead ;
479
+ scan -> kill_prior_tuple = all_dead ;
492
480
493
481
/*
494
482
* The AM's gettuple proc finds the next index entry matching the
@@ -521,151 +509,31 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
521
509
if (prev_buf != scan -> xs_cbuf )
522
510
heap_page_prune_opt (scan -> heapRelation , scan -> xs_cbuf ,
523
511
RecentGlobalXmin );
524
-
525
- /* Prepare to scan HOT chain starting at index-referenced offnum */
526
- offnum = ItemPointerGetOffsetNumber (tid );
527
- at_chain_start = true;
528
-
529
- /* We don't know what the first tuple's xmin should be */
530
- scan -> xs_prev_xmax = InvalidTransactionId ;
531
-
532
- /* Initialize flag to detect if all entries are dead */
533
- scan -> xs_hot_dead = true;
534
512
}
535
513
536
514
/* Obtain share-lock on the buffer so we can examine visibility */
537
515
LockBuffer (scan -> xs_cbuf , BUFFER_LOCK_SHARE );
516
+ got_heap_tuple = heap_hot_search_buffer (tid , scan -> heapRelation ,
517
+ scan -> xs_cbuf ,
518
+ scan -> xs_snapshot ,
519
+ & scan -> xs_ctup ,
520
+ & all_dead ,
521
+ !scan -> xs_continue_hot );
522
+ LockBuffer (scan -> xs_cbuf , BUFFER_LOCK_UNLOCK );
538
523
539
- dp = (Page ) BufferGetPage (scan -> xs_cbuf );
540
-
541
- /* Scan through possible multiple members of HOT-chain */
542
- for (;;)
524
+ if (got_heap_tuple )
543
525
{
544
- ItemId lp ;
545
- ItemPointer ctid ;
546
- bool valid ;
547
-
548
- /* check for bogus TID */
549
- if (offnum < FirstOffsetNumber ||
550
- offnum > PageGetMaxOffsetNumber (dp ))
551
- break ;
552
-
553
- lp = PageGetItemId (dp , offnum );
554
-
555
- /* check for unused, dead, or redirected items */
556
- if (!ItemIdIsNormal (lp ))
557
- {
558
- /* We should only see a redirect at start of chain */
559
- if (ItemIdIsRedirected (lp ) && at_chain_start )
560
- {
561
- /* Follow the redirect */
562
- offnum = ItemIdGetRedirect (lp );
563
- at_chain_start = false;
564
- continue ;
565
- }
566
- /* else must be end of chain */
567
- break ;
568
- }
569
-
570
- /*
571
- * We must initialize all of *heapTuple (ie, scan->xs_ctup) since
572
- * it is returned to the executor on success.
573
- */
574
- heapTuple -> t_data = (HeapTupleHeader ) PageGetItem (dp , lp );
575
- heapTuple -> t_len = ItemIdGetLength (lp );
576
- ItemPointerSetOffsetNumber (tid , offnum );
577
- heapTuple -> t_tableOid = RelationGetRelid (scan -> heapRelation );
578
- ctid = & heapTuple -> t_data -> t_ctid ;
579
-
580
526
/*
581
- * Shouldn't see a HEAP_ONLY tuple at chain start. (This test
582
- * should be unnecessary, since the chain root can't be removed
583
- * while we have pin on the index entry, but let's make it
584
- * anyway.)
527
+ * Only in a non-MVCC snapshot can more than one member of the
528
+ * HOT chain be visible.
585
529
*/
586
- if (at_chain_start && HeapTupleIsHeapOnly (heapTuple ))
587
- break ;
588
-
589
- /*
590
- * The xmin should match the previous xmax value, else chain is
591
- * broken. (Note: this test is not optional because it protects
592
- * us against the case where the prior chain member's xmax aborted
593
- * since we looked at it.)
594
- */
595
- if (TransactionIdIsValid (scan -> xs_prev_xmax ) &&
596
- !TransactionIdEquals (scan -> xs_prev_xmax ,
597
- HeapTupleHeaderGetXmin (heapTuple -> t_data )))
598
- break ;
599
-
600
- /* If it's visible per the snapshot, we must return it */
601
- valid = HeapTupleSatisfiesVisibility (heapTuple , scan -> xs_snapshot ,
602
- scan -> xs_cbuf );
603
-
604
- CheckForSerializableConflictOut (valid , scan -> heapRelation ,
605
- heapTuple , scan -> xs_cbuf ,
606
- scan -> xs_snapshot );
607
-
608
- if (valid )
609
- {
610
- /*
611
- * If the snapshot is MVCC, we know that it could accept at
612
- * most one member of the HOT chain, so we can skip examining
613
- * any more members. Otherwise, check for continuation of the
614
- * HOT-chain, and set state for next time.
615
- */
616
- if (IsMVCCSnapshot (scan -> xs_snapshot ))
617
- scan -> xs_next_hot = InvalidOffsetNumber ;
618
- else if (HeapTupleIsHotUpdated (heapTuple ))
619
- {
620
- Assert (ItemPointerGetBlockNumber (ctid ) ==
621
- ItemPointerGetBlockNumber (tid ));
622
- scan -> xs_next_hot = ItemPointerGetOffsetNumber (ctid );
623
- scan -> xs_prev_xmax = HeapTupleHeaderGetXmax (heapTuple -> t_data );
624
- }
625
- else
626
- scan -> xs_next_hot = InvalidOffsetNumber ;
627
-
628
- PredicateLockTuple (scan -> heapRelation , heapTuple , scan -> xs_snapshot );
629
-
630
- LockBuffer (scan -> xs_cbuf , BUFFER_LOCK_UNLOCK );
631
-
632
- pgstat_count_heap_fetch (scan -> indexRelation );
633
-
634
- return heapTuple ;
635
- }
636
-
637
- /*
638
- * If we can't see it, maybe no one else can either. Check to see
639
- * if the tuple is dead to all transactions. If we find that all
640
- * the tuples in the HOT chain are dead, we'll signal the index AM
641
- * to not return that TID on future indexscans.
642
- */
643
- if (scan -> xs_hot_dead &&
644
- HeapTupleSatisfiesVacuum (heapTuple -> t_data , RecentGlobalXmin ,
645
- scan -> xs_cbuf ) != HEAPTUPLE_DEAD )
646
- scan -> xs_hot_dead = false;
647
-
648
- /*
649
- * Check to see if HOT chain continues past this tuple; if so
650
- * fetch the next offnum (we don't bother storing it into
651
- * xs_next_hot, but must store xs_prev_xmax), and loop around.
652
- */
653
- if (HeapTupleIsHotUpdated (heapTuple ))
654
- {
655
- Assert (ItemPointerGetBlockNumber (ctid ) ==
656
- ItemPointerGetBlockNumber (tid ));
657
- offnum = ItemPointerGetOffsetNumber (ctid );
658
- at_chain_start = false;
659
- scan -> xs_prev_xmax = HeapTupleHeaderGetXmax (heapTuple -> t_data );
660
- }
661
- else
662
- break ; /* end of chain */
663
- } /* loop over a single HOT chain */
664
-
665
- LockBuffer (scan -> xs_cbuf , BUFFER_LOCK_UNLOCK );
530
+ scan -> xs_continue_hot = !IsMVCCSnapshot (scan -> xs_snapshot );
531
+ pgstat_count_heap_fetch (scan -> indexRelation );
532
+ return heapTuple ;
533
+ }
666
534
667
535
/* Loop around to ask index AM for another TID */
668
- scan -> xs_next_hot = InvalidOffsetNumber ;
536
+ scan -> xs_continue_hot = false ;
669
537
}
670
538
671
539
/* Release any held pin on a heap page */
0 commit comments