PostgreSQL Source Code  git master
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/lmgr.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 540 of file gistget.c.

541 {
542  GISTSearchItem *item;
543 
544  if (!pairingheap_is_empty(so->queue))
545  {
547  }
548  else
549  {
550  /* Done when both heaps are empty */
551  item = NULL;
552  }
553 
554  /* Return item; caller is responsible to pfree it */
555  return item;
556 }
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 562 of file gistget.c.

563 {
564  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
565  bool res = false;
566 
567  if (scan->xs_hitup)
568  {
569  /* free previously returned tuple */
570  pfree(scan->xs_hitup);
571  scan->xs_hitup = NULL;
572  }
573 
574  do
575  {
577 
578  if (!item)
579  break;
580 
581  if (GISTSearchItemIsHeap(*item))
582  {
583  /* found a heap item at currently minimal distance */
584  scan->xs_heaptid = item->data.heap.heapPtr;
585  scan->xs_recheck = item->data.heap.recheck;
586 
588  item->distances,
589  item->data.heap.recheckDistances);
590 
591  /* in an index-only scan, also return the reconstructed tuple. */
592  if (scan->xs_want_itup)
593  scan->xs_hitup = item->data.heap.recontup;
594  res = true;
595  }
596  else
597  {
598  /* visit an index page, extract its items into queue */
600 
601  gistScanPage(scan, item, item->distances, NULL, NULL);
602  }
603 
604  pfree(item);
605  } while (!res);
606 
607  return res;
608 }
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:181
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:145
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:540
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:329
void index_store_float8_orderby_distances(IndexScanDesc scan, Oid *orderByTypes, IndexOrderByDistance *distances, bool recheckOrderBy)
Definition: indexam.c:879
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
void pfree(void *pointer)
Definition: mcxt.c:1456
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
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::@42 data
HeapTuple xs_hitup
Definition: relscan.h:144
ItemPointerData xs_heaptid
Definition: relscan.h:147

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, res, 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 795 of file gistget.c.

796 {
800  return true;
801  else
802  return false;
803 }
#define OidIsValid(objectId)
Definition: c.h:759
#define GIST_FETCH_PROC
Definition: gist.h:38
#define GIST_COMPRESS_PROC
Definition: gist.h:32
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:777
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:523
Definition: type.h:95

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 {
747  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
748  int64 ntids = 0;
749  GISTSearchItem fakeItem;
750 
751  if (!so->qual_ok)
752  return 0;
753 
755 
756  /* Begin the scan by processing the root page */
757  so->curPageData = so->nPageData = 0;
758  scan->xs_hitup = NULL;
759  if (so->pageDataCxt)
761 
762  fakeItem.blkno = GIST_ROOT_BLKNO;
763  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
764  gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
765 
766  /*
767  * While scanning a leaf page, ItemPointers of matching heap tuples will
768  * be stored directly into tbm, so we don't need to deal with them here.
769  */
770  for (;;)
771  {
773 
774  if (!item)
775  break;
776 
778 
779  gistScanPage(scan, item, item->distances, tbm, &ntids);
780 
781  pfree(item);
782  }
783 
784  return ntids;
785 }
XLogRecPtr GistNSN
Definition: gist.h:60
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:330
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:623
OffsetNumber nPageData
Definition: gist_private.h:175
OffsetNumber curPageData
Definition: gist_private.h:176
MemoryContext pageDataCxt
Definition: gist_private.h:177
Relation indexRelation
Definition: relscan.h:118

References CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curPageData, GISTSearchItem::distances, getNextGISTSearchItem(), GIST_ROOT_BLKNO, gistScanPage(), if(), IndexScanDescData::indexRelation, MemoryContextReset(), GISTScanOpaqueData::nPageData, 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 614 of file gistget.c.

615 {
616  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
617 
618  if (dir != ForwardScanDirection)
619  elog(ERROR, "GiST only supports forward scan direction");
620 
621  if (!so->qual_ok)
622  return false;
623 
624  if (so->firstCall)
625  {
626  /* Begin the scan by processing the root page */
627  GISTSearchItem fakeItem;
628 
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
static bool getNextNearest(IndexScanDesc scan)
Definition: gistget.c:562
static void gistkillitems(IndexScanDesc scan)
Definition: gistget.c:39
#define MaxIndexTuplesPerPage
Definition: itup.h:165
void * palloc(Size size)
Definition: mcxt.c:1226
uint16 OffsetNumber
Definition: off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
@ 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:121
bool kill_prior_tuple
Definition: relscan.h:128

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, InvalidBlockNumber, IndexScanDescData::kill_prior_tuple, GISTScanOpaqueData::killedItems, MaxIndexTuplesPerPage, MemoryContextReset(), MemoryContextSwitchTo(), GISTScanOpaqueData::nPageData, 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 126 of file gistget.c.

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

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 39 of file gistget.c.

40 {
42  Buffer buffer;
43  Page page;
44  OffsetNumber offnum;
45  ItemId iid;
46  int i;
47  bool killedsomething = false;
48 
51  Assert(so->killedItems != NULL);
52 
53  buffer = ReadBuffer(scan->indexRelation, so->curBlkno);
54  if (!BufferIsValid(buffer))
55  return;
56 
57  LockBuffer(buffer, GIST_SHARE);
58  gistcheckpage(scan->indexRelation, buffer);
59  page = BufferGetPage(buffer);
60 
61  /*
62  * If page LSN differs it means that the page was modified since the last
63  * read. killedItems could be not valid so LP_DEAD hints applying is not
64  * safe.
65  */
66  if (BufferGetLSNAtomic(buffer) != so->curPageLSN)
67  {
68  UnlockReleaseBuffer(buffer);
69  so->numKilled = 0; /* reset counter */
70  return;
71  }
72 
73  Assert(GistPageIsLeaf(page));
74 
75  /*
76  * Mark all killedItems as dead. We need no additional recheck, because,
77  * if page was modified, curPageLSN must have changed.
78  */
79  for (i = 0; i < so->numKilled; i++)
80  {
81  offnum = so->killedItems[i];
82  iid = PageGetItemId(page, offnum);
83  ItemIdMarkDead(iid);
84  killedsomething = true;
85  }
86 
87  if (killedsomething)
88  {
90  MarkBufferDirtyHint(buffer, true);
91  }
92 
93  UnlockReleaseBuffer(buffer);
94 
95  /*
96  * Always reset the scan state, so we don't look for same items on other
97  * pages.
98  */
99  so->numKilled = 0;
100 }
int Buffer
Definition: buf.h:23
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3551
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4497
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4715
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4544
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:708
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:355
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:303
Pointer Page
Definition: bufpage.h:78
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
#define GistMarkPageHasGarbage(page)
Definition: gist.h:177
#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 329 of file gistget.c.

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

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, TestForOldSnapshot(), UnlockReleaseBuffer(), XLogRecPtrIsInvalid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_snapshot, and IndexScanDescData::xs_want_itup.

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