PostgreSQL Source Code  git master
hashsearch.c File Reference
#include "postgres.h"
#include "access/hash.h"
#include "access/relscan.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "utils/rel.h"
#include "storage/predicate.h"
Include dependency graph for hashsearch.c:

Go to the source code of this file.

Functions

static bool _hash_readpage (IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
 
static int _hash_load_qualified_items (IndexScanDesc scan, Page page, OffsetNumber offnum, ScanDirection dir)
 
static void _hash_saveitem (HashScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup)
 
static void _hash_readnext (IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
 
bool _hash_next (IndexScanDesc scan, ScanDirection dir)
 
static void _hash_readprev (IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
 
bool _hash_first (IndexScanDesc scan, ScanDirection dir)
 

Function Documentation

◆ _hash_first()

bool _hash_first ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 292 of file hashsearch.c.

References _hash_datum2hashkey(), _hash_datum2hashkey_type(), _hash_dropbuf(), _hash_get_oldblock_from_newbucket(), _hash_getbucketbuf_from_hashkey(), _hash_getbuf(), _hash_readnext(), _hash_readpage(), Assert, BlockNumberIsValid, buf, HashScanPosData::buf, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferIsInvalid, cur, HashScanOpaqueData::currPos, ereport, errcode(), errmsg(), ERROR, H_BUCKET_BEING_POPULATED, HASH_READ, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_sk_hash, HashScanOpaqueData::hashso_split_bucket_buf, HTEqualStrategyNumber, IndexScanDescData::indexRelation, InvalidBuffer, InvalidOid, HashScanPosData::itemIndex, HashScanPosData::items, IndexScanDescData::keyData, LH_BUCKET_PAGE, LockBuffer(), IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, PageGetSpecialPointer, pgstat_count_index_scan, PredicateLockPage(), RelationData::rd_opcintype, ScanDirectionIsBackward, SK_ISNULL, HeapTupleData::t_self, TestForOldSnapshot(), IndexScanDescData::xs_ctup, and IndexScanDescData::xs_snapshot.

Referenced by hashgetbitmap(), and hashgettuple().

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 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
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
static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:452
#define HTEqualStrategyNumber
Definition: hash.h:336
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
Relation indexRelation
Definition: relscan.h:91
#define HASH_READ
Definition: hash.h:329
uint32 Bucket
Definition: hash.h:34
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define BufferIsInvalid(buffer)
Definition: buf.h:31
static char * buf
Definition: pg_test_fsync.c:67
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1291
unsigned int uint32
Definition: c.h:325
#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
bool hashso_buc_populated
Definition: hash.h:182
Buffer buf
Definition: hash.h:119
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
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:65
#define Assert(condition)
Definition: c.h:699
HeapTupleData xs_ctup
Definition: relscan.h:121
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:96
ScanKey keyData
Definition: relscan.h:95
BlockNumber _hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket)
Definition: hashutil.c:430
HashScanPosData currPos
Definition: hash.h:197
bool hashso_buc_split
Definition: hash.h:188
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
int errmsg(const char *fmt,...)
Definition: elog.c:797
Buffer hashso_split_bucket_buf
Definition: hash.h:179
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
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
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:135

◆ _hash_load_qualified_items()

static int _hash_load_qualified_items ( IndexScanDesc  scan,
Page  page,
OffsetNumber  offnum,
ScanDirection  dir 
)
static

Definition at line 608 of file hashsearch.c.

References _hash_checkqual(), _hash_get_indextuple_hashkey(), _hash_saveitem(), Assert, FirstOffsetNumber, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_sk_hash, IndexScanDescData::ignore_killed_tuples, INDEX_MOVED_BY_SPLIT_MASK, ItemIdIsDead, MaxIndexTuplesPerPage, OffsetNumberNext, OffsetNumberPrev, IndexScanDescData::opaque, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, and ScanDirectionIsForward.

Referenced by _hash_readpage().

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 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
static void _hash_saveitem(HashScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup)
Definition: hashsearch.c:714
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
#define ItemIdIsDead(itemId)
Definition: itemid.h:112
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
bool ignore_killed_tuples
Definition: relscan.h:102
uint16 OffsetNumber
Definition: off.h:24
bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup)
Definition: hashutil.c:31
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition: hashutil.c:299
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
bool hashso_buc_populated
Definition: hash.h:182
uint32 hashso_sk_hash
Definition: hash.h:169
#define Assert(condition)
Definition: c.h:699
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define OffsetNumberPrev(offsetNumber)
Definition: off.h:55
bool hashso_buc_split
Definition: hash.h:188
#define MaxIndexTuplesPerPage
Definition: itup.h:145
#define INDEX_MOVED_BY_SPLIT_MASK
Definition: hash.h:283
#define PageGetItem(page, itemId)
Definition: bufpage.h:336

◆ _hash_next()

bool _hash_next ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 48 of file hashsearch.c.

References _hash_dropbuf(), _hash_dropscanbuf(), _hash_getbuf(), _hash_kill_items(), _hash_readpage(), BlockNumberIsValid, buf, BufferGetPage, HashScanOpaqueData::currPos, HashScanPosData::firstItem, HASH_READ, HashScanPosInvalidate, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_split_bucket_buf, IndexScanDescData::indexRelation, HashScanPosData::itemIndex, HashScanPosData::items, HashScanPosData::lastItem, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, HashScanPosData::nextPage, HashScanOpaqueData::numKilled, IndexScanDescData::opaque, HashScanPosData::prevPage, ScanDirectionIsForward, HeapTupleData::t_self, TestForOldSnapshot(), IndexScanDescData::xs_ctup, and IndexScanDescData::xs_snapshot.

Referenced by hashgetbitmap(), and hashgettuple().

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 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
void _hash_dropscanbuf(Relation rel, HashScanOpaque so)
Definition: hashpage.c:298
static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:452
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
Snapshot xs_snapshot
Definition: relscan.h:92
uint32 BlockNumber
Definition: block.h:31
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
Relation indexRelation
Definition: relscan.h:91
#define HASH_READ
Definition: hash.h:329
ItemPointerData t_self
Definition: htup.h:65
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer hashso_bucket_buf
Definition: hash.h:172
#define HashScanPosInvalidate(scanpos)
Definition: hash.h:152
#define LH_OVERFLOW_PAGE
Definition: hash.h:64
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:65
int lastItem
Definition: hash.h:132
HeapTupleData xs_ctup
Definition: relscan.h:121
void _hash_kill_items(IndexScanDesc scan)
Definition: hashutil.c:544
HashScanPosData currPos
Definition: hash.h:197
Buffer hashso_split_bucket_buf
Definition: hash.h:179
BlockNumber nextPage
Definition: hash.h:121
int itemIndex
Definition: hash.h:133
int firstItem
Definition: hash.h:131
BlockNumber prevPage
Definition: hash.h:122
int Buffer
Definition: buf.h:23
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:135

◆ _hash_readnext()

static void _hash_readnext ( IndexScanDesc  scan,
Buffer bufp,
Page pagep,
HashPageOpaque opaquep 
)
static

Definition at line 133 of file hashsearch.c.

References _hash_getbuf(), _hash_relbuf(), Assert, BlockNumberIsValid, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, CHECK_FOR_INTERRUPTS, HASH_READ, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_split_bucket_buf, IndexScanDescData::indexRelation, InvalidBuffer, LH_OVERFLOW_PAGE, LockBuffer(), IndexScanDescData::opaque, PageGetSpecialPointer, PredicateLockPage(), TestForOldSnapshot(), and IndexScanDescData::xs_snapshot.

Referenced by _hash_first(), _hash_readpage(), and _hash_readprev().

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 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
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
Snapshot xs_snapshot
Definition: relscan.h:92
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:79
Relation indexRelation
Definition: relscan.h:91
#define HASH_READ
Definition: hash.h:329
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer hashso_bucket_buf
Definition: hash.h:172
bool hashso_buc_populated
Definition: hash.h:182
#define LH_OVERFLOW_PAGE
Definition: hash.h:64
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:275
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define Assert(condition)
Definition: c.h:699
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:96
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
bool hashso_buc_split
Definition: hash.h:188
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
Buffer hashso_split_bucket_buf
Definition: hash.h:179
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98

◆ _hash_readpage()

static bool _hash_readpage ( IndexScanDesc  scan,
Buffer bufP,
ScanDirection  dir 
)
static

Definition at line 452 of file hashsearch.c.

References _hash_binsearch(), _hash_binsearch_last(), _hash_checkpage(), _hash_kill_items(), _hash_load_qualified_items(), _hash_readnext(), _hash_readprev(), _hash_relbuf(), Assert, buf, HashScanPosData::buf, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, HashScanPosData::currPage, HashScanOpaqueData::currPos, HashScanPosData::firstItem, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_sk_hash, HashScanOpaqueData::hashso_split_bucket_buf, IndexScanDescData::indexRelation, InvalidBlockNumber, InvalidBuffer, HashScanPosData::itemIndex, HashScanPosData::lastItem, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, LockBuffer(), MaxIndexTuplesPerPage, HashScanPosData::nextPage, HashScanOpaqueData::numKilled, IndexScanDescData::opaque, PageGetSpecialPointer, HashScanPosData::prevPage, and ScanDirectionIsForward.

Referenced by _hash_first(), and _hash_next().

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 }
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
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
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
Relation indexRelation
Definition: relscan.h:91
uint16 OffsetNumber
Definition: off.h:24
unsigned short uint16
Definition: c.h:324
static char * buf
Definition: pg_test_fsync.c:67
BlockNumber currPage
Definition: hash.h:120
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer hashso_bucket_buf
Definition: hash.h:172
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:225
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
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:275
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
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:96
void _hash_kill_items(IndexScanDesc scan)
Definition: hashutil.c:544
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
static void _hash_readprev(IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
Definition: hashsearch.c:200
HashScanPosData currPos
Definition: hash.h:197
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define MaxIndexTuplesPerPage
Definition: itup.h:145
Buffer hashso_split_bucket_buf
Definition: hash.h:179
BlockNumber nextPage
Definition: hash.h:121
int itemIndex
Definition: hash.h:133
int firstItem
Definition: hash.h:131
BlockNumber prevPage
Definition: hash.h:122
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ _hash_readprev()

static void _hash_readprev ( IndexScanDesc  scan,
Buffer bufp,
Page pagep,
HashPageOpaque opaquep 
)
static

Definition at line 200 of file hashsearch.c.

References _hash_dropbuf(), _hash_getbuf(), _hash_readnext(), _hash_relbuf(), Assert, BlockNumberIsValid, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, BufferIsValid, CHECK_FOR_INTERRUPTS, HASH_READ, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_split_bucket_buf, IndexScanDescData::indexRelation, InvalidBuffer, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, LockBuffer(), IndexScanDescData::opaque, PageGetSpecialPointer, TestForOldSnapshot(), and IndexScanDescData::xs_snapshot.

Referenced by _hash_readpage().

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 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
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
Snapshot xs_snapshot
Definition: relscan.h:92
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
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
Relation indexRelation
Definition: relscan.h:91
#define HASH_READ
Definition: hash.h:329
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer hashso_bucket_buf
Definition: hash.h:172
bool hashso_buc_populated
Definition: hash.h:182
#define LH_OVERFLOW_PAGE
Definition: hash.h:64
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:275
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:65
#define Assert(condition)
Definition: c.h:699
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:96
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
bool hashso_buc_split
Definition: hash.h:188
Buffer hashso_split_bucket_buf
Definition: hash.h:179
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98

◆ _hash_saveitem()

static void _hash_saveitem ( HashScanOpaque  so,
int  itemIndex,
OffsetNumber  offnum,
IndexTuple  itup 
)
inlinestatic

Definition at line 714 of file hashsearch.c.

References HashScanOpaqueData::currPos, HashScanPosItem::heapTid, HashScanPosItem::indexOffset, HashScanPosData::items, and IndexTupleData::t_tid.

Referenced by _hash_load_qualified_items().

716 {
717  HashScanPosItem *currItem = &so->currPos.items[itemIndex];
718 
719  currItem->heapTid = itup->t_tid;
720  currItem->indexOffset = offnum;
721 }
ItemPointerData t_tid
Definition: itup.h:37
HashScanPosData currPos
Definition: hash.h:197
OffsetNumber indexOffset
Definition: hash.h:114
ItemPointerData heapTid
Definition: hash.h:113
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:135