1/*-------------------------------------------------------------------------
4 * Hash table page management code for the Postgres hash access method
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/hash/hashpage.c
14 * Postgres hash pages look like ordinary relation pages. The opaque
15 * data at high addresses includes information about the page including
16 * whether a page is an overflow page or a true bucket, the bucket
17 * number, and the block numbers of the preceding and following pages
20 * The first page in a hash relation, page zero, is special -- it stores
21 * information describing the hash table; it is referred to as the
22 * "meta page." Pages one and higher store the actual data.
24 * There are also bitmap pages, which are not manipulated here;
27 *-------------------------------------------------------------------------
53 * _hash_getbuf() -- Get a buffer by block number for read or write.
55 * 'access' must be HASH_READ, HASH_WRITE, or HASH_NOLOCK.
56 * 'flags' is a bitwise OR of the allowed page types.
58 * This must be used only to fetch pages that are expected to be valid
59 * already. _hash_checkpage() is applied using the given flags.
61 * When this routine returns, the appropriate lock is set on the
62 * requested buffer and its reference count has been incremented
63 * (ie, the buffer is "locked and pinned").
65 * P_NEW is disallowed because this routine can only be used
66 * to access pages that are known to be before the filesystem EOF.
67 * Extending the index should be done with _hash_getnewbuf.
75 elog(
ERROR,
"hash AM does not use P_NEW");
82 /* ref count and lock type are correct */
90 * _hash_getbuf_with_condlock_cleanup() -- Try to get a buffer for cleanup.
92 * We read the page and try to acquire a cleanup lock. If we get it,
93 * we return the buffer; otherwise, we return InvalidBuffer.
101 elog(
ERROR,
"hash AM does not use P_NEW");
111 /* ref count and lock type are correct */
119 * _hash_getinitbuf() -- Get and initialize a buffer by block number.
121 * This must be used only to fetch pages that are known to be before
122 * the index's filesystem EOF, but are to be filled from scratch.
123 * _hash_pageinit() is applied automatically. Otherwise it has
124 * effects similar to _hash_getbuf() with access = HASH_WRITE.
126 * When this routine returns, a write lock is set on the
127 * requested buffer and its reference count has been incremented
128 * (ie, the buffer is "locked and pinned").
130 * P_NEW is disallowed because this routine can only be used
131 * to access pages that are known to be before the filesystem EOF.
132 * Extending the index should be done with _hash_getnewbuf.
140 elog(
ERROR,
"hash AM does not use P_NEW");
145 /* ref count and lock type are correct */
147 /* initialize the page */
154 * _hash_initbuf() -- Get and initialize a buffer by bucket number.
165 /* initialize the page */
172 * Set hasho_prevblkno with current hashm_maxbucket. This value will be
173 * used to validate cached HashMetaPageData. See
174 * _hash_getbucketbuf_from_hashkey().
184 * _hash_getnewbuf() -- Get a new page at the end of the index.
186 * This has the same API as _hash_getinitbuf, except that we are adding
187 * a page to the index, and hence expect the page to be past the
188 * logical EOF. (However, we have to support the case where it isn't,
189 * since a prior try might have crashed after extending the filesystem
190 * EOF but before updating the metapage to reflect the added page.)
192 * It is caller's responsibility to ensure that only one process can
193 * extend the index at a time. In practice, this function is called
194 * only while holding write lock on the metapage, because adding a page
195 * is always associated with an update of metapage data.
204 elog(
ERROR,
"hash AM does not use P_NEW");
206 elog(
ERROR,
"access to noncontiguous page in hash index \"%s\"",
209 /* smgr insists we explicitly extend the relation */
210 if (blkno == nblocks)
215 elog(
ERROR,
"unexpected hash relation size: %u, should be %u",
224 /* ref count and lock type are correct */
226 /* initialize the page */
233 * _hash_getbuf_with_strategy() -- Get a buffer with nondefault strategy.
235 * This is identical to _hash_getbuf() but also allows a buffer access
236 * strategy to be specified. We use this for VACUUM operations.
246 elog(
ERROR,
"hash AM does not use P_NEW");
253 /* ref count and lock type are correct */
261 * _hash_relbuf() -- release a locked buffer.
263 * Lock and pin (refcount) are both dropped.
272 * _hash_dropbuf() -- release an unlocked buffer.
274 * This is used to unpin a buffer on which we hold no lock.
283 * _hash_dropscanbuf() -- release buffers used in scan.
285 * This routine unpins the buffers used during scan on which we
291 /* release pin we hold on primary bucket page */
297 /* release pin we hold on primary bucket page of bucket being split */
303 /* release any pin we still hold */
308 /* reset split scan */
315 * _hash_init() -- Initialize the metadata page of a hash index,
316 * the initial buckets, and the initial bitmap page.
318 * The initial number of buckets is dependent on num_tuples, an estimate
319 * of the number of tuples to be loaded into the index initially. The
320 * chosen number of buckets is returned.
322 * We are fairly cavalier about locking here, since we know that no one else
323 * could be accessing this index. In particular the rule about not holding
324 * multiple buffer locks is ignored.
344 elog(
ERROR,
"cannot initialize non-empty hash index \"%s\"",
348 * WAL log creation of pages if the relation is persistent, or this is the
349 * init fork. Init forks for unlogged relations always need to be WAL
355 * Determine the target fill factor (in tuples per bucket) for this index.
356 * The idea is to make the fill factor correspond to pages about as full
357 * as the user-settable fillfactor parameter says. We can compute it
358 * exactly since the index datatype (i.e. uint32 hash key) is fixed-width.
360 data_width =
sizeof(
uint32);
362 sizeof(
ItemIdData);
/* include the line pointer */
364 /* keep to a sane range */
371 * We initialize the metapage, the first N bucket pages, and the first
372 * bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
373 * calls to occur. This ensures that the smgr level has the right idea of
374 * the physical index length.
376 * Critical section not required, because on error the creation of the
377 * whole relation will be rolled back.
408 * Release buffer lock on the metapage while we initialize buckets.
409 * Otherwise, we'll be in interrupt holdoff and the CHECK_FOR_INTERRUPTS
410 * won't accomplish anything. It's a bad idea to hold buffer locks for
411 * long intervals in any case, since that can block the bgwriter.
416 * Initialize and WAL Log the first N buckets
418 for (
i = 0;
i < num_buckets;
i++)
422 /* Allow interrupts, in case N is huge */
439 /* Now reacquire buffer lock on metapage */
443 * Initialize bitmap page
449 /* add the new bitmap page to the metapage's list of bitmaps */
450 /* metapage already has a write lock */
453 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
454 errmsg(
"out of overflow pages in hash index \"%s\"",
475 * This is safe only because nobody else can be modifying the index at
476 * this stage; it's only visible to the transaction that is creating
495 * _hash_init_metabuffer() -- Initialize the metadata page of a hash index.
499 uint16 ffactor,
bool initpage)
510 * Choose the number of initial bucket pages to match the fill factor
511 * given the estimated number of tuples. We round up the result to the
512 * total number of buckets which has to be allocated before using its
513 * hashm_spares element. However always force at least 2 bucket pages. The
514 * upper limit is determined by considerations explained in
515 * _hash_expandtable().
517 dnumbuckets = num_tuples / ffactor;
518 if (dnumbuckets <= 2.0)
520 else if (dnumbuckets >= (
double) 0x40000000)
521 num_buckets = 0x40000000;
548 /* find largest bitmap array size that will fit in page size */
556 * Label the index with its primary hash support function's OID. This is
557 * pretty useless for normal operation (in fact, hashm_procid is not used
558 * anywhere), but it might be handy for forensic purposes so we keep it.
563 * We initialize the index with N buckets, 0 .. N-1, occupying physical
564 * blocks 1 to N. The first freespace bitmap page is in block N+1.
569 * Set highmask as next immediate ((2 ^ x) - 1), which should be
570 * sufficient to cover num_buckets.
578 /* Set up mapping for one spare page after the initial splitpoints */
584 * Set pd_lower just past the end of the metadata. This is essential,
585 * because without doing so, metadata will be lost if xlog.c compresses
593 * _hash_pageinit() -- Initialize a new hash index page.
602 * Attempt to expand the hash table by creating one new bucket.
604 * This will silently do nothing if we don't get cleanup lock on old or
607 * Complete the pending splits and remove the tuples from old bucket,
608 * if there are any left over from the previous split.
610 * The caller must hold a pin, but no lock, on the metapage buffer.
611 * The buffer is returned in the same state.
631 bool metap_update_masks =
false;
632 bool metap_update_splitpoint =
false;
637 * Write-lock the meta page. It used to be necessary to acquire a
638 * heavyweight lock to begin a split, but that is no longer required.
646 * Check to see if split is still needed; someone else might have already
647 * done one while we waited for the lock.
649 * Make sure this stays in sync with _hash_doinsert()
656 * Can't split anymore if maxbucket has reached its maximum possible
659 * Ideally we'd allow bucket numbers up to UINT_MAX-1 (no higher because
660 * the calculation maxbucket+1 mustn't overflow). Currently we restrict
661 * to half that to prevent failure of pg_ceil_log2_32() and insufficient
662 * space in hashm_spares[]. It's moot anyway because an index with 2^32
663 * buckets would certainly overflow BlockNumber and hence
664 * _hash_alloc_buckets() would fail, but if we supported buckets smaller
665 * than a disk block then this would be an independent constraint.
667 * If you change this, see also the maximum initial number of buckets in
674 * Determine which bucket is to be split, and attempt to take cleanup lock
675 * on the old bucket. If we can't get the lock, give up.
677 * The cleanup lock protects us not only against other backends, but
678 * against our own backend as well.
680 * The cleanup lock is mainly to protect the split from concurrent
681 * inserts. See src/backend/access/hash/README, Lock Definitions for
682 * further details. Due to this locking restriction, if there is any
683 * pending scan, the split will give up which is not good, but harmless.
699 * We want to finish the split from a bucket as there is no apparent
700 * benefit by not doing so and it will make the code complicated to finish
701 * the split that involves multiple buckets considering the case where new
702 * split also fails. We don't need to consider the new bucket for
703 * completing the split here as it is not possible that a re-split of new
704 * bucket starts when there is still a pending split from old bucket.
709 * Copy bucket mapping info now; refer the comment in code below where
710 * we copy this information before calling _hash_splitbucket to see
718 * Release the lock on metapage and old_bucket, before completing the
727 /* release the pin on old buffer and retry for expand. */
734 * Clean the tuples remained from the previous split. This operation
735 * requires cleanup lock and we already have one on the old bucket, so
736 * let's do it. We also don't want to allow further splits from the bucket
737 * till the garbage of previous split is cleaned. This has two
738 * advantages; first, it helps in avoiding the bloat due to garbage and
739 * second is, during cleanup of bucket, we are always sure that the
740 * garbage tuples belong to most recently split bucket. On the contrary,
741 * if we allow cleanup of bucket after meta page is updated to indicate
742 * the new split and before the actual split, the cleanup operation won't
743 * be able to decide whether the tuple has been moved to the newly created
744 * bucket and ended up deleting such tuples.
749 * Copy bucket mapping info now; refer to the comment in code below
750 * where we copy this information before calling _hash_splitbucket to
751 * see why this is okay.
757 /* Release the metapage lock. */
761 maxbucket, highmask, lowmask, NULL, NULL,
true,
770 * There shouldn't be any active scan on new bucket.
772 * Note: it is safe to compute the new bucket's blkno here, even though we
773 * may still need to update the BUCKET_TO_BLKNO mapping. This is because
774 * the current value of hashm_spares[hashm_ovflpoint] correctly shows
775 * where we are going to put a new splitpoint's worth of buckets.
780 * If the split point is increasing we need to allocate a new batch of
791 * We treat allocation of buckets as a separate WAL-logged action.
792 * Even if we fail after this operation, won't leak bucket pages;
793 * rather, the next split will consume this space. In any case, even
794 * without failure we don't use all the space in one split operation.
799 /* can't split due to BlockNumber overflow */
806 * Physically allocate the new bucket's primary page. We want to do this
807 * before changing the metapage's mapping info, in case we can't get the
810 * XXX It doesn't make sense to call _hash_getnewbuf first, zeroing the
811 * buffer, and then only afterwards check whether we have a cleanup lock.
812 * However, since no scan can be accessing the buffer yet, any concurrent
813 * accesses will just be from processes like the bgwriter or checkpointer
814 * which don't care about its contents, so it doesn't really matter.
825 * Since we are scribbling on the pages in the shared buffers, establish a
826 * critical section. Any failure in this next code leaves us with a big
827 * problem: the metapage is effectively corrupt but could get written back
833 * Okay to proceed with split. Update the metapage bucket mapping info.
839 /* Starting a new doubling */
842 metap_update_masks =
true;
846 * If the split point is increasing we need to adjust the hashm_spares[]
847 * array and hashm_ovflpoint so that future overflow pages will be created
848 * beyond this new batch of bucket pages.
854 metap_update_splitpoint =
true;
860 * Copy bucket mapping info now; this saves re-accessing the meta page
861 * inside _hash_splitbucket's inner loop. Note that once we drop the
862 * split lock, other splits could begin, so these values might be out of
863 * date before _hash_splitbucket finishes. That's okay, since all it
864 * needs is to tell which of these two buckets to map hashkeys into.
874 * Mark the old bucket to indicate that split is in progress. (At
875 * operation end, we will clear the split-in-progress flag.) Also, for a
876 * primary bucket page, hasho_prevblkno stores the number of buckets that
877 * existed as of the last split, so we must update that value here.
887 * initialize the new bucket's primary page and mark it to indicate that
888 * split is in progress.
916 if (metap_update_masks)
923 if (metap_update_splitpoint)
944 /* drop lock, but keep pin */
947 /* Relocate records to the new bucket */
949 old_bucket, new_bucket,
950 buf_oblkno, buf_nblkno, NULL,
951 maxbucket, highmask, lowmask);
953 /* all done, now release the pins on primary buckets. */
959 /* Here if decide not to split or fail to acquire old bucket lock */
962 /* We didn't write the metapage, so just drop lock */
968 * _hash_alloc_buckets -- allocate a new splitpoint's worth of bucket pages
970 * This does not need to initialize the new bucket pages; we'll do that as
971 * each one is used by _hash_expandtable(). But we have to extend the logical
972 * EOF to the end of the splitpoint; this keeps smgr's idea of the EOF in
973 * sync with ours, so that we don't get complaints from smgr.
975 * We do this by writing a page of zeroes at the end of the splitpoint range.
976 * We expect that the filesystem will ensure that the intervening pages read
977 * as zeroes too. On many filesystems this "hole" will not be allocated
978 * immediately, which means that the index file may end up more fragmented
979 * than if we forced it all to be allocated now; but since we don't scan
980 * hash indexes sequentially anyway, that probably doesn't matter.
982 * XXX It's annoying that this code is executed with the metapage lock held.
983 * We need to interlock against _hash_addovflpage() adding a new overflow page
984 * concurrently, but it'd likely be better to use LockRelationForExtension
985 * for the purpose. OTOH, adding a splitpoint is a very infrequent operation,
986 * so it may not be worth worrying about.
988 * Returns true if successful, or false if allocation failed due to
989 * BlockNumber overflow.
999 lastblock = firstblock + nblocks - 1;
1002 * Check for overflow in block number calculation; if so, we cannot extend
1003 * the index anymore.
1011 * Initialize the page. Just zeroing the page won't work; see
1012 * _hash_freeovflpage for similar usage. We take care to make the special
1013 * space valid for the benefit of tools such as pageinspect.
1041 * _hash_splitbucket -- split 'obucket' into 'obucket' and 'nbucket'
1043 * This routine is used to partition the tuples between old and new bucket and
1044 * is used to finish the incomplete split operations. To finish the previously
1045 * interrupted split operation, the caller needs to fill htab. If htab is set,
1046 * then we skip the movement of tuples that exists in htab, otherwise NULL
1047 * value of htab indicates movement of all the tuples that belong to the new
1050 * We are splitting a bucket that consists of a base bucket page and zero
1051 * or more overflow (bucket chain) pages. We must relocate tuples that
1052 * belong in the new bucket.
1054 * The caller must hold cleanup locks on both buckets to ensure that
1055 * no one else is trying to access them (see README).
1057 * The caller must hold a pin, but no lock, on the metapage buffer.
1058 * The buffer is returned in the same state. (The metapage is only
1059 * touched if it becomes necessary to add or remove overflow pages.)
1061 * Split needs to retain pin on primary bucket pages of both old and new
1062 * buckets till end of operation. This is to prevent vacuum from starting
1063 * while a split is in progress.
1065 * In addition, the caller must have created the new bucket's base page,
1066 * which is passed in buffer nbuf, pinned and write-locked. The lock will be
1067 * released here and pin must be released by the caller. (The API is set up
1068 * this way because we must do _hash_getnewbuf() before releasing the metapage
1069 * write lock. So instead of passing the new bucket's start block number, we
1070 * pass an actual buffer.)
1092 Size all_tups_size = 0;
1104 /* Copy the predicate locks from old bucket to new bucket. */
1110 * Partition the tuples in the old bucket between the old bucket and the
1111 * new bucket, advancing along the old bucket's overflow bucket chain and
1112 * adding overflow pages to the new bucket as needed. Outer loop iterates
1113 * once per page in old bucket.
1121 /* Scan each tuple in old page */
1124 ooffnum <= omaxoffnum;
1132 /* skip dead tuples */
1137 * Before inserting a tuple, probe the hash table containing TIDs
1138 * of tuples belonging to new bucket, if we find a match, then
1139 * skip that tuple, else fetch the item's hash key (conveniently
1140 * stored in the item) and determine which bucket it now belongs
1153 maxbucket, highmask, lowmask);
1155 if (bucket == nbucket)
1160 * make a copy of index tuple as we have to scribble on it.
1165 * mark the index tuple as moved by split, such tuples are
1166 * skipped by scan if there is split in progress for a bucket.
1171 * insert the tuple into the new bucket. if it doesn't fit on
1172 * the current page in the new bucket, we must allocate a new
1173 * overflow page and place the tuple on that page instead.
1181 * Change the shared buffer state in critical section,
1182 * otherwise any error could make it unrecoverable.
1188 /* log the split operation before releasing the lock */
1193 /* drop lock, but keep pin */
1197 for (
i = 0;
i < nitups;
i++)
1202 /* chain to a new overflow page */
1208 itups[nitups++] = new_itup;
1209 all_tups_size += itemsz;
1214 * the tuple stays on this page, so nothing to do.
1216 Assert(bucket == obucket);
1222 /* retain the pin on the old primary bucket */
1223 if (obuf == bucket_obuf)
1228 /* Exit loop if no more overflow pages in old bucket */
1232 * Change the shared buffer state in critical section, otherwise
1233 * any error could make it unrecoverable.
1239 /* log the split operation before releasing the lock */
1244 if (nbuf == bucket_nbuf)
1250 for (
i = 0;
i < nitups;
i++)
1255 /* Else, advance to next old page */
1262 * We're at the end of the old bucket chain, so we're done partitioning
1263 * the tuples. Mark the old and new buckets to indicate split is
1266 * To avoid deadlocks due to locking order of buckets, first lock the old
1267 * bucket and then the new bucket.
1279 oopaque->
hasho_flag &= ~LH_BUCKET_BEING_SPLIT;
1280 nopaque->
hasho_flag &= ~LH_BUCKET_BEING_POPULATED;
1283 * After the split is finished, mark the old bucket to indicate that it
1284 * contains deletable tuples. We will clear split-cleanup flag after
1285 * deleting such tuples either at the end of split or at the next split
1286 * from old bucket or at the time of vacuum.
1291 * now write the buffers, here we don't release the locks as caller is
1292 * responsible to release locks.
1321 * If possible, clean up the old bucket. We might not be able to do this
1322 * if someone else has a pin on it, but if not then we can go ahead. This
1323 * isn't absolutely necessary, but it reduces bloat; if we don't do it
1324 * now, VACUUM will do it eventually, but maybe not until new overflow
1325 * pages have been allocated. Note that there's no need to clean up the
1333 maxbucket, highmask, lowmask, NULL, NULL,
true,
1344 * _hash_finish_split() -- Finish the previously interrupted split operation
1346 * To complete the split operation, we form the hash table of TIDs in new
1347 * bucket which is then used by split operation to skip tuples that are
1348 * already moved before the split operation was previously interrupted.
1350 * The caller must hold a pin, but no lock, on the metapage and old bucket's
1351 * primary page buffer. The buffers are returned in the same state. (The
1352 * metapage is only touched if it becomes necessary to add or remove overflow
1370 /* Initialize hash tables used to track TIDs */
1377 256,
/* arbitrary initial size */
1384 * Scan the new bucket and build hash table of TIDs
1394 /* remember the primary bucket buffer to acquire cleanup lock on it. */
1395 if (nblkno == bucket_nblkno)
1401 /* Scan each tuple in new page */
1404 noffnum <= nmaxoffnum;
1409 /* Fetch the item's TID and insert it in hash table. */
1421 * release our write lock without modifying buffer and ensure to
1422 * retain the pin on primary bucket.
1424 if (nbuf == bucket_nbuf)
1429 /* Exit loop if no more overflow pages in new bucket */
1435 * Conditionally get the cleanup lock on old and new buckets to perform
1436 * the split operation. If we don't get the cleanup locks, silently give
1437 * up and next insertion on old bucket will try again to complete the
1457 nbucket, obuf, bucket_nbuf, tidhtab,
1458 maxbucket, highmask, lowmask);
1465 * log_split_page() -- Log the split operation
1467 * We log the split operation when the new page in new bucket gets full,
1468 * so we log the entire page.
1470 * 'buf' must be locked by the caller which is also responsible for unlocking
1491 * _hash_getcachedmetap() -- Returns cached metapage data.
1493 * If metabuf is not InvalidBuffer, caller must hold a pin, but no lock, on
1494 * the metapage. If not set, we'll set it before returning if we have to
1495 * refresh the cache, and return with a pin but no lock on it; caller is
1496 * responsible for releasing the pin.
1498 * We refresh the cache if it's not initialized yet or force_refresh is true.
1506 if (force_refresh || rel->
rd_amcache == NULL)
1511 * It's important that we don't set rd_amcache to an invalid value.
1512 * Either MemoryContextAlloc or _hash_getbuf could fail, so don't
1513 * install a pointer to the newly-allocated storage in the actual
1514 * relcache entry until both have succeeded.
1520 /* Read the metapage. */
1528 /* Populate the cache. */
1534 /* Release metapage lock, but keep the pin. */
1542 * _hash_getbucketbuf_from_hashkey() -- Get the bucket's buffer for the given
1545 * Bucket pages do not move or get removed once they are allocated. This give
1546 * us an opportunity to use the previously saved metapage contents to reach
1547 * the target bucket buffer, instead of reading from the metapage every time.
1548 * This saves one buffer access every time we want to reach the target bucket
1549 * buffer, which is very helpful savings in bufmgr traffic and contention.
1551 * The access type parameter (HASH_READ or HASH_WRITE) indicates whether the
1552 * bucket buffer has to be locked for reading or writing.
1554 * The out parameter cachedmetap is set with metapage contents used for
1555 * hashkey to bucket buffer mapping. Some callers need this info to reach the
1556 * old bucket in case of bucket split, see _hash_doinsert().
1570 /* We read from target bucket buffer, hence locking is must. */
1577 * Loop until we get a lock on the correct target bucket.
1582 * Compute the target bucket number, and convert to block number.
1591 /* Fetch the primary bucket page for the bucket */
1599 * If this bucket hasn't been split, we're done.
1604 /* Drop lock on this buffer, update cached metapage, and retry. */
1614 *cachedmetap = metap;
#define InvalidBlockNumber
static bool BlockNumberIsValid(BlockNumber blockNumber)
BlockNumber BufferGetBlockNumber(Buffer buffer)
bool IsBufferCleanupOK(Buffer buffer)
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
BlockNumber RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
void ReleaseBuffer(Buffer buffer)
void UnlockReleaseBuffer(Buffer buffer)
void MarkBufferDirty(Buffer buffer)
void LockBuffer(Buffer buffer, int mode)
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
bool ConditionalLockBufferForCleanup(Buffer buffer)
#define BUFFER_LOCK_UNLOCK
#define BUFFER_LOCK_SHARE
static Page BufferGetPage(Buffer buffer)
static Size BufferGetPageSize(Buffer buffer)
#define BUFFER_LOCK_EXCLUSIVE
static bool BufferIsValid(Buffer bufnum)
Size PageGetFreeSpaceForMultipleTuples(const PageData *page, int ntups)
void PageSetChecksumInplace(Page page, BlockNumber blkno)
void PageInit(Page page, Size pageSize, Size specialSize)
PageHeaderData * PageHeader
static Item PageGetItem(const PageData *page, const ItemIdData *itemId)
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
static void PageSetLSN(Page page, XLogRecPtr lsn)
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
#define MemSet(start, val, len)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
void hash_destroy(HTAB *hashp)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
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)
#define HashPageGetOpaque(page)
#define HASHSTANDARD_PROC
#define HASH_MAX_SPLITPOINTS
#define H_BUCKET_BEING_SPLIT(opaque)
#define HashPageGetMeta(page)
#define LH_BUCKET_BEING_POPULATED
#define BUCKET_TO_BLKNO(metap, B)
#define HashGetMaxBitmapSize(page)
#define INDEX_MOVED_BY_SPLIT_MASK
#define H_NEEDS_SPLIT_CLEANUP(opaque)
#define LH_BUCKET_NEEDS_SPLIT_CLEANUP
#define LH_BUCKET_BEING_SPLIT
#define HashGetTargetPageUsage(relation)
#define BMPG_SHIFT(metap)
#define SizeOfHashInitBitmapPage
#define XLOG_HASH_INIT_BITMAP_PAGE
#define SizeOfHashSplitComplete
#define XLOG_HASH_SPLIT_ALLOCATE_PAGE
#define XLOG_HASH_SPLIT_PAGE
#define XLOG_HASH_INIT_META_PAGE
#define XLOG_HASH_SPLIT_COMPLETE
#define SizeOfHashSplitAllocPage
#define SizeOfHashInitMetaPage
#define XLH_SPLIT_META_UPDATE_SPLITPOINT
#define XLH_SPLIT_META_UPDATE_MASKS
Assert(PointerIsAligned(start, uint64))
void _hash_pgaddmultitup(Relation rel, Buffer buf, IndexTuple *itups, OffsetNumber *itup_offsets, uint16 nitups)
void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage)
Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin)
Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno)
HashMetaPage _hash_getcachedmetap(Relation rel, Buffer *metabuf, bool force_refresh)
void _hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket, uint32 flag, bool initpage)
void _hash_relbuf(Relation rel, Buffer buf)
Buffer _hash_getbuf_with_condlock_cleanup(Relation rel, BlockNumber blkno, int flags)
void _hash_pageinit(Page page, Size size)
static void _hash_splitbucket(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket, Buffer obuf, Buffer nbuf, HTAB *htab, uint32 maxbucket, uint32 highmask, uint32 lowmask)
uint32 _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
void _hash_dropbuf(Relation rel, Buffer buf)
void _hash_dropscanbuf(Relation rel, HashScanOpaque so)
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
void _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Buffer _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey, int access, HashMetaPage *cachedmetap)
void _hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid, uint16 ffactor, bool initpage)
static void log_split_page(Relation rel, Buffer buf)
static bool _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, int access, int flags, BufferAccessStrategy bstrategy)
Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
void _hash_expandtable(Relation rel, Buffer metabuf)
uint32 _hash_spareindex(uint32 num_bucket)
BlockNumber _hash_get_newblock_from_oldbucket(Relation rel, Bucket old_bucket)
uint32 _hash_get_totalbuckets(uint32 splitpoint_phase)
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask)
void _hash_checkpage(Relation rel, Buffer buf, int flags)
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
IndexTuple CopyIndexTuple(IndexTuple source)
struct ItemIdData ItemIdData
#define ItemIdIsDead(itemId)
struct ItemPointerData ItemPointerData
IndexTupleData * IndexTuple
static Size IndexTupleSize(const IndexTupleData *itup)
#define MaxIndexTuplesPerPage
void * MemoryContextAlloc(MemoryContext context, Size size)
void pfree(void *pointer)
MemoryContext CurrentMemoryContext
#define START_CRIT_SECTION()
#define CHECK_FOR_INTERRUPTS()
#define END_CRIT_SECTION()
#define OffsetNumberNext(offsetNumber)
#define FirstOffsetNumber
static uint32 pg_nextpower2_32(uint32 num)
static int pg_leftmost_one_pos32(uint32 word)
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
static SMgrRelation RelationGetSmgr(Relation rel)
#define RelationGetRelationName(relation)
#define RelationNeedsWAL(relation)
void smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
RegProcedure hashm_procid
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
BlockNumber hasho_nextblkno
BlockNumber hasho_prevblkno
bool hashso_buc_populated
Buffer hashso_split_bucket_buf
MemoryContext rd_indexcxt
RelFileLocator rd_locator
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
void XLogRegisterData(const void *data, uint32 len)
XLogRecPtr log_newpage(RelFileLocator *rlocator, ForkNumber forknum, BlockNumber blkno, Page page, bool page_std)
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
void XLogBeginInsert(void)
#define REGBUF_FORCE_IMAGE