PostgreSQL Source Code  git master
hash.h File Reference
#include "access/amapi.h"
#include "access/itup.h"
#include "access/sdir.h"
#include "catalog/pg_am_d.h"
#include "common/hashfn.h"
#include "lib/stringinfo.h"
#include "storage/bufmgr.h"
#include "storage/lockdefs.h"
#include "utils/hsearch.h"
#include "utils/relcache.h"
Include dependency graph for hash.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  HashPageOpaqueData
 
struct  HashScanPosItem
 
struct  HashScanPosData
 
struct  HashScanOpaqueData
 
struct  HashMetaPageData
 
struct  HashOptions
 

Macros

#define InvalidBucket   ((Bucket) 0xFFFFFFFF)
 
#define BUCKET_TO_BLKNO(metap, B)   ((BlockNumber) ((B) + ((B) ? (metap)->hashm_spares[_hash_spareindex((B)+1)-1] : 0)) + 1)
 
#define LH_UNUSED_PAGE   (0)
 
#define LH_OVERFLOW_PAGE   (1 << 0)
 
#define LH_BUCKET_PAGE   (1 << 1)
 
#define LH_BITMAP_PAGE   (1 << 2)
 
#define LH_META_PAGE   (1 << 3)
 
#define LH_BUCKET_BEING_POPULATED   (1 << 4)
 
#define LH_BUCKET_BEING_SPLIT   (1 << 5)
 
#define LH_BUCKET_NEEDS_SPLIT_CLEANUP   (1 << 6)
 
#define LH_PAGE_HAS_DEAD_TUPLES   (1 << 7)
 
#define LH_PAGE_TYPE   (LH_OVERFLOW_PAGE | LH_BUCKET_PAGE | LH_BITMAP_PAGE | LH_META_PAGE)
 
#define H_NEEDS_SPLIT_CLEANUP(opaque)   (((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) != 0)
 
#define H_BUCKET_BEING_SPLIT(opaque)   (((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) != 0)
 
#define H_BUCKET_BEING_POPULATED(opaque)   (((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) != 0)
 
#define H_HAS_DEAD_TUPLES(opaque)   (((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) != 0)
 
#define HASHO_PAGE_ID   0xFF80
 
#define HashScanPosIsPinned(scanpos)
 
#define HashScanPosIsValid(scanpos)
 
#define HashScanPosInvalidate(scanpos)
 
#define HASH_METAPAGE   0 /* metapage is always block 0 */
 
#define HASH_MAGIC   0x6440640
 
#define HASH_VERSION   4
 
#define HASH_MAX_BITMAPS   Min(BLCKSZ / 8, 1024)
 
#define HASH_SPLITPOINT_PHASE_BITS   2
 
#define HASH_SPLITPOINT_PHASES_PER_GRP   (1 << HASH_SPLITPOINT_PHASE_BITS)
 
#define HASH_SPLITPOINT_PHASE_MASK   (HASH_SPLITPOINT_PHASES_PER_GRP - 1)
 
#define HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE   10
 
#define HASH_MAX_SPLITPOINT_GROUP   32
 
#define HASH_MAX_SPLITPOINTS
 
#define HashGetFillFactor(relation)
 
#define HashGetTargetPageUsage(relation)   (BLCKSZ * HashGetFillFactor(relation) / 100)
 
#define HashMaxItemSize(page)
 
#define INDEX_MOVED_BY_SPLIT_MASK   INDEX_AM_RESERVED_BIT
 
#define HASH_MIN_FILLFACTOR   10
 
#define HASH_DEFAULT_FILLFACTOR   75
 
#define BYTE_TO_BIT   3 /* 2^3 bits/byte */
 
#define ALL_SET   ((uint32) ~0)
 
#define BMPGSZ_BYTE(metap)   ((metap)->hashm_bmsize)
 
#define BMPGSZ_BIT(metap)   ((metap)->hashm_bmsize << BYTE_TO_BIT)
 
#define BMPG_SHIFT(metap)   ((metap)->hashm_bmshift)
 
#define BMPG_MASK(metap)   (BMPGSZ_BIT(metap) - 1)
 
#define HashPageGetBitmap(page)   ((uint32 *) PageGetContents(page))
 
#define HashGetMaxBitmapSize(page)
 
#define HashPageGetMeta(page)   ((HashMetaPage) PageGetContents(page))
 
#define BITS_PER_MAP   32 /* Number of bits in uint32 */
 
#define CLRBIT(A, N)   ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
 
#define SETBIT(A, N)   ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
 
#define ISSET(A, N)   ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
 
#define HASH_READ   BUFFER_LOCK_SHARE
 
#define HASH_WRITE   BUFFER_LOCK_EXCLUSIVE
 
#define HASH_NOLOCK   (-1)
 
#define HASHSTANDARD_PROC   1
 
#define HASHEXTENDED_PROC   2
 
#define HASHOPTIONS_PROC   3
 
#define HASHNProcs   3
 

Typedefs

typedef uint32 Bucket
 
typedef struct HashPageOpaqueData HashPageOpaqueData
 
typedef HashPageOpaqueDataHashPageOpaque
 
typedef struct HashScanPosItem HashScanPosItem
 
typedef struct HashScanPosData HashScanPosData
 
typedef struct HashScanOpaqueData HashScanOpaqueData
 
typedef HashScanOpaqueDataHashScanOpaque
 
typedef struct HashMetaPageData HashMetaPageData
 
typedef HashMetaPageDataHashMetaPage
 
typedef struct HashOptions HashOptions
 
typedef struct HSpool HSpool
 

Functions

IndexBuildResulthashbuild (Relation heap, Relation index, struct IndexInfo *indexInfo)
 
void hashbuildempty (Relation index)
 
bool hashinsert (Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, struct IndexInfo *indexInfo)
 
bool hashgettuple (IndexScanDesc scan, ScanDirection dir)
 
int64 hashgetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
IndexScanDesc hashbeginscan (Relation rel, int nkeys, int norderbys)
 
void hashrescan (IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
 
void hashendscan (IndexScanDesc scan)
 
IndexBulkDeleteResulthashbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResulthashvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
byteahashoptions (Datum reloptions, bool validate)
 
bool hashvalidate (Oid opclassoid)
 
void hashadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 
void _hash_doinsert (Relation rel, IndexTuple itup, Relation heapRel)
 
OffsetNumber _hash_pgaddtup (Relation rel, Buffer buf, Size itemsize, IndexTuple itup)
 
void _hash_pgaddmultitup (Relation rel, Buffer buf, IndexTuple *itups, OffsetNumber *itup_offsets, uint16 nitups)
 
Buffer _hash_addovflpage (Relation rel, Buffer metabuf, Buffer buf, bool retain_pin)
 
BlockNumber _hash_freeovflpage (Relation rel, Buffer bucketbuf, Buffer ovflbuf, Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets, Size *tups_size, uint16 nitups, BufferAccessStrategy bstrategy)
 
void _hash_initbitmapbuffer (Buffer buf, uint16 bmsize, bool initpage)
 
void _hash_squeezebucket (Relation rel, Bucket bucket, BlockNumber bucket_blkno, Buffer bucket_buf, BufferAccessStrategy bstrategy)
 
uint32 _hash_ovflblkno_to_bitno (HashMetaPage metap, BlockNumber ovflblkno)
 
Buffer _hash_getbuf (Relation rel, BlockNumber blkno, int access, int flags)
 
Buffer _hash_getbuf_with_condlock_cleanup (Relation rel, BlockNumber blkno, int flags)
 
HashMetaPage _hash_getcachedmetap (Relation rel, Buffer *metabuf, bool force_refresh)
 
Buffer _hash_getbucketbuf_from_hashkey (Relation rel, uint32 hashkey, int access, HashMetaPage *cachedmetap)
 
Buffer _hash_getinitbuf (Relation rel, BlockNumber blkno)
 
void _hash_initbuf (Buffer buf, uint32 max_bucket, uint32 num_bucket, uint32 flag, bool initpage)
 
Buffer _hash_getnewbuf (Relation rel, BlockNumber blkno, ForkNumber forkNum)
 
Buffer _hash_getbuf_with_strategy (Relation rel, BlockNumber blkno, int access, int flags, BufferAccessStrategy bstrategy)
 
void _hash_relbuf (Relation rel, Buffer buf)
 
void _hash_dropbuf (Relation rel, Buffer buf)
 
void _hash_dropscanbuf (Relation rel, HashScanOpaque so)
 
uint32 _hash_init (Relation rel, double num_tuples, ForkNumber forkNum)
 
void _hash_init_metabuffer (Buffer buf, double num_tuples, RegProcedure procid, uint16 ffactor, bool initpage)
 
void _hash_pageinit (Page page, Size size)
 
void _hash_expandtable (Relation rel, Buffer metabuf)
 
void _hash_finish_split (Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket, uint32 maxbucket, uint32 highmask, uint32 lowmask)
 
bool _hash_next (IndexScanDesc scan, ScanDirection dir)
 
bool _hash_first (IndexScanDesc scan, ScanDirection dir)
 
HSpool_h_spoolinit (Relation heap, Relation index, uint32 num_buckets)
 
void _h_spooldestroy (HSpool *hspool)
 
void _h_spool (HSpool *hspool, ItemPointer self, Datum *values, bool *isnull)
 
void _h_indexbuild (HSpool *hspool, Relation heapRel)
 
bool _hash_checkqual (IndexScanDesc scan, IndexTuple itup)
 
uint32 _hash_datum2hashkey (Relation rel, Datum key)
 
uint32 _hash_datum2hashkey_type (Relation rel, Datum key, Oid keytype)
 
Bucket _hash_hashkey2bucket (uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask)
 
uint32 _hash_spareindex (uint32 num_bucket)
 
uint32 _hash_get_totalbuckets (uint32 splitpoint_phase)
 
void _hash_checkpage (Relation rel, Buffer buf, int flags)
 
uint32 _hash_get_indextuple_hashkey (IndexTuple itup)
 
bool _hash_convert_tuple (Relation index, Datum *user_values, bool *user_isnull, Datum *index_values, bool *index_isnull)
 
OffsetNumber _hash_binsearch (Page page, uint32 hash_value)
 
OffsetNumber _hash_binsearch_last (Page page, uint32 hash_value)
 
BlockNumber _hash_get_oldblock_from_newbucket (Relation rel, Bucket new_bucket)
 
BlockNumber _hash_get_newblock_from_oldbucket (Relation rel, Bucket old_bucket)
 
Bucket _hash_get_newbucket_from_oldbucket (Relation rel, Bucket old_bucket, uint32 lowmask, uint32 maxbucket)
 
void _hash_kill_items (IndexScanDesc scan)
 
void hashbucketcleanup (Relation rel, Bucket cur_bucket, Buffer bucket_buf, BlockNumber bucket_blkno, BufferAccessStrategy bstrategy, uint32 maxbucket, uint32 highmask, uint32 lowmask, double *tuples_removed, double *num_index_tuples, bool split_cleanup, IndexBulkDeleteCallback callback, void *callback_state)
 

Macro Definition Documentation

◆ ALL_SET

#define ALL_SET   ((uint32) ~0)

Definition at line 300 of file hash.h.

Referenced by _hash_addovflpage().

◆ BITS_PER_MAP

#define BITS_PER_MAP   32 /* Number of bits in uint32 */

Definition at line 327 of file hash.h.

Referenced by _hash_addovflpage(), and _hash_firstfreebit().

◆ BMPG_MASK

#define BMPG_MASK (   metap)    (BMPGSZ_BIT(metap) - 1)

◆ BMPG_SHIFT

#define BMPG_SHIFT (   metap)    ((metap)->hashm_bmshift)

◆ BMPGSZ_BIT

#define BMPGSZ_BIT (   metap)    ((metap)->hashm_bmsize << BYTE_TO_BIT)

Definition at line 310 of file hash.h.

Referenced by _hash_addovflpage().

◆ BMPGSZ_BYTE

#define BMPGSZ_BYTE (   metap)    ((metap)->hashm_bmsize)

Definition at line 309 of file hash.h.

◆ BUCKET_TO_BLKNO

#define BUCKET_TO_BLKNO (   metap,
 
)    ((BlockNumber) ((B) + ((B) ? (metap)->hashm_spares[_hash_spareindex((B)+1)-1] : 0)) + 1)

◆ BYTE_TO_BIT

#define BYTE_TO_BIT   3 /* 2^3 bits/byte */

Definition at line 299 of file hash.h.

Referenced by _hash_init_metabuffer().

◆ CLRBIT

#define CLRBIT (   A,
 
)    ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))

Definition at line 330 of file hash.h.

◆ H_BUCKET_BEING_POPULATED

#define H_BUCKET_BEING_POPULATED (   opaque)    (((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) != 0)

Definition at line 90 of file hash.h.

Referenced by _hash_first().

◆ H_BUCKET_BEING_SPLIT

#define H_BUCKET_BEING_SPLIT (   opaque)    (((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) != 0)

Definition at line 89 of file hash.h.

Referenced by _hash_doinsert(), _hash_expandtable(), and hashbulkdelete().

◆ H_HAS_DEAD_TUPLES

#define H_HAS_DEAD_TUPLES (   opaque)    (((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) != 0)

Definition at line 91 of file hash.h.

Referenced by _hash_doinsert(), and hashbucketcleanup().

◆ H_NEEDS_SPLIT_CLEANUP

#define H_NEEDS_SPLIT_CLEANUP (   opaque)    (((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) != 0)

Definition at line 88 of file hash.h.

Referenced by _hash_expandtable(), and hashbulkdelete().

◆ HASH_DEFAULT_FILLFACTOR

#define HASH_DEFAULT_FILLFACTOR   75

Definition at line 294 of file hash.h.

◆ HASH_MAGIC

#define HASH_MAGIC   0x6440640

Definition at line 198 of file hash.h.

Referenced by _hash_checkpage(), _hash_init_metabuffer(), and verify_hash_page().

◆ HASH_MAX_BITMAPS

#define HASH_MAX_BITMAPS   Min(BLCKSZ / 8, 1024)

Definition at line 228 of file hash.h.

Referenced by _hash_addovflpage(), _hash_init(), and hash_metapage_info().

◆ HASH_MAX_SPLITPOINT_GROUP

#define HASH_MAX_SPLITPOINT_GROUP   32

Definition at line 236 of file hash.h.

◆ HASH_MAX_SPLITPOINTS

#define HASH_MAX_SPLITPOINTS
Value:
HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE)
#define HASH_MAX_SPLITPOINT_GROUP
Definition: hash.h:236
#define HASH_SPLITPOINT_PHASES_PER_GRP
Definition: hash.h:231
#define HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE
Definition: hash.h:233

Definition at line 237 of file hash.h.

Referenced by _hash_init_metabuffer(), and hash_metapage_info().

◆ HASH_METAPAGE

◆ HASH_MIN_FILLFACTOR

#define HASH_MIN_FILLFACTOR   10

Definition at line 293 of file hash.h.

◆ HASH_NOLOCK

#define HASH_NOLOCK   (-1)

Definition at line 339 of file hash.h.

Referenced by _hash_doinsert(), _hash_getbuf(), _hash_getbuf_with_strategy(), and hashbulkdelete().

◆ HASH_READ

◆ HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE

#define HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE   10

Definition at line 233 of file hash.h.

Referenced by _hash_get_totalbuckets(), and _hash_spareindex().

◆ HASH_SPLITPOINT_PHASE_BITS

#define HASH_SPLITPOINT_PHASE_BITS   2

Definition at line 230 of file hash.h.

Referenced by _hash_get_totalbuckets(), and _hash_spareindex().

◆ HASH_SPLITPOINT_PHASE_MASK

#define HASH_SPLITPOINT_PHASE_MASK   (HASH_SPLITPOINT_PHASES_PER_GRP - 1)

Definition at line 232 of file hash.h.

Referenced by _hash_get_totalbuckets(), and _hash_spareindex().

◆ HASH_SPLITPOINT_PHASES_PER_GRP

#define HASH_SPLITPOINT_PHASES_PER_GRP   (1 << HASH_SPLITPOINT_PHASE_BITS)

Definition at line 231 of file hash.h.

◆ HASH_VERSION

#define HASH_VERSION   4

Definition at line 199 of file hash.h.

Referenced by _hash_checkpage(), _hash_init_metabuffer(), and verify_hash_page().

◆ HASH_WRITE

◆ HASHEXTENDED_PROC

◆ HashGetFillFactor

#define HashGetFillFactor (   relation)
Value:
(AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
relation->rd_rel->relam == HASH_AM_OID), \
(relation)->rd_options ? \
((HashOptions *) (relation)->rd_options)->fillfactor : \
HASH_DEFAULT_FILLFACTOR)
#define AssertMacro(condition)
Definition: c.h:746

Definition at line 273 of file hash.h.

◆ HashGetMaxBitmapSize

#define HashGetMaxBitmapSize (   page)
Value:
(PageGetPageSize((Page) page) - \
#define SizeOfPageHeaderData
Definition: bufpage.h:216
#define PageGetPageSize(page)
Definition: bufpage.h:268
#define MAXALIGN(LEN)
Definition: c.h:698
Pointer Page
Definition: bufpage.h:78

Definition at line 317 of file hash.h.

Referenced by _hash_init_metabuffer().

◆ HashGetTargetPageUsage

#define HashGetTargetPageUsage (   relation)    (BLCKSZ * HashGetFillFactor(relation) / 100)

Definition at line 279 of file hash.h.

Referenced by _hash_init().

◆ HashMaxItemSize

#define HashMaxItemSize (   page)
Value:
sizeof(ItemIdData) - \
#define SizeOfPageHeaderData
Definition: bufpage.h:216
#define PageGetPageSize(page)
Definition: bufpage.h:268
#define MAXALIGN(LEN)
Definition: c.h:698
#define MAXALIGN_DOWN(LEN)
Definition: c.h:710

Definition at line 285 of file hash.h.

Referenced by _hash_doinsert().

◆ HASHNProcs

#define HASHNProcs   3

Definition at line 356 of file hash.h.

Referenced by hashhandler().

◆ HASHO_PAGE_ID

◆ HASHOPTIONS_PROC

#define HASHOPTIONS_PROC   3

Definition at line 355 of file hash.h.

Referenced by hashhandler(), and hashvalidate().

◆ HashPageGetBitmap

#define HashPageGetBitmap (   page)    ((uint32 *) PageGetContents(page))

◆ HashPageGetMeta

◆ HashScanPosInvalidate

#define HashScanPosInvalidate (   scanpos)
Value:
do { \
(scanpos).buf = InvalidBuffer; \
(scanpos).currPage = InvalidBlockNumber; \
(scanpos).nextPage = InvalidBlockNumber; \
(scanpos).prevPage = InvalidBlockNumber; \
(scanpos).firstItem = 0; \
(scanpos).lastItem = 0; \
(scanpos).itemIndex = 0; \
} while (0)
#define InvalidBuffer
Definition: buf.h:25
static char * buf
Definition: pg_test_fsync.c:67
#define InvalidBlockNumber
Definition: block.h:33

Definition at line 142 of file hash.h.

Referenced by _hash_next(), hashbeginscan(), and hashrescan().

◆ HashScanPosIsPinned

#define HashScanPosIsPinned (   scanpos)
Value:
( \
AssertMacro(BlockNumberIsValid((scanpos).currPage) || \
!BufferIsValid((scanpos).buf)), \
BufferIsValid((scanpos).buf) \
)
static char * buf
Definition: pg_test_fsync.c:67
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123

Definition at line 128 of file hash.h.

Referenced by _hash_kill_items().

◆ HashScanPosIsValid

#define HashScanPosIsValid (   scanpos)
Value:
( \
AssertMacro(BlockNumberIsValid((scanpos).currPage) || \
!BufferIsValid((scanpos).buf)), \
BlockNumberIsValid((scanpos).currPage) \
)
static char * buf
Definition: pg_test_fsync.c:67
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123

Definition at line 135 of file hash.h.

Referenced by _hash_kill_items(), hashendscan(), hashgettuple(), and hashrescan().

◆ HASHSTANDARD_PROC

◆ INDEX_MOVED_BY_SPLIT_MASK

#define INDEX_MOVED_BY_SPLIT_MASK   INDEX_AM_RESERVED_BIT

Definition at line 291 of file hash.h.

Referenced by _hash_load_qualified_items(), and _hash_splitbucket().

◆ InvalidBucket

#define InvalidBucket   ((Bucket) 0xFFFFFFFF)

Definition at line 37 of file hash.h.

Referenced by hashbucketcleanup().

◆ ISSET

#define ISSET (   A,
 
)    ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))

Definition at line 332 of file hash.h.

Referenced by _hash_freeovflpage(), and hash_bitmap_info().

◆ LH_BITMAP_PAGE

◆ LH_BUCKET_BEING_POPULATED

#define LH_BUCKET_BEING_POPULATED   (1 << 4)

Definition at line 58 of file hash.h.

Referenced by _hash_expandtable(), and _hash_splitbucket().

◆ LH_BUCKET_BEING_SPLIT

#define LH_BUCKET_BEING_SPLIT   (1 << 5)

Definition at line 59 of file hash.h.

Referenced by _hash_expandtable(), and _hash_splitbucket().

◆ LH_BUCKET_NEEDS_SPLIT_CLEANUP

#define LH_BUCKET_NEEDS_SPLIT_CLEANUP   (1 << 6)

Definition at line 60 of file hash.h.

Referenced by _hash_splitbucket(), hash_xlog_split_cleanup(), and hashbucketcleanup().

◆ LH_BUCKET_PAGE

◆ LH_META_PAGE

◆ LH_OVERFLOW_PAGE

◆ LH_PAGE_HAS_DEAD_TUPLES

#define LH_PAGE_HAS_DEAD_TUPLES   (1 << 7)

◆ LH_PAGE_TYPE

◆ LH_UNUSED_PAGE

#define LH_UNUSED_PAGE   (0)

◆ SETBIT

#define SETBIT (   A,
 
)    ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))

Definition at line 331 of file hash.h.

Typedef Documentation

◆ Bucket

typedef uint32 Bucket

Definition at line 35 of file hash.h.

◆ HashMetaPage

Definition at line 265 of file hash.h.

◆ HashMetaPageData

◆ HashOptions

typedef struct HashOptions HashOptions

◆ HashPageOpaque

Definition at line 86 of file hash.h.

◆ HashPageOpaqueData

◆ HashScanOpaque

Definition at line 190 of file hash.h.

◆ HashScanOpaqueData

◆ HashScanPosData

◆ HashScanPosItem

◆ HSpool

typedef struct HSpool HSpool

Definition at line 444 of file hash.h.

Function Documentation

◆ _h_indexbuild()

void _h_indexbuild ( HSpool hspool,
Relation  heapRel 
)

Definition at line 119 of file hashsort.c.

References _hash_doinsert(), _hash_get_indextuple_hashkey(), _hash_hashkey2bucket(), Assert, HSpool::high_mask, HSpool::index, HSpool::low_mask, HSpool::max_buckets, pgstat_progress_update_param(), PROGRESS_CREATEIDX_TUPLES_DONE, HSpool::sortstate, tuplesort_getindextuple(), and tuplesort_performsort().

Referenced by hashbuild().

120 {
121  IndexTuple itup;
122  int64 tups_done = 0;
123 #ifdef USE_ASSERT_CHECKING
124  uint32 hashkey = 0;
125 #endif
126 
128 
129  while ((itup = tuplesort_getindextuple(hspool->sortstate, true)) != NULL)
130  {
131  /*
132  * Technically, it isn't critical that hash keys be found in sorted
133  * order, since this sorting is only used to increase locality of
134  * access as a performance optimization. It still seems like a good
135  * idea to test tuplesort.c's handling of hash index tuple sorts
136  * through an assertion, though.
137  */
138 #ifdef USE_ASSERT_CHECKING
139  uint32 lasthashkey = hashkey;
140 
142  hspool->max_buckets, hspool->high_mask,
143  hspool->low_mask);
144  Assert(hashkey >= lasthashkey);
145 #endif
146 
147  _hash_doinsert(hspool->index, itup, heapRel);
148 
150  ++tups_done);
151  }
152 }
IndexTuple tuplesort_getindextuple(Tuplesortstate *state, bool forward)
Definition: tuplesort.c:2446
void _hash_doinsert(Relation rel, IndexTuple itup, Relation heapRel)
Definition: hashinsert.c:36
void tuplesort_performsort(Tuplesortstate *state)
Definition: tuplesort.c:2021
Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashutil.c:126
void pgstat_progress_update_param(int index, int64 val)
Definition: pgstat.c:3231
Tuplesortstate * sortstate
Definition: hashsort.c:41
uint32 low_mask
Definition: hashsort.c:50
uint32 high_mask
Definition: hashsort.c:49
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition: hashutil.c:292
unsigned int uint32
Definition: c.h:374
uint32 max_buckets
Definition: hashsort.c:51
Relation index
Definition: hashsort.c:42
#define Assert(condition)
Definition: c.h:745
#define PROGRESS_CREATEIDX_TUPLES_DONE
Definition: progress.h:85

◆ _h_spool()

void _h_spool ( HSpool hspool,
ItemPointer  self,
Datum values,
bool isnull 
)

Definition at line 108 of file hashsort.c.

References HSpool::index, HSpool::sortstate, and tuplesort_putindextuplevalues().

Referenced by hashbuildCallback().

109 {
111  self, values, isnull);
112 }
Tuplesortstate * sortstate
Definition: hashsort.c:41
Relation index
Definition: hashsort.c:42
void tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel, ItemPointer self, Datum *values, bool *isnull)
Definition: tuplesort.c:1708
static Datum values[MAXATTR]
Definition: bootstrap.c:165

◆ _h_spooldestroy()

void _h_spooldestroy ( HSpool hspool)

Definition at line 98 of file hashsort.c.

References pfree(), HSpool::sortstate, and tuplesort_end().

Referenced by hashbuild().

99 {
100  tuplesort_end(hspool->sortstate);
101  pfree(hspool);
102 }
Tuplesortstate * sortstate
Definition: hashsort.c:41
void pfree(void *pointer)
Definition: mcxt.c:1057
void tuplesort_end(Tuplesortstate *state)
Definition: tuplesort.c:1445

◆ _h_spoolinit()

HSpool* _h_spoolinit ( Relation  heap,
Relation  index,
uint32  num_buckets 
)

Definition at line 59 of file hashsort.c.

References HSpool::high_mask, HSpool::index, HSpool::low_mask, maintenance_work_mem, HSpool::max_buckets, palloc0(), pg_nextpower2_32(), HSpool::sortstate, and tuplesort_begin_index_hash().

Referenced by hashbuild().

60 {
61  HSpool *hspool = (HSpool *) palloc0(sizeof(HSpool));
62 
63  hspool->index = index;
64 
65  /*
66  * Determine the bitmask for hash code values. Since there are currently
67  * num_buckets buckets in the index, the appropriate mask can be computed
68  * as follows.
69  *
70  * NOTE : This hash mask calculation should be in sync with similar
71  * calculation in _hash_init_metabuffer.
72  */
73  hspool->high_mask = pg_nextpower2_32(num_buckets + 1) - 1;
74  hspool->low_mask = (hspool->high_mask >> 1);
75  hspool->max_buckets = num_buckets - 1;
76 
77  /*
78  * We size the sort area as maintenance_work_mem rather than work_mem to
79  * speed index creation. This should be OK since a single backend can't
80  * run multiple index creations in parallel.
81  */
83  index,
84  hspool->high_mask,
85  hspool->low_mask,
86  hspool->max_buckets,
88  NULL,
89  false);
90 
91  return hspool;
92 }
Tuplesortstate * tuplesort_begin_index_hash(Relation heapRel, Relation indexRel, uint32 high_mask, uint32 low_mask, uint32 max_buckets, int workMem, SortCoordinate coordinate, bool randomAccess)
Definition: tuplesort.c:1125
Tuplesortstate * sortstate
Definition: hashsort.c:41
uint32 low_mask
Definition: hashsort.c:50
uint32 high_mask
Definition: hashsort.c:49
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:146
void * palloc0(Size size)
Definition: mcxt.c:981
uint32 max_buckets
Definition: hashsort.c:51
Relation index
Definition: hashsort.c:42
int maintenance_work_mem
Definition: globals.c:123

◆ _hash_addovflpage()

Buffer _hash_addovflpage ( Relation  rel,
Buffer  metabuf,
Buffer  buf,
bool  retain_pin 
)

Definition at line 111 of file hashovfl.c.

References _hash_checkpage(), _hash_firstfreebit(), _hash_getbuf(), _hash_getinitbuf(), _hash_getnewbuf(), _hash_initbitmapbuffer(), _hash_relbuf(), ALL_SET, Assert, bit(), bitno_to_blkno(), BITS_PER_MAP, BlockNumberIsValid, xl_hash_add_ovfl_page::bmpage_found, BMPG_MASK, BMPG_SHIFT, BMPGSZ_BIT, xl_hash_add_ovfl_page::bmsize, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, HASH_MAX_BITMAPS, HASH_WRITE, HashMetaPageData::hashm_bmsize, HashMetaPageData::hashm_firstfree, HashMetaPageData::hashm_mapp, HashMetaPageData::hashm_nmaps, HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_spares, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetBitmap, HashPageGetMeta, i, InvalidBlockNumber, InvalidBuffer, LH_BITMAP_PAGE, LH_BUCKET_PAGE, LH_META_PAGE, LH_OVERFLOW_PAGE, LH_PAGE_TYPE, LockBuffer(), MAIN_FORKNUM, MarkBufferDirty(), PageGetSpecialPointer, PageSetLSN, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, SETBIT, SizeOfHashAddOvflPage, START_CRIT_SECTION, XLOG_HASH_ADD_OVFL_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _hash_doinsert(), and _hash_splitbucket().

112 {
113  Buffer ovflbuf;
114  Page page;
115  Page ovflpage;
116  HashPageOpaque pageopaque;
117  HashPageOpaque ovflopaque;
118  HashMetaPage metap;
119  Buffer mapbuf = InvalidBuffer;
120  Buffer newmapbuf = InvalidBuffer;
121  BlockNumber blkno;
122  uint32 orig_firstfree;
123  uint32 splitnum;
124  uint32 *freep = NULL;
125  uint32 max_ovflpg;
126  uint32 bit;
127  uint32 bitmap_page_bit;
128  uint32 first_page;
129  uint32 last_bit;
130  uint32 last_page;
131  uint32 i,
132  j;
133  bool page_found = false;
134 
135  /*
136  * Write-lock the tail page. Here, we need to maintain locking order such
137  * that, first acquire the lock on tail page of bucket, then on meta page
138  * to find and lock the bitmap page and if it is found, then lock on meta
139  * page is released, then finally acquire the lock on new overflow buffer.
140  * We need this locking order to avoid deadlock with backends that are
141  * doing inserts.
142  *
143  * Note: We could have avoided locking many buffers here if we made two
144  * WAL records for acquiring an overflow page (one to allocate an overflow
145  * page and another to add it to overflow bucket chain). However, doing
146  * so can leak an overflow page, if the system crashes after allocation.
147  * Needless to say, it is better to have a single record from a
148  * performance point of view as well.
149  */
151 
152  /* probably redundant... */
154 
155  /* loop to find current tail page, in case someone else inserted too */
156  for (;;)
157  {
158  BlockNumber nextblkno;
159 
160  page = BufferGetPage(buf);
161  pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
162  nextblkno = pageopaque->hasho_nextblkno;
163 
164  if (!BlockNumberIsValid(nextblkno))
165  break;
166 
167  /* we assume we do not need to write the unmodified page */
168  if (retain_pin)
169  {
170  /* pin will be retained only for the primary bucket page */
171  Assert((pageopaque->hasho_flag & LH_PAGE_TYPE) == LH_BUCKET_PAGE);
173  }
174  else
175  _hash_relbuf(rel, buf);
176 
177  retain_pin = false;
178 
179  buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
180  }
181 
182  /* Get exclusive lock on the meta page */
184 
185  _hash_checkpage(rel, metabuf, LH_META_PAGE);
186  metap = HashPageGetMeta(BufferGetPage(metabuf));
187 
188  /* start search at hashm_firstfree */
189  orig_firstfree = metap->hashm_firstfree;
190  first_page = orig_firstfree >> BMPG_SHIFT(metap);
191  bit = orig_firstfree & BMPG_MASK(metap);
192  i = first_page;
193  j = bit / BITS_PER_MAP;
194  bit &= ~(BITS_PER_MAP - 1);
195 
196  /* outer loop iterates once per bitmap page */
197  for (;;)
198  {
199  BlockNumber mapblkno;
200  Page mappage;
201  uint32 last_inpage;
202 
203  /* want to end search with the last existing overflow page */
204  splitnum = metap->hashm_ovflpoint;
205  max_ovflpg = metap->hashm_spares[splitnum] - 1;
206  last_page = max_ovflpg >> BMPG_SHIFT(metap);
207  last_bit = max_ovflpg & BMPG_MASK(metap);
208 
209  if (i > last_page)
210  break;
211 
212  Assert(i < metap->hashm_nmaps);
213  mapblkno = metap->hashm_mapp[i];
214 
215  if (i == last_page)
216  last_inpage = last_bit;
217  else
218  last_inpage = BMPGSZ_BIT(metap) - 1;
219 
220  /* Release exclusive lock on metapage while reading bitmap page */
221  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
222 
223  mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE, LH_BITMAP_PAGE);
224  mappage = BufferGetPage(mapbuf);
225  freep = HashPageGetBitmap(mappage);
226 
227  for (; bit <= last_inpage; j++, bit += BITS_PER_MAP)
228  {
229  if (freep[j] != ALL_SET)
230  {
231  page_found = true;
232 
233  /* Reacquire exclusive lock on the meta page */
235 
236  /* convert bit to bit number within page */
237  bit += _hash_firstfreebit(freep[j]);
238  bitmap_page_bit = bit;
239 
240  /* convert bit to absolute bit number */
241  bit += (i << BMPG_SHIFT(metap));
242  /* Calculate address of the recycled overflow page */
243  blkno = bitno_to_blkno(metap, bit);
244 
245  /* Fetch and init the recycled page */
246  ovflbuf = _hash_getinitbuf(rel, blkno);
247 
248  goto found;
249  }
250  }
251 
252  /* No free space here, try to advance to next map page */
253  _hash_relbuf(rel, mapbuf);
254  mapbuf = InvalidBuffer;
255  i++;
256  j = 0; /* scan from start of next map page */
257  bit = 0;
258 
259  /* Reacquire exclusive lock on the meta page */
261  }
262 
263  /*
264  * No free pages --- have to extend the relation to add an overflow page.
265  * First, check to see if we have to add a new bitmap page too.
266  */
267  if (last_bit == (uint32) (BMPGSZ_BIT(metap) - 1))
268  {
269  /*
270  * We create the new bitmap page with all pages marked "in use".
271  * Actually two pages in the new bitmap's range will exist
272  * immediately: the bitmap page itself, and the following page which
273  * is the one we return to the caller. Both of these are correctly
274  * marked "in use". Subsequent pages do not exist yet, but it is
275  * convenient to pre-mark them as "in use" too.
276  */
277  bit = metap->hashm_spares[splitnum];
278 
279  /* metapage already has a write lock */
280  if (metap->hashm_nmaps >= HASH_MAX_BITMAPS)
281  ereport(ERROR,
282  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
283  errmsg("out of overflow pages in hash index \"%s\"",
284  RelationGetRelationName(rel))));
285 
286  newmapbuf = _hash_getnewbuf(rel, bitno_to_blkno(metap, bit), MAIN_FORKNUM);
287  }
288  else
289  {
290  /*
291  * Nothing to do here; since the page will be past the last used page,
292  * we know its bitmap bit was preinitialized to "in use".
293  */
294  }
295 
296  /* Calculate address of the new overflow page */
297  bit = BufferIsValid(newmapbuf) ?
298  metap->hashm_spares[splitnum] + 1 : metap->hashm_spares[splitnum];
299  blkno = bitno_to_blkno(metap, bit);
300 
301  /*
302  * Fetch the page with _hash_getnewbuf to ensure smgr's idea of the
303  * relation length stays in sync with ours. XXX It's annoying to do this
304  * with metapage write lock held; would be better to use a lock that
305  * doesn't block incoming searches.
306  *
307  * It is okay to hold two buffer locks here (one on tail page of bucket
308  * and other on new overflow page) since there cannot be anyone else
309  * contending for access to ovflbuf.
310  */
311  ovflbuf = _hash_getnewbuf(rel, blkno, MAIN_FORKNUM);
312 
313 found:
314 
315  /*
316  * Do the update. No ereport(ERROR) until changes are logged. We want to
317  * log the changes for bitmap page and overflow page together to avoid
318  * loss of pages in case the new page is added.
319  */
321 
322  if (page_found)
323  {
324  Assert(BufferIsValid(mapbuf));
325 
326  /* mark page "in use" in the bitmap */
327  SETBIT(freep, bitmap_page_bit);
328  MarkBufferDirty(mapbuf);
329  }
330  else
331  {
332  /* update the count to indicate new overflow page is added */
333  metap->hashm_spares[splitnum]++;
334 
335  if (BufferIsValid(newmapbuf))
336  {
337  _hash_initbitmapbuffer(newmapbuf, metap->hashm_bmsize, false);
338  MarkBufferDirty(newmapbuf);
339 
340  /* add the new bitmap page to the metapage's list of bitmaps */
341  metap->hashm_mapp[metap->hashm_nmaps] = BufferGetBlockNumber(newmapbuf);
342  metap->hashm_nmaps++;
343  metap->hashm_spares[splitnum]++;
344  }
345 
346  MarkBufferDirty(metabuf);
347 
348  /*
349  * for new overflow page, we don't need to explicitly set the bit in
350  * bitmap page, as by default that will be set to "in use".
351  */
352  }
353 
354  /*
355  * Adjust hashm_firstfree to avoid redundant searches. But don't risk
356  * changing it if someone moved it while we were searching bitmap pages.
357  */
358  if (metap->hashm_firstfree == orig_firstfree)
359  {
360  metap->hashm_firstfree = bit + 1;
361  MarkBufferDirty(metabuf);
362  }
363 
364  /* initialize new overflow page */
365  ovflpage = BufferGetPage(ovflbuf);
366  ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
368  ovflopaque->hasho_nextblkno = InvalidBlockNumber;
369  ovflopaque->hasho_bucket = pageopaque->hasho_bucket;
370  ovflopaque->hasho_flag = LH_OVERFLOW_PAGE;
371  ovflopaque->hasho_page_id = HASHO_PAGE_ID;
372 
373  MarkBufferDirty(ovflbuf);
374 
375  /* logically chain overflow page to previous page */
376  pageopaque->hasho_nextblkno = BufferGetBlockNumber(ovflbuf);
377 
379 
380  /* XLOG stuff */
381  if (RelationNeedsWAL(rel))
382  {
383  XLogRecPtr recptr;
384  xl_hash_add_ovfl_page xlrec;
385 
386  xlrec.bmpage_found = page_found;
387  xlrec.bmsize = metap->hashm_bmsize;
388 
389  XLogBeginInsert();
390  XLogRegisterData((char *) &xlrec, SizeOfHashAddOvflPage);
391 
393  XLogRegisterBufData(0, (char *) &pageopaque->hasho_bucket, sizeof(Bucket));
394 
396 
397  if (BufferIsValid(mapbuf))
398  {
400  XLogRegisterBufData(2, (char *) &bitmap_page_bit, sizeof(uint32));
401  }
402 
403  if (BufferIsValid(newmapbuf))
404  XLogRegisterBuffer(3, newmapbuf, REGBUF_WILL_INIT);
405 
406  XLogRegisterBuffer(4, metabuf, REGBUF_STANDARD);
407  XLogRegisterBufData(4, (char *) &metap->hashm_firstfree, sizeof(uint32));
408 
409  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_ADD_OVFL_PAGE);
410 
411  PageSetLSN(BufferGetPage(ovflbuf), recptr);
412  PageSetLSN(BufferGetPage(buf), recptr);
413 
414  if (BufferIsValid(mapbuf))
415  PageSetLSN(BufferGetPage(mapbuf), recptr);
416 
417  if (BufferIsValid(newmapbuf))
418  PageSetLSN(BufferGetPage(newmapbuf), recptr);
419 
420  PageSetLSN(BufferGetPage(metabuf), recptr);
421  }
422 
424 
425  if (retain_pin)
427  else
428  _hash_relbuf(rel, buf);
429 
430  if (BufferIsValid(mapbuf))
431  _hash_relbuf(rel, mapbuf);
432 
433  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
434 
435  if (BufferIsValid(newmapbuf))
436  _hash_relbuf(rel, newmapbuf);
437 
438  return ovflbuf;
439 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:368
uint16 hasho_page_id
Definition: hash.h:83
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define SETBIT(x, i)
Definition: blutils.c:32
#define HashPageGetBitmap(page)
Definition: hash.h:314
#define LH_BITMAP_PAGE
Definition: hash.h:56
static BlockNumber bitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum)
Definition: hashovfl.c:34
#define LH_META_PAGE
Definition: hash.h:57
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1469
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
#define ALL_SET
Definition: hash.h:300
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
Definition: hashpage.c:197
Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno)
Definition: hashpage.c:134
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#define LH_PAGE_TYPE
Definition: hash.h:63
static uint32 _hash_firstfreebit(uint32 map)
Definition: hashovfl.c:447
uint32 Bucket
Definition: hash.h:35
BlockNumber hasho_prevblkno
Definition: hash.h:79
#define ERROR
Definition: elog.h:43
#define XLOG_HASH_ADD_OVFL_PAGE
Definition: hash_xlog.h:30
uint32 hashm_nmaps
Definition: hash.h:258
static char * buf
Definition: pg_test_fsync.c:67
#define HASH_WRITE
Definition: hash.h:338
#define BMPG_MASK(metap)
Definition: hash.h:312
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define RelationGetRelationName(relation)
Definition: rel.h:490
unsigned int uint32
Definition: c.h:374
#define BITS_PER_MAP
Definition: hash.h:327
#define BMPG_SHIFT(metap)
Definition: hash.h:311
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define HASH_MAX_BITMAPS
Definition: hash.h:228
uint32 hashm_ovflpoint
Definition: hash.h:255
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:211
#define LH_OVERFLOW_PAGE
Definition: hash.h:54
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
uint32 hashm_firstfree
Definition: hash.h:257
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
Definition: hash.h:260
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define ereport(elevel,...)
Definition: elog.h:144
void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage)
Definition: hashovfl.c:740
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:55
Datum bit(PG_FUNCTION_ARGS)
Definition: varbit.c:390
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define HASHO_PAGE_ID
Definition: hash.h:99
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
#define RelationNeedsWAL(relation)
Definition: rel.h:562
#define SizeOfHashAddOvflPage
Definition: hash_xlog.h:86
uint16 hasho_flag
Definition: hash.h:82
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2668
#define HashPageGetMeta(page)
Definition: hash.h:321
int errmsg(const char *fmt,...)
Definition: elog.c:824
int i
BlockNumber hasho_nextblkno
Definition: hash.h:80
uint16 hashm_bmsize
Definition: hash.h:249
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
Definition: hash.h:262
int Buffer
Definition: buf.h:23
#define BMPGSZ_BIT(metap)
Definition: hash.h:310
Pointer Page
Definition: bufpage.h:78

◆ _hash_binsearch()

OffsetNumber _hash_binsearch ( Page  page,
uint32  hash_value 
)

Definition at line 351 of file hashutil.c.

References _hash_get_indextuple_hashkey(), Assert, FirstOffsetNumber, lower(), OffsetNumberIsValid, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, and upper().

Referenced by _hash_pgaddmultitup(), _hash_pgaddtup(), and _hash_readpage().

352 {
355 
356  /* Loop invariant: lower <= desired place <= upper */
357  upper = PageGetMaxOffsetNumber(page) + 1;
358  lower = FirstOffsetNumber;
359 
360  while (upper > lower)
361  {
362  OffsetNumber off;
363  IndexTuple itup;
364  uint32 hashkey;
365 
366  off = (upper + lower) / 2;
368 
369  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
370  hashkey = _hash_get_indextuple_hashkey(itup);
371  if (hashkey < hash_value)
372  lower = off + 1;
373  else
374  upper = off;
375  }
376 
377  return lower;
378 }
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:44
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:75
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition: hashutil.c:292
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
unsigned int uint32
Definition: c.h:374
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define Assert(condition)
Definition: c.h:745
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:39
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ _hash_binsearch_last()

OffsetNumber _hash_binsearch_last ( Page  page,
uint32  hash_value 
)

Definition at line 389 of file hashutil.c.

References _hash_get_indextuple_hashkey(), Assert, FirstOffsetNumber, lower(), OffsetNumberIsValid, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, and upper().

Referenced by _hash_readpage().

390 {
393 
394  /* Loop invariant: lower <= desired place <= upper */
395  upper = PageGetMaxOffsetNumber(page);
396  lower = FirstOffsetNumber - 1;
397 
398  while (upper > lower)
399  {
400  IndexTuple itup;
401  OffsetNumber off;
402  uint32 hashkey;
403 
404  off = (upper + lower + 1) / 2;
406 
407  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
408  hashkey = _hash_get_indextuple_hashkey(itup);
409  if (hashkey > hash_value)
410  upper = off - 1;
411  else
412  lower = off;
413  }
414 
415  return lower;
416 }
Datum lower(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:44
Datum upper(PG_FUNCTION_ARGS)
Definition: oracle_compat.c:75
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition: hashutil.c:292
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
unsigned int uint32
Definition: c.h:374
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define Assert(condition)
Definition: c.h:745
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:39
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ _hash_checkpage()

void _hash_checkpage ( Relation  rel,
Buffer  buf,
int  flags 
)

Definition at line 211 of file hashutil.c.

References BufferGetBlockNumber(), BufferGetPage, ereport, errcode(), errhint(), errmsg(), ERROR, HASH_MAGIC, HASH_VERSION, HashMetaPageData::hashm_magic, HashMetaPageData::hashm_version, HashPageOpaqueData::hasho_flag, HashPageGetMeta, LH_META_PAGE, MAXALIGN, PageGetSpecialPointer, PageGetSpecialSize, PageIsNew, and RelationGetRelationName.

Referenced by _hash_addovflpage(), _hash_expandtable(), _hash_freeovflpage(), _hash_getbuf(), _hash_getbuf_with_condlock_cleanup(), _hash_getbuf_with_strategy(), _hash_pgaddmultitup(), _hash_pgaddtup(), _hash_readpage(), and hashbulkdelete().

212 {
213  Page page = BufferGetPage(buf);
214 
215  /*
216  * ReadBuffer verifies that every newly-read page passes
217  * PageHeaderIsValid, which means it either contains a reasonably sane
218  * page header or is all-zero. We have to defend against the all-zero
219  * case, however.
220  */
221  if (PageIsNew(page))
222  ereport(ERROR,
223  (errcode(ERRCODE_INDEX_CORRUPTED),
224  errmsg("index \"%s\" contains unexpected zero page at block %u",
227  errhint("Please REINDEX it.")));
228 
229  /*
230  * Additionally check that the special area looks sane.
231  */
232  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
233  ereport(ERROR,
234  (errcode(ERRCODE_INDEX_CORRUPTED),
235  errmsg("index \"%s\" contains corrupted page at block %u",
238  errhint("Please REINDEX it.")));
239 
240  if (flags)
241  {
243 
244  if ((opaque->hasho_flag & flags) == 0)
245  ereport(ERROR,
246  (errcode(ERRCODE_INDEX_CORRUPTED),
247  errmsg("index \"%s\" contains corrupted page at block %u",
250  errhint("Please REINDEX it.")));
251  }
252 
253  /*
254  * When checking the metapage, also verify magic number and version.
255  */
256  if (flags == LH_META_PAGE)
257  {
258  HashMetaPage metap = HashPageGetMeta(page);
259 
260  if (metap->hashm_magic != HASH_MAGIC)
261  ereport(ERROR,
262  (errcode(ERRCODE_INDEX_CORRUPTED),
263  errmsg("index \"%s\" is not a hash index",
264  RelationGetRelationName(rel))));
265 
266  if (metap->hashm_version != HASH_VERSION)
267  ereport(ERROR,
268  (errcode(ERRCODE_INDEX_CORRUPTED),
269  errmsg("index \"%s\" has wrong hash version",
271  errhint("Please REINDEX it.")));
272  }
273 }
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define LH_META_PAGE
Definition: hash.h:57
uint32 hashm_magic
Definition: hash.h:244
int errcode(int sqlerrcode)
Definition: elog.c:610
#define HASH_VERSION
Definition: hash.h:199
#define HASH_MAGIC
Definition: hash.h:198
#define ERROR
Definition: elog.h:43
uint32 hashm_version
Definition: hash.h:245
static char * buf
Definition: pg_test_fsync.c:67
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define ereport(elevel,...)
Definition: elog.h:144
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define MAXALIGN(LEN)
Definition: c.h:698
#define PageGetSpecialSize(page)
Definition: bufpage.h:300
uint16 hasho_flag
Definition: hash.h:82
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2668
#define PageIsNew(page)
Definition: bufpage.h:229
#define HashPageGetMeta(page)
Definition: hash.h:321
int errmsg(const char *fmt,...)
Definition: elog.c:824
Pointer Page
Definition: bufpage.h:78

◆ _hash_checkqual()

bool _hash_checkqual ( IndexScanDesc  scan,
IndexTuple  itup 
)

Definition at line 32 of file hashutil.c.

References DatumGetBool, FunctionCall2Coll(), index_getattr, IndexScanDescData::indexRelation, sort-test::key, IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, RelationGetDescr, ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_collation, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, and test().

Referenced by _hash_load_qualified_items().

33 {
34  /*
35  * Currently, we can't check any of the scan conditions since we do not
36  * have the original index entry value to supply to the sk_func. Always
37  * return true; we expect that hashgettuple already set the recheck flag
38  * to make the main indexscan code do it.
39  */
40 #ifdef NOT_USED
41  TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
42  ScanKey key = scan->keyData;
43  int scanKeySize = scan->numberOfKeys;
44 
45  while (scanKeySize > 0)
46  {
47  Datum datum;
48  bool isNull;
49  Datum test;
50 
51  datum = index_getattr(itup,
52  key->sk_attno,
53  tupdesc,
54  &isNull);
55 
56  /* assume sk_func is strict */
57  if (isNull)
58  return false;
59  if (key->sk_flags & SK_ISNULL)
60  return false;
61 
62  test = FunctionCall2Coll(&key->sk_func, key->sk_collation,
63  datum, key->sk_argument);
64 
65  if (!DatumGetBool(test))
66  return false;
67 
68  key++;
69  scanKeySize--;
70  }
71 #endif
72 
73  return true;
74 }
static void test(void)
#define RelationGetDescr(relation)
Definition: rel.h:482
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1152
Relation indexRelation
Definition: relscan.h:115
FmgrInfo sk_func
Definition: skey.h:71
#define DatumGetBool(X)
Definition: postgres.h:393
#define SK_ISNULL
Definition: skey.h:115
uintptr_t Datum
Definition: postgres.h:367
int sk_flags
Definition: skey.h:66
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
struct ScanKeyData * keyData
Definition: relscan.h:119
Oid sk_collation
Definition: skey.h:70
Datum sk_argument
Definition: skey.h:72
AttrNumber sk_attno
Definition: skey.h:67

◆ _hash_convert_tuple()

bool _hash_convert_tuple ( Relation  index,
Datum user_values,
bool user_isnull,
Datum index_values,
bool index_isnull 
)

Definition at line 319 of file hashutil.c.

References _hash_datum2hashkey(), and UInt32GetDatum.

Referenced by hashbuildCallback(), and hashinsert().

322 {
323  uint32 hashkey;
324 
325  /*
326  * We do not insert null values into hash indexes. This is okay because
327  * the only supported search operator is '=', and we assume it is strict.
328  */
329  if (user_isnull[0])
330  return false;
331 
332  hashkey = _hash_datum2hashkey(index, user_values[0]);
333  index_values[0] = UInt32GetDatum(hashkey);
334  index_isnull[0] = false;
335  return true;
336 }
uint32 _hash_datum2hashkey(Relation rel, Datum key)
Definition: hashutil.c:83
unsigned int uint32
Definition: c.h:374
#define UInt32GetDatum(X)
Definition: postgres.h:493

◆ _hash_datum2hashkey()

uint32 _hash_datum2hashkey ( Relation  rel,
Datum  key 
)

Definition at line 83 of file hashutil.c.

References DatumGetUInt32, FunctionCall1Coll(), HASHSTANDARD_PROC, index_getprocinfo(), and RelationData::rd_indcollation.

Referenced by _hash_convert_tuple(), and _hash_first().

84 {
85  FmgrInfo *procinfo;
86  Oid collation;
87 
88  /* XXX assumes index has only one attribute */
89  procinfo = index_getprocinfo(rel, 1, HASHSTANDARD_PROC);
90  collation = rel->rd_indcollation[0];
91 
92  return DatumGetUInt32(FunctionCall1Coll(procinfo, collation, key));
93 }
#define DatumGetUInt32(X)
Definition: postgres.h:486
Definition: fmgr.h:56
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:801
unsigned int Oid
Definition: postgres_ext.h:31
Oid * rd_indcollation
Definition: rel.h:199
#define HASHSTANDARD_PROC
Definition: hash.h:353
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1132

◆ _hash_datum2hashkey_type()

uint32 _hash_datum2hashkey_type ( Relation  rel,
Datum  key,
Oid  keytype 
)

Definition at line 103 of file hashutil.c.

References DatumGetUInt32, elog, ERROR, get_opfamily_proc(), HASHSTANDARD_PROC, OidFunctionCall1Coll(), RelationData::rd_indcollation, RelationData::rd_opfamily, RegProcedureIsValid, and RelationGetRelationName.

Referenced by _hash_first().

104 {
105  RegProcedure hash_proc;
106  Oid collation;
107 
108  /* XXX assumes index has only one attribute */
109  hash_proc = get_opfamily_proc(rel->rd_opfamily[0],
110  keytype,
111  keytype,
113  if (!RegProcedureIsValid(hash_proc))
114  elog(ERROR, "missing support function %d(%u,%u) for index \"%s\"",
115  HASHSTANDARD_PROC, keytype, keytype,
117  collation = rel->rd_indcollation[0];
118 
119  return DatumGetUInt32(OidFunctionCall1Coll(hash_proc, collation, key));
120 }
#define DatumGetUInt32(X)
Definition: postgres.h:486
regproc RegProcedure
Definition: c.h:518
unsigned int Oid
Definition: postgres_ext.h:31
Oid * rd_indcollation
Definition: rel.h:199
#define ERROR
Definition: elog.h:43
#define RegProcedureIsValid(p)
Definition: c.h:653
#define RelationGetRelationName(relation)
Definition: rel.h:490
Oid * rd_opfamily
Definition: rel.h:189
#define HASHSTANDARD_PROC
Definition: hash.h:353
Datum OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
Definition: fmgr.c:1414
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:794
#define elog(elevel,...)
Definition: elog.h:214

◆ _hash_doinsert()

void _hash_doinsert ( Relation  rel,
IndexTuple  itup,
Relation  heapRel 
)

Definition at line 36 of file hashinsert.c.

References _hash_addovflpage(), _hash_dropbuf(), _hash_expandtable(), _hash_finish_split(), _hash_get_indextuple_hashkey(), _hash_getbucketbuf_from_hashkey(), _hash_getbuf(), _hash_pgaddtup(), _hash_relbuf(), _hash_vacuum_one_page(), Assert, BlockNumberIsValid, buf, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, CheckForSerializableConflictIn(), END_CRIT_SECTION, ereport, errcode(), errhint(), errmsg(), ERROR, H_BUCKET_BEING_SPLIT, H_HAS_DEAD_TUPLES, HASH_METAPAGE, HASH_NOLOCK, HASH_WRITE, HashMetaPageData::hashm_ffactor, HashMetaPageData::hashm_highmask, HashMetaPageData::hashm_lowmask, HashMetaPageData::hashm_maxbucket, HashMetaPageData::hashm_ntuples, HashMaxItemSize, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageGetMeta, IndexTupleSize, InvalidBuffer, IsBufferCleanupOK(), LH_META_PAGE, LH_OVERFLOW_PAGE, LH_PAGE_TYPE, LockBuffer(), MarkBufferDirty(), MAXALIGN, xl_hash_insert::offnum, PageGetFreeSpace(), PageGetSpecialPointer, PageSetLSN, REGBUF_STANDARD, RelationNeedsWAL, SizeOfHashInsert, START_CRIT_SECTION, XLOG_HASH_INSERT, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _h_indexbuild(), hashbuildCallback(), and hashinsert().

37 {
39  Buffer bucket_buf;
40  Buffer metabuf;
41  HashMetaPage metap;
42  HashMetaPage usedmetap = NULL;
43  Page metapage;
44  Page page;
45  HashPageOpaque pageopaque;
46  Size itemsz;
47  bool do_expand;
48  uint32 hashkey;
49  Bucket bucket;
50  OffsetNumber itup_off;
51 
52  /*
53  * Get the hash key for the item (it's stored in the index tuple itself).
54  */
55  hashkey = _hash_get_indextuple_hashkey(itup);
56 
57  /* compute item size too */
58  itemsz = IndexTupleSize(itup);
59  itemsz = MAXALIGN(itemsz); /* be safe, PageAddItem will do this but we
60  * need to be consistent */
61 
62 restart_insert:
63 
64  /*
65  * Read the metapage. We don't lock it yet; HashMaxItemSize() will
66  * examine pd_pagesize_version, but that can't change so we can examine it
67  * without a lock.
68  */
70  metapage = BufferGetPage(metabuf);
71 
72  /*
73  * Check whether the item can fit on a hash page at all. (Eventually, we
74  * ought to try to apply TOAST methods if not.) Note that at this point,
75  * itemsz doesn't include the ItemId.
76  *
77  * XXX this is useless code if we are only storing hash keys.
78  */
79  if (itemsz > HashMaxItemSize(metapage))
80  ereport(ERROR,
81  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
82  errmsg("index row size %zu exceeds hash maximum %zu",
83  itemsz, HashMaxItemSize(metapage)),
84  errhint("Values larger than a buffer page cannot be indexed.")));
85 
86  /* Lock the primary bucket page for the target bucket. */
87  buf = _hash_getbucketbuf_from_hashkey(rel, hashkey, HASH_WRITE,
88  &usedmetap);
89  Assert(usedmetap != NULL);
90 
92 
93  /* remember the primary bucket buffer to release the pin on it at end. */
94  bucket_buf = buf;
95 
96  page = BufferGetPage(buf);
97  pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
98  bucket = pageopaque->hasho_bucket;
99 
100  /*
101  * If this bucket is in the process of being split, try to finish the
102  * split before inserting, because that might create room for the
103  * insertion to proceed without allocating an additional overflow page.
104  * It's only interesting to finish the split if we're trying to insert
105  * into the bucket from which we're removing tuples (the "old" bucket),
106  * not if we're trying to insert into the bucket into which tuples are
107  * being moved (the "new" bucket).
108  */
109  if (H_BUCKET_BEING_SPLIT(pageopaque) && IsBufferCleanupOK(buf))
110  {
111  /* release the lock on bucket buffer, before completing the split. */
113 
114  _hash_finish_split(rel, metabuf, buf, bucket,
115  usedmetap->hashm_maxbucket,
116  usedmetap->hashm_highmask,
117  usedmetap->hashm_lowmask);
118 
119  /* release the pin on old and meta buffer. retry for insert. */
120  _hash_dropbuf(rel, buf);
121  _hash_dropbuf(rel, metabuf);
122  goto restart_insert;
123  }
124 
125  /* Do the insertion */
126  while (PageGetFreeSpace(page) < itemsz)
127  {
128  BlockNumber nextblkno;
129 
130  /*
131  * Check if current page has any DEAD tuples. If yes, delete these
132  * tuples and see if we can get a space for the new item to be
133  * inserted before moving to the next page in the bucket chain.
134  */
135  if (H_HAS_DEAD_TUPLES(pageopaque))
136  {
137 
138  if (IsBufferCleanupOK(buf))
139  {
140  _hash_vacuum_one_page(rel, heapRel, metabuf, buf);
141 
142  if (PageGetFreeSpace(page) >= itemsz)
143  break; /* OK, now we have enough space */
144  }
145  }
146 
147  /*
148  * no space on this page; check for an overflow page
149  */
150  nextblkno = pageopaque->hasho_nextblkno;
151 
152  if (BlockNumberIsValid(nextblkno))
153  {
154  /*
155  * ovfl page exists; go get it. if it doesn't have room, we'll
156  * find out next pass through the loop test above. we always
157  * release both the lock and pin if this is an overflow page, but
158  * only the lock if this is the primary bucket page, since the pin
159  * on the primary bucket must be retained throughout the scan.
160  */
161  if (buf != bucket_buf)
162  _hash_relbuf(rel, buf);
163  else
165  buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
166  page = BufferGetPage(buf);
167  }
168  else
169  {
170  /*
171  * we're at the end of the bucket chain and we haven't found a
172  * page with enough room. allocate a new overflow page.
173  */
174 
175  /* release our write lock without modifying buffer */
177 
178  /* chain to a new overflow page */
179  buf = _hash_addovflpage(rel, metabuf, buf, (buf == bucket_buf) ? true : false);
180  page = BufferGetPage(buf);
181 
182  /* should fit now, given test above */
183  Assert(PageGetFreeSpace(page) >= itemsz);
184  }
185  pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
186  Assert((pageopaque->hasho_flag & LH_PAGE_TYPE) == LH_OVERFLOW_PAGE);
187  Assert(pageopaque->hasho_bucket == bucket);
188  }
189 
190  /*
191  * Write-lock the metapage so we can increment the tuple count. After
192  * incrementing it, check to see if it's time for a split.
193  */
195 
196  /* Do the update. No ereport(ERROR) until changes are logged */
198 
199  /* found page with enough space, so add the item here */
200  itup_off = _hash_pgaddtup(rel, buf, itemsz, itup);
201  MarkBufferDirty(buf);
202 
203  /* metapage operations */
204  metap = HashPageGetMeta(metapage);
205  metap->hashm_ntuples += 1;
206 
207  /* Make sure this stays in sync with _hash_expandtable() */
208  do_expand = metap->hashm_ntuples >
209  (double) metap->hashm_ffactor * (metap->hashm_maxbucket + 1);
210 
211  MarkBufferDirty(metabuf);
212 
213  /* XLOG stuff */
214  if (RelationNeedsWAL(rel))
215  {
216  xl_hash_insert xlrec;
217  XLogRecPtr recptr;
218 
219  xlrec.offnum = itup_off;
220 
221  XLogBeginInsert();
222  XLogRegisterData((char *) &xlrec, SizeOfHashInsert);
223 
224  XLogRegisterBuffer(1, metabuf, REGBUF_STANDARD);
225 
227  XLogRegisterBufData(0, (char *) itup, IndexTupleSize(itup));
228 
229  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_INSERT);
230 
231  PageSetLSN(BufferGetPage(buf), recptr);
232  PageSetLSN(BufferGetPage(metabuf), recptr);
233  }
234 
236 
237  /* drop lock on metapage, but keep pin */
238  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
239 
240  /*
241  * Release the modified page and ensure to release the pin on primary
242  * page.
243  */
244  _hash_relbuf(rel, buf);
245  if (buf != bucket_buf)
246  _hash_dropbuf(rel, bucket_buf);
247 
248  /* Attempt to split if a split is needed */
249  if (do_expand)
250  _hash_expandtable(rel, metabuf);
251 
252  /* Finally drop our pin on the metapage */
253  _hash_dropbuf(rel, metabuf);
254 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:368
#define HashMaxItemSize(page)
Definition: hash.h:285
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define XLOG_HASH_INSERT
Definition: hash_xlog.h:29
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define LH_META_PAGE
Definition: hash.h:57
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1469
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
uint16 hashm_ffactor
Definition: hash.h:247
uint32 hashm_highmask
Definition: hash.h:253
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
int errcode(int sqlerrcode)
Definition: elog.c:610
Buffer _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey, int access, HashMetaPage *cachedmetap)
Definition: hashpage.c:1555
uint32 BlockNumber
Definition: block.h:31
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
uint32 hashm_lowmask
Definition: hash.h:254
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:782
uint16 OffsetNumber
Definition: off.h:24
#define LH_PAGE_TYPE
Definition: hash.h:63
uint32 Bucket
Definition: hash.h:35
#define SizeOfHashInsert
Definition: hash_xlog.h:67
#define ERROR
Definition: elog.h:43
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition: hashutil.c:292
void _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashpage.c:1351
static char * buf
Definition: pg_test_fsync.c:67
#define HASH_WRITE
Definition: hash.h:338
#define HASH_NOLOCK
Definition: hash.h:339
#define REGBUF_STANDARD
Definition: xloginsert.h:35
unsigned int uint32
Definition: c.h:374
void _hash_expandtable(Relation rel, Buffer metabuf)
Definition: hashpage.c:613
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool IsBufferCleanupOK(Buffer buffer)
Definition: bufmgr.c:4007
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
#define HASH_METAPAGE
Definition: hash.h:196
double hashm_ntuples
Definition: hash.h:246
#define LH_OVERFLOW_PAGE
Definition: hash.h:54
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4377
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define ereport(elevel,...)
Definition: elog.h:144
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define H_BUCKET_BEING_SPLIT(opaque)
Definition: hash.h:89
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
size_t Size
Definition: c.h:473
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
OffsetNumber offnum
Definition: hash_xlog.h:64
Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin)
Definition: hashovfl.c:111
#define MAXALIGN(LEN)
Definition: c.h:698
#define RelationNeedsWAL(relation)
Definition: rel.h:562
uint32 hashm_maxbucket
Definition: hash.h:252
OffsetNumber _hash_pgaddtup(Relation rel, Buffer buf, Size itemsize, IndexTuple itup)
Definition: hashinsert.c:268
uint16 hasho_flag
Definition: hash.h:82
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2668
#define HashPageGetMeta(page)
Definition: hash.h:321
int errmsg(const char *fmt,...)
Definition: elog.c:824
BlockNumber hasho_nextblkno
Definition: hash.h:80
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define H_HAS_DEAD_TUPLES(opaque)
Definition: hash.h:91
static void _hash_vacuum_one_page(Relation rel, Relation hrel, Buffer metabuf, Buffer buf)
Definition: hashinsert.c:338
Pointer Page
Definition: bufpage.h:78
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ _hash_dropbuf()

void _hash_dropbuf ( Relation  rel,
Buffer  buf 
)

Definition at line 276 of file hashpage.c.

References ReleaseBuffer().

Referenced by _hash_doinsert(), _hash_dropscanbuf(), _hash_expandtable(), _hash_finish_split(), _hash_first(), _hash_getbucketbuf_from_hashkey(), _hash_next(), _hash_readprev(), and hashbulkdelete().

277 {
279 }
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3518
static char * buf
Definition: pg_test_fsync.c:67

◆ _hash_dropscanbuf()

void _hash_dropscanbuf ( Relation  rel,
HashScanOpaque  so 
)

Definition at line 288 of file hashpage.c.

References _hash_dropbuf(), HashScanPosData::buf, BufferIsValid, HashScanOpaqueData::currPos, HashScanOpaqueData::hashso_buc_populated, HashScanOpaqueData::hashso_buc_split, HashScanOpaqueData::hashso_bucket_buf, HashScanOpaqueData::hashso_split_bucket_buf, and InvalidBuffer.

Referenced by _hash_next(), hashendscan(), and hashrescan().

289 {
290  /* release pin we hold on primary bucket page */
291  if (BufferIsValid(so->hashso_bucket_buf) &&
292  so->hashso_bucket_buf != so->currPos.buf)
295 
296  /* release pin we hold on primary bucket page of bucket being split */
301 
302  /* release any pin we still hold */
303  if (BufferIsValid(so->currPos.buf))
304  _hash_dropbuf(rel, so->currPos.buf);
305  so->currPos.buf = InvalidBuffer;
306 
307  /* reset split scan */
308  so->hashso_buc_populated = false;
309  so->hashso_buc_split = false;
310 }
#define InvalidBuffer
Definition: buf.h:25
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
Buffer hashso_bucket_buf
Definition: hash.h:162
bool hashso_buc_populated
Definition: hash.h:172
Buffer buf
Definition: hash.h:109
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
HashScanPosData currPos
Definition: hash.h:187
bool hashso_buc_split
Definition: hash.h:178
Buffer hashso_split_bucket_buf
Definition: hash.h:169

◆ _hash_expandtable()

void _hash_expandtable ( Relation  rel,
Buffer  metabuf 
)

Definition at line 613 of file hashpage.c.

References _hash_alloc_buckets(), _hash_checkpage(), _hash_dropbuf(), _hash_finish_split(), _hash_get_totalbuckets(), _hash_getbuf_with_condlock_cleanup(), _hash_getnewbuf(), _hash_relbuf(), _hash_spareindex(), _hash_splitbucket(), Assert, BUCKET_TO_BLKNO, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, END_CRIT_SECTION, xl_hash_split_allocate_page::flags, H_BUCKET_BEING_SPLIT, H_NEEDS_SPLIT_CLEANUP, hashbucketcleanup(), HashMetaPageData::hashm_ffactor, HashMetaPageData::hashm_highmask, HashMetaPageData::hashm_lowmask, HashMetaPageData::hashm_maxbucket, HashMetaPageData::hashm_ntuples, HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_spares, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetMeta, InvalidBlockNumber, IsBufferCleanupOK(), LH_BUCKET_BEING_POPULATED, LH_BUCKET_BEING_SPLIT, LH_BUCKET_PAGE, LH_META_PAGE, LockBuffer(), MAIN_FORKNUM, MarkBufferDirty(), xl_hash_split_allocate_page::new_bucket, xl_hash_split_allocate_page::new_bucket_flag, xl_hash_split_allocate_page::old_bucket_flag, PageGetSpecialPointer, PageSetLSN, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationNeedsWAL, SizeOfHashSplitAllocPage, START_CRIT_SECTION, XLH_SPLIT_META_UPDATE_MASKS, XLH_SPLIT_META_UPDATE_SPLITPOINT, XLOG_HASH_SPLIT_ALLOCATE_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _hash_doinsert().

614 {
615  HashMetaPage metap;
616  Bucket old_bucket;
617  Bucket new_bucket;
618  uint32 spare_ndx;
619  BlockNumber start_oblkno;
620  BlockNumber start_nblkno;
621  Buffer buf_nblkno;
622  Buffer buf_oblkno;
623  Page opage;
624  Page npage;
625  HashPageOpaque oopaque;
626  HashPageOpaque nopaque;
627  uint32 maxbucket;
628  uint32 highmask;
629  uint32 lowmask;
630  bool metap_update_masks = false;
631  bool metap_update_splitpoint = false;
632 
633 restart_expand:
634 
635  /*
636  * Write-lock the meta page. It used to be necessary to acquire a
637  * heavyweight lock to begin a split, but that is no longer required.
638  */
640 
641  _hash_checkpage(rel, metabuf, LH_META_PAGE);
642  metap = HashPageGetMeta(BufferGetPage(metabuf));
643 
644  /*
645  * Check to see if split is still needed; someone else might have already
646  * done one while we waited for the lock.
647  *
648  * Make sure this stays in sync with _hash_doinsert()
649  */
650  if (metap->hashm_ntuples <=
651  (double) metap->hashm_ffactor * (metap->hashm_maxbucket + 1))
652  goto fail;
653 
654  /*
655  * Can't split anymore if maxbucket has reached its maximum possible
656  * value.
657  *
658  * Ideally we'd allow bucket numbers up to UINT_MAX-1 (no higher because
659  * the calculation maxbucket+1 mustn't overflow). Currently we restrict
660  * to half that to prevent failure of pg_ceil_log2_32() and insufficient
661  * space in hashm_spares[]. It's moot anyway because an index with 2^32
662  * buckets would certainly overflow BlockNumber and hence
663  * _hash_alloc_buckets() would fail, but if we supported buckets smaller
664  * than a disk block then this would be an independent constraint.
665  *
666  * If you change this, see also the maximum initial number of buckets in
667  * _hash_init().
668  */
669  if (metap->hashm_maxbucket >= (uint32) 0x7FFFFFFE)
670  goto fail;
671 
672  /*
673  * Determine which bucket is to be split, and attempt to take cleanup lock
674  * on the old bucket. If we can't get the lock, give up.
675  *
676  * The cleanup lock protects us not only against other backends, but
677  * against our own backend as well.
678  *
679  * The cleanup lock is mainly to protect the split from concurrent
680  * inserts. See src/backend/access/hash/README, Lock Definitions for
681  * further details. Due to this locking restriction, if there is any
682  * pending scan, the split will give up which is not good, but harmless.
683  */
684  new_bucket = metap->hashm_maxbucket + 1;
685 
686  old_bucket = (new_bucket & metap->hashm_lowmask);
687 
688  start_oblkno = BUCKET_TO_BLKNO(metap, old_bucket);
689 
690  buf_oblkno = _hash_getbuf_with_condlock_cleanup(rel, start_oblkno, LH_BUCKET_PAGE);
691  if (!buf_oblkno)
692  goto fail;
693 
694  opage = BufferGetPage(buf_oblkno);
695  oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
696 
697  /*
698  * We want to finish the split from a bucket as there is no apparent
699  * benefit by not doing so and it will make the code complicated to finish
700  * the split that involves multiple buckets considering the case where new
701  * split also fails. We don't need to consider the new bucket for
702  * completing the split here as it is not possible that a re-split of new
703  * bucket starts when there is still a pending split from old bucket.
704  */
705  if (H_BUCKET_BEING_SPLIT(oopaque))
706  {
707  /*
708  * Copy bucket mapping info now; refer the comment in code below where
709  * we copy this information before calling _hash_splitbucket to see
710  * why this is okay.
711  */
712  maxbucket = metap->hashm_maxbucket;
713  highmask = metap->hashm_highmask;
714  lowmask = metap->hashm_lowmask;
715 
716  /*
717  * Release the lock on metapage and old_bucket, before completing the
718  * split.
719  */
720  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
721  LockBuffer(buf_oblkno, BUFFER_LOCK_UNLOCK);
722 
723  _hash_finish_split(rel, metabuf, buf_oblkno, old_bucket, maxbucket,
724  highmask, lowmask);
725 
726  /* release the pin on old buffer and retry for expand. */
727  _hash_dropbuf(rel, buf_oblkno);
728 
729  goto restart_expand;
730  }
731 
732  /*
733  * Clean the tuples remained from the previous split. This operation
734  * requires cleanup lock and we already have one on the old bucket, so
735  * let's do it. We also don't want to allow further splits from the bucket
736  * till the garbage of previous split is cleaned. This has two
737  * advantages; first, it helps in avoiding the bloat due to garbage and
738  * second is, during cleanup of bucket, we are always sure that the
739  * garbage tuples belong to most recently split bucket. On the contrary,
740  * if we allow cleanup of bucket after meta page is updated to indicate
741  * the new split and before the actual split, the cleanup operation won't
742  * be able to decide whether the tuple has been moved to the newly created
743  * bucket and ended up deleting such tuples.
744  */
745  if (H_NEEDS_SPLIT_CLEANUP(oopaque))
746  {
747  /*
748  * Copy bucket mapping info now; refer to the comment in code below
749  * where we copy this information before calling _hash_splitbucket to
750  * see why this is okay.
751  */
752  maxbucket = metap->hashm_maxbucket;
753  highmask = metap->hashm_highmask;
754  lowmask = metap->hashm_lowmask;
755 
756  /* Release the metapage lock. */
757  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
758 
759  hashbucketcleanup(rel, old_bucket, buf_oblkno, start_oblkno, NULL,
760  maxbucket, highmask, lowmask, NULL, NULL, true,
761  NULL, NULL);
762 
763  _hash_dropbuf(rel, buf_oblkno);
764 
765  goto restart_expand;
766  }
767 
768  /*
769  * There shouldn't be any active scan on new bucket.
770  *
771  * Note: it is safe to compute the new bucket's blkno here, even though we
772  * may still need to update the BUCKET_TO_BLKNO mapping. This is because
773  * the current value of hashm_spares[hashm_ovflpoint] correctly shows
774  * where we are going to put a new splitpoint's worth of buckets.
775  */
776  start_nblkno = BUCKET_TO_BLKNO(metap, new_bucket);
777 
778  /*
779  * If the split point is increasing we need to allocate a new batch of
780  * bucket pages.
781  */
782  spare_ndx = _hash_spareindex(new_bucket + 1);
783  if (spare_ndx > metap->hashm_ovflpoint)
784  {
785  uint32 buckets_to_add;
786 
787  Assert(spare_ndx == metap->hashm_ovflpoint + 1);
788 
789  /*
790  * We treat allocation of buckets as a separate WAL-logged action.
791  * Even if we fail after this operation, won't leak bucket pages;
792  * rather, the next split will consume this space. In any case, even
793  * without failure we don't use all the space in one split operation.
794  */
795  buckets_to_add = _hash_get_totalbuckets(spare_ndx) - new_bucket;
796  if (!_hash_alloc_buckets(rel, start_nblkno, buckets_to_add))
797  {
798  /* can't split due to BlockNumber overflow */
799  _hash_relbuf(rel, buf_oblkno);
800  goto fail;
801  }
802  }
803 
804  /*
805  * Physically allocate the new bucket's primary page. We want to do this
806  * before changing the metapage's mapping info, in case we can't get the
807  * disk space. Ideally, we don't need to check for cleanup lock on new
808  * bucket as no other backend could find this bucket unless meta page is
809  * updated. However, it is good to be consistent with old bucket locking.
810  */
811  buf_nblkno = _hash_getnewbuf(rel, start_nblkno, MAIN_FORKNUM);
812  if (!IsBufferCleanupOK(buf_nblkno))
813  {
814  _hash_relbuf(rel, buf_oblkno);
815  _hash_relbuf(rel, buf_nblkno);
816  goto fail;
817  }
818 
819  /*
820  * Since we are scribbling on the pages in the shared buffers, establish a
821  * critical section. Any failure in this next code leaves us with a big
822  * problem: the metapage is effectively corrupt but could get written back
823  * to disk.
824  */
826 
827  /*
828  * Okay to proceed with split. Update the metapage bucket mapping info.
829  */
830  metap->hashm_maxbucket = new_bucket;
831 
832  if (new_bucket > metap->hashm_highmask)
833  {
834  /* Starting a new doubling */
835  metap->hashm_lowmask = metap->hashm_highmask;
836  metap->hashm_highmask = new_bucket | metap->hashm_lowmask;
837  metap_update_masks = true;
838  }
839 
840  /*
841  * If the split point is increasing we need to adjust the hashm_spares[]
842  * array and hashm_ovflpoint so that future overflow pages will be created
843  * beyond this new batch of bucket pages.
844  */
845  if (spare_ndx > metap->hashm_ovflpoint)
846  {
847  metap->hashm_spares[spare_ndx] = metap->hashm_spares[metap->hashm_ovflpoint];
848  metap->hashm_ovflpoint = spare_ndx;
849  metap_update_splitpoint = true;
850  }
851 
852  MarkBufferDirty(metabuf);
853 
854  /*
855  * Copy bucket mapping info now; this saves re-accessing the meta page
856  * inside _hash_splitbucket's inner loop. Note that once we drop the
857  * split lock, other splits could begin, so these values might be out of
858  * date before _hash_splitbucket finishes. That's okay, since all it
859  * needs is to tell which of these two buckets to map hashkeys into.
860  */
861  maxbucket = metap->hashm_maxbucket;
862  highmask = metap->hashm_highmask;
863  lowmask = metap->hashm_lowmask;
864 
865  opage = BufferGetPage(buf_oblkno);
866  oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
867 
868  /*
869  * Mark the old bucket to indicate that split is in progress. (At
870  * operation end, we will clear the split-in-progress flag.) Also, for a
871  * primary bucket page, hasho_prevblkno stores the number of buckets that
872  * existed as of the last split, so we must update that value here.
873  */
874  oopaque->hasho_flag |= LH_BUCKET_BEING_SPLIT;
875  oopaque->hasho_prevblkno = maxbucket;
876 
877  MarkBufferDirty(buf_oblkno);
878 
879  npage = BufferGetPage(buf_nblkno);
880 
881  /*
882  * initialize the new bucket's primary page and mark it to indicate that
883  * split is in progress.
884  */
885  nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
886  nopaque->hasho_prevblkno = maxbucket;
888  nopaque->hasho_bucket = new_bucket;
890  nopaque->hasho_page_id = HASHO_PAGE_ID;
891 
892  MarkBufferDirty(buf_nblkno);
893 
894  /* XLOG stuff */
895  if (RelationNeedsWAL(rel))
896  {
898  XLogRecPtr recptr;
899 
900  xlrec.new_bucket = maxbucket;
901  xlrec.old_bucket_flag = oopaque->hasho_flag;
902  xlrec.new_bucket_flag = nopaque->hasho_flag;
903  xlrec.flags = 0;
904 
905  XLogBeginInsert();
906 
907  XLogRegisterBuffer(0, buf_oblkno, REGBUF_STANDARD);
908  XLogRegisterBuffer(1, buf_nblkno, REGBUF_WILL_INIT);
909  XLogRegisterBuffer(2, metabuf, REGBUF_STANDARD);
910 
911  if (metap_update_masks)
912  {
914  XLogRegisterBufData(2, (char *) &metap->hashm_lowmask, sizeof(uint32));
915  XLogRegisterBufData(2, (char *) &metap->hashm_highmask, sizeof(uint32));
916  }
917 
918  if (metap_update_splitpoint)
919  {
921  XLogRegisterBufData(2, (char *) &metap->hashm_ovflpoint,
922  sizeof(uint32));
924  (char *) &metap->hashm_spares[metap->hashm_ovflpoint],
925  sizeof(uint32));
926  }
927 
928  XLogRegisterData((char *) &xlrec, SizeOfHashSplitAllocPage);
929 
930  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_SPLIT_ALLOCATE_PAGE);
931 
932  PageSetLSN(BufferGetPage(buf_oblkno), recptr);
933  PageSetLSN(BufferGetPage(buf_nblkno), recptr);
934  PageSetLSN(BufferGetPage(metabuf), recptr);
935  }
936 
938 
939  /* drop lock, but keep pin */
940  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
941 
942  /* Relocate records to the new bucket */
943  _hash_splitbucket(rel, metabuf,
944  old_bucket, new_bucket,
945  buf_oblkno, buf_nblkno, NULL,
946  maxbucket, highmask, lowmask);
947 
948  /* all done, now release the pins on primary buckets. */
949  _hash_dropbuf(rel, buf_oblkno);
950  _hash_dropbuf(rel, buf_nblkno);
951 
952  return;
953 
954  /* Here if decide not to split or fail to acquire old bucket lock */
955 fail:
956 
957  /* We didn't write the metapage, so just drop lock */
958  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
959 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:368
uint16 hasho_page_id
Definition: hash.h:83
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define XLH_SPLIT_META_UPDATE_SPLITPOINT
Definition: hash_xlog.h:52
#define LH_META_PAGE
Definition: hash.h:57
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1469
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
uint16 hashm_ffactor
Definition: hash.h:247
uint32 hashm_highmask
Definition: hash.h:253
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
void hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, BlockNumber bucket_blkno, BufferAccessStrategy bstrategy, uint32 maxbucket, uint32 highmask, uint32 lowmask, double *tuples_removed, double *num_index_tuples, bool split_cleanup, IndexBulkDeleteCallback callback, void *callback_state)
Definition: hash.c:682
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
Definition: hashpage.c:197
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
uint32 hashm_lowmask
Definition: hash.h:254
#define BUCKET_TO_BLKNO(metap, B)
Definition: hash.h:39
static bool _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
Definition: hashpage.c:987
uint32 Bucket
Definition: hash.h:35
#define H_NEEDS_SPLIT_CLEANUP(opaque)
Definition: hash.h:88
BlockNumber hasho_prevblkno
Definition: hash.h:79
#define SizeOfHashSplitAllocPage
Definition: hash_xlog.h:106
uint32 _hash_spareindex(uint32 num_bucket)
Definition: hashutil.c:143
uint32 _hash_get_totalbuckets(uint32 splitpoint_phase)
Definition: hashutil.c:175
void _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashpage.c:1351
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define LH_BUCKET_BEING_SPLIT
Definition: hash.h:59
unsigned int uint32
Definition: c.h:374
Buffer _hash_getbuf_with_condlock_cleanup(Relation rel, BlockNumber blkno, int flags)
Definition: hashpage.c:95
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool IsBufferCleanupOK(Buffer buffer)
Definition: bufmgr.c:4007
uint32 hashm_ovflpoint
Definition: hash.h:255
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
#define LH_BUCKET_BEING_POPULATED
Definition: hash.h:58
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:211
double hashm_ntuples
Definition: hash.h:246
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
Definition: hash.h:260
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define LH_BUCKET_PAGE
Definition: hash.h:55
#define H_BUCKET_BEING_SPLIT(opaque)
Definition: hash.h:89
static void _hash_splitbucket(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket, Buffer obuf, Buffer nbuf, HTAB *htab, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashpage.c:1068
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define HASHO_PAGE_ID
Definition: hash.h:99
#define RelationNeedsWAL(relation)
Definition: rel.h:562
uint32 hashm_maxbucket
Definition: hash.h:252
uint16 hasho_flag
Definition: hash.h:82
#define XLOG_HASH_SPLIT_ALLOCATE_PAGE
Definition: hash_xlog.h:31
#define HashPageGetMeta(page)
Definition: hash.h:321
BlockNumber hasho_nextblkno
Definition: hash.h:80
#define XLH_SPLIT_META_UPDATE_MASKS
Definition: hash_xlog.h:51
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ _hash_finish_split()

void _hash_finish_split ( Relation  rel,
Buffer  metabuf,
Buffer  obuf,
Bucket  obucket,
uint32  maxbucket,
uint32  highmask,
uint32  lowmask 
)

Definition at line 1351 of file hashpage.c.

References _hash_dropbuf(), _hash_get_newblock_from_oldbucket(), _hash_getbuf(), _hash_relbuf(), _hash_splitbucket(), Assert, BlockNumberIsValid, BUFFER_LOCK_UNLOCK, BufferGetPage, ConditionalLockBufferForCleanup(), CurrentMemoryContext, HASHCTL::entrysize, FirstOffsetNumber, HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, HASH_READ, hash_search(), HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_nextblkno, HASHCTL::hcxt, InvalidBuffer, HASHCTL::keysize, LH_BUCKET_PAGE, LH_OVERFLOW_PAGE, LockBuffer(), OffsetNumberNext, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, and IndexTupleData::t_tid.

Referenced by _hash_doinsert(), and _hash_expandtable().

1353 {
1354  HASHCTL hash_ctl;
1355  HTAB *tidhtab;
1356  Buffer bucket_nbuf = InvalidBuffer;
1357  Buffer nbuf;
1358  Page npage;
1359  BlockNumber nblkno;
1360  BlockNumber bucket_nblkno;
1361  HashPageOpaque npageopaque;
1362  Bucket nbucket;
1363  bool found;
1364 
1365  /* Initialize hash tables used to track TIDs */
1366  memset(&hash_ctl, 0, sizeof(hash_ctl));
1367  hash_ctl.keysize = sizeof(ItemPointerData);
1368  hash_ctl.entrysize = sizeof(ItemPointerData);
1369  hash_ctl.hcxt = CurrentMemoryContext;
1370 
1371  tidhtab =
1372  hash_create("bucket ctids",
1373  256, /* arbitrary initial size */
1374  &hash_ctl,
1376 
1377  bucket_nblkno = nblkno = _hash_get_newblock_from_oldbucket(rel, obucket);
1378 
1379  /*
1380  * Scan the new bucket and build hash table of TIDs
1381  */
1382  for (;;)
1383  {
1384  OffsetNumber noffnum;
1385  OffsetNumber nmaxoffnum;
1386 
1387  nbuf = _hash_getbuf(rel, nblkno, HASH_READ,
1389 
1390  /* remember the primary bucket buffer to acquire cleanup lock on it. */
1391  if (nblkno == bucket_nblkno)
1392  bucket_nbuf = nbuf;
1393 
1394  npage = BufferGetPage(nbuf);
1395  npageopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
1396 
1397  /* Scan each tuple in new page */
1398  nmaxoffnum = PageGetMaxOffsetNumber(npage);
1399  for (noffnum = FirstOffsetNumber;
1400  noffnum <= nmaxoffnum;
1401  noffnum = OffsetNumberNext(noffnum))
1402  {
1403  IndexTuple itup;
1404 
1405  /* Fetch the item's TID and insert it in hash table. */
1406  itup = (IndexTuple) PageGetItem(npage,
1407  PageGetItemId(npage, noffnum));
1408 
1409  (void) hash_search(tidhtab, &itup->t_tid, HASH_ENTER, &found);
1410 
1411  Assert(!found);
1412  }
1413 
1414  nblkno = npageopaque->hasho_nextblkno;
1415 
1416  /*
1417  * release our write lock without modifying buffer and ensure to
1418  * retain the pin on primary bucket.
1419  */
1420  if (nbuf == bucket_nbuf)
1422  else
1423  _hash_relbuf(rel, nbuf);
1424 
1425  /* Exit loop if no more overflow pages in new bucket */
1426  if (!BlockNumberIsValid(nblkno))
1427  break;
1428  }
1429 
1430  /*
1431  * Conditionally get the cleanup lock on old and new buckets to perform
1432  * the split operation. If we don't get the cleanup locks, silently give
1433  * up and next insertion on old bucket will try again to complete the
1434  * split.
1435  */
1437  {
1438  hash_destroy(tidhtab);
1439  return;
1440  }
1441  if (!ConditionalLockBufferForCleanup(bucket_nbuf))
1442  {
1444  hash_destroy(tidhtab);
1445  return;
1446  }
1447 
1448  npage = BufferGetPage(bucket_nbuf);
1449  npageopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
1450  nbucket = npageopaque->hasho_bucket;
1451 
1452  _hash_splitbucket(rel, metabuf, obucket,
1453  nbucket, obuf, bucket_nbuf, tidhtab,
1454  maxbucket, highmask, lowmask);
1455 
1456  _hash_dropbuf(rel, bucket_nbuf);
1457  hash_destroy(tidhtab);
1458 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:827
#define HASH_CONTEXT
Definition: hsearch.h:91
#define HASH_ELEM
Definition: hsearch.h:85
MemoryContext hcxt
Definition: hsearch.h:77
ItemPointerData t_tid
Definition: itup.h:37
#define InvalidBuffer
Definition: buf.h:25
Size entrysize
Definition: hsearch.h:72
uint32 BlockNumber
Definition: block.h:31
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define HASH_READ
Definition: hash.h:337
uint32 Bucket
Definition: hash.h:35
Definition: dynahash.c:218
bool ConditionalLockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3951
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
#define LH_OVERFLOW_PAGE
Definition: hash.h:54
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
Size keysize
Definition: hsearch.h:71
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
BlockNumber _hash_get_newblock_from_oldbucket(Relation rel, Bucket old_bucket)
Definition: hashutil.c:462
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:55
static void _hash_splitbucket(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket, Buffer obuf, Buffer nbuf, HTAB *htab, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashpage.c:1068
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
struct ItemPointerData ItemPointerData
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
BlockNumber hasho_nextblkno
Definition: hash.h:80
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ _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, TestForOldSnapshot(), IndexScanDescData::xs_heaptid, 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_heaptid = currItem->heapTid;
436 
437  /* if we're here, _hash_readpage found a valid tuples */
438  return true;
439 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:190
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
void PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot)
Definition: predicate.c:2523
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:277
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 InvalidBuffer
Definition: buf.h:25
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:610
Buffer _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey, int access, HashMetaPage *cachedmetap)
Definition: hashpage.c:1555
struct SnapshotData * xs_snapshot
Definition: relscan.h:116
uint32 BlockNumber
Definition: block.h:31
uint32 _hash_datum2hashkey(Relation rel, Datum key)
Definition: hashutil.c:83
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
Relation indexRelation
Definition: relscan.h:115
#define HASH_READ
Definition: hash.h:337
uint32 Bucket
Definition: hash.h:35
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
#define ERROR
Definition: elog.h:43
#define HTEqualStrategyNumber
Definition: stratnum.h:41
ItemPointerData xs_heaptid
Definition: relscan.h:144
#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:1417
unsigned int uint32
Definition: c.h:374
#define SK_ISNULL
Definition: skey.h:115
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Buffer hashso_bucket_buf
Definition: hash.h:162
#define H_BUCKET_BEING_POPULATED(opaque)
Definition: hash.h:90
bool hashso_buc_populated
Definition: hash.h:172
Buffer buf
Definition: hash.h:109
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
uint32 hashso_sk_hash
Definition: hash.h:159
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:55
#define Assert(condition)
Definition: c.h:745
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
BlockNumber _hash_get_oldblock_from_newbucket(Relation rel, Bucket new_bucket)
Definition: hashutil.c:423
struct ScanKeyData * keyData
Definition: relscan.h:119
HashScanPosData currPos
Definition: hash.h:187
bool hashso_buc_split
Definition: hash.h:178
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2668
int errmsg(const char *fmt,...)
Definition: elog.c:824
Buffer hashso_split_bucket_buf
Definition: hash.h:169
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
uint32 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype)
Definition: hashutil.c:103
int itemIndex
Definition: hash.h:123
Oid * rd_opcintype
Definition: rel.h:190
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:125

◆ _hash_freeovflpage()

BlockNumber _hash_freeovflpage ( Relation  rel,
Buffer  bucketbuf,
Buffer  ovflbuf,
Buffer  wbuf,
IndexTuple itups,
OffsetNumber itup_offsets,
Size tups_size,
uint16  nitups,
BufferAccessStrategy  bstrategy 
)

Definition at line 489 of file hashovfl.c.

References _hash_checkpage(), _hash_getbuf(), _hash_getbuf_with_strategy(), _hash_ovflblkno_to_bitno(), _hash_pageinit(), _hash_pgaddmultitup(), _hash_relbuf(), Assert, BlockNumberIsValid, BMPG_MASK, BMPG_SHIFT, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferGetPageSize, BufferIsValid, CLRBIT, elog, END_CRIT_SECTION, ERROR, HASH_METAPAGE, HASH_READ, HASH_WRITE, HASH_XLOG_FREE_OVFL_BUFS, HashMetaPageData::hashm_firstfree, HashMetaPageData::hashm_mapp, HashMetaPageData::hashm_nmaps, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetBitmap, HashPageGetMeta, i, InvalidBlockNumber, InvalidBuffer, xl_hash_squeeze_page::is_prev_bucket_same_wrt, xl_hash_squeeze_page::is_prim_bucket_same_wrt, ISSET, LH_BITMAP_PAGE, LH_BUCKET_PAGE, LH_META_PAGE, LH_OVERFLOW_PAGE, LH_UNUSED_PAGE, LockBuffer(), MarkBufferDirty(), xl_hash_squeeze_page::nextblkno, xl_hash_squeeze_page::ntups, PageGetSpecialPointer, PageSetLSN, PG_USED_FOR_ASSERTS_ONLY, xl_hash_squeeze_page::prevblkno, REGBUF_NO_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, SizeOfHashSqueezePage, START_CRIT_SECTION, XLOG_HASH_SQUEEZE_PAGE, XLogBeginInsert(), XLogEnsureRecordSpace(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _hash_squeezebucket().

493 {
494  HashMetaPage metap;
495  Buffer metabuf;
496  Buffer mapbuf;
497  BlockNumber ovflblkno;
498  BlockNumber prevblkno;
499  BlockNumber blkno;
500  BlockNumber nextblkno;
501  BlockNumber writeblkno;
502  HashPageOpaque ovflopaque;
503  Page ovflpage;
504  Page mappage;
505  uint32 *freep;
506  uint32 ovflbitno;
507  int32 bitmappage,
508  bitmapbit;
510  Buffer prevbuf = InvalidBuffer;
511  Buffer nextbuf = InvalidBuffer;
512  bool update_metap = false;
513 
514  /* Get information from the doomed page */
515  _hash_checkpage(rel, ovflbuf, LH_OVERFLOW_PAGE);
516  ovflblkno = BufferGetBlockNumber(ovflbuf);
517  ovflpage = BufferGetPage(ovflbuf);
518  ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
519  nextblkno = ovflopaque->hasho_nextblkno;
520  prevblkno = ovflopaque->hasho_prevblkno;
521  writeblkno = BufferGetBlockNumber(wbuf);
522  bucket = ovflopaque->hasho_bucket;
523 
524  /*
525  * Fix up the bucket chain. this is a doubly-linked list, so we must fix
526  * up the bucket chain members behind and ahead of the overflow page being
527  * deleted. Concurrency issues are avoided by using lock chaining as
528  * described atop hashbucketcleanup.
529  */
530  if (BlockNumberIsValid(prevblkno))
531  {
532  if (prevblkno == writeblkno)
533  prevbuf = wbuf;
534  else
535  prevbuf = _hash_getbuf_with_strategy(rel,
536  prevblkno,
537  HASH_WRITE,
539  bstrategy);
540  }
541  if (BlockNumberIsValid(nextblkno))
542  nextbuf = _hash_getbuf_with_strategy(rel,
543  nextblkno,
544  HASH_WRITE,
546  bstrategy);
547 
548  /* Note: bstrategy is intentionally not used for metapage and bitmap */
549 
550  /* Read the metapage so we can determine which bitmap page to use */
552  metap = HashPageGetMeta(BufferGetPage(metabuf));
553 
554  /* Identify which bit to set */
555  ovflbitno = _hash_ovflblkno_to_bitno(metap, ovflblkno);
556 
557  bitmappage = ovflbitno >> BMPG_SHIFT(metap);
558  bitmapbit = ovflbitno & BMPG_MASK(metap);
559 
560  if (bitmappage >= metap->hashm_nmaps)
561  elog(ERROR, "invalid overflow bit number %u", ovflbitno);
562  blkno = metap->hashm_mapp[bitmappage];
563 
564  /* Release metapage lock while we access the bitmap page */
565  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
566 
567  /* read the bitmap page to clear the bitmap bit */
568  mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BITMAP_PAGE);
569  mappage = BufferGetPage(mapbuf);
570  freep = HashPageGetBitmap(mappage);
571  Assert(ISSET(freep, bitmapbit));
572 
573  /* Get write-lock on metapage to update firstfree */
575 
576  /* This operation needs to log multiple tuples, prepare WAL for that */
577  if (RelationNeedsWAL(rel))
579 
581 
582  /*
583  * we have to insert tuples on the "write" page, being careful to preserve
584  * hashkey ordering. (If we insert many tuples into the same "write" page
585  * it would be worth qsort'ing them).
586  */
587  if (nitups > 0)
588  {
589  _hash_pgaddmultitup(rel, wbuf, itups, itup_offsets, nitups);
590  MarkBufferDirty(wbuf);
591  }
592 
593  /*
594  * Reinitialize the freed overflow page. Just zeroing the page won't
595  * work, because WAL replay routines expect pages to be initialized. See
596  * explanation of RBM_NORMAL mode atop XLogReadBufferExtended. We are
597  * careful to make the special space valid here so that tools like
598  * pageinspect won't get confused.
599  */
600  _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
601 
602  ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
603 
604  ovflopaque->hasho_prevblkno = InvalidBlockNumber;
605  ovflopaque->hasho_nextblkno = InvalidBlockNumber;
606  ovflopaque->hasho_bucket = -1;
607  ovflopaque->hasho_flag = LH_UNUSED_PAGE;
608  ovflopaque->hasho_page_id = HASHO_PAGE_ID;
609 
610  MarkBufferDirty(ovflbuf);
611 
612  if (BufferIsValid(prevbuf))
613  {
614  Page prevpage = BufferGetPage(prevbuf);
615  HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage);
616 
617  Assert(prevopaque->hasho_bucket == bucket);
618  prevopaque->hasho_nextblkno = nextblkno;
619  MarkBufferDirty(prevbuf);
620  }
621  if (BufferIsValid(nextbuf))
622  {
623  Page nextpage = BufferGetPage(nextbuf);
624  HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage);
625 
626  Assert(nextopaque->hasho_bucket == bucket);
627  nextopaque->hasho_prevblkno = prevblkno;
628  MarkBufferDirty(nextbuf);
629  }
630 
631  /* Clear the bitmap bit to indicate that this overflow page is free */
632  CLRBIT(freep, bitmapbit);
633  MarkBufferDirty(mapbuf);
634 
635  /* if this is now the first free page, update hashm_firstfree */
636  if (ovflbitno < metap->hashm_firstfree)
637  {
638  metap->hashm_firstfree = ovflbitno;
639  update_metap = true;
640  MarkBufferDirty(metabuf);
641  }
642 
643  /* XLOG stuff */
644  if (RelationNeedsWAL(rel))
645  {
646  xl_hash_squeeze_page xlrec;
647  XLogRecPtr recptr;
648  int i;
649 
650  xlrec.prevblkno = prevblkno;
651  xlrec.nextblkno = nextblkno;
652  xlrec.ntups = nitups;
653  xlrec.is_prim_bucket_same_wrt = (wbuf == bucketbuf);
654  xlrec.is_prev_bucket_same_wrt = (wbuf == prevbuf);
655 
656  XLogBeginInsert();
657  XLogRegisterData((char *) &xlrec, SizeOfHashSqueezePage);
658 
659  /*
660  * bucket buffer needs to be registered to ensure that we can acquire
661  * a cleanup lock on it during replay.
662  */
663  if (!xlrec.is_prim_bucket_same_wrt)
665 
667  if (xlrec.ntups > 0)
668  {
669  XLogRegisterBufData(1, (char *) itup_offsets,
670  nitups * sizeof(OffsetNumber));
671  for (i = 0; i < nitups; i++)
672  XLogRegisterBufData(1, (char *) itups[i], tups_size[i]);
673  }
674 
675  XLogRegisterBuffer(2, ovflbuf, REGBUF_STANDARD);
676 
677  /*
678  * If prevpage and the writepage (block in which we are moving tuples
679  * from overflow) are same, then no need to separately register
680  * prevpage. During replay, we can directly update the nextblock in
681  * writepage.
682  */
683  if (BufferIsValid(prevbuf) && !xlrec.is_prev_bucket_same_wrt)
684  XLogRegisterBuffer(3, prevbuf, REGBUF_STANDARD);
685 
686  if (BufferIsValid(nextbuf))
687  XLogRegisterBuffer(4, nextbuf, REGBUF_STANDARD);
688 
690  XLogRegisterBufData(5, (char *) &bitmapbit, sizeof(uint32));
691 
692  if (update_metap)
693  {
694  XLogRegisterBuffer(6, metabuf, REGBUF_STANDARD);
695  XLogRegisterBufData(6, (char *) &metap->hashm_firstfree, sizeof(uint32));
696  }
697 
698  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_SQUEEZE_PAGE);
699 
700  PageSetLSN(BufferGetPage(wbuf), recptr);
701  PageSetLSN(BufferGetPage(ovflbuf), recptr);
702 
703  if (BufferIsValid(prevbuf) && !xlrec.is_prev_bucket_same_wrt)
704  PageSetLSN(BufferGetPage(prevbuf), recptr);
705  if (BufferIsValid(nextbuf))
706  PageSetLSN(BufferGetPage(nextbuf), recptr);
707 
708  PageSetLSN(BufferGetPage(mapbuf), recptr);
709 
710  if (update_metap)
711  PageSetLSN(BufferGetPage(metabuf), recptr);
712  }
713 
715 
716  /* release previous bucket if it is not same as write bucket */
717  if (BufferIsValid(prevbuf) && prevblkno != writeblkno)
718  _hash_relbuf(rel, prevbuf);
719 
720  if (BufferIsValid(ovflbuf))
721  _hash_relbuf(rel, ovflbuf);
722 
723  if (BufferIsValid(nextbuf))
724  _hash_relbuf(rel, nextbuf);
725 
726  _hash_relbuf(rel, mapbuf);
727  _hash_relbuf(rel, metabuf);
728 
729  return nextblkno;
730 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:368
uint16 hasho_page_id
Definition: hash.h:83
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
void _hash_pgaddmultitup(Relation rel, Buffer buf, IndexTuple *itups, OffsetNumber *itup_offsets, uint16 nitups)
Definition: hashinsert.c:299
#define HashPageGetBitmap(page)
Definition: hash.h:314
#define LH_BITMAP_PAGE
Definition: hash.h:56
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:595
#define LH_META_PAGE
Definition: hash.h:57
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1469
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, int access, int flags, BufferAccessStrategy bstrategy)
Definition: hashpage.c:238
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
signed int int32
Definition: c.h:362
BlockNumber prevblkno
Definition: hash_xlog.h:161
#define LH_UNUSED_PAGE
Definition: hash.h:53
bool is_prim_bucket_same_wrt
Definition: hash_xlog.h:164
uint16 OffsetNumber
Definition: off.h:24
#define HASH_READ
Definition: hash.h:337
uint32 Bucket
Definition: hash.h:35
#define SizeOfHashSqueezePage
Definition: hash_xlog.h:173
BlockNumber hasho_prevblkno
Definition: hash.h:79
#define ERROR
Definition: elog.h:43
BlockNumber nextblkno
Definition: hash_xlog.h:162
uint32 hashm_nmaps
Definition: hash.h:258
#define HASH_WRITE
Definition: hash.h:338
#define BMPG_MASK(metap)
Definition: hash.h:312
#define REGBUF_STANDARD
Definition: xloginsert.h:35
unsigned int uint32
Definition: c.h:374
#define BMPG_SHIFT(metap)
Definition: hash.h:311
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define HASH_XLOG_FREE_OVFL_BUFS
Definition: hash_xlog.h:22
#define ISSET(A, N)
Definition: hash.h:332
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:211
#define CLRBIT(x, i)
Definition: blutils.c:31
#define HASH_METAPAGE
Definition: hash.h:196
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
#define LH_OVERFLOW_PAGE
Definition: hash.h:54
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
uint32 hashm_firstfree
Definition: hash.h:257
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:55
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
bool is_prev_bucket_same_wrt
Definition: hash_xlog.h:167
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define REGBUF_NO_IMAGE
Definition: xloginsert.h:32
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition: xloginsert.c:149
#define HASHO_PAGE_ID
Definition: hash.h:99
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
#define RelationNeedsWAL(relation)
Definition: rel.h:562
uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno)
Definition: hashovfl.c:61
uint16 hasho_flag
Definition: hash.h:82
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2668
#define HashPageGetMeta(page)
Definition: hash.h:321
#define elog(elevel,...)
Definition: elog.h:214
int i
#define XLOG_HASH_SQUEEZE_PAGE
Definition: hash_xlog.h:36
BlockNumber hasho_nextblkno
Definition: hash.h:80
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
Definition: hash.h:262
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:121

◆ _hash_get_indextuple_hashkey()

uint32 _hash_get_indextuple_hashkey ( IndexTuple  itup)

Definition at line 292 of file hashutil.c.

References IndexInfoFindDataOffset, and IndexTupleData::t_info.

Referenced by _h_indexbuild(), _hash_binsearch(), _hash_binsearch_last(), _hash_doinsert(), _hash_load_qualified_items(), _hash_pgaddmultitup(), _hash_pgaddtup(), _hash_splitbucket(), hash_page_items(), and hashbucketcleanup().

293 {
294  char *attp;
295 
296  /*
297  * We assume the hash key is the first attribute and can't be null, so
298  * this can be done crudely but very very cheaply ...
299  */
300  attp = (char *) itup + IndexInfoFindDataOffset(itup->t_info);
301  return *((uint32 *) attp);
302 }
#define IndexInfoFindDataOffset(t_info)
Definition: itup.h:80
unsigned int uint32
Definition: c.h:374
unsigned short t_info
Definition: itup.h:49

◆ _hash_get_newblock_from_oldbucket()

BlockNumber _hash_get_newblock_from_oldbucket ( Relation  rel,
Bucket  old_bucket 
)

Definition at line 462 of file hashutil.c.

References _hash_get_newbucket_from_oldbucket(), _hash_getbuf(), _hash_relbuf(), BUCKET_TO_BLKNO, BufferGetPage, HASH_METAPAGE, HASH_READ, HashMetaPageData::hashm_lowmask, HashMetaPageData::hashm_maxbucket, HashPageGetMeta, and LH_META_PAGE.

Referenced by _hash_finish_split().

463 {
464  Bucket new_bucket;
465  Buffer metabuf;
466  HashMetaPage metap;
467  BlockNumber blkno;
468 
470  metap = HashPageGetMeta(BufferGetPage(metabuf));
471 
472  new_bucket = _hash_get_newbucket_from_oldbucket(rel, old_bucket,
473  metap->hashm_lowmask,
474  metap->hashm_maxbucket);
475  blkno = BUCKET_TO_BLKNO(metap, new_bucket);
476 
477  _hash_relbuf(rel, metabuf);
478 
479  return blkno;
480 }
#define LH_META_PAGE
Definition: hash.h:57
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
uint32 hashm_lowmask
Definition: hash.h:254
#define BUCKET_TO_BLKNO(metap, B)
Definition: hash.h:39
#define HASH_READ
Definition: hash.h:337
uint32 Bucket
Definition: hash.h:35
Bucket _hash_get_newbucket_from_oldbucket(Relation rel, Bucket old_bucket, uint32 lowmask, uint32 maxbucket)
Definition: hashutil.c:495
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define HASH_METAPAGE
Definition: hash.h:196
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
uint32 hashm_maxbucket
Definition: hash.h:252
#define HashPageGetMeta(page)
Definition: hash.h:321
int Buffer
Definition: buf.h:23

◆ _hash_get_newbucket_from_oldbucket()

Bucket _hash_get_newbucket_from_oldbucket ( Relation  rel,
Bucket  old_bucket,
uint32  lowmask,
uint32  maxbucket 
)

Definition at line 495 of file hashutil.c.

References CALC_NEW_BUCKET.

Referenced by _hash_get_newblock_from_oldbucket(), and hashbucketcleanup().

497 {
498  Bucket new_bucket;
499 
500  new_bucket = CALC_NEW_BUCKET(old_bucket, lowmask);
501  if (new_bucket > maxbucket)
502  {
503  lowmask = lowmask >> 1;
504  new_bucket = CALC_NEW_BUCKET(old_bucket, lowmask);
505  }
506 
507  return new_bucket;
508 }
#define CALC_NEW_BUCKET(old_bucket, lowmask)
Definition: hashutil.c:25
uint32 Bucket
Definition: hash.h:35

◆ _hash_get_oldblock_from_newbucket()

BlockNumber _hash_get_oldblock_from_newbucket ( Relation  rel,
Bucket  new_bucket 
)

Definition at line 423 of file hashutil.c.

References _hash_getbuf(), _hash_relbuf(), BUCKET_TO_BLKNO, BufferGetPage, fls(), HASH_METAPAGE, HASH_READ, HashPageGetMeta, and LH_META_PAGE.

Referenced by _hash_first().

424 {
425  Bucket old_bucket;
426  uint32 mask;
427  Buffer metabuf;
428  HashMetaPage metap;
429  BlockNumber blkno;
430 
431  /*
432  * To get the old bucket from the current bucket, we need a mask to modulo
433  * into lower half of table. This mask is stored in meta page as
434  * hashm_lowmask, but here we can't rely on the same, because we need a
435  * value of lowmask that was prevalent at the time when bucket split was
436  * started. Masking the most significant bit of new bucket would give us
437  * old bucket.
438  */
439  mask = (((uint32) 1) << (fls(new_bucket) - 1)) - 1;
440  old_bucket = new_bucket & mask;
441 
443  metap = HashPageGetMeta(BufferGetPage(metabuf));
444 
445  blkno = BUCKET_TO_BLKNO(metap, old_bucket);
446 
447  _hash_relbuf(rel, metabuf);
448 
449  return blkno;
450 }
#define LH_META_PAGE
Definition: hash.h:57
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define BUCKET_TO_BLKNO(metap, B)
Definition: hash.h:39
int fls(int mask)
Definition: fls.c:55
#define HASH_READ
Definition: hash.h:337
uint32 Bucket
Definition: hash.h:35
unsigned int uint32
Definition: c.h:374
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define HASH_METAPAGE
Definition: hash.h:196
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define HashPageGetMeta(page)
Definition: hash.h:321
int Buffer
Definition: buf.h:23

◆ _hash_get_totalbuckets()

uint32 _hash_get_totalbuckets ( uint32  splitpoint_phase)

Definition at line 175 of file hashutil.c.

References HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE, HASH_SPLITPOINT_PHASE_BITS, and HASH_SPLITPOINT_PHASE_MASK.

Referenced by _hash_expandtable(), _hash_init_metabuffer(), _hash_ovflblkno_to_bitno(), and bitno_to_blkno().

176 {
177  uint32 splitpoint_group;
178  uint32 total_buckets;
179  uint32 phases_within_splitpoint_group;
180 
181  if (splitpoint_phase < HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE)
182  return (1 << splitpoint_phase);
183 
184  /* get splitpoint's group */
185  splitpoint_group = HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE;
186  splitpoint_group +=
187  ((splitpoint_phase - HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE) >>
189 
190  /* account for buckets before splitpoint_group */
191  total_buckets = (1 << (splitpoint_group - 1));
192 
193  /* account for buckets within splitpoint_group */
194  phases_within_splitpoint_group =
195  (((splitpoint_phase - HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE) &
196  HASH_SPLITPOINT_PHASE_MASK) + 1); /* from 0-based to 1-based */
197  total_buckets +=
198  (((1 << (splitpoint_group - 1)) >> HASH_SPLITPOINT_PHASE_BITS) *
199  phases_within_splitpoint_group);
200 
201  return total_buckets;
202 }
#define HASH_SPLITPOINT_PHASE_MASK
Definition: hash.h:232
#define HASH_SPLITPOINT_PHASE_BITS
Definition: hash.h:230
unsigned int uint32
Definition: c.h:374
#define HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE
Definition: hash.h:233

◆ _hash_getbucketbuf_from_hashkey()

Buffer _hash_getbucketbuf_from_hashkey ( Relation  rel,
uint32  hashkey,
int  access,
HashMetaPage cachedmetap 
)

Definition at line 1555 of file hashpage.c.

References _hash_dropbuf(), _hash_getbuf(), _hash_getcachedmetap(), _hash_hashkey2bucket(), _hash_relbuf(), Assert, BUCKET_TO_BLKNO, buf, BufferGetPage, BufferIsValid, HASH_READ, HASH_WRITE, HashMetaPageData::hashm_highmask, HashMetaPageData::hashm_lowmask, HashMetaPageData::hashm_maxbucket, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_prevblkno, InvalidBlockNumber, InvalidBuffer, LH_BUCKET_PAGE, and PageGetSpecialPointer.

Referenced by _hash_doinsert(), and _hash_first().

1557 {
1558  HashMetaPage metap;
1559  Buffer buf;
1560  Buffer metabuf = InvalidBuffer;
1561  Page page;
1562  Bucket bucket;
1563  BlockNumber blkno;
1564  HashPageOpaque opaque;
1565 
1566  /* We read from target bucket buffer, hence locking is must. */
1567  Assert(access == HASH_READ || access == HASH_WRITE);
1568 
1569  metap = _hash_getcachedmetap(rel, &metabuf, false);
1570  Assert(metap != NULL);
1571 
1572  /*
1573  * Loop until we get a lock on the correct target bucket.
1574  */
1575  for (;;)
1576  {
1577  /*
1578  * Compute the target bucket number, and convert to block number.
1579  */
1580  bucket = _hash_hashkey2bucket(hashkey,
1581  metap->hashm_maxbucket,
1582  metap->hashm_highmask,
1583  metap->hashm_lowmask);
1584 
1585  blkno = BUCKET_TO_BLKNO(metap, bucket);
1586 
1587  /* Fetch the primary bucket page for the bucket */
1588  buf = _hash_getbuf(rel, blkno, access, LH_BUCKET_PAGE);
1589  page = BufferGetPage(buf);
1590  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
1591  Assert(opaque->hasho_bucket == bucket);
1593 
1594  /*
1595  * If this bucket hasn't been split, we're done.
1596  */
1597  if (opaque->hasho_prevblkno <= metap->hashm_maxbucket)
1598  break;
1599 
1600  /* Drop lock on this buffer, update cached metapage, and retry. */
1601  _hash_relbuf(rel, buf);
1602  metap = _hash_getcachedmetap(rel, &metabuf, true);
1603  Assert(metap != NULL);
1604  }
1605 
1606  if (BufferIsValid(metabuf))
1607  _hash_dropbuf(rel, metabuf);
1608 
1609  if (cachedmetap)
1610  *cachedmetap = metap;
1611 
1612  return buf;
1613 }
Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition: hashutil.c:126
uint32 hashm_highmask
Definition: hash.h:253
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
uint32 hashm_lowmask
Definition: hash.h:254
#define BUCKET_TO_BLKNO(metap, B)
Definition: hash.h:39
#define HASH_READ
Definition: hash.h:337
uint32 Bucket
Definition: hash.h:35
BlockNumber hasho_prevblkno
Definition: hash.h:79
static char * buf
Definition: pg_test_fsync.c:67
#define HASH_WRITE
Definition: hash.h:338
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
HashMetaPage _hash_getcachedmetap(Relation rel, Buffer *metabuf, bool force_refresh)
Definition: hashpage.c:1497
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define LH_BUCKET_PAGE
Definition: hash.h:55
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
uint32 hashm_maxbucket
Definition: hash.h:252
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ _hash_getbuf()

Buffer _hash_getbuf ( Relation  rel,
BlockNumber  blkno,
int  access,
int  flags 
)

Definition at line 69 of file hashpage.c.

References _hash_checkpage(), buf, elog, ERROR, HASH_NOLOCK, LockBuffer(), P_NEW, and ReadBuffer().

Referenced by _hash_addovflpage(), _hash_doinsert(), _hash_finish_split(), _hash_first(), _hash_freeovflpage(), _hash_get_newblock_from_oldbucket(), _hash_get_oldblock_from_newbucket(), _hash_getbucketbuf_from_hashkey(), _hash_getcachedmetap(), _hash_kill_items(), _hash_next(), _hash_readnext(), _hash_readprev(), _hash_splitbucket(), hash_bitmap_info(), hashbulkdelete(), and pgstathashindex().

70 {
71  Buffer buf;
72 
73  if (blkno == P_NEW)
74  elog(ERROR, "hash AM does not use P_NEW");
75 
76  buf = ReadBuffer(rel, blkno);
77 
78  if (access != HASH_NOLOCK)
79  LockBuffer(buf, access);
80 
81  /* ref count and lock type are correct */
82 
83  _hash_checkpage(rel, buf, flags);
84 
85  return buf;
86 }
#define P_NEW
Definition: bufmgr.h:91
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define HASH_NOLOCK
Definition: hash.h:339
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:211
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:607
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23

◆ _hash_getbuf_with_condlock_cleanup()

Buffer _hash_getbuf_with_condlock_cleanup ( Relation  rel,
BlockNumber  blkno,
int  flags 
)

Definition at line 95 of file hashpage.c.

References _hash_checkpage(), buf, ConditionalLockBufferForCleanup(), elog, ERROR, InvalidBuffer, P_NEW, ReadBuffer(), and ReleaseBuffer().

Referenced by _hash_expandtable().

96 {
97  Buffer buf;
98 
99  if (blkno == P_NEW)
100  elog(ERROR, "hash AM does not use P_NEW");
101 
102  buf = ReadBuffer(rel, blkno);
103 
105  {
106  ReleaseBuffer(buf);
107  return InvalidBuffer;
108  }
109 
110  /* ref count and lock type are correct */
111 
112  _hash_checkpage(rel, buf, flags);
113 
114  return buf;
115 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3518
#define P_NEW
Definition: bufmgr.h:91
bool ConditionalLockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3951
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:607
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23

◆ _hash_getbuf_with_strategy()

Buffer _hash_getbuf_with_strategy ( Relation  rel,
BlockNumber  blkno,
int  access,
int  flags,
BufferAccessStrategy  bstrategy 
)

Definition at line 238 of file hashpage.c.

References _hash_checkpage(), buf, elog, ERROR, HASH_NOLOCK, LockBuffer(), MAIN_FORKNUM, P_NEW, RBM_NORMAL, and ReadBufferExtended().

Referenced by _hash_freeovflpage(), _hash_squeezebucket(), hashbucketcleanup(), and pgstat_hash_page().

241 {
242  Buffer buf;
243 
244  if (blkno == P_NEW)
245  elog(ERROR, "hash AM does not use P_NEW");
246 
247  buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
248 
249  if (access != HASH_NOLOCK)
250  LockBuffer(buf, access);
251 
252  /* ref count and lock type are correct */
253 
254  _hash_checkpage(rel, buf, flags);
255 
256  return buf;
257 }
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:653
#define P_NEW
Definition: bufmgr.h:91
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define HASH_NOLOCK
Definition: hash.h:339
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:211
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23

◆ _hash_getcachedmetap()

HashMetaPage _hash_getcachedmetap ( Relation  rel,
Buffer metabuf,
bool  force_refresh 
)

Definition at line 1497 of file hashpage.c.

References _hash_getbuf(), Assert, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, BufferIsValid, HASH_METAPAGE, HASH_READ, HashPageGetMeta, LH_META_PAGE, LockBuffer(), MemoryContextAlloc(), RelationData::rd_amcache, and RelationData::rd_indexcxt.

Referenced by _hash_getbucketbuf_from_hashkey(), and hashbulkdelete().

1498 {
1499  Page page;
1500 
1501  Assert(metabuf);
1502  if (force_refresh || rel->rd_amcache == NULL)
1503  {
1504  char *cache = NULL;
1505 
1506  /*
1507  * It's important that we don't set rd_amcache to an invalid value.
1508  * Either MemoryContextAlloc or _hash_getbuf could fail, so don't
1509  * install a pointer to the newly-allocated storage in the actual
1510  * relcache entry until both have succeeded.
1511  */
1512  if (rel->rd_amcache == NULL)
1513  cache = MemoryContextAlloc(rel->rd_indexcxt,
1514  sizeof(HashMetaPageData));
1515 
1516  /* Read the metapage. */
1517  if (BufferIsValid(*metabuf))
1518  LockBuffer(*metabuf, BUFFER_LOCK_SHARE);
1519  else
1520  *metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ,
1521  LH_META_PAGE);
1522  page = BufferGetPage(*metabuf);
1523 
1524  /* Populate the cache. */
1525  if (rel->rd_amcache == NULL)
1526  rel->rd_amcache = cache;
1527  memcpy(rel->rd_amcache, HashPageGetMeta(page),
1528  sizeof(HashMetaPageData));
1529 
1530  /* Release metapage lock, but keep the pin. */
1531  LockBuffer(*metabuf, BUFFER_LOCK_UNLOCK);
1532  }
1533 
1534  return (HashMetaPage) rel->rd_amcache;
1535 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define LH_META_PAGE
Definition: hash.h:57
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define HASH_READ
Definition: hash.h:337
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define HASH_METAPAGE
Definition: hash.h:196
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
#define Assert(condition)
Definition: c.h:745
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
#define HashPageGetMeta(page)
Definition: hash.h:321
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
MemoryContext rd_indexcxt
Definition: rel.h:186
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
void * rd_amcache
Definition: rel.h:211
Pointer Page
Definition: bufpage.h:78

◆ _hash_getinitbuf()

Buffer _hash_getinitbuf ( Relation  rel,
BlockNumber  blkno 
)

Definition at line 134 of file hashpage.c.

References _hash_pageinit(), buf, BufferGetPage, BufferGetPageSize, elog, ERROR, MAIN_FORKNUM, P_NEW, RBM_ZERO_AND_LOCK, and ReadBufferExtended().

Referenced by _hash_addovflpage().

135 {
136  Buffer buf;
137 
138  if (blkno == P_NEW)
139  elog(ERROR, "hash AM does not use P_NEW");
140 
142  NULL);
143 
144  /* ref count and lock type are correct */
145 
146  /* initialize the page */
148 
149  return buf;
150 }
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:595
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:653
#define P_NEW
Definition: bufmgr.h:91
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23

◆ _hash_getnewbuf()

Buffer _hash_getnewbuf ( Relation  rel,
BlockNumber  blkno,
ForkNumber  forkNum 
)

Definition at line 197 of file hashpage.c.

References _hash_pageinit(), buf, BufferGetBlockNumber(), BufferGetPage, BufferGetPageSize, elog, ERROR, HASH_WRITE, LockBuffer(), P_NEW, RBM_NORMAL, RBM_ZERO_AND_LOCK, ReadBufferExtended(), RelationGetNumberOfBlocksInFork(), and RelationGetRelationName.

Referenced by _hash_addovflpage(), _hash_expandtable(), and _hash_init().

198 {
199  BlockNumber nblocks = RelationGetNumberOfBlocksInFork(rel, forkNum);
200  Buffer buf;
201 
202  if (blkno == P_NEW)
203  elog(ERROR, "hash AM does not use P_NEW");
204  if (blkno > nblocks)
205  elog(ERROR, "access to noncontiguous page in hash index \"%s\"",
207 
208  /* smgr insists we use P_NEW to extend the relation */
209  if (blkno == nblocks)
210  {
211  buf = ReadBufferExtended(rel, forkNum, P_NEW, RBM_NORMAL, NULL);
212  if (BufferGetBlockNumber(buf) != blkno)
213  elog(ERROR, "unexpected hash relation size: %u, should be %u",
214  BufferGetBlockNumber(buf), blkno);
215  LockBuffer(buf, HASH_WRITE);
216  }
217  else
218  {
219  buf = ReadBufferExtended(rel, forkNum, blkno, RBM_ZERO_AND_LOCK,
220  NULL);
221  }
222 
223  /* ref count and lock type are correct */
224 
225  /* initialize the page */
227 
228  return buf;
229 }
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:595
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:653
uint32 BlockNumber
Definition: block.h:31
#define P_NEW
Definition: bufmgr.h:91
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define HASH_WRITE
Definition: hash.h:338
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition: bufmgr.c:2855
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2668
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23

◆ _hash_hashkey2bucket()

Bucket _hash_hashkey2bucket ( uint32  hashkey,
uint32  maxbucket,
uint32  highmask,
uint32  lowmask 
)

Definition at line 126 of file hashutil.c.

Referenced by _h_indexbuild(), _hash_getbucketbuf_from_hashkey(), _hash_splitbucket(), comparetup_index_hash(), and hashbucketcleanup().

128 {
129  Bucket bucket;
130 
131  bucket = hashkey & highmask;
132  if (bucket > maxbucket)
133  bucket = bucket & lowmask;
134 
135  return bucket;
136 }
uint32 Bucket
Definition: hash.h:35

◆ _hash_init()

uint32 _hash_init ( Relation  rel,
double  num_tuples,
ForkNumber  forkNum 
)

Definition at line 326 of file hashpage.c.

References _hash_getnewbuf(), _hash_init_metabuffer(), _hash_initbitmapbuffer(), _hash_initbuf(), _hash_relbuf(), xl_hash_init_bitmap_page::bmsize, BUCKET_TO_BLKNO, buf, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, CHECK_FOR_INTERRUPTS, elog, ereport, errcode(), errmsg(), ERROR, xl_hash_init_meta_page::ffactor, HASH_MAX_BITMAPS, HASH_METAPAGE, HashGetTargetPageUsage, HashMetaPageData::hashm_bmsize, HashMetaPageData::hashm_ffactor, HashMetaPageData::hashm_mapp, HashMetaPageData::hashm_maxbucket, HashMetaPageData::hashm_nmaps, HashMetaPageData::hashm_procid, HashPageGetMeta, HASHSTANDARD_PROC, i, index_getprocid(), INIT_FORKNUM, LH_BUCKET_PAGE, LockBuffer(), log_newpage(), MarkBufferDirty(), MAXALIGN, xl_hash_init_meta_page::num_tuples, PageSetLSN, xl_hash_init_meta_page::procid, RelationData::rd_node, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetNumberOfBlocksInFork(), RelationGetRelationName, RelationNeedsWAL, SizeOfHashInitBitmapPage, SizeOfHashInitMetaPage, XLOG_HASH_INIT_BITMAP_PAGE, XLOG_HASH_INIT_META_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by hashbuild(), and hashbuildempty().

327 {
328  Buffer metabuf;
329  Buffer buf;
330  Buffer bitmapbuf;
331  Page pg;
332  HashMetaPage metap;
333  RegProcedure procid;
334  int32 data_width;
335  int32 item_width;
336  int32 ffactor;
337  uint32 num_buckets;
338  uint32 i;
339  bool use_wal;
340 
341  /* safety check */
342  if (RelationGetNumberOfBlocksInFork(rel, forkNum) != 0)
343  elog(ERROR, "cannot initialize non-empty hash index \"%s\"",
345 
346  /*
347  * WAL log creation of pages if the relation is persistent, or this is the
348  * init fork. Init forks for unlogged relations always need to be WAL
349  * logged.
350  */
351  use_wal = RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM;
352 
353  /*
354  * Determine the target fill factor (in tuples per bucket) for this index.
355  * The idea is to make the fill factor correspond to pages about as full
356  * as the user-settable fillfactor parameter says. We can compute it
357  * exactly since the index datatype (i.e. uint32 hash key) is fixed-width.
358  */
359  data_width = sizeof(uint32);
360  item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
361  sizeof(ItemIdData); /* include the line pointer */
362  ffactor = HashGetTargetPageUsage(rel) / item_width;
363  /* keep to a sane range */
364  if (ffactor < 10)
365  ffactor = 10;
366 
367  procid = index_getprocid(rel, 1, HASHSTANDARD_PROC);
368 
369  /*
370  * We initialize the metapage, the first N bucket pages, and the first
371  * bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
372  * calls to occur. This ensures that the smgr level has the right idea of
373  * the physical index length.
374  *
375  * Critical section not required, because on error the creation of the
376  * whole relation will be rolled back.
377  */
378  metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, forkNum);
379  _hash_init_metabuffer(metabuf, num_tuples, procid, ffactor, false);
380  MarkBufferDirty(metabuf);
381 
382  pg = BufferGetPage(metabuf);
383  metap = HashPageGetMeta(pg);
384 
385  /* XLOG stuff */
386  if (use_wal)
387  {
389  XLogRecPtr recptr;
390 
391  xlrec.num_tuples = num_tuples;
392  xlrec.procid = metap->hashm_procid;
393  xlrec.ffactor = metap->hashm_ffactor;
394 
395  XLogBeginInsert();
396  XLogRegisterData((char *) &xlrec, SizeOfHashInitMetaPage);
398 
399  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_INIT_META_PAGE);
400 
401  PageSetLSN(BufferGetPage(metabuf), recptr);
402  }
403 
404  num_buckets = metap->hashm_maxbucket + 1;
405 
406  /*
407  * Release buffer lock on the metapage while we initialize buckets.
408  * Otherwise, we'll be in interrupt holdoff and the CHECK_FOR_INTERRUPTS
409  * won't accomplish anything. It's a bad idea to hold buffer locks for
410  * long intervals in any case, since that can block the bgwriter.
411  */
412  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
413 
414  /*
415  * Initialize and WAL Log the first N buckets
416  */
417  for (i = 0; i < num_buckets; i++)
418  {
419  BlockNumber blkno;
420 
421  /* Allow interrupts, in case N is huge */
423 
424  blkno = BUCKET_TO_BLKNO(metap, i);
425  buf = _hash_getnewbuf(rel, blkno, forkNum);
426  _hash_initbuf(buf, metap->hashm_maxbucket, i, LH_BUCKET_PAGE, false);
427  MarkBufferDirty(buf);
428 
429  if (use_wal)
430  log_newpage(&rel->rd_node,
431  forkNum,
432  blkno,
433  BufferGetPage(buf),
434  true);
435  _hash_relbuf(rel, buf);
436  }
437 
438  /* Now reacquire buffer lock on metapage */
440 
441  /*
442  * Initialize bitmap page
443  */
444  bitmapbuf = _hash_getnewbuf(rel, num_buckets + 1, forkNum);
445  _hash_initbitmapbuffer(bitmapbuf, metap->hashm_bmsize, false);
446  MarkBufferDirty(bitmapbuf);
447 
448  /* add the new bitmap page to the metapage's list of bitmaps */
449  /* metapage already has a write lock */
450  if (metap->hashm_nmaps >= HASH_MAX_BITMAPS)
451  ereport(ERROR,
452  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
453  errmsg("out of overflow pages in hash index \"%s\"",
454  RelationGetRelationName(rel))));
455 
456  metap->hashm_mapp[metap->hashm_nmaps] = num_buckets + 1;
457 
458  metap->hashm_nmaps++;
459  MarkBufferDirty(metabuf);
460 
461  /* XLOG stuff */
462  if (use_wal)
463  {
465  XLogRecPtr recptr;
466 
467  xlrec.bmsize = metap->hashm_bmsize;
468 
469  XLogBeginInsert();
470  XLogRegisterData((char *) &xlrec, SizeOfHashInitBitmapPage);
471  XLogRegisterBuffer(0, bitmapbuf, REGBUF_WILL_INIT);
472 
473  /*
474  * This is safe only because nobody else can be modifying the index at
475  * this stage; it's only visible to the transaction that is creating
476  * it.
477  */
478  XLogRegisterBuffer(1, metabuf, REGBUF_STANDARD);
479 
480  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_INIT_BITMAP_PAGE);
481 
482  PageSetLSN(BufferGetPage(bitmapbuf), recptr);
483  PageSetLSN(BufferGetPage(metabuf), recptr);
484  }
485 
486  /* all done */
487  _hash_relbuf(rel, bitmapbuf);
488  _hash_relbuf(rel, metabuf);
489 
490  return num_buckets;
491 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
RegProcedure hashm_procid
Definition: hash.h:259
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1469
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
regproc RegProcedure
Definition: c.h:518
#define XLOG_HASH_INIT_BITMAP_PAGE
Definition: hash_xlog.h:28
uint16 hashm_ffactor
Definition: hash.h:247
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
Definition: hashpage.c:197
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#define HashGetTargetPageUsage(relation)
Definition: hash.h:279
signed int int32
Definition: c.h:362
#define BUCKET_TO_BLKNO(metap, B)
Definition: hash.h:39
#define ERROR
Definition: elog.h:43
#define SizeOfHashInitMetaPage
Definition: hash_xlog.h:223
void _hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid, uint16 ffactor, bool initpage)
Definition: hashpage.c:497
#define SizeOfHashInitBitmapPage
Definition: hash_xlog.h:239
uint32 hashm_nmaps
Definition: hash.h:258
static char * buf
Definition: pg_test_fsync.c:67
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define RelationGetRelationName(relation)
Definition: rel.h:490
unsigned int uint32
Definition: c.h:374
struct ItemIdData ItemIdData
#define XLOG_HASH_INIT_META_PAGE
Definition: hash_xlog.h:27
#define HASHSTANDARD_PROC
Definition: hash.h:353
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define HASH_MAX_BITMAPS
Definition: hash.h:228
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
#define HASH_METAPAGE
Definition: hash.h:196
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define ereport(elevel,...)
Definition: elog.h:144
void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage)
Definition: hashovfl.c:740
#define LH_BUCKET_PAGE
Definition: hash.h:55
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
Definition: bufmgr.c:2855
RelFileNode rd_node
Definition: rel.h:55
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void _hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket, uint32 flag, bool initpage)
Definition: hashpage.c:156
#define MAXALIGN(LEN)
Definition: c.h:698
#define RelationNeedsWAL(relation)
Definition: rel.h:562
uint32 hashm_maxbucket
Definition: hash.h:252
RegProcedure procid
Definition: hash_xlog.h:219
#define HashPageGetMeta(page)
Definition: hash.h:321
int errmsg(const char *fmt,...)
Definition: elog.c:824
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:996
#define elog(elevel,...)
Definition: elog.h:214
int i
uint16 hashm_bmsize
Definition: hash.h:249
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
Definition: hash.h:262
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:767

◆ _hash_init_metabuffer()

void _hash_init_metabuffer ( Buffer  buf,
double  num_tuples,
RegProcedure  procid,
uint16  ffactor,
bool  initpage 
)

Definition at line 497 of file hashpage.c.

References _hash_get_totalbuckets(), _hash_pageinit(), _hash_spareindex(), Assert, BMPG_MASK, BMPG_SHIFT, BufferGetPage, BufferGetPageSize, BYTE_TO_BIT, HASH_MAGIC, HASH_MAX_SPLITPOINTS, HASH_VERSION, HashGetMaxBitmapSize, HashMetaPageData::hashm_bmshift, HashMetaPageData::hashm_bmsize, HashMetaPageData::hashm_bsize, HashMetaPageData::hashm_ffactor, HashMetaPageData::hashm_firstfree, HashMetaPageData::hashm_highmask, HashMetaPageData::hashm_lowmask, HashMetaPageData::hashm_magic, HashMetaPageData::hashm_mapp, HashMetaPageData::hashm_maxbucket, HashMetaPageData::hashm_nmaps, HashMetaPageData::hashm_ntuples, HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_procid, HashMetaPageData::hashm_spares, HashMetaPageData::hashm_version, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetMeta, InvalidBlockNumber, LH_META_PAGE, MemSet, PageGetSpecialPointer, pg_leftmost_one_pos32(), and pg_nextpower2_32().

Referenced by _hash_init(), and hash_xlog_init_meta_page().

499 {
500  HashMetaPage metap;
501  HashPageOpaque pageopaque;
502  Page page;
503  double dnumbuckets;
504  uint32 num_buckets;
505  uint32 spare_index;
506  uint32 lshift;
507 
508  /*
509  * Choose the number of initial bucket pages to match the fill factor
510  * given the estimated number of tuples. We round up the result to the
511  * total number of buckets which has to be allocated before using its
512  * hashm_spares element. However always force at least 2 bucket pages. The
513  * upper limit is determined by considerations explained in
514  * _hash_expandtable().
515  */
516  dnumbuckets = num_tuples / ffactor;
517  if (dnumbuckets <= 2.0)
518  num_buckets = 2;
519  else if (dnumbuckets >= (double) 0x40000000)
520  num_buckets = 0x40000000;
521  else
522  num_buckets = _hash_get_totalbuckets(_hash_spareindex(dnumbuckets));
523 
524  spare_index = _hash_spareindex(num_buckets);
525  Assert(spare_index < HASH_MAX_SPLITPOINTS);
526 
527  page = BufferGetPage(buf);
528  if (initpage)
530 
531  pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
532  pageopaque->hasho_prevblkno = InvalidBlockNumber;
533  pageopaque->hasho_nextblkno = InvalidBlockNumber;
534  pageopaque->hasho_bucket = -1;
535  pageopaque->hasho_flag = LH_META_PAGE;
536  pageopaque->hasho_page_id = HASHO_PAGE_ID;
537 
538  metap = HashPageGetMeta(page);
539 
540  metap->hashm_magic = HASH_MAGIC;
541  metap->hashm_version = HASH_VERSION;
542  metap->hashm_ntuples = 0;
543  metap->hashm_nmaps = 0;
544  metap->hashm_ffactor = ffactor;
545  metap->hashm_bsize = HashGetMaxBitmapSize(page);
546 
547  /* find largest bitmap array size that will fit in page size */
548  lshift = pg_leftmost_one_pos32(metap->hashm_bsize);
549  Assert(lshift > 0);
550  metap->hashm_bmsize = 1 << lshift;
551  metap->hashm_bmshift = lshift + BYTE_TO_BIT;
552  Assert((1 << BMPG_SHIFT(metap)) == (BMPG_MASK(metap) + 1));
553 
554  /*
555  * Label the index with its primary hash support function's OID. This is
556  * pretty useless for normal operation (in fact, hashm_procid is not used
557  * anywhere), but it might be handy for forensic purposes so we keep it.
558  */
559  metap->hashm_procid = procid;
560 
561  /*
562  * We initialize the index with N buckets, 0 .. N-1, occupying physical
563  * blocks 1 to N. The first freespace bitmap page is in block N+1.
564  */
565  metap->hashm_maxbucket = num_buckets - 1;
566 
567  /*
568  * Set highmask as next immediate ((2 ^ x) - 1), which should be
569  * sufficient to cover num_buckets.
570  */
571  metap->hashm_highmask = pg_nextpower2_32(num_buckets + 1) - 1;
572  metap->hashm_lowmask = (metap->hashm_highmask >> 1);
573 
574  MemSet(metap->hashm_spares, 0, sizeof(metap->hashm_spares));
575  MemSet(metap->hashm_mapp, 0, sizeof(metap->hashm_mapp));
576 
577  /* Set up mapping for one spare page after the initial splitpoints */
578  metap->hashm_spares[spare_index] = 1;
579  metap->hashm_ovflpoint = spare_index;
580  metap->hashm_firstfree = 0;
581 
582  /*
583  * Set pd_lower just past the end of the metadata. This is essential,
584  * because without doing so, metadata will be lost if xlog.c compresses
585  * the page.
586  */
587  ((PageHeader) page)->pd_lower =
588  ((char *) metap + sizeof(HashMetaPageData)) - (char *) page;
589 }
uint16 hashm_bmshift
Definition: hash.h:251
uint16 hasho_page_id
Definition: hash.h:83
RegProcedure hashm_procid
Definition: hash.h:259
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:595
#define LH_META_PAGE
Definition: hash.h:57
#define BYTE_TO_BIT
Definition: hash.h:299
uint32 hashm_magic
Definition: hash.h:244
uint16 hashm_ffactor
Definition: hash.h:247
uint32 hashm_highmask
Definition: hash.h:253
#define MemSet(start, val, len)
Definition: c.h:949
static int pg_leftmost_one_pos32(uint32 word)
Definition: pg_bitutils.h:32
#define HASH_VERSION
Definition: hash.h:199
uint32 hashm_lowmask
Definition: hash.h:254
#define HASH_MAX_SPLITPOINTS
Definition: hash.h:237
#define HASH_MAGIC
Definition: hash.h:198
#define HashGetMaxBitmapSize(page)
Definition: hash.h:317
BlockNumber hasho_prevblkno
Definition: hash.h:79
uint32 _hash_spareindex(uint32 num_bucket)
Definition: hashutil.c:143
uint32 _hash_get_totalbuckets(uint32 splitpoint_phase)
Definition: hashutil.c:175
uint32 hashm_version
Definition: hash.h:245
uint32 hashm_nmaps
Definition: hash.h:258
static char * buf
Definition: pg_test_fsync.c:67
#define BMPG_MASK(metap)
Definition: hash.h:312
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:146
unsigned int uint32
Definition: c.h:374
#define BMPG_SHIFT(metap)
Definition: hash.h:311
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
uint32 hashm_ovflpoint
Definition: hash.h:255
uint16 hashm_bsize
Definition: hash.h:248
double hashm_ntuples
Definition: hash.h:246
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
uint32 hashm_firstfree
Definition: hash.h:257
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
Definition: hash.h:260
PageHeaderData * PageHeader
Definition: bufpage.h:166
#define Assert(condition)
Definition: c.h:745
Bucket hasho_bucket
Definition: hash.h:81
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define HASHO_PAGE_ID
Definition: hash.h:99
uint32 hashm_maxbucket
Definition: hash.h:252
uint16 hasho_flag
Definition: hash.h:82
#define HashPageGetMeta(page)
Definition: hash.h:321
BlockNumber hasho_nextblkno
Definition: hash.h:80
uint16 hashm_bmsize
Definition: hash.h:249
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
Definition: hash.h:262
Pointer Page
Definition: bufpage.h:78

◆ _hash_initbitmapbuffer()

void _hash_initbitmapbuffer ( Buffer  buf,
uint16  bmsize,
bool  initpage 
)

Definition at line 740 of file hashovfl.c.

References _hash_pageinit(), BufferGetPage, BufferGetPageSize, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetBitmap, InvalidBlockNumber, LH_BITMAP_PAGE, MemSet, and PageGetSpecialPointer.

Referenced by _hash_addovflpage(), _hash_init(), hash_xlog_add_ovfl_page(), and hash_xlog_init_bitmap_page().

741 {
742  Page pg;
743  HashPageOpaque op;
744  uint32 *freep;
745 
746  pg = BufferGetPage(buf);
747 
748  /* initialize the page */
749  if (initpage)
751 
752  /* initialize the page's special space */
756  op->hasho_bucket = -1;
759 
760  /* set all of the bits to 1 */
761  freep = HashPageGetBitmap(pg);
762  MemSet(freep, 0xFF, bmsize);
763 
764  /*
765  * Set pd_lower just past the end of the bitmap page data. We could even
766  * set pd_lower equal to pd_upper, but this is more precise and makes the
767  * page look compressible to xlog.c.
768  */
769  ((PageHeader) pg)->pd_lower = ((char *) freep + bmsize) - (char *) pg;
770 }
uint16 hasho_page_id
Definition: hash.h:83
#define HashPageGetBitmap(page)
Definition: hash.h:314
#define LH_BITMAP_PAGE
Definition: hash.h:56
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:595
#define MemSet(start, val, len)
Definition: c.h:949
BlockNumber hasho_prevblkno
Definition: hash.h:79
static char * buf
Definition: pg_test_fsync.c:67
unsigned int uint32
Definition: c.h:374
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
PageHeaderData * PageHeader
Definition: bufpage.h:166
Bucket hasho_bucket
Definition: hash.h:81
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define HASHO_PAGE_ID
Definition: hash.h:99
uint16 hasho_flag
Definition: hash.h:82
BlockNumber hasho_nextblkno
Definition: hash.h:80
Pointer Page
Definition: bufpage.h:78

◆ _hash_initbuf()

void _hash_initbuf ( Buffer  buf,
uint32  max_bucket,
uint32  num_bucket,
uint32  flag,
bool  initpage 
)

Definition at line 156 of file hashpage.c.

References _hash_pageinit(), BufferGetPage, BufferGetPageSize, flag(), HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, InvalidBlockNumber, and PageGetSpecialPointer.

Referenced by _hash_init(), hash_xlog_add_ovfl_page(), and hash_xlog_split_allocate_page().

158 {
159  HashPageOpaque pageopaque;
160  Page page;
161 
162  page = BufferGetPage(buf);
163 
164  /* initialize the page */
165  if (initpage)
167 
168  pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
169 
170  /*
171  * Set hasho_prevblkno with current hashm_maxbucket. This value will be
172  * used to validate cached HashMetaPageData. See
173  * _hash_getbucketbuf_from_hashkey().
174  */
175  pageopaque->hasho_prevblkno = max_bucket;
176  pageopaque->hasho_nextblkno = InvalidBlockNumber;
177  pageopaque->hasho_bucket = num_bucket;
178  pageopaque->hasho_flag = flag;
179  pageopaque->hasho_page_id = HASHO_PAGE_ID;
180 }
uint16 hasho_page_id
Definition: hash.h:83
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:595
BlockNumber hasho_prevblkno
Definition: hash.h:79
static char * buf
Definition: pg_test_fsync.c:67
char * flag(int b)
Definition: test-ctype.c:33
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
Bucket hasho_bucket
Definition: hash.h:81
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
#define HASHO_PAGE_ID
Definition: hash.h:99
uint16 hasho_flag
Definition: hash.h:82
BlockNumber hasho_nextblkno
Definition: hash.h:80
Pointer Page
Definition: bufpage.h:78

◆ _hash_kill_items()

void _hash_kill_items ( IndexScanDesc  scan)

Definition at line 537 of file hashutil.c.

References _hash_getbuf(), _hash_relbuf(), Assert, buf, HashScanPosData::buf, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, HashScanPosData::currPage, HashScanOpaqueData::currPos, HashScanPosData::firstItem, HASH_READ, HashScanPosIsPinned, HashScanPosIsValid, HashScanOpaqueData::hashso_bucket_buf, HashScanPosItem::heapTid, i, HashScanPosItem::indexOffset, IndexScanDescData::indexRelation, ItemIdMarkDead, ItemPointerEquals(), HashScanPosData::items, HashScanOpaqueData::killedItems, LH_OVERFLOW_PAGE, LH_PAGE_HAS_DEAD_TUPLES, LockBuffer(), MarkBufferDirtyHint(), HashScanOpaqueData::numKilled, OffsetNumberNext, IndexScanDescData::opaque, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, and IndexTupleData::t_tid.

Referenced by _hash_next(), _hash_readpage(), hashendscan(), and hashrescan().

538 {
539  HashScanOpaque so = (HashScanOpaque) scan->opaque;
540  Relation rel = scan->indexRelation;
541  BlockNumber blkno;
542  Buffer buf;
543  Page page;
544  HashPageOpaque opaque;
545  OffsetNumber offnum,
546  maxoff;
547  int numKilled = so->numKilled;
548  int i;
549  bool killedsomething = false;
550  bool havePin = false;
551 
552  Assert(so->numKilled > 0);
553  Assert(so->killedItems != NULL);
555 
556  /*
557  * Always reset the scan state, so we don't look for same items on other
558  * pages.
559  */
560  so->numKilled = 0;
561 
562  blkno = so->currPos.currPage;
563  if (HashScanPosIsPinned(so->currPos))
564  {
565  /*
566  * We already have pin on this buffer, so, all we need to do is
567  * acquire lock on it.
568  */
569  havePin = true;
570  buf = so->currPos.buf;
572  }
573  else
574  buf = _hash_getbuf(rel, blkno, HASH_READ, LH_OVERFLOW_PAGE);
575 
576  page = BufferGetPage(buf);
577  opaque = (HashPageOpaque) PageGetSpecialPointer(page);
578  maxoff = PageGetMaxOffsetNumber(page);
579 
580  for (i = 0; i < numKilled; i++)
581  {
582  int itemIndex = so->killedItems[i];
583  HashScanPosItem *currItem = &so->currPos.items[itemIndex];
584 
585  offnum = currItem->indexOffset;
586 
587  Assert(itemIndex >= so->currPos.firstItem &&
588  itemIndex <= so->currPos.lastItem);
589 
590  while (offnum <= maxoff)
591  {
592  ItemId iid = PageGetItemId(page, offnum);
593  IndexTuple ituple = (IndexTuple) PageGetItem(page, iid);
594 
595  if (ItemPointerEquals(&ituple->t_tid, &currItem->heapTid))
596  {
597  /* found the item */
598  ItemIdMarkDead(iid);
599  killedsomething = true;
600  break; /* out of inner search loop */
601  }
602  offnum = OffsetNumberNext(offnum);
603  }
604  }
605 
606  /*
607  * Since this can be redone later if needed, mark as dirty hint. Whenever
608  * we mark anything LP_DEAD, we also set the page's
609  * LH_PAGE_HAS_DEAD_TUPLES flag, which is likewise just a hint.
610  */
611  if (killedsomething)
612  {
613  opaque->hasho_flag |= LH_PAGE_HAS_DEAD_TUPLES;
614  MarkBufferDirtyHint(buf, true);
615  }
616 
617  if (so->hashso_bucket_buf == so->currPos.buf ||
618  havePin)
620  else
621  _hash_relbuf(rel, buf);
622 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:190
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:3588
#define ItemIdMarkDead(itemId)
Definition: itemid.h:179
#define HashScanPosIsPinned(scanpos)
Definition: hash.h:128
#define HashScanPosIsValid(scanpos)
Definition: hash.h:135
ItemPointerData t_tid
Definition: itup.h:37
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
Relation indexRelation
Definition: relscan.h:115
uint16 OffsetNumber
Definition: off.h:24
#define HASH_READ
Definition: hash.h:337
int * killedItems
Definition: hash.h:180
static char * buf
Definition: pg_test_fsync.c:67
IndexTupleData * IndexTuple
Definition: itup.h:53
BlockNumber currPage
Definition: hash.h:110
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Buffer hashso_bucket_buf
Definition: hash.h:162
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
Buffer buf
Definition: hash.h:109
#define LH_OVERFLOW_PAGE
Definition: hash.h:54
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3757
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:265
#define Assert(condition)
Definition: c.h:745
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:86
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
HashScanPosData currPos
Definition: hash.h:187
OffsetNumber indexOffset
Definition: hash.h:104
int i
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
ItemPointerData heapTid
Definition: hash.h:103
int firstItem
Definition: hash.h:121
int Buffer
Definition: buf.h:23
#define LH_PAGE_HAS_DEAD_TUPLES
Definition: hash.h:61
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:125

◆ _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, TestForOldSnapshot(), IndexScanDescData::xs_heaptid, 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_heaptid = currItem->heapTid;
123 
124  return true;
125 }
HashScanOpaqueData * HashScanOpaque
Definition: hash.h:190
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:277
void _hash_dropscanbuf(Relation rel, HashScanOpaque so)
Definition: hashpage.c:288
static bool _hash_readpage(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
Definition: hashsearch.c:452
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
struct SnapshotData * xs_snapshot
Definition: relscan.h:116
uint32 BlockNumber
Definition: block.h:31
void _hash_dropbuf(Relation rel, Buffer buf)
Definition: hashpage.c:276
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:69
Relation indexRelation
Definition: relscan.h:115
#define HASH_READ
Definition: hash.h:337
ItemPointerData xs_heaptid
Definition: relscan.h:144
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Buffer hashso_bucket_buf
Definition: hash.h:162
#define HashScanPosInvalidate(scanpos)
Definition: hash.h:142
#define LH_OVERFLOW_PAGE
Definition: hash.h:54
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:55
int lastItem
Definition: hash.h:122
void _hash_kill_items(IndexScanDesc scan)
Definition: hashutil.c:537
HashScanPosData currPos
Definition: hash.h:187
Buffer hashso_split_bucket_buf
Definition: hash.h:169
BlockNumber nextPage
Definition: hash.h:111
int itemIndex
Definition: hash.h:123
int firstItem
Definition: hash.h:121
BlockNumber prevPage
Definition: hash.h:112
int Buffer
Definition: buf.h:23
HashScanPosItem items[MaxIndexTuplesPerPage]
Definition: hash.h:125

◆ _hash_ovflblkno_to_bitno()

uint32 _hash_ovflblkno_to_bitno ( HashMetaPage  metap,
BlockNumber  ovflblkno 
)

Definition at line 61 of file hashovfl.c.

References _hash_get_totalbuckets(), ereport, errcode(), errmsg(), ERROR, HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_spares, and i.

Referenced by _hash_freeovflpage(), and hash_bitmap_info().

62 {
63  uint32 splitnum = metap->hashm_ovflpoint;
64  uint32 i;
65  uint32 bitnum;
66 
67  /* Determine the split number containing this page */
68  for (i = 1; i <= splitnum; i++)
69  {
70  if (ovflblkno <= (BlockNumber) _hash_get_totalbuckets(i))
71  break; /* oops */
72  bitnum = ovflblkno - _hash_get_totalbuckets(i);
73 
74  /*
75  * bitnum has to be greater than number of overflow page added in
76  * previous split point. The overflow page at this splitnum (i) if any
77  * should start from (_hash_get_totalbuckets(i) +
78  * metap->hashm_spares[i - 1] + 1).
79  */
80  if (bitnum > metap->hashm_spares[i - 1] &&
81  bitnum <= metap->hashm_spares[i])
82  return bitnum - 1; /* -1 to convert 1-based to 0-based */
83  }
84 
85  ereport(ERROR,
86  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
87  errmsg("invalid overflow block number %u", ovflblkno)));
88  return 0; /* keep compiler quiet */
89 }
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: