PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gistget.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/gist_private.h"
#include "access/relscan.h"
#include "lib/pairingheap.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/predicate.h"
#include "utils/float.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistget.c:

Go to the source code of this file.

Functions

static void gistkillitems (IndexScanDesc scan)
 
static bool gistindex_keytest (IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p)
 
static void gistScanPage (IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
 
static GISTSearchItemgetNextGISTSearchItem (GISTScanOpaque so)
 
static bool getNextNearest (IndexScanDesc scan)
 
bool gistgettuple (IndexScanDesc scan, ScanDirection dir)
 
int64 gistgetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
bool gistcanreturn (Relation index, int attno)
 

Function Documentation

◆ getNextGISTSearchItem()

static GISTSearchItem * getNextGISTSearchItem ( GISTScanOpaque  so)
static

Definition at line 538 of file gistget.c.

539{
540 GISTSearchItem *item;
541
542 if (!pairingheap_is_empty(so->queue))
543 {
545 }
546 else
547 {
548 /* Done when both heaps are empty */
549 item = NULL;
550 }
551
552 /* Return item; caller is responsible to pfree it */
553 return item;
554}
pairingheap_node * pairingheap_remove_first(pairingheap *heap)
Definition: pairingheap.c:145
#define pairingheap_is_empty(h)
Definition: pairingheap.h:96
pairingheap * queue
Definition: gist_private.h:159

References pairingheap_is_empty, pairingheap_remove_first(), and GISTScanOpaqueData::queue.

Referenced by getNextNearest(), gistgetbitmap(), and gistgettuple().

◆ getNextNearest()

static bool getNextNearest ( IndexScanDesc  scan)
static

Definition at line 560 of file gistget.c.

561{
563 bool res = false;
564
565 if (scan->xs_hitup)
566 {
567 /* free previously returned tuple */
568 pfree(scan->xs_hitup);
569 scan->xs_hitup = NULL;
570 }
571
572 do
573 {
575
576 if (!item)
577 break;
578
579 if (GISTSearchItemIsHeap(*item))
580 {
581 /* found a heap item at currently minimal distance */
582 scan->xs_heaptid = item->data.heap.heapPtr;
583 scan->xs_recheck = item->data.heap.recheck;
584
586 item->distances,
588
589 /* in an index-only scan, also return the reconstructed tuple. */
590 if (scan->xs_want_itup)
591 scan->xs_hitup = item->data.heap.recontup;
592 res = true;
593 }
594 else
595 {
596 /* visit an index page, extract its items into queue */
598
599 gistScanPage(scan, item, item->distances, NULL, NULL);
600 }
601
602 pfree(item);
603 } while (!res);
604
605 return res;
606}
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:181
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:145
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:538
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:328
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:975
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void pfree(void *pointer)
Definition: mcxt.c:2150
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
ItemPointerData heapPtr
Definition: gist_private.h:120
GISTSearchHeapItem heap
Definition: gist_private.h:138
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:142
union GISTSearchItem::@45 data
HeapTuple xs_hitup
Definition: relscan.h:169
ItemPointerData xs_heaptid
Definition: relscan.h:172

References CHECK_FOR_INTERRUPTS, GISTSearchItem::data, GISTSearchItem::distances, getNextGISTSearchItem(), gistScanPage(), GISTSearchItemIsHeap, GISTSearchItem::heap, GISTSearchHeapItem::heapPtr, if(), index_store_float8_orderby_distances(), IndexScanDescData::opaque, GISTScanOpaqueData::orderByTypes, pfree(), GISTSearchHeapItem::recheck, GISTSearchHeapItem::recheckDistances, GISTSearchHeapItem::recontup, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gistgettuple().

◆ gistcanreturn()

bool gistcanreturn ( Relation  index,
int  attno 
)

Definition at line 797 of file gistget.c.

798{
802 return true;
803 else
804 return false;
805}
#define OidIsValid(objectId)
Definition: c.h:746
#define GIST_FETCH_PROC
Definition: gist.h:40
#define GIST_COMPRESS_PROC
Definition: gist.h:34
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:873
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:535
Definition: type.h:96

References GIST_COMPRESS_PROC, GIST_FETCH_PROC, index_getprocid(), IndexRelationGetNumberOfKeyAttributes, and OidIsValid.

Referenced by gisthandler().

◆ gistgetbitmap()

int64 gistgetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 745 of file gistget.c.

746{
748 int64 ntids = 0;
749 GISTSearchItem fakeItem;
750
751 if (!so->qual_ok)
752 return 0;
753
755 if (scan->instrument)
756 scan->instrument->nsearches++;
757
758 /* Begin the scan by processing the root page */
759 so->curPageData = so->nPageData = 0;
760 scan->xs_hitup = NULL;
761 if (so->pageDataCxt)
763
764 fakeItem.blkno = GIST_ROOT_BLKNO;
765 memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
766 gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
767
768 /*
769 * While scanning a leaf page, ItemPointers of matching heap tuples will
770 * be stored directly into tbm, so we don't need to deal with them here.
771 */
772 for (;;)
773 {
775
776 if (!item)
777 break;
778
780
781 gistScanPage(scan, item, item->distances, tbm, &ntids);
782
783 pfree(item);
784 }
785
786 return ntids;
787}
int64_t int64
Definition: c.h:499
XLogRecPtr GistNSN
Definition: gist.h:63
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:414
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:694
OffsetNumber nPageData
Definition: gist_private.h:175
OffsetNumber curPageData
Definition: gist_private.h:176
MemoryContext pageDataCxt
Definition: gist_private.h:177
struct IndexScanInstrumentation * instrument
Definition: relscan.h:159
Relation indexRelation
Definition: relscan.h:137

References CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curPageData, GISTSearchItem::distances, getNextGISTSearchItem(), GIST_ROOT_BLKNO, gistScanPage(), if(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, MemoryContextReset(), GISTScanOpaqueData::nPageData, IndexScanInstrumentation::nsearches, IndexScanDescData::opaque, GISTScanOpaqueData::pageDataCxt, pfree(), pgstat_count_index_scan, GISTScanOpaqueData::qual_ok, and IndexScanDescData::xs_hitup.

Referenced by gisthandler().

◆ gistgettuple()

bool gistgettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 612 of file gistget.c.

613{
615
616 if (dir != ForwardScanDirection)
617 elog(ERROR, "GiST only supports forward scan direction");
618
619 if (!so->qual_ok)
620 return false;
621
622 if (so->firstCall)
623 {
624 /* Begin the scan by processing the root page */
625 GISTSearchItem fakeItem;
626
628 if (scan->instrument)
629 scan->instrument->nsearches++;
630
631 so->firstCall = false;
632 so->curPageData = so->nPageData = 0;
633 scan->xs_hitup = NULL;
634 if (so->pageDataCxt)
636
637 fakeItem.blkno = GIST_ROOT_BLKNO;
638 memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
639 gistScanPage(scan, &fakeItem, NULL, NULL, NULL);
640 }
641
642 if (scan->numberOfOrderBys > 0)
643 {
644 /* Must fetch tuples in strict distance order */
645 return getNextNearest(scan);
646 }
647 else
648 {
649 /* Fetch tuples index-page-at-a-time */
650 for (;;)
651 {
652 if (so->curPageData < so->nPageData)
653 {
654 if (scan->kill_prior_tuple && so->curPageData > 0)
655 {
656
657 if (so->killedItems == NULL)
658 {
659 MemoryContext oldCxt =
661
662 so->killedItems =
664 * sizeof(OffsetNumber));
665
666 MemoryContextSwitchTo(oldCxt);
667 }
669 so->killedItems[so->numKilled++] =
670 so->pageData[so->curPageData - 1].offnum;
671 }
672 /* 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;
675
676 /* in an index-only scan, also return the reconstructed tuple */
677 if (scan->xs_want_itup)
678 scan->xs_hitup = so->pageData[so->curPageData].recontup;
679
680 so->curPageData++;
681
682 return true;
683 }
684
685 /*
686 * Check the last returned tuple and add it to killedItems if
687 * necessary
688 */
689 if (scan->kill_prior_tuple
690 && so->curPageData > 0
691 && so->curPageData == so->nPageData)
692 {
693
694 if (so->killedItems == NULL)
695 {
696 MemoryContext oldCxt =
698
699 so->killedItems =
701 * sizeof(OffsetNumber));
702
703 MemoryContextSwitchTo(oldCxt);
704 }
706 so->killedItems[so->numKilled++] =
707 so->pageData[so->curPageData - 1].offnum;
708 }
709 /* find and process the next index page */
710 do
711 {
712 GISTSearchItem *item;
713
714 if ((so->curBlkno != InvalidBlockNumber) && (so->numKilled > 0))
715 gistkillitems(scan);
716
717 item = getNextGISTSearchItem(so);
718
719 if (!item)
720 return false;
721
723
724 /* save current item BlockNumber for next gistkillitems() call */
725 so->curBlkno = item->blkno;
726
727 /*
728 * While scanning a leaf page, ItemPointers of matching heap
729 * tuples are stored in so->pageData. If there are any on
730 * this page, we fall out of the inner "do" and loop around to
731 * return them.
732 */
733 gistScanPage(scan, item, item->distances, NULL, NULL);
734
735 pfree(item);
736 } while (so->nPageData == 0);
737 }
738 }
739}
#define InvalidBlockNumber
Definition: block.h:33
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
static bool getNextNearest(IndexScanDesc scan)
Definition: gistget.c:560
static void gistkillitems(IndexScanDesc scan)
Definition: gistget.c:38
#define MaxIndexTuplesPerPage
Definition: itup.h:181
void * palloc(Size size)
Definition: mcxt.c:1943
uint16 OffsetNumber
Definition: off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
@ ForwardScanDirection
Definition: sdir.h:28
MemoryContext scanCxt
Definition: gist_private.h:77
OffsetNumber * killedItems
Definition: gist_private.h:168
GISTSTATE * giststate
Definition: gist_private.h:156
GISTSearchHeapItem pageData[BLCKSZ/sizeof(IndexTupleData)]
Definition: gist_private.h:174
BlockNumber curBlkno
Definition: gist_private.h:170
OffsetNumber offnum
Definition: gist_private.h:125
BlockNumber blkno
Definition: gist_private.h:133
GistNSN parentlsn
Definition: gist_private.h:136
int numberOfOrderBys
Definition: relscan.h:140
bool kill_prior_tuple
Definition: relscan.h:147

References GISTSearchItem::blkno, CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageData, GISTSearchItem::data, GISTSearchItem::distances, elog, ERROR, GISTScanOpaqueData::firstCall, ForwardScanDirection, getNextGISTSearchItem(), getNextNearest(), GIST_ROOT_BLKNO, gistkillitems(), gistScanPage(), GISTScanOpaqueData::giststate, GISTSearchHeapItem::heapPtr, if(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, InvalidBlockNumber, IndexScanDescData::kill_prior_tuple, GISTScanOpaqueData::killedItems, MaxIndexTuplesPerPage, MemoryContextReset(), MemoryContextSwitchTo(), GISTScanOpaqueData::nPageData, IndexScanInstrumentation::nsearches, IndexScanDescData::numberOfOrderBys, GISTScanOpaqueData::numKilled, GISTSearchHeapItem::offnum, IndexScanDescData::opaque, GISTScanOpaqueData::pageData, GISTScanOpaqueData::pageDataCxt, palloc(), GISTSearchItem::parentlsn, pfree(), pgstat_count_index_scan, GISTScanOpaqueData::qual_ok, GISTSearchHeapItem::recheck, GISTSearchHeapItem::recontup, GISTSTATE::scanCxt, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

◆ gistindex_keytest()

static bool gistindex_keytest ( IndexScanDesc  scan,
IndexTuple  tuple,
Page  page,
OffsetNumber  offset,
bool *  recheck_p,
bool *  recheck_distances_p 
)
static

Definition at line 125 of file gistget.c.

131{
133 GISTSTATE *giststate = so->giststate;
134 ScanKey key = scan->keyData;
135 int keySize = scan->numberOfKeys;
136 IndexOrderByDistance *distance_p;
137 Relation r = scan->indexRelation;
138
139 *recheck_p = false;
140 *recheck_distances_p = false;
141
142 /*
143 * If it's a leftover invalid tuple from pre-9.1, treat it as a match with
144 * minimum possible distances. This means we'll always follow it to the
145 * referenced page.
146 */
147 if (GistTupleIsInvalid(tuple))
148 {
149 int i;
150
151 if (GistPageIsLeaf(page)) /* shouldn't happen */
152 elog(ERROR, "invalid GiST tuple found on leaf page");
153 for (i = 0; i < scan->numberOfOrderBys; i++)
154 {
156 so->distances[i].isnull = false;
157 }
158 return true;
159 }
160
161 /* Check whether it matches according to the Consistent functions */
162 while (keySize > 0)
163 {
164 Datum datum;
165 bool isNull;
166
167 datum = index_getattr(tuple,
168 key->sk_attno,
169 giststate->leafTupdesc,
170 &isNull);
171
172 if (key->sk_flags & SK_ISNULL)
173 {
174 /*
175 * On non-leaf page we can't conclude that child hasn't NULL
176 * values because of assumption in GiST: union (VAL, NULL) is VAL.
177 * But if on non-leaf page key IS NULL, then all children are
178 * NULL.
179 */
180 if (key->sk_flags & SK_SEARCHNULL)
181 {
182 if (GistPageIsLeaf(page) && !isNull)
183 return false;
184 }
185 else
186 {
187 Assert(key->sk_flags & SK_SEARCHNOTNULL);
188 if (isNull)
189 return false;
190 }
191 }
192 else if (isNull)
193 {
194 return false;
195 }
196 else
197 {
198 Datum test;
199 bool recheck;
200 GISTENTRY de;
201
202 gistdentryinit(giststate, key->sk_attno - 1, &de,
203 datum, r, page, offset,
204 false, isNull);
205
206 /*
207 * Call the Consistent function to evaluate the test. The
208 * arguments are the index datum (as a GISTENTRY*), the comparison
209 * datum, the comparison operator's strategy number and subtype
210 * from pg_amop, and the recheck flag.
211 *
212 * (Presently there's no need to pass the subtype since it'll
213 * always be zero, but might as well pass it for possible future
214 * use.)
215 *
216 * We initialize the recheck flag to true (the safest assumption)
217 * in case the Consistent function forgets to set it.
218 */
219 recheck = true;
220
221 test = FunctionCall5Coll(&key->sk_func,
222 key->sk_collation,
223 PointerGetDatum(&de),
224 key->sk_argument,
225 Int16GetDatum(key->sk_strategy),
226 ObjectIdGetDatum(key->sk_subtype),
227 PointerGetDatum(&recheck));
228
229 if (!DatumGetBool(test))
230 return false;
231 *recheck_p |= recheck;
232 }
233
234 key++;
235 keySize--;
236 }
237
238 /* OK, it passes --- now let's compute the distances */
239 key = scan->orderByData;
240 distance_p = so->distances;
241 keySize = scan->numberOfOrderBys;
242 while (keySize > 0)
243 {
244 Datum datum;
245 bool isNull;
246
247 datum = index_getattr(tuple,
248 key->sk_attno,
249 giststate->leafTupdesc,
250 &isNull);
251
252 if ((key->sk_flags & SK_ISNULL) || isNull)
253 {
254 /* Assume distance computes as null */
255 distance_p->value = 0.0;
256 distance_p->isnull = true;
257 }
258 else
259 {
260 Datum dist;
261 bool recheck;
262 GISTENTRY de;
263
264 gistdentryinit(giststate, key->sk_attno - 1, &de,
265 datum, r, page, offset,
266 false, isNull);
267
268 /*
269 * Call the Distance function to evaluate the distance. The
270 * arguments are the index datum (as a GISTENTRY*), the comparison
271 * datum, the ordering operator's strategy number and subtype from
272 * pg_amop, and the recheck flag.
273 *
274 * (Presently there's no need to pass the subtype since it'll
275 * always be zero, but might as well pass it for possible future
276 * use.)
277 *
278 * If the function sets the recheck flag, the returned distance is
279 * a lower bound on the true distance and needs to be rechecked.
280 * We initialize the flag to 'false'. This flag was added in
281 * version 9.5; distance functions written before that won't know
282 * about the flag, but are expected to never be lossy.
283 */
284 recheck = false;
285 dist = FunctionCall5Coll(&key->sk_func,
286 key->sk_collation,
287 PointerGetDatum(&de),
288 key->sk_argument,
289 Int16GetDatum(key->sk_strategy),
290 ObjectIdGetDatum(key->sk_subtype),
291 PointerGetDatum(&recheck));
292 *recheck_distances_p |= recheck;
293 distance_p->value = DatumGetFloat8(dist);
294 distance_p->isnull = false;
295 }
296
297 key++;
298 distance_p++;
299 keySize--;
300 }
301
302 return true;
303}
static float8 get_float8_infinity(void)
Definition: float.h:94
Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1223
#define GistPageIsLeaf(page)
Definition: gist.h:170
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:288
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:547
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: itup.h:131
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
static float8 DatumGetFloat8(Datum X)
Definition: postgres.h:499
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static void test(void)
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
#define SK_ISNULL
Definition: skey.h:115
IndexOrderByDistance * distances
Definition: gist_private.h:165
struct ScanKeyData * keyData
Definition: relscan.h:141
struct ScanKeyData * orderByData
Definition: relscan.h:142

References Assert(), DatumGetBool(), DatumGetFloat8(), GISTScanOpaqueData::distances, elog, ERROR, FunctionCall5Coll(), get_float8_infinity(), gistdentryinit(), GistPageIsLeaf, GISTScanOpaqueData::giststate, GistTupleIsInvalid, i, if(), index_getattr(), IndexScanDescData::indexRelation, Int16GetDatum(), IndexOrderByDistance::isnull, sort-test::key, IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, ObjectIdGetDatum(), IndexScanDescData::opaque, IndexScanDescData::orderByData, PointerGetDatum(), SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, test(), and IndexOrderByDistance::value.

Referenced by gistScanPage().

◆ gistkillitems()

static void gistkillitems ( IndexScanDesc  scan)
static

Definition at line 38 of file gistget.c.

39{
41 Buffer buffer;
42 Page page;
43 OffsetNumber offnum;
44 ItemId iid;
45 int i;
46 bool killedsomething = false;
47
50 Assert(so->killedItems != NULL);
51
52 buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
53 if (!BufferIsValid(buffer))
54 return;
55
56 LockBuffer(buffer, GIST_SHARE);
57 gistcheckpage(scan->indexRelation, buffer);
58 page = BufferGetPage(buffer);
59
60 /*
61 * If page LSN differs it means that the page was modified since the last
62 * read. killedItems could be not valid so LP_DEAD hints applying is not
63 * safe.
64 */
65 if (BufferGetLSNAtomic(buffer) != so->curPageLSN)
66 {
67 UnlockReleaseBuffer(buffer);
68 so->numKilled = 0; /* reset counter */
69 return;
70 }
71
73
74 /*
75 * Mark all killedItems as dead. We need no additional recheck, because,
76 * if page was modified, curPageLSN must have changed.
77 */
78 for (i = 0; i < so->numKilled; i++)
79 {
80 offnum = so->killedItems[i];
81 iid = PageGetItemId(page, offnum);
82 ItemIdMarkDead(iid);
83 killedsomething = true;
84 }
85
86 if (killedsomething)
87 {
89 MarkBufferDirtyHint(buffer, true);
90 }
91
92 UnlockReleaseBuffer(buffer);
93
94 /*
95 * Always reset the scan state, so we don't look for same items on other
96 * pages.
97 */
98 so->numKilled = 0;
99}
int Buffer
Definition: buf.h:23
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:4493
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5390
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5607
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:5437
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:758
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:417
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:368
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:244
PageData * Page
Definition: bufpage.h:82
#define GistMarkPageHasGarbage(page)
Definition: gist.h:180
#define GIST_SHARE
Definition: gist_private.h:42
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:785
#define ItemIdMarkDead(itemId)
Definition: itemid.h:179
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References Assert(), BufferGetLSNAtomic(), BufferGetPage(), BufferIsValid(), GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageLSN, GIST_SHARE, gistcheckpage(), GistMarkPageHasGarbage, GistPageIsLeaf, i, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdMarkDead, GISTScanOpaqueData::killedItems, LockBuffer(), MarkBufferDirtyHint(), GISTScanOpaqueData::numKilled, IndexScanDescData::opaque, PageGetItemId(), ReadBuffer(), UnlockReleaseBuffer(), and XLogRecPtrIsInvalid.

Referenced by gistgettuple().

◆ gistScanPage()

static void gistScanPage ( IndexScanDesc  scan,
GISTSearchItem pageItem,
IndexOrderByDistance myDistances,
TIDBitmap tbm,
int64 ntids 
)
static

Definition at line 328 of file gistget.c.

330{
332 GISTSTATE *giststate = so->giststate;
333 Relation r = scan->indexRelation;
334 Buffer buffer;
335 Page page;
336 GISTPageOpaque opaque;
337 OffsetNumber maxoff;
339 MemoryContext oldcxt;
340
341 Assert(!GISTSearchItemIsHeap(*pageItem));
342
343 buffer = ReadBuffer(scan->indexRelation, pageItem->blkno);
344 LockBuffer(buffer, GIST_SHARE);
346 gistcheckpage(scan->indexRelation, buffer);
347 page = BufferGetPage(buffer);
348 opaque = GistPageGetOpaque(page);
349
350 /*
351 * Check if we need to follow the rightlink. We need to follow it if the
352 * page was concurrently split since we visited the parent (in which case
353 * parentlsn < nsn), or if the system crashed after a page split but
354 * before the downlink was inserted into the parent.
355 */
356 if (!XLogRecPtrIsInvalid(pageItem->data.parentlsn) &&
357 (GistFollowRight(page) ||
358 pageItem->data.parentlsn < GistPageGetNSN(page)) &&
359 opaque->rightlink != InvalidBlockNumber /* sanity check */ )
360 {
361 /* There was a page split, follow right link to add pages */
362 GISTSearchItem *item;
363
364 /* This can't happen when starting at the root */
365 Assert(myDistances != NULL);
366
367 oldcxt = MemoryContextSwitchTo(so->queueCxt);
368
369 /* Create new GISTSearchItem for the right sibling index page */
371 item->blkno = opaque->rightlink;
372 item->data.parentlsn = pageItem->data.parentlsn;
373
374 /* Insert it into the queue using same distances as for this page */
375 memcpy(item->distances, myDistances,
376 sizeof(item->distances[0]) * scan->numberOfOrderBys);
377
378 pairingheap_add(so->queue, &item->phNode);
379
380 MemoryContextSwitchTo(oldcxt);
381 }
382
383 /*
384 * Check if the page was deleted after we saw the downlink. There's
385 * nothing of interest on a deleted page. Note that we must do this after
386 * checking the NSN for concurrent splits! It's possible that the page
387 * originally contained some tuples that are visible to us, but was split
388 * so that all the visible tuples were moved to another page, and then
389 * this page was deleted.
390 */
391 if (GistPageIsDeleted(page))
392 {
393 UnlockReleaseBuffer(buffer);
394 return;
395 }
396
397 so->nPageData = so->curPageData = 0;
398 scan->xs_hitup = NULL; /* might point into pageDataCxt */
399 if (so->pageDataCxt)
401
402 /*
403 * We save the LSN of the page as we read it, so that we know whether it
404 * safe to apply LP_DEAD hints to the page later. This allows us to drop
405 * the pin for MVCC scans, which allows vacuum to avoid blocking.
406 */
407 so->curPageLSN = BufferGetLSNAtomic(buffer);
408
409 /*
410 * check all tuples on page
411 */
412 maxoff = PageGetMaxOffsetNumber(page);
413 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
414 {
415 ItemId iid = PageGetItemId(page, i);
416 IndexTuple it;
417 bool match;
418 bool recheck;
419 bool recheck_distances;
420
421 /*
422 * If the scan specifies not to return killed tuples, then we treat a
423 * killed tuple as not passing the qual.
424 */
425 if (scan->ignore_killed_tuples && ItemIdIsDead(iid))
426 continue;
427
428 it = (IndexTuple) PageGetItem(page, iid);
429
430 /*
431 * Must call gistindex_keytest in tempCxt, and clean up any leftover
432 * junk afterward.
433 */
435
436 match = gistindex_keytest(scan, it, page, i,
437 &recheck, &recheck_distances);
438
439 MemoryContextSwitchTo(oldcxt);
441
442 /* Ignore tuple if it doesn't match */
443 if (!match)
444 continue;
445
446 if (tbm && GistPageIsLeaf(page))
447 {
448 /*
449 * getbitmap scan, so just push heap tuple TIDs into the bitmap
450 * without worrying about ordering
451 */
452 tbm_add_tuples(tbm, &it->t_tid, 1, recheck);
453 (*ntids)++;
454 }
455 else if (scan->numberOfOrderBys == 0 && GistPageIsLeaf(page))
456 {
457 /*
458 * Non-ordered scan, so report tuples in so->pageData[]
459 */
460 so->pageData[so->nPageData].heapPtr = it->t_tid;
461 so->pageData[so->nPageData].recheck = recheck;
462 so->pageData[so->nPageData].offnum = i;
463
464 /*
465 * In an index-only scan, also fetch the data from the tuple. The
466 * reconstructed tuples are stored in pageDataCxt.
467 */
468 if (scan->xs_want_itup)
469 {
471 so->pageData[so->nPageData].recontup =
472 gistFetchTuple(giststate, r, it);
473 MemoryContextSwitchTo(oldcxt);
474 }
475 so->nPageData++;
476 }
477 else
478 {
479 /*
480 * Must push item into search queue. We get here for any lower
481 * index page, and also for heap tuples if doing an ordered
482 * search.
483 */
484 GISTSearchItem *item;
485 int nOrderBys = scan->numberOfOrderBys;
486
487 oldcxt = MemoryContextSwitchTo(so->queueCxt);
488
489 /* Create new GISTSearchItem for this item */
491
492 if (GistPageIsLeaf(page))
493 {
494 /* Creating heap-tuple GISTSearchItem */
496 item->data.heap.heapPtr = it->t_tid;
497 item->data.heap.recheck = recheck;
498 item->data.heap.recheckDistances = recheck_distances;
499
500 /*
501 * In an index-only scan, also fetch the data from the tuple.
502 */
503 if (scan->xs_want_itup)
504 item->data.heap.recontup = gistFetchTuple(giststate, r, it);
505 }
506 else
507 {
508 /* Creating index-page GISTSearchItem */
510
511 /*
512 * LSN of current page is lsn of parent page for child. We
513 * only have a shared lock, so we need to get the LSN
514 * atomically.
515 */
516 item->data.parentlsn = BufferGetLSNAtomic(buffer);
517 }
518
519 /* Insert it into the queue using new distance data */
520 memcpy(item->distances, so->distances,
521 sizeof(item->distances[0]) * nOrderBys);
522
523 pairingheap_add(so->queue, &item->phNode);
524
525 MemoryContextSwitchTo(oldcxt);
526 }
527 }
528
529 UnlockReleaseBuffer(buffer);
530}
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:4231
static Item PageGetItem(const PageData *page, const ItemIdData *itemId)
Definition: bufpage.h:354
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition: bufpage.h:372
#define GistFollowRight(page)
Definition: gist.h:183
#define GistPageIsDeleted(page)
Definition: gist.h:173
#define GistPageGetOpaque(page)
Definition: gist.h:168
#define GistPageGetNSN(page)
Definition: gist.h:187
#define SizeOfGISTSearchItem(n_distances)
Definition: gist_private.h:147
static bool gistindex_keytest(IndexScanDesc scan, IndexTuple tuple, Page page, OffsetNumber offset, bool *recheck_p, bool *recheck_distances_p)
Definition: gistget.c:125
HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
Definition: gistutil.c:667
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition: itemptr.h:103
IndexTupleData * IndexTuple
Definition: itup.h:53
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define FirstOffsetNumber
Definition: off.h:27
void pairingheap_add(pairingheap *heap, pairingheap_node *node)
Definition: pairingheap.c:112
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition: predicate.c:2599
MemoryContext tempCxt
Definition: gist_private.h:78
MemoryContext queueCxt
Definition: gist_private.h:160
pairingheap_node phNode
Definition: gist_private.h:132
bool ignore_killed_tuples
Definition: relscan.h:148
struct SnapshotData * xs_snapshot
Definition: relscan.h:138
ItemPointerData t_tid
Definition: itup.h:37
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, bool recheck)
Definition: tidbitmap.c:366

References Assert(), GISTSearchItem::blkno, BufferGetBlockNumber(), BufferGetLSNAtomic(), BufferGetPage(), GISTScanOpaqueData::curPageData, GISTScanOpaqueData::curPageLSN, GISTSearchItem::data, GISTSearchItem::distances, GISTScanOpaqueData::distances, FirstOffsetNumber, GIST_SHARE, gistcheckpage(), gistFetchTuple(), GistFollowRight, gistindex_keytest(), GistPageGetNSN, GistPageGetOpaque, GistPageIsDeleted, GistPageIsLeaf, GISTSearchItemIsHeap, GISTScanOpaqueData::giststate, GISTSearchItem::heap, GISTSearchHeapItem::heapPtr, i, IndexScanDescData::ignore_killed_tuples, IndexScanDescData::indexRelation, InvalidBlockNumber, ItemIdIsDead, ItemPointerGetBlockNumber(), LockBuffer(), MemoryContextReset(), MemoryContextSwitchTo(), GISTScanOpaqueData::nPageData, IndexScanDescData::numberOfOrderBys, GISTSearchHeapItem::offnum, OffsetNumberNext, IndexScanDescData::opaque, GISTScanOpaqueData::pageData, GISTScanOpaqueData::pageDataCxt, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), pairingheap_add(), palloc(), GISTSearchItem::parentlsn, GISTSearchItem::phNode, PredicateLockPage(), GISTScanOpaqueData::queue, GISTScanOpaqueData::queueCxt, ReadBuffer(), GISTSearchHeapItem::recheck, GISTSearchHeapItem::recheckDistances, GISTSearchHeapItem::recontup, SizeOfGISTSearchItem, IndexTupleData::t_tid, tbm_add_tuples(), GISTSTATE::tempCxt, UnlockReleaseBuffer(), XLogRecPtrIsInvalid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

Referenced by getNextNearest(), gistgetbitmap(), and gistgettuple().