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

bool _hash_next (IndexScanDesc scan, ScanDirection dir)
 
static void _hash_readnext (IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
 
static void _hash_readprev (IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
 
bool _hash_first (IndexScanDesc scan, ScanDirection dir)
 
bool _hash_step (IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
 

Function Documentation

bool _hash_first ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 222 of file hashsearch.c.

References _hash_checkpage(), _hash_datum2hashkey(), _hash_datum2hashkey_type(), _hash_dropbuf(), _hash_get_oldblock_from_newbucket(), _hash_getbucketbuf_from_hashkey(), _hash_getbuf(), _hash_readnext(), _hash_step(), Assert, BlockNumberIsValid, buf, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, cur, ereport, errcode(), errmsg(), ERROR, H_BUCKET_BEING_POPULATED, HASH_READ, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_curpos, HashScanOpaqueData::hashso_heappos, HashScanOpaqueData::hashso_sk_hash, HashScanOpaqueData::hashso_split_bucket_buf, HTEqualStrategyNumber, IndexScanDescData::indexRelation, InvalidBuffer, InvalidOid, ItemPointerGetOffsetNumber, ItemPointerSetInvalid, IndexScanDescData::keyData, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, LockBuffer(), NULL, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, PageGetItem, PageGetItemId, PageGetSpecialPointer, pgstat_count_index_scan, RelationData::rd_opcintype, ScanDirectionIsBackward, SK_ISNULL, TestForOldSnapshot(), and IndexScanDescData::xs_snapshot.

Referenced by hashgetbitmap(), and hashgettuple().

223 {
224  Relation rel = scan->indexRelation;
225  HashScanOpaque so = (HashScanOpaque) scan->opaque;
226  ScanKey cur;
227  uint32 hashkey;
228  Bucket bucket;
229  Buffer buf;
230  Page page;
231  HashPageOpaque opaque;
232  IndexTuple itup;
233  ItemPointer current;
234  OffsetNumber offnum;
235 
237 
238  current = &(so->hashso_curpos);
239  ItemPointerSetInvalid(current);
240 
241  /*
242  * We do not support hash scans with no index qualification, because we
243  * would have to read the whole index rather than just one bucket. That
244  * creates a whole raft of problems, since we haven't got a practical way
245  * to lock all the buckets against splits or compactions.
246  */
247  if (scan->numberOfKeys < 1)
248  ereport(ERROR,
249  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
250  errmsg("hash indexes do not support whole-index scans")));
251 
252  /* There may be more than one index qual, but we hash only the first */
253  cur = &scan->keyData[0];
254 
255  /* We support only single-column hash indexes */
256  Assert(cur->sk_attno == 1);
257  /* And there's only one operator strategy, too */
258  Assert(cur->sk_strategy == HTEqualStrategyNumber);
259 
260  /*
261  * If the constant in the index qual is NULL, assume it cannot match any
262  * items in the index.
263  */
264  if (cur->sk_flags & SK_ISNULL)
265  return false;
266 
267  /*
268  * Okay to compute the hash key. We want to do this before acquiring any
269  * locks, in case a user-defined hash function happens to be slow.
270  *
271  * If scankey operator is not a cross-type comparison, we can use the
272  * cached hash function; otherwise gotta look it up in the catalogs.
273  *
274  * We support the convention that sk_subtype == InvalidOid means the
275  * opclass input type; this is a hack to simplify life for ScanKeyInit().
276  */
277  if (cur->sk_subtype == rel->rd_opcintype[0] ||
278  cur->sk_subtype == InvalidOid)
279  hashkey = _hash_datum2hashkey(rel, cur->sk_argument);
280  else
281  hashkey = _hash_datum2hashkey_type(rel, cur->sk_argument,
282  cur->sk_subtype);
283 
284  so->hashso_sk_hash = hashkey;
285 
287  page = BufferGetPage(buf);
288  TestForOldSnapshot(scan->xs_snapshot, rel, page);
289  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
290  bucket = opaque->hasho_bucket;
291 
292  so->hashso_bucket_buf = buf;
293 
294  /*
295  * If a bucket split is in progress, then while scanning the bucket being
296  * populated, we need to skip tuples that were copied from bucket being
297  * split. We also need to maintain a pin on the bucket being split to
298  * ensure that split-cleanup work done by vacuum doesn't remove tuples
299  * from it till this scan is done. We need to maintain a pin on the
300  * bucket being populated to ensure that vacuum doesn't squeeze that
301  * bucket till this scan is complete; otherwise, the ordering of tuples
302  * can't be maintained during forward and backward scans. Here, we have
303  * to be cautious about locking order: first, acquire the lock on bucket
304  * being split; then, release the lock on it but not the pin; then,
305  * acquire a lock on bucket being populated and again re-verify whether
306  * the bucket split is still in progress. Acquiring the lock on bucket
307  * being split first ensures that the vacuum waits for this scan to
308  * finish.
309  */
310  if (H_BUCKET_BEING_POPULATED(opaque))
311  {
312  BlockNumber old_blkno;
313  Buffer old_buf;
314 
315  old_blkno = _hash_get_oldblock_from_newbucket(rel, bucket);
316 
317  /*
318  * release the lock on new bucket and re-acquire it after acquiring
319  * the lock on old bucket.
320  */
322 
323  old_buf = _hash_getbuf(rel, old_blkno, HASH_READ, LH_BUCKET_PAGE);
324  TestForOldSnapshot(scan->xs_snapshot, rel, BufferGetPage(old_buf));
325 
326  /*
327  * remember the split bucket buffer so as to use it later for
328  * scanning.
329  */
330  so->hashso_split_bucket_buf = old_buf;
331  LockBuffer(old_buf, BUFFER_LOCK_UNLOCK);
332 
334  page = BufferGetPage(buf);
335  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
336  Assert(opaque->hasho_bucket == bucket);
337 
338  if (H_BUCKET_BEING_POPULATED(opaque))
339  so->hashso_buc_populated = true;
340  else
341  {
344  }
345  }
346 
347  /* If a backwards scan is requested, move to the end of the chain */
348  if (ScanDirectionIsBackward(dir))
349  {
350  /*
351  * Backward scans that start during split needs to start from end of
352  * bucket being split.
353  */
354  while (BlockNumberIsValid(opaque->hasho_nextblkno) ||
356  _hash_readnext(scan, &buf, &page, &opaque);
357  }
358 
359  /* Now find the first tuple satisfying the qualification */
360  if (!_hash_step(scan, &buf, dir))
361  return false;
362 
363  /* if we're here, _hash_step found a valid tuple */
364  offnum = ItemPointerGetOffsetNumber(current);
366  page = BufferGetPage(buf);
367  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
368  so->hashso_heappos = itup->t_tid;
369 
370  return true;
371 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:152
#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:71
bool _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:391
#define HTEqualStrategyNumber
Definition: hash.h:289
Snapshot xs_snapshot
Definition: relscan.h:90
#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:1530
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:89
uint16 OffsetNumber
Definition: off.h:24
#define HASH_READ
Definition: hash.h:282
uint32 Bucket
Definition: hash.h:34
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:66
IndexTupleData * IndexTuple
Definition: itup.h:53
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1263
unsigned int uint32
Definition: c.h:268
#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:124
#define H_BUCKET_BEING_POPULATED(opaque)
Definition: hash.h:89
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:225
bool hashso_buc_populated
Definition: hash.h:140
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
uint32 hashso_sk_hash
Definition: hash.h:113
#define InvalidOid
Definition: postgres_ext.h:36
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:54
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
ItemPointerData hashso_curpos
Definition: hash.h:134
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
ScanKey keyData
Definition: relscan.h:93
BlockNumber _hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket)
Definition: hashutil.c:430
bool hashso_buc_split
Definition: hash.h:146
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:797
Buffer hashso_split_bucket_buf
Definition: hash.h:131
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
uint32 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype)
Definition: hashutil.c:102
Oid * rd_opcintype
Definition: rel.h:183
int Buffer
Definition: buf.h:23
ItemPointerData hashso_heappos
Definition: hash.h:137
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
bool _hash_next ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 34 of file hashsearch.c.

References _hash_checkpage(), _hash_step(), Assert, buf, BufferGetPage, BufferIsValid, HashScanOpaqueData::hashso_curbuf, HashScanOpaqueData::hashso_curpos, HashScanOpaqueData::hashso_heappos, IndexScanDescData::indexRelation, ItemPointerGetOffsetNumber, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, IndexScanDescData::opaque, PageGetItem, and PageGetItemId.

Referenced by hashgetbitmap(), and hashgettuple().

35 {
36  Relation rel = scan->indexRelation;
38  Buffer buf;
39  Page page;
40  OffsetNumber offnum;
41  ItemPointer current;
42  IndexTuple itup;
43 
44  /* we still have the buffer pinned and read-locked */
45  buf = so->hashso_curbuf;
47 
48  /*
49  * step to next valid tuple.
50  */
51  if (!_hash_step(scan, &buf, dir))
52  return false;
53 
54  /* if we're here, _hash_step found a valid tuple */
55  current = &(so->hashso_curpos);
56  offnum = ItemPointerGetOffsetNumber(current);
58  page = BufferGetPage(buf);
59  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
60  so->hashso_heappos = itup->t_tid;
61 
62  return true;
63 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:152
bool _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:391
Relation indexRelation
Definition: relscan.h:89
uint16 OffsetNumber
Definition: off.h:24
static char * buf
Definition: pg_test_fsync.c:66
IndexTupleData * IndexTuple
Definition: itup.h:53
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:225
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
#define LH_BUCKET_PAGE
Definition: hash.h:54
#define Assert(condition)
Definition: c.h:675
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
ItemPointerData hashso_curpos
Definition: hash.h:134
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
int Buffer
Definition: buf.h:23
ItemPointerData hashso_heappos
Definition: hash.h:137
Buffer hashso_curbuf
Definition: hash.h:121
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
static void _hash_readnext ( IndexScanDesc  scan,
Buffer bufp,
Page pagep,
HashPageOpaque opaquep 
)
static

Definition at line 71 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_readprev(), and _hash_step().

73 {
74  BlockNumber blkno;
75  Relation rel = scan->indexRelation;
77  bool block_found = false;
78 
79  blkno = (*opaquep)->hasho_nextblkno;
80 
81  /*
82  * Retain the pin on primary bucket page till the end of scan. Refer the
83  * comments in _hash_first to know the reason of retaining pin.
84  */
85  if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf)
87  else
88  _hash_relbuf(rel, *bufp);
89 
90  *bufp = InvalidBuffer;
91  /* check for interrupts while we're not holding any buffer lock */
93  if (BlockNumberIsValid(blkno))
94  {
95  *bufp = _hash_getbuf(rel, blkno, HASH_READ, LH_OVERFLOW_PAGE);
96  block_found = true;
97  }
98  else if (so->hashso_buc_populated && !so->hashso_buc_split)
99  {
100  /*
101  * end of bucket, scan bucket being split if there was a split in
102  * progress at the start of scan.
103  */
104  *bufp = so->hashso_split_bucket_buf;
105 
106  /*
107  * buffer for bucket being split must be valid as we acquire the pin
108  * on it before the start of scan and retain it till end of scan.
109  */
110  Assert(BufferIsValid(*bufp));
111 
113 
114  /*
115  * setting hashso_buc_split to true indicates that we are scanning
116  * bucket being split.
117  */
118  so->hashso_buc_split = true;
119 
120  block_found = true;
121  }
122 
123  if (block_found)
124  {
125  *pagep = BufferGetPage(*bufp);
126  TestForOldSnapshot(scan->xs_snapshot, rel, *pagep);
127  *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
128  }
129 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:152
#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:90
#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:89
#define HASH_READ
Definition: hash.h:282
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer hashso_bucket_buf
Definition: hash.h:124
bool hashso_buc_populated
Definition: hash.h:140
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
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:675
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
bool hashso_buc_split
Definition: hash.h:146
Buffer hashso_split_bucket_buf
Definition: hash.h:131
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
static void _hash_readprev ( IndexScanDesc  scan,
Buffer bufp,
Page pagep,
HashPageOpaque opaquep 
)
static

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

139 {
140  BlockNumber blkno;
141  Relation rel = scan->indexRelation;
142  HashScanOpaque so = (HashScanOpaque) scan->opaque;
143  bool haveprevblk;
144 
145  blkno = (*opaquep)->hasho_prevblkno;
146 
147  /*
148  * Retain the pin on primary bucket page till the end of scan. Refer the
149  * comments in _hash_first to know the reason of retaining pin.
150  */
151  if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf)
152  {
154  haveprevblk = false;
155  }
156  else
157  {
158  _hash_relbuf(rel, *bufp);
159  haveprevblk = true;
160  }
161 
162  *bufp = InvalidBuffer;
163  /* check for interrupts while we're not holding any buffer lock */
165 
166  if (haveprevblk)
167  {
168  Assert(BlockNumberIsValid(blkno));
169  *bufp = _hash_getbuf(rel, blkno, HASH_READ,
171  *pagep = BufferGetPage(*bufp);
172  TestForOldSnapshot(scan->xs_snapshot, rel, *pagep);
173  *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
174 
175  /*
176  * We always maintain the pin on bucket page for whole scan operation,
177  * so releasing the additional pin we have acquired here.
178  */
179  if (*bufp == so->hashso_bucket_buf || *bufp == so->hashso_split_bucket_buf)
180  _hash_dropbuf(rel, *bufp);
181  }
182  else if (so->hashso_buc_populated && so->hashso_buc_split)
183  {
184  /*
185  * end of bucket, scan bucket being populated if there was a split in
186  * progress at the start of scan.
187  */
188  *bufp = so->hashso_bucket_buf;
189 
190  /*
191  * buffer for bucket being populated must be valid as we acquire the
192  * pin on it before the start of scan and retain it till end of scan.
193  */
194  Assert(BufferIsValid(*bufp));
195 
197  *pagep = BufferGetPage(*bufp);
198  *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
199 
200  /* move to the end of bucket chain */
201  while (BlockNumberIsValid((*opaquep)->hasho_nextblkno))
202  _hash_readnext(scan, bufp, pagep, opaquep);
203 
204  /*
205  * setting hashso_buc_split to false indicates that we are scanning
206  * bucket being populated.
207  */
208  so->hashso_buc_split = false;
209  }
210 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:152
#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:71
Snapshot xs_snapshot
Definition: relscan.h:90
#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:89
#define HASH_READ
Definition: hash.h:282
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer hashso_bucket_buf
Definition: hash.h:124
bool hashso_buc_populated
Definition: hash.h:140
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
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:54
#define Assert(condition)
Definition: c.h:675
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
bool hashso_buc_split
Definition: hash.h:146
Buffer hashso_split_bucket_buf
Definition: hash.h:131
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
bool _hash_step ( IndexScanDesc  scan,
Buffer bufP,
ScanDirection  dir 
)

Definition at line 391 of file hashsearch.c.

References _hash_binsearch(), _hash_binsearch_last(), _hash_checkpage(), _hash_checkqual(), _hash_dropscanbuf(), _hash_get_indextuple_hashkey(), _hash_kill_items(), _hash_readnext(), _hash_readprev(), Assert, BackwardScanDirection, buf, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, FirstOffsetNumber, ForwardScanDirection, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_curbuf, HashScanOpaqueData::hashso_curpos, HashScanOpaqueData::hashso_sk_hash, INDEX_MOVED_BY_SPLIT_MASK, IndexScanDescData::indexRelation, InvalidBuffer, InvalidOffsetNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, ItemPointerSet, ItemPointerSetInvalid, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, NULL, HashScanOpaqueData::numKilled, OffsetNumberNext, OffsetNumberPrev, IndexScanDescData::opaque, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, TestForOldSnapshot(), and IndexScanDescData::xs_snapshot.

Referenced by _hash_first(), and _hash_next().

392 {
393  Relation rel = scan->indexRelation;
394  HashScanOpaque so = (HashScanOpaque) scan->opaque;
395  ItemPointer current;
396  Buffer buf;
397  Page page;
398  HashPageOpaque opaque;
399  OffsetNumber maxoff;
400  OffsetNumber offnum;
401  BlockNumber blkno;
402  IndexTuple itup;
403 
404  current = &(so->hashso_curpos);
405 
406  buf = *bufP;
408  page = BufferGetPage(buf);
409  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
410 
411  /*
412  * If _hash_step is called from _hash_first, current will not be valid, so
413  * we can't dereference it. However, in that case, we presumably want to
414  * start at the beginning/end of the page...
415  */
416  maxoff = PageGetMaxOffsetNumber(page);
417  if (ItemPointerIsValid(current))
418  offnum = ItemPointerGetOffsetNumber(current);
419  else
420  offnum = InvalidOffsetNumber;
421 
422  /*
423  * 'offnum' now points to the last tuple we examined (if any).
424  *
425  * continue to step through tuples until: 1) we get to the end of the
426  * bucket chain or 2) we find a valid tuple.
427  */
428  do
429  {
430  switch (dir)
431  {
433  if (offnum != InvalidOffsetNumber)
434  offnum = OffsetNumberNext(offnum); /* move forward */
435  else
436  {
437  /* new page, locate starting position by binary search */
438  offnum = _hash_binsearch(page, so->hashso_sk_hash);
439  }
440 
441  for (;;)
442  {
443  /*
444  * check if we're still in the range of items with the
445  * target hash key
446  */
447  if (offnum <= maxoff)
448  {
449  Assert(offnum >= FirstOffsetNumber);
450  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
451 
452  /*
453  * skip the tuples that are moved by split operation
454  * for the scan that has started when split was in
455  * progress
456  */
457  if (so->hashso_buc_populated && !so->hashso_buc_split &&
458  (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK))
459  {
460  offnum = OffsetNumberNext(offnum); /* move forward */
461  continue;
462  }
463 
465  break; /* yes, so exit for-loop */
466  }
467 
468  /* Before leaving current page, deal with any killed items */
469  if (so->numKilled > 0)
470  _hash_kill_items(scan);
471 
472  /*
473  * ran off the end of this page, try the next
474  */
475  _hash_readnext(scan, &buf, &page, &opaque);
476  if (BufferIsValid(buf))
477  {
478  maxoff = PageGetMaxOffsetNumber(page);
479  offnum = _hash_binsearch(page, so->hashso_sk_hash);
480  }
481  else
482  {
483  itup = NULL;
484  break; /* exit for-loop */
485  }
486  }
487  break;
488 
490  if (offnum != InvalidOffsetNumber)
491  offnum = OffsetNumberPrev(offnum); /* move back */
492  else
493  {
494  /* new page, locate starting position by binary search */
495  offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
496  }
497 
498  for (;;)
499  {
500  /*
501  * check if we're still in the range of items with the
502  * target hash key
503  */
504  if (offnum >= FirstOffsetNumber)
505  {
506  Assert(offnum <= maxoff);
507  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
508 
509  /*
510  * skip the tuples that are moved by split operation
511  * for the scan that has started when split was in
512  * progress
513  */
514  if (so->hashso_buc_populated && !so->hashso_buc_split &&
515  (itup->t_info & INDEX_MOVED_BY_SPLIT_MASK))
516  {
517  offnum = OffsetNumberPrev(offnum); /* move back */
518  continue;
519  }
520 
522  break; /* yes, so exit for-loop */
523  }
524 
525  /* Before leaving current page, deal with any killed items */
526  if (so->numKilled > 0)
527  _hash_kill_items(scan);
528 
529  /*
530  * ran off the end of this page, try the next
531  */
532  _hash_readprev(scan, &buf, &page, &opaque);
533  if (BufferIsValid(buf))
534  {
535  TestForOldSnapshot(scan->xs_snapshot, rel, page);
536  maxoff = PageGetMaxOffsetNumber(page);
537  offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
538  }
539  else
540  {
541  itup = NULL;
542  break; /* exit for-loop */
543  }
544  }
545  break;
546 
547  default:
548  /* NoMovementScanDirection */
549  /* this should not be reached */
550  itup = NULL;
551  break;
552  }
553 
554  if (itup == NULL)
555  {
556  /*
557  * We ran off the end of the bucket without finding a match.
558  * Release the pin on bucket buffers. Normally, such pins are
559  * released at end of scan, however scrolling cursors can
560  * reacquire the bucket lock and pin in the same scan multiple
561  * times.
562  */
563  *bufP = so->hashso_curbuf = InvalidBuffer;
564  ItemPointerSetInvalid(current);
565  _hash_dropscanbuf(rel, so);
566  return false;
567  }
568 
569  /* check the tuple quals, loop around if not met */
570  } while (!_hash_checkqual(scan, itup));
571 
572  /* if we made it to here, we've found a valid tuple */
573  blkno = BufferGetBlockNumber(buf);
574  *bufP = so->hashso_curbuf = buf;
575  ItemPointerSet(current, blkno, offnum);
576  return true;
577 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:152
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:71
OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value)
Definition: hashutil.c:396
void _hash_dropscanbuf(Relation rel, HashScanOpaque so)
Definition: hashpage.c:297
Snapshot xs_snapshot
Definition: relscan.h:90
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
Relation indexRelation
Definition: relscan.h:89
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
static char * buf
Definition: pg_test_fsync.c:66
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:225
bool hashso_buc_populated
Definition: hash.h:140
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
uint32 hashso_sk_hash
Definition: hash.h:113
#define InvalidOffsetNumber
Definition: off.h:26
OffsetNumber _hash_binsearch(Page page, uint32 hash_value)
Definition: hashutil.c:358
#define LH_BUCKET_PAGE
Definition: hash.h:54
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
#define OffsetNumberPrev(offsetNumber)
Definition: off.h:55
void _hash_kill_items(IndexScanDesc scan)
Definition: hashutil.c:529
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
ItemPointerData hashso_curpos
Definition: hash.h:134
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
static void _hash_readprev(IndexScanDesc scan, Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
Definition: hashsearch.c:137
bool hashso_buc_split
Definition: hash.h:146
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:149
#define INDEX_MOVED_BY_SPLIT_MASK
Definition: hash.h:236
int Buffer
Definition: buf.h:23
Buffer hashso_curbuf
Definition: hash.h:121
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:104