17
17
#include "access/genam.h"
18
18
#include "access/gist_private.h"
19
19
#include "access/relscan.h"
20
+ #include "access/tableam.h"
20
21
#include "lib/pairingheap.h"
21
22
#include "miscadmin.h"
22
23
#include "pgstat.h"
@@ -394,10 +395,14 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
394
395
return ;
395
396
}
396
397
397
- so -> nPageData = so -> curPageData = 0 ;
398
+ if (scan -> numberOfOrderBys )
399
+ so -> os .nsortData = 0 ;
400
+ else
401
+ so -> nos .nPageData = so -> nos .curPageData = 0 ;
402
+
398
403
scan -> xs_hitup = NULL ; /* might point into pageDataCxt */
399
- if (so -> pageDataCxt )
400
- MemoryContextReset (so -> pageDataCxt );
404
+ if (so -> nos . pageDataCxt )
405
+ MemoryContextReset (so -> nos . pageDataCxt );
401
406
402
407
/*
403
408
* We save the LSN of the page as we read it, so that we know whether it
@@ -457,22 +462,22 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
457
462
/*
458
463
* Non-ordered scan, so report tuples in so->pageData[]
459
464
*/
460
- so -> pageData [so -> nPageData ].heapPtr = it -> t_tid ;
461
- so -> pageData [so -> nPageData ].recheck = recheck ;
462
- so -> pageData [so -> nPageData ].offnum = i ;
465
+ so -> nos . pageData [so -> nos . nPageData ].heapPtr = it -> t_tid ;
466
+ so -> nos . pageData [so -> nos . nPageData ].recheck = recheck ;
467
+ so -> nos . pageData [so -> nos . nPageData ].offnum = i ;
463
468
464
469
/*
465
470
* In an index-only scan, also fetch the data from the tuple. The
466
471
* reconstructed tuples are stored in pageDataCxt.
467
472
*/
468
473
if (scan -> xs_want_itup )
469
474
{
470
- oldcxt = MemoryContextSwitchTo (so -> pageDataCxt );
471
- so -> pageData [so -> nPageData ].recontup =
475
+ oldcxt = MemoryContextSwitchTo (so -> nos . pageDataCxt );
476
+ so -> nos . pageData [so -> nos . nPageData ].recontup =
472
477
gistFetchTuple (giststate , r , it );
473
478
MemoryContextSwitchTo (oldcxt );
474
479
}
475
- so -> nPageData ++ ;
480
+ so -> nos . nPageData ++ ;
476
481
}
477
482
else
478
483
{
@@ -501,7 +506,11 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
501
506
* In an index-only scan, also fetch the data from the tuple.
502
507
*/
503
508
if (scan -> xs_want_itup )
509
+ {
504
510
item -> data .heap .recontup = gistFetchTuple (giststate , r , it );
511
+ so -> os .sortData [so -> os .nsortData ] = & item -> data .heap ;
512
+ so -> os .nsortData += 1 ;
513
+ }
505
514
}
506
515
else
507
516
{
@@ -526,7 +535,101 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
526
535
}
527
536
}
528
537
529
- UnlockReleaseBuffer (buffer );
538
+ /* Allow writes to the buffer, but don't yet allow VACUUM */
539
+ LockBuffer (buffer , BUFFER_LOCK_UNLOCK );
540
+
541
+ /*
542
+ * If we're in an index-only scan, we need to do visibility checks before
543
+ * we release the pin, so that VACUUM can't clean up dead tuples from this
544
+ * index page and mark the page ALL_VISIBLE before the tuple was returned.
545
+ *
546
+ * See also docs section "Index Locking Considerations".
547
+ */
548
+ if (scan -> xs_want_itup )
549
+ {
550
+ TM_IndexVisibilityCheckOp op ;
551
+ op .vmbuf = & so -> vmbuf ;
552
+
553
+ if (scan -> numberOfOrderBys > 0 )
554
+ {
555
+ op .checkntids = so -> os .nsortData ;
556
+
557
+ if (op .checkntids > 0 )
558
+ {
559
+ op .checktids = palloc (op .checkntids * sizeof (TM_VisCheck ));
560
+
561
+ for (int off = 0 ; off < op .checkntids ; off ++ )
562
+ {
563
+ Assert (ItemPointerIsValid (& so -> os .sortData [off ]-> heapPtr ));
564
+
565
+ PopulateTMVischeck (& op .checktids [off ],
566
+ & so -> os .sortData [off ]-> heapPtr ,
567
+ off );
568
+ }
569
+ }
570
+ }
571
+ else
572
+ {
573
+ op .checkntids = so -> nos .nPageData ;
574
+
575
+ if (op .checkntids > 0 )
576
+ {
577
+ op .checktids = palloc_array (TM_VisCheck , op .checkntids );
578
+
579
+ for (int off = 0 ; off < op .checkntids ; off ++ )
580
+ {
581
+ Assert (ItemPointerIsValid (& so -> nos .pageData [off ].heapPtr ));
582
+
583
+ PopulateTMVischeck (& op .checktids [off ],
584
+ & so -> nos .pageData [off ].heapPtr ,
585
+ off );
586
+ }
587
+ }
588
+ }
589
+
590
+ if (op .checkntids > 0 )
591
+ {
592
+ table_index_vischeck_tuples (scan -> heapRelation , & op );
593
+
594
+ if (scan -> numberOfOrderBys > 0 )
595
+ {
596
+ for (int off = 0 ; off < op .checkntids ; off ++ )
597
+ {
598
+ TM_VisCheck * check = & op .checktids [off ];
599
+ GISTSearchHeapItem * item = so -> os .sortData [check -> idxoffnum ];
600
+
601
+ /* sanity checks */
602
+ Assert (check -> idxoffnum < op .checkntids );
603
+ Assert (check -> tidblkno == ItemPointerGetBlockNumberNoCheck (& item -> heapPtr ));
604
+ Assert (check -> tidoffset == ItemPointerGetOffsetNumberNoCheck (& item -> heapPtr ));
605
+
606
+ item -> visrecheck = check -> vischeckresult ;
607
+ }
608
+ /* reset state */
609
+ so -> os .nsortData = 0 ;
610
+ }
611
+ else
612
+ {
613
+ for (int off = 0 ; off < op .checkntids ; off ++ )
614
+ {
615
+ TM_VisCheck * check = & op .checktids [off ];
616
+ GISTSearchHeapItem * item = & so -> nos .pageData [check -> idxoffnum ];
617
+
618
+ Assert (check -> idxoffnum < op .checkntids );
619
+ Assert (check -> tidblkno == ItemPointerGetBlockNumberNoCheck (& item -> heapPtr ));
620
+ Assert (check -> tidoffset == ItemPointerGetOffsetNumberNoCheck (& item -> heapPtr ));
621
+
622
+ item -> visrecheck = check -> vischeckresult ;
623
+ }
624
+ }
625
+
626
+ /* clean up the used resources */
627
+ pfree (op .checktids );
628
+ }
629
+ }
630
+
631
+ /* Allow VACUUM to process the buffer again */
632
+ ReleaseBuffer (buffer );
530
633
}
531
634
532
635
/*
@@ -588,7 +691,10 @@ getNextNearest(IndexScanDesc scan)
588
691
589
692
/* in an index-only scan, also return the reconstructed tuple. */
590
693
if (scan -> xs_want_itup )
694
+ {
591
695
scan -> xs_hitup = item -> data .heap .recontup ;
696
+ scan -> xs_visrecheck = item -> data .heap .visrecheck ;
697
+ }
592
698
res = true;
593
699
}
594
700
else
@@ -629,10 +735,10 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
629
735
scan -> instrument -> nsearches ++ ;
630
736
631
737
so -> firstCall = false;
632
- so -> curPageData = so -> nPageData = 0 ;
738
+ so -> nos . curPageData = so -> nos . nPageData = 0 ;
633
739
scan -> xs_hitup = NULL ;
634
- if (so -> pageDataCxt )
635
- MemoryContextReset (so -> pageDataCxt );
740
+ if (so -> nos . pageDataCxt )
741
+ MemoryContextReset (so -> nos . pageDataCxt );
636
742
637
743
fakeItem .blkno = GIST_ROOT_BLKNO ;
638
744
memset (& fakeItem .data .parentlsn , 0 , sizeof (GistNSN ));
@@ -649,9 +755,9 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
649
755
/* Fetch tuples index-page-at-a-time */
650
756
for (;;)
651
757
{
652
- if (so -> curPageData < so -> nPageData )
758
+ if (so -> nos . curPageData < so -> nos . nPageData )
653
759
{
654
- if (scan -> kill_prior_tuple && so -> curPageData > 0 )
760
+ if (scan -> kill_prior_tuple && so -> nos . curPageData > 0 )
655
761
{
656
762
657
763
if (so -> killedItems == NULL )
@@ -667,17 +773,20 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
667
773
}
668
774
if (so -> numKilled < MaxIndexTuplesPerPage )
669
775
so -> killedItems [so -> numKilled ++ ] =
670
- so -> pageData [so -> curPageData - 1 ].offnum ;
776
+ so -> nos . pageData [so -> nos . curPageData - 1 ].offnum ;
671
777
}
672
778
/* continuing to return tuples from a leaf page */
673
- scan -> xs_heaptid = so -> pageData [so -> curPageData ].heapPtr ;
674
- scan -> xs_recheck = so -> pageData [so -> curPageData ].recheck ;
779
+ scan -> xs_heaptid = so -> nos . pageData [so -> nos . curPageData ].heapPtr ;
780
+ scan -> xs_recheck = so -> nos . pageData [so -> nos . curPageData ].recheck ;
675
781
676
782
/* in an index-only scan, also return the reconstructed tuple */
677
783
if (scan -> xs_want_itup )
678
- scan -> xs_hitup = so -> pageData [so -> curPageData ].recontup ;
784
+ {
785
+ scan -> xs_hitup = so -> nos .pageData [so -> nos .curPageData ].recontup ;
786
+ scan -> xs_visrecheck = so -> nos .pageData [so -> nos .curPageData ].visrecheck ;
787
+ }
679
788
680
- so -> curPageData ++ ;
789
+ so -> nos . curPageData ++ ;
681
790
682
791
return true;
683
792
}
@@ -687,8 +796,8 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
687
796
* necessary
688
797
*/
689
798
if (scan -> kill_prior_tuple
690
- && so -> curPageData > 0
691
- && so -> curPageData == so -> nPageData )
799
+ && so -> nos . curPageData > 0
800
+ && so -> nos . curPageData == so -> nos . nPageData )
692
801
{
693
802
694
803
if (so -> killedItems == NULL )
@@ -704,7 +813,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
704
813
}
705
814
if (so -> numKilled < MaxIndexTuplesPerPage )
706
815
so -> killedItems [so -> numKilled ++ ] =
707
- so -> pageData [so -> curPageData - 1 ].offnum ;
816
+ so -> nos . pageData [so -> nos . curPageData - 1 ].offnum ;
708
817
}
709
818
/* find and process the next index page */
710
819
do
@@ -733,7 +842,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
733
842
gistScanPage (scan , item , item -> distances , NULL , NULL );
734
843
735
844
pfree (item );
736
- } while (so -> nPageData == 0 );
845
+ } while (so -> nos . nPageData == 0 );
737
846
}
738
847
}
739
848
}
@@ -756,10 +865,10 @@ gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
756
865
scan -> instrument -> nsearches ++ ;
757
866
758
867
/* Begin the scan by processing the root page */
759
- so -> curPageData = so -> nPageData = 0 ;
868
+ so -> nos . curPageData = so -> nos . nPageData = 0 ;
760
869
scan -> xs_hitup = NULL ;
761
- if (so -> pageDataCxt )
762
- MemoryContextReset (so -> pageDataCxt );
870
+ if (so -> nos . pageDataCxt )
871
+ MemoryContextReset (so -> nos . pageDataCxt );
763
872
764
873
fakeItem .blkno = GIST_ROOT_BLKNO ;
765
874
memset (& fakeItem .data .parentlsn , 0 , sizeof (GistNSN ));
0 commit comments