PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 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

bool _hash_first ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 290 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, 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, RelationData::rd_opcintype, ScanDirectionIsBackward, SK_ISNULL, HeapTupleData::t_self, TestForOldSnapshot(), IndexScanDescData::xs_ctup, and IndexScanDescData::xs_snapshot.

Referenced by hashgetbitmap(), and hashgettuple().

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 }
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:132
static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:449
#define HTEqualStrategyNumber
Definition: hash.h:336
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
Relation indexRelation
Definition: relscan.h:90
#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:1275
unsigned int uint32
Definition: c.h:258
#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:681
HeapTupleData xs_ctup
Definition: relscan.h:120
#define PageGetSpecialPointer(page)
Definition: bufpage.h:322
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:96
ScanKey keyData
Definition: relscan.h:94
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
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:183
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:135
static int _hash_load_qualified_items ( IndexScanDesc  scan,
Page  page,
OffsetNumber  offnum,
ScanDirection  dir 
)
static

Definition at line 605 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().

607 {
608  HashScanOpaque so = (HashScanOpaque) scan->opaque;
609  IndexTuple itup;
610  int itemIndex;
611  OffsetNumber maxoff;
612 
613  maxoff = PageGetMaxOffsetNumber(page);
614 
615  if (ScanDirectionIsForward(dir))
616  {
617  /* load items[] in ascending order */
618  itemIndex = 0;
619 
620  while (offnum <= maxoff)
621  {
622  Assert(offnum >= FirstOffsetNumber);
623  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
624 
625  /*
626  * skip the tuples that are moved by split operation for the scan
627  * that has started when split was in progress. Also, skip the
628  * tuples that are marked as dead.
629  */
630  if ((so->hashso_buc_populated && !so->hashso_buc_split &&
631  (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK)) ||
632  (scan->ignore_killed_tuples &&
633  (ItemIdIsDead(PageGetItemId(page, offnum)))))
634  {
635  offnum = OffsetNumberNext(offnum); /* move forward */
636  continue;
637  }
638 
639  if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup) &&
640  _hash_checkqual(scan, itup))
641  {
642  /* tuple is qualified, so remember it */
643  _hash_saveitem(so, itemIndex, offnum, itup);
644  itemIndex++;
645  }
646  else
647  {
648  /*
649  * No more matching tuples exist in this page. so, exit while
650  * loop.
651  */
652  break;
653  }
654 
655  offnum = OffsetNumberNext(offnum);
656  }
657 
658  Assert(itemIndex <= MaxIndexTuplesPerPage);
659  return itemIndex;
660  }
661  else
662  {
663  /* load items[] in descending order */
664  itemIndex = MaxIndexTuplesPerPage;
665 
666  while (offnum >= FirstOffsetNumber)
667  {
668  Assert(offnum <= maxoff);
669  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
670 
671  /*
672  * skip the tuples that are moved by split operation for the scan
673  * that has started when split was in progress. Also, skip the
674  * tuples that are marked as dead.
675  */
676  if ((so->hashso_buc_populated && !so->hashso_buc_split &&
677  (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK)) ||
678  (scan->ignore_killed_tuples &&
679  (ItemIdIsDead(PageGetItemId(page, offnum)))))
680  {
681  offnum = OffsetNumberPrev(offnum); /* move back */
682  continue;
683  }
684 
685  if (so->hashso_sk_hash == _hash_get_indextuple_hashkey(itup) &&
686  _hash_checkqual(scan, itup))
687  {
688  itemIndex--;
689  /* tuple is qualified, so remember it */
690  _hash_saveitem(so, itemIndex, offnum, itup);
691  }
692  else
693  {
694  /*
695  * No more matching tuples exist in this page. so, exit while
696  * loop.
697  */
698  break;
699  }
700 
701  offnum = OffsetNumberPrev(offnum);
702  }
703 
704  Assert(itemIndex >= 0);
705  return itemIndex;
706  }
707 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:200
static void _hash_saveitem(HashScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup)
Definition: hashsearch.c:711
#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:101
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:681
#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:137
#define INDEX_MOVED_BY_SPLIT_MASK
Definition: hash.h:283
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
bool _hash_next ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 47 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().

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 }
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:297
static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:449
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
Snapshot xs_snapshot
Definition: relscan.h:91
uint32 BlockNumber
Definition: block.h:31
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
Relation indexRelation
Definition: relscan.h:90
#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:120
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
static void _hash_readnext ( IndexScanDesc  scan,
Buffer bufp,
Page pagep,
HashPageOpaque opaquep 
)
static

Definition at line 132 of file hashsearch.c.

References _hash_getbuf(), _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_OVERFLOW_PAGE, LockBuffer(), IndexScanDescData::opaque, PageGetSpecialPointer, TestForOldSnapshot(), and IndexScanDescData::xs_snapshot.

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

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 }
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
Snapshot xs_snapshot
Definition: relscan.h:91
#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:78
Relation indexRelation
Definition: relscan.h:90
#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:274
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define Assert(condition)
Definition: c.h:681
#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
static bool _hash_readpage ( IndexScanDesc  scan,
Buffer bufP,
ScanDirection  dir 
)
static

Definition at line 449 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().

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;
467 
468  if (ScanDirectionIsForward(dir))
469  {
470  BlockNumber prev_blkno = InvalidBlockNumber;
471 
472  for (;;)
473  {
474  /* new page, locate starting position by binary search */
475  offnum = _hash_binsearch(page, so->hashso_sk_hash);
476 
477  itemIndex = _hash_load_qualified_items(scan, page, offnum, dir);
478 
479  if (itemIndex != 0)
480  break;
481 
482  /*
483  * Could not find any matching tuples in the current page, move to
484  * the next page. Before leaving the current page, deal with any
485  * killed items.
486  */
487  if (so->numKilled > 0)
488  _hash_kill_items(scan);
489 
490  /*
491  * If this is a primary bucket page, hasho_prevblkno is not a real
492  * block number.
493  */
494  if (so->currPos.buf == so->hashso_bucket_buf ||
496  prev_blkno = InvalidBlockNumber;
497  else
498  prev_blkno = opaque->hasho_prevblkno;
499 
500  _hash_readnext(scan, &buf, &page, &opaque);
501  if (BufferIsValid(buf))
502  {
503  so->currPos.buf = buf;
505  }
506  else
507  {
508  /*
509  * Remember next and previous block numbers for scrollable
510  * cursors to know the start position and return FALSE
511  * indicating that no more matching tuples were found. Also,
512  * don't reset currPage or lsn, because we expect
513  * _hash_kill_items to be called for the old page after this
514  * function returns.
515  */
516  so->currPos.prevPage = prev_blkno;
518  so->currPos.buf = buf;
519  return false;
520  }
521  }
522 
523  so->currPos.firstItem = 0;
524  so->currPos.lastItem = itemIndex - 1;
525  so->currPos.itemIndex = 0;
526  }
527  else
528  {
529  BlockNumber next_blkno = InvalidBlockNumber;
530 
531  for (;;)
532  {
533  /* new page, locate starting position by binary search */
534  offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
535 
536  itemIndex = _hash_load_qualified_items(scan, page, offnum, dir);
537 
538  if (itemIndex != MaxIndexTuplesPerPage)
539  break;
540 
541  /*
542  * Could not find any matching tuples in the current page, move to
543  * the previous page. Before leaving the current page, deal with
544  * any killed items.
545  */
546  if (so->numKilled > 0)
547  _hash_kill_items(scan);
548 
549  if (so->currPos.buf == so->hashso_bucket_buf ||
551  next_blkno = opaque->hasho_nextblkno;
552 
553  _hash_readprev(scan, &buf, &page, &opaque);
554  if (BufferIsValid(buf))
555  {
556  so->currPos.buf = buf;
558  }
559  else
560  {
561  /*
562  * Remember next and previous block numbers for scrollable
563  * cursors to know the start position and return FALSE
564  * indicating that no more matching tuples were found. Also,
565  * don't reset currPage or lsn, because we expect
566  * _hash_kill_items to be called for the old page after this
567  * function returns.
568  */
570  so->currPos.nextPage = next_blkno;
571  so->currPos.buf = buf;
572  return false;
573  }
574  }
575 
576  so->currPos.firstItem = itemIndex;
579  }
580 
581  if (so->currPos.buf == so->hashso_bucket_buf ||
583  {
585  so->currPos.nextPage = opaque->hasho_nextblkno;
587  }
588  else
589  {
590  so->currPos.prevPage = opaque->hasho_prevblkno;
591  so->currPos.nextPage = opaque->hasho_nextblkno;
592  _hash_relbuf(rel, so->currPos.buf);
593  so->currPos.buf = InvalidBuffer;
594  }
595 
597  return true;
598 }
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:605
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
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
Relation indexRelation
Definition: relscan.h:90
uint16 OffsetNumber
Definition: off.h:24
unsigned short uint16
Definition: c.h:257
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:274
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:681
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:198
HashScanPosData currPos
Definition: hash.h:197
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define MaxIndexTuplesPerPage
Definition: itup.h:137
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
static void _hash_readprev ( IndexScanDesc  scan,
Buffer bufp,
Page pagep,
HashPageOpaque opaquep 
)
static

Definition at line 198 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().

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 }
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:132
Snapshot xs_snapshot
Definition: relscan.h:91
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
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
Relation indexRelation
Definition: relscan.h:90
#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:274
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:65
#define Assert(condition)
Definition: c.h:681
#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
static void _hash_saveitem ( HashScanOpaque  so,
int  itemIndex,
OffsetNumber  offnum,
IndexTuple  itup 
)
inlinestatic

Definition at line 711 of file hashsearch.c.

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

Referenced by _hash_load_qualified_items().

713 {
714  HashScanPosItem *currItem = &so->currPos.items[itemIndex];
715 
716  currItem->heapTid = itup->t_tid;
717  currItem->indexOffset = offnum;
718 }
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