PostgreSQL Source Code  git master
hashsearch.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * hashsearch.c
4  * search code for postgres hash tables
5  *
6  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/access/hash/hashsearch.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/hash.h"
18 #include "access/relscan.h"
19 #include "miscadmin.h"
20 #include "pgstat.h"
21 #include "utils/rel.h"
22 #include "storage/predicate.h"
23 
24 static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP,
25  ScanDirection dir);
26 static int _hash_load_qualified_items(IndexScanDesc scan, Page page,
27  OffsetNumber offnum, ScanDirection dir);
28 static inline void _hash_saveitem(HashScanOpaque so, int itemIndex,
29  OffsetNumber offnum, IndexTuple itup);
30 static void _hash_readnext(IndexScanDesc scan, Buffer *bufp,
31  Page *pagep, HashPageOpaque *opaquep);
32 
33 /*
34  * _hash_next() -- Get the next item in a scan.
35  *
36  * On entry, so->currPos describes the current page, which may
37  * be pinned but not locked, and so->currPos.itemIndex identifies
38  * which item was previously returned.
39  *
40  * On successful exit, scan->xs_ctup.t_self is set to the TID
41  * of the next heap tuple. so->currPos is updated as needed.
42  *
43  * On failure exit (no more tuples), we return false with pin
44  * held on bucket page but no pins or locks held on overflow
45  * page.
46  */
47 bool
49 {
50  Relation rel = scan->indexRelation;
52  HashScanPosItem *currItem;
53  BlockNumber blkno;
54  Buffer buf;
55  bool end_of_scan = false;
56 
57  /*
58  * Advance to the next tuple on the current page; or if done, try to read
59  * data from the next or previous page based on the scan direction. Before
60  * moving to the next or previous page make sure that we deal with all the
61  * killed items.
62  */
63  if (ScanDirectionIsForward(dir))
64  {
65  if (++so->currPos.itemIndex > so->currPos.lastItem)
66  {
67  if (so->numKilled > 0)
68  _hash_kill_items(scan);
69 
70  blkno = so->currPos.nextPage;
71  if (BlockNumberIsValid(blkno))
72  {
75  if (!_hash_readpage(scan, &buf, dir))
76  end_of_scan = true;
77  }
78  else
79  end_of_scan = true;
80  }
81  }
82  else
83  {
84  if (--so->currPos.itemIndex < so->currPos.firstItem)
85  {
86  if (so->numKilled > 0)
87  _hash_kill_items(scan);
88 
89  blkno = so->currPos.prevPage;
90  if (BlockNumberIsValid(blkno))
91  {
92  buf = _hash_getbuf(rel, blkno, HASH_READ,
95 
96  /*
97  * We always maintain the pin on bucket page for whole scan
98  * operation, so releasing the additional pin we have acquired
99  * here.
100  */
101  if (buf == so->hashso_bucket_buf ||
103  _hash_dropbuf(rel, buf);
104 
105  if (!_hash_readpage(scan, &buf, dir))
106  end_of_scan = true;
107  }
108  else
109  end_of_scan = true;
110  }
111  }
112 
113  if (end_of_scan)
114  {
115  _hash_dropscanbuf(rel, so);
117  return false;
118  }
119 
120  /* OK, itemIndex says what to return */
121  currItem = &so->currPos.items[so->currPos.itemIndex];
122  scan->xs_ctup.t_self = currItem->heapTid;
123 
124  return true;
125 }
126 
127 /*
128  * Advance to next page in a bucket, if any. If we are scanning the bucket
129  * being populated during split operation then this function advances to the
130  * bucket being split after the last bucket page of bucket being populated.
131  */
132 static void
134  Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
135 {
136  BlockNumber blkno;
137  Relation rel = scan->indexRelation;
138  HashScanOpaque so = (HashScanOpaque) scan->opaque;
139  bool block_found = false;
140 
141  blkno = (*opaquep)->hasho_nextblkno;
142 
143  /*
144  * Retain the pin on primary bucket page till the end of scan. Refer the
145  * comments in _hash_first to know the reason of retaining pin.
146  */
147  if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf)
149  else
150  _hash_relbuf(rel, *bufp);
151 
152  *bufp = InvalidBuffer;
153  /* check for interrupts while we're not holding any buffer lock */
155  if (BlockNumberIsValid(blkno))
156  {
157  *bufp = _hash_getbuf(rel, blkno, HASH_READ, LH_OVERFLOW_PAGE);
158  block_found = true;
159  }
160  else if (so->hashso_buc_populated && !so->hashso_buc_split)
161  {
162  /*
163  * end of bucket, scan bucket being split if there was a split in
164  * progress at the start of scan.
165  */
166  *bufp = so->hashso_split_bucket_buf;
167 
168  /*
169  * buffer for bucket being split must be valid as we acquire the pin
170  * on it before the start of scan and retain it till end of scan.
171  */
172  Assert(BufferIsValid(*bufp));
173 
176 
177  /*
178  * setting hashso_buc_split to true indicates that we are scanning
179  * bucket being split.
180  */
181  so->hashso_buc_split = true;
182 
183  block_found = true;
184  }
185 
186  if (block_found)
187  {
188  *pagep = BufferGetPage(*bufp);
189  TestForOldSnapshot(scan->xs_snapshot, rel, *pagep);
190  *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
191  }
192 }
193 
194 /*
195  * Advance to previous page in a bucket, if any. If the current scan has
196  * started during split operation then this function advances to bucket
197  * being populated after the first bucket page of bucket being split.
198  */
199 static void
201  Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
202 {
203  BlockNumber blkno;
204  Relation rel = scan->indexRelation;
205  HashScanOpaque so = (HashScanOpaque) scan->opaque;
206  bool haveprevblk;
207 
208  blkno = (*opaquep)->hasho_prevblkno;
209 
210  /*
211  * Retain the pin on primary bucket page till the end of scan. Refer the
212  * comments in _hash_first to know the reason of retaining pin.
213  */
214  if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf)
215  {
217  haveprevblk = false;
218  }
219  else
220  {
221  _hash_relbuf(rel, *bufp);
222  haveprevblk = true;
223  }
224 
225  *bufp = InvalidBuffer;
226  /* check for interrupts while we're not holding any buffer lock */
228 
229  if (haveprevblk)
230  {
231  Assert(BlockNumberIsValid(blkno));
232  *bufp = _hash_getbuf(rel, blkno, HASH_READ,
234  *pagep = BufferGetPage(*bufp);
235  TestForOldSnapshot(scan->xs_snapshot, rel, *pagep);
236  *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
237 
238  /*
239  * We always maintain the pin on bucket page for whole scan operation,
240  * so releasing the additional pin we have acquired here.
241  */
242  if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf)
243  _hash_dropbuf(rel, *bufp);
244  }
245  else if (so->hashso_buc_populated && so->hashso_buc_split)
246  {
247  /*
248  * end of bucket, scan bucket being populated if there was a split in
249  * progress at the start of scan.
250  */
251  *bufp = so->hashso_bucket_buf;
252 
253  /*
254  * buffer for bucket being populated must be valid as we acquire the
255  * pin on it before the start of scan and retain it till end of scan.
256  */
257  Assert(BufferIsValid(*bufp));
258 
260  *pagep = BufferGetPage(*bufp);
261  *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
262 
263  /* move to the end of bucket chain */
264  while (BlockNumberIsValid((*opaquep)->hasho_nextblkno))
265  _hash_readnext(scan, bufp, pagep, opaquep);
266 
267  /*
268  * setting hashso_buc_split to false indicates that we are scanning
269  * bucket being populated.
270  */
271  so->hashso_buc_split = false;
272  }
273 }
274 
275 /*
276  * _hash_first() -- Find the first item in a scan.
277  *
278  * We find the first item (or, if backward scan, the last item) in the
279  * index that satisfies the qualification associated with the scan
280  * descriptor.
281  *
282  * On successful exit, if the page containing current index tuple is an
283  * overflow page, both pin and lock are released whereas if it is a bucket
284  * page then it is pinned but not locked and data about the matching
285  * tuple(s) on the page has been loaded into so->currPos,
286  * scan->xs_ctup.t_self is set to the heap TID of the current tuple.
287  *
288  * On failure exit (no more tuples), we return false, with pin held on
289  * bucket page but no pins or locks held on overflow page.
290  */
291 bool
293 {
294  Relation rel = scan->indexRelation;
295  HashScanOpaque so = (HashScanOpaque) scan->opaque;
296  ScanKey cur;
297  uint32 hashkey;
298  Bucket bucket;
299  Buffer buf;
300  Page page;
301  HashPageOpaque opaque;
302  HashScanPosItem *currItem;
303 
305 
306  /*
307  * We do not support hash scans with no index qualification, because we
308  * would have to read the whole index rather than just one bucket. That
309  * creates a whole raft of problems, since we haven't got a practical way
310  * to lock all the buckets against splits or compactions.
311  */
312  if (scan->numberOfKeys < 1)
313  ereport(ERROR,
314  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
315  errmsg("hash indexes do not support whole-index scans")));
316 
317  /* There may be more than one index qual, but we hash only the first */
318  cur = &scan->keyData[0];
319 
320  /* We support only single-column hash indexes */
321  Assert(cur->sk_attno == 1);
322  /* And there's only one operator strategy, too */
323  Assert(cur->sk_strategy == HTEqualStrategyNumber);
324 
325  /*
326  * If the constant in the index qual is NULL, assume it cannot match any
327  * items in the index.
328  */
329  if (cur->sk_flags & SK_ISNULL)
330  return false;
331 
332  /*
333  * Okay to compute the hash key. We want to do this before acquiring any
334  * locks, in case a user-defined hash function happens to be slow.
335  *
336  * If scankey operator is not a cross-type comparison, we can use the
337  * cached hash function; otherwise gotta look it up in the catalogs.
338  *
339  * We support the convention that sk_subtype == InvalidOid means the
340  * opclass input type; this is a hack to simplify life for ScanKeyInit().
341  */
342  if (cur->sk_subtype == rel->rd_opcintype[0] ||
343  cur->sk_subtype == InvalidOid)
344  hashkey = _hash_datum2hashkey(rel, cur->sk_argument);
345  else
346  hashkey = _hash_datum2hashkey_type(rel, cur->sk_argument,
347  cur->sk_subtype);
348 
349  so->hashso_sk_hash = hashkey;
350 
351  buf = _hash_getbucketbuf_from_hashkey(rel, hashkey, HASH_READ, NULL);
353  page = BufferGetPage(buf);
354  TestForOldSnapshot(scan->xs_snapshot, rel, page);
355  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
356  bucket = opaque->hasho_bucket;
357 
358  so->hashso_bucket_buf = buf;
359 
360  /*
361  * If a bucket split is in progress, then while scanning the bucket being
362  * populated, we need to skip tuples that were copied from bucket being
363  * split. We also need to maintain a pin on the bucket being split to
364  * ensure that split-cleanup work done by vacuum doesn't remove tuples
365  * from it till this scan is done. We need to maintain a pin on the
366  * bucket being populated to ensure that vacuum doesn't squeeze that
367  * bucket till this scan is complete; otherwise, the ordering of tuples
368  * can't be maintained during forward and backward scans. Here, we have
369  * to be cautious about locking order: first, acquire the lock on bucket
370  * being split; then, release the lock on it but not the pin; then,
371  * acquire a lock on bucket being populated and again re-verify whether
372  * the bucket split is still in progress. Acquiring the lock on bucket
373  * being split first ensures that the vacuum waits for this scan to
374  * finish.
375  */
376  if (H_BUCKET_BEING_POPULATED(opaque))
377  {
378  BlockNumber old_blkno;
379  Buffer old_buf;
380 
381  old_blkno = _hash_get_oldblock_from_newbucket(rel, bucket);
382 
383  /*
384  * release the lock on new bucket and re-acquire it after acquiring
385  * the lock on old bucket.
386  */
388 
389  old_buf = _hash_getbuf(rel, old_blkno, HASH_READ, LH_BUCKET_PAGE);
390  TestForOldSnapshot(scan->xs_snapshot, rel, BufferGetPage(old_buf));
391 
392  /*
393  * remember the split bucket buffer so as to use it later for
394  * scanning.
395  */
396  so->hashso_split_bucket_buf = old_buf;
397  LockBuffer(old_buf, BUFFER_LOCK_UNLOCK);
398 
400  page = BufferGetPage(buf);
401  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
402  Assert(opaque->hasho_bucket == bucket);
403 
404  if (H_BUCKET_BEING_POPULATED(opaque))
405  so->hashso_buc_populated = true;
406  else
407  {
410  }
411  }
412 
413  /* If a backwards scan is requested, move to the end of the chain */
414  if (ScanDirectionIsBackward(dir))
415  {
416  /*
417  * Backward scans that start during split needs to start from end of
418  * bucket being split.
419  */
420  while (BlockNumberIsValid(opaque->hasho_nextblkno) ||
422  _hash_readnext(scan, &buf, &page, &opaque);
423  }
424 
425  /* remember which buffer we have pinned, if any */
427  so->currPos.buf = buf;
428 
429  /* Now find all the tuples satisfying the qualification from a page */
430  if (!_hash_readpage(scan, &buf, dir))
431  return false;
432 
433  /* OK, itemIndex says what to return */
434  currItem = &so->currPos.items[so->currPos.itemIndex];
435  scan->xs_ctup.t_self = currItem->heapTid;
436 
437  /* if we're here, _hash_readpage found a valid tuples */
438  return true;
439 }
440 
441 /*
442  * _hash_readpage() -- Load data from current index page into so->currPos
443  *
444  * We scan all the items in the current index page and save them into
445  * so->currPos if it satisfies the qualification. If no matching items
446  * are found in the current page, we move to the next or previous page
447  * in a bucket chain as indicated by the direction.
448  *
449  * Return true if any matching items are found else return false.
450  */
451 static bool
453 {
454  Relation rel = scan->indexRelation;
455  HashScanOpaque so = (HashScanOpaque) scan->opaque;
456  Buffer buf;
457  Page page;
458  HashPageOpaque opaque;
459  OffsetNumber offnum;
460  uint16 itemIndex;
461 
462  buf = *bufP;
465  page = BufferGetPage(buf);
466  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
467 
468  so->currPos.buf = buf;
470 
471  if (ScanDirectionIsForward(dir))
472  {
473  BlockNumber prev_blkno = InvalidBlockNumber;
474 
475  for (;;)
476  {
477  /* new page, locate starting position by binary search */
478  offnum = _hash_binsearch(page, so->hashso_sk_hash);
479 
480  itemIndex = _hash_load_qualified_items(scan, page, offnum, dir);
481 
482  if (itemIndex != 0)
483  break;
484 
485  /*
486  * Could not find any matching tuples in the current page, move to
487  * the next page. Before leaving the current page, deal with any
488  * killed items.
489  */
490  if (so->numKilled > 0)
491  _hash_kill_items(scan);
492 
493  /*
494  * If this is a primary bucket page, hasho_prevblkno is not a real
495  * block number.
496  */
497  if (so->currPos.buf == so->hashso_bucket_buf ||
499  prev_blkno = InvalidBlockNumber;
500  else
501  prev_blkno = opaque->hasho_prevblkno;
502 
503  _hash_readnext(scan, &buf, &page, &opaque);
504  if (BufferIsValid(buf))
505  {
506  so->currPos.buf = buf;
508  }
509  else
510  {
511  /*
512  * Remember next and previous block numbers for scrollable
513  * cursors to know the start position and return false
514  * indicating that no more matching tuples were found. Also,
515  * don't reset currPage or lsn, because we expect
516  * _hash_kill_items to be called for the old page after this
517  * function returns.
518  */
519  so->currPos.prevPage = prev_blkno;
521  so->currPos.buf = buf;
522  return false;
523  }
524  }
525 
526  so->currPos.firstItem = 0;
527  so->currPos.lastItem = itemIndex - 1;
528  so->currPos.itemIndex = 0;
529  }
530  else
531  {
532  BlockNumber next_blkno = InvalidBlockNumber;
533 
534  for (;;)
535  {
536  /* new page, locate starting position by binary search */
537  offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
538 
539  itemIndex = _hash_load_qualified_items(scan, page, offnum, dir);
540 
541  if (itemIndex != MaxIndexTuplesPerPage)
542  break;
543 
544  /*
545  * Could not find any matching tuples in the current page, move to
546  * the previous page. Before leaving the current page, deal with
547  * any killed items.
548  */
549  if (so->numKilled > 0)
550  _hash_kill_items(scan);
551 
552  if (so->currPos.buf == so->hashso_bucket_buf ||
554  next_blkno = opaque->hasho_nextblkno;
555 
556  _hash_readprev(scan, &buf, &page, &opaque);
557  if (BufferIsValid(buf))
558  {
559  so->currPos.buf = buf;
561  }
562  else
563  {
564  /*
565  * Remember next and previous block numbers for scrollable
566  * cursors to know the start position and return false
567  * indicating that no more matching tuples were found. Also,
568  * don't reset currPage or lsn, because we expect
569  * _hash_kill_items to be called for the old page after this
570  * function returns.
571  */
573  so->currPos.nextPage = next_blkno;
574  so->currPos.buf = buf;
575  return false;
576  }
577  }
578 
579  so->currPos.firstItem = itemIndex;
582  }
583 
584  if (so->currPos.buf == so->hashso_bucket_buf ||
586  {
588  so->currPos.nextPage = opaque->hasho_nextblkno;
590  }
591  else
592  {
593  so->currPos.prevPage = opaque->hasho_prevblkno;
594  so->currPos.nextPage = opaque->hasho_nextblkno;
595  _hash_relbuf(rel, so->currPos.buf);
596  so->currPos.buf = InvalidBuffer;
597  }
598 
600  return true;
601 }
602 
603 /*
604  * Load all the qualified items from a current index page
605  * into so->currPos. Helper function for _hash_readpage.
606  */
607 static int
609  OffsetNumber offnum, ScanDirection dir)
610 {
611  HashScanOpaque so = (HashScanOpaque) scan->opaque;
612  IndexTuple itup;
613  int itemIndex;
614  OffsetNumber maxoff;
615 
616  maxoff = PageGetMaxOffsetNumber(page);
617 
618  if (ScanDirectionIsForward(dir))
619  {
620  /* load items[] in ascending order */
621  itemIndex = 0;
622 
623  while (offnum <= maxoff)
624  {
625  Assert(offnum >= FirstOffsetNumber);
626  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
627 
628  /*
629  * skip the tuples that are moved by split operation for the scan
630  * that has started when split was in progress. Also, skip the
631  * tuples that are marked as dead.
632  */
633  if ((so->hashso_buc_populated && !so->hashso_buc_split &&
634  (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK)) ||
635  (scan->ignore_killed_tuples &&
636  (ItemIdIsDead(PageGetItemId(page, offnum)))))
637  {
638  offnum = OffsetNumberNext(offnum); /* move forward */
639  continue;
640  }
641 
642  if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup) &&
643  _hash_checkqual(scan, itup))
644  {
645  /* tuple is qualified, so remember it */
646  _hash_saveitem(so, itemIndex, offnum, itup);
647  itemIndex++;
648  }
649  else
650  {
651  /*
652  * No more matching tuples exist in this page. so, exit while
653  * loop.
654  */
655  break;
656  }
657 
658  offnum = OffsetNumberNext(offnum);
659  }
660 
661  Assert(itemIndex <= MaxIndexTuplesPerPage);
662  return itemIndex;
663  }
664  else
665  {
666  /* load items[] in descending order */
667  itemIndex = MaxIndexTuplesPerPage;
668 
669  while (offnum >= FirstOffsetNumber)
670  {
671  Assert(offnum <= maxoff);
672  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
673 
674  /*
675  * skip the tuples that are moved by split operation for the scan
676  * that has started when split was in progress. Also, skip the
677  * tuples that are marked as dead.
678  */
679  if ((so->hashso_buc_populated && !so->hashso_buc_split &&
680  (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK)) ||
681  (scan->ignore_killed_tuples &&
682  (ItemIdIsDead(PageGetItemId(page, offnum)))))
683  {
684  offnum = OffsetNumberPrev(offnum); /* move back */
685  continue;
686  }
687 
688  if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup) &&
689  _hash_checkqual(scan, itup))
690  {
691  itemIndex--;
692  /* tuple is qualified, so remember it */
693  _hash_saveitem(so, itemIndex, offnum, itup);
694  }
695  else
696  {
697  /*
698  * No more matching tuples exist in this page. so, exit while
699  * loop.
700  */
701  break;
702  }
703 
704  offnum = OffsetNumberPrev(offnum);
705  }
706 
707  Assert(itemIndex >= 0);
708  return itemIndex;
709  }
710 }
711 
712 /* Save an index item into so->currPos.items[itemIndex] */
713 static inline void
714 _hash_saveitem(HashScanOpaque so, int itemIndex,
715  OffsetNumber offnum, IndexTuple itup)
716 {
717  HashScanPosItem *currItem = &so->currPos.items[itemIndex];
718 
719  currItem->heapTid = itup->t_tid;
720  currItem->indexOffset = offnum;
721 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
static int _hash_load_qualified_items(IndexScanDesc scan, Page page, OffsetNumber offnum, ScanDirection dir)
Definition: hashsearch.c:608
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition: predicate.c:2475
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
static void _hash_readnext(IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
Definition: hashsearch.c:133
OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value)
Definition: hashutil.c:396
void _hash_dropscanbuf(Relation rel, HashScanOpaque so)
Definition: hashpage.c:298
static void _hash_saveitem(HashScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup)
Definition: hashsearch.c:714
static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:452
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
#define HTEqualStrategyNumber
Definition: hash.h:336
ItemPointerData t_tid
Definition: itup.h:37
Snapshot xs_snapshot
Definition: relscan.h:92
#define InvalidBuffer
Definition: buf.h:25
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:575
Buffer _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey, int access, HashMetaPage *cachedmetap)
Definition: hashpage.c:1567
uint32 BlockNumber
Definition: block.h:31
uint32 _hash_datum2hashkey(Relation rel, Datum key)
Definition: hashutil.c:82
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:286
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:79
#define ItemIdIsDead(itemId)
Definition: itemid.h:112
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
bool ignore_killed_tuples
Definition: relscan.h:102
Relation indexRelation
Definition: relscan.h:91
uint16 OffsetNumber
Definition: off.h:24
#define HASH_READ
Definition: hash.h:329
uint32 Bucket
Definition: hash.h:34
bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup)
Definition: hashutil.c:31
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
unsigned short uint16
Definition: c.h:324
#define ERROR
Definition: elog.h:43
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition: hashutil.c:299
bool _hash_first(IndexScanDesc scan, ScanDirection dir)
Definition: hashsearch.c:292
ItemPointerData t_self
Definition: htup.h:65
bool _hash_next(IndexScanDesc scan, ScanDirection dir)
Definition: hashsearch.c:48
#define BufferIsInvalid(buffer)
Definition: buf.h:31
static char * buf
Definition: pg_test_fsync.c:67
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
ScanDirection
Definition: sdir.h:22
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1291
unsigned int uint32
Definition: c.h:325
BlockNumber currPage
Definition: hash.h:120
#define SK_ISNULL
Definition: skey.h:115
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
Buffer hashso_bucket_buf
Definition: hash.h:172
#define H_BUCKET_BEING_POPULATED(opaque)
Definition: hash.h:100
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:225
#define HashScanPosInvalidate(scanpos)
Definition: hash.h:152
bool hashso_buc_populated
Definition: hash.h:182
Buffer buf
Definition: hash.h:119
#define LH_OVERFLOW_PAGE
Definition: hash.h:64
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
uint32 hashso_sk_hash
Definition: hash.h:169
#define InvalidOid
Definition: postgres_ext.h:36
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:275
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
OffsetNumber _hash_binsearch(Page page, uint32 hash_value)
Definition: hashutil.c:358
#define LH_BUCKET_PAGE
Definition: hash.h:65
#define Assert(condition)
Definition: c.h:699
int lastItem
Definition: hash.h:132
HeapTupleData xs_ctup
Definition: relscan.h:121
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:96
#define OffsetNumberPrev(offsetNumber)
Definition: off.h:55
void _hash_kill_items(IndexScanDesc scan)
Definition: hashutil.c:544
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
ScanKey keyData
Definition: relscan.h:95
BlockNumber _hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket)
Definition: hashutil.c:430
static void _hash_readprev(IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
Definition: hashsearch.c:200
HashScanPosData currPos
Definition: hash.h:197
bool hashso_buc_split
Definition: hash.h:188
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define MaxIndexTuplesPerPage
Definition: itup.h:145
int errmsg(const char *fmt,...)
Definition: elog.c:797
OffsetNumber indexOffset
Definition: hash.h:114
Buffer hashso_split_bucket_buf
Definition: hash.h:179
BlockNumber nextPage
Definition: hash.h:121
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
ItemPointerData heapTid
Definition: hash.h:113
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
uint32 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype)
Definition: hashutil.c:102
int itemIndex
Definition: hash.h:133
Oid * rd_opcintype
Definition: rel.h:155
#define INDEX_MOVED_BY_SPLIT_MASK
Definition: hash.h:283
int firstItem
Definition: hash.h:131
BlockNumber prevPage
Definition: hash.h:122
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:135