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