PostgreSQL Source Code git master
Loading...
Searching...
No Matches
hash.c File Reference
#include "postgres.h"
#include "access/hash.h"
#include "access/hash_xlog.h"
#include "access/relscan.h"
#include "access/stratnum.h"
#include "access/tableam.h"
#include "access/xloginsert.h"
#include "commands/progress.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "optimizer/plancat.h"
#include "pgstat.h"
#include "storage/read_stream.h"
#include "utils/fmgrprotos.h"
#include "utils/index_selfuncs.h"
#include "utils/rel.h"
Include dependency graph for hash.c:

Go to the source code of this file.

Data Structures

struct  HashBuildState
 
struct  HashBulkDeleteStreamPrivate
 

Functions

static void hashbuildCallback (Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
 
static BlockNumber hash_bulkdelete_read_stream_cb (ReadStream *stream, void *callback_private_data, void *per_buffer_data)
 
Datum hashhandler (PG_FUNCTION_ARGS)
 
IndexBuildResulthashbuild (Relation heap, Relation index, IndexInfo *indexInfo)
 
void hashbuildempty (Relation index)
 
bool hashinsert (Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, 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)
 
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)
 
CompareType hashtranslatestrategy (StrategyNumber strategy, Oid opfamily)
 
StrategyNumber hashtranslatecmptype (CompareType cmptype, Oid opfamily)
 

Function Documentation

◆ hash_bulkdelete_read_stream_cb()

static BlockNumber hash_bulkdelete_read_stream_cb ( ReadStream stream,
void callback_private_data,
void per_buffer_data 
)
static

Definition at line 473 of file hash.c.

476{
477 HashBulkDeleteStreamPrivate *p = callback_private_data;
479
480 if (p->next_bucket > p->max_bucket)
481 return InvalidBlockNumber;
482
483 bucket = p->next_bucket++;
484 return BUCKET_TO_BLKNO(p->metap, bucket);
485}
#define InvalidBlockNumber
Definition block.h:33
#define BUCKET_TO_BLKNO(metap, B)
Definition hash.h:39
uint32 Bucket
Definition hash.h:35
static int fb(int x)
HashMetaPage metap
Definition hash.c:49

References BUCKET_TO_BLKNO, fb(), InvalidBlockNumber, HashBulkDeleteStreamPrivate::max_bucket, HashBulkDeleteStreamPrivate::metap, and HashBulkDeleteStreamPrivate::next_bucket.

Referenced by hashbulkdelete().

◆ hashbeginscan()

IndexScanDesc hashbeginscan ( Relation  rel,
int  nkeys,
int  norderbys 
)

Definition at line 386 of file hash.c.

387{
388 IndexScanDesc scan;
390
391 /* no order by operators allowed */
392 Assert(norderbys == 0);
393
394 scan = RelationGetIndexScan(rel, nkeys, norderbys);
395
397 HashScanPosInvalidate(so->currPos);
398 so->hashso_bucket_buf = InvalidBuffer;
399 so->hashso_split_bucket_buf = InvalidBuffer;
400
401 so->hashso_buc_populated = false;
402 so->hashso_buc_split = false;
403
404 so->killedItems = NULL;
405 so->numKilled = 0;
406
407 scan->opaque = so;
408
409 return scan;
410}
#define InvalidBuffer
Definition buf.h:25
#define Assert(condition)
Definition c.h:945
#define palloc_object(type)
Definition fe_memutils.h:74
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition genam.c:80
#define HashScanPosInvalidate(scanpos)
Definition hash.h:144
HashScanOpaqueData * HashScanOpaque
Definition hash.h:192

References Assert, fb(), HashScanPosInvalidate, InvalidBuffer, IndexScanDescData::opaque, palloc_object, and RelationGetIndexScan().

Referenced by hashhandler().

◆ hashbucketcleanup()

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 at line 767 of file hash.c.

773{
774 BlockNumber blkno;
775 Buffer buf;
777 bool bucket_dirty = false;
779
780 blkno = bucket_blkno;
781 buf = bucket_buf;
782
783 if (split_cleanup)
786
787 /* Scan each page in bucket */
788 for (;;)
789 {
790 HashPageOpaque opaque;
794 Page page;
796 int ndeletable = 0;
797 bool retain_pin = false;
798 bool clear_dead_marking = false;
799
800 vacuum_delay_point(false);
801
802 page = BufferGetPage(buf);
803 opaque = HashPageGetOpaque(page);
804
805 /* Scan each tuple in page */
808 offno <= maxoffno;
810 {
811 ItemPointer htup;
812 IndexTuple itup;
814 bool kill_tuple = false;
815
816 itup = (IndexTuple) PageGetItem(page,
817 PageGetItemId(page, offno));
818 htup = &(itup->t_tid);
819
820 /*
821 * To remove the dead tuples, we strictly want to rely on results
822 * of callback function. refer btvacuumpage for detailed reason.
823 */
824 if (callback && callback(htup, callback_state))
825 {
826 kill_tuple = true;
827 if (tuples_removed)
828 *tuples_removed += 1;
829 }
830 else if (split_cleanup)
831 {
832 /* delete the tuples that are moved by split. */
834 maxbucket,
835 highmask,
836 lowmask);
837 /* mark the item for deletion */
838 if (bucket != cur_bucket)
839 {
840 /*
841 * We expect tuples to either belong to current bucket or
842 * new_bucket. This is ensured because we don't allow
843 * further splits from bucket that contains garbage. See
844 * comments in _hash_expandtable.
845 */
846 Assert(bucket == new_bucket);
847 kill_tuple = true;
848 }
849 }
850
851 if (kill_tuple)
852 {
853 /* mark the item for deletion */
855 }
856 else
857 {
858 /* we're keeping it, so count it */
859 if (num_index_tuples)
860 *num_index_tuples += 1;
861 }
862 }
863
864 /* retain the pin on primary bucket page till end of bucket scan */
865 if (blkno == bucket_blkno)
866 retain_pin = true;
867 else
868 retain_pin = false;
869
870 blkno = opaque->hasho_nextblkno;
871
872 /*
873 * Apply deletions, advance to next page and write page if needed.
874 */
875 if (ndeletable > 0)
876 {
877 /* No ereport(ERROR) until changes are logged */
879
881 bucket_dirty = true;
882
883 /*
884 * Let us mark the page as clean if vacuum removes the DEAD tuples
885 * from an index page. We do this by clearing
886 * LH_PAGE_HAS_DEAD_TUPLES flag.
887 */
888 if (tuples_removed && *tuples_removed > 0 &&
889 H_HAS_DEAD_TUPLES(opaque))
890 {
892 clear_dead_marking = true;
893 }
894
896
897 /* XLOG stuff */
898 if (RelationNeedsWAL(rel))
899 {
901
902 xlrec.clear_dead_marking = clear_dead_marking;
903 xlrec.is_primary_bucket_page = (buf == bucket_buf);
904
907
908 /*
909 * bucket buffer was not changed, but still needs to be
910 * registered to ensure that we can acquire a cleanup lock on
911 * it during replay.
912 */
913 if (!xlrec.is_primary_bucket_page)
914 {
916
918 }
919
922 ndeletable * sizeof(OffsetNumber));
923
925 }
926 else
927 recptr = XLogGetFakeLSN(rel);
928
930
932 }
933
934 /* bail out if there are no more pages to scan. */
935 if (!BlockNumberIsValid(blkno))
936 break;
937
940 bstrategy);
941
942 /*
943 * release the lock on previous page after acquiring the lock on next
944 * page
945 */
946 if (retain_pin)
948 else
949 _hash_relbuf(rel, buf);
950
951 buf = next_buf;
952 }
953
954 /*
955 * lock the bucket page to clear the garbage flag and squeeze the bucket.
956 * if the current buffer is same as bucket buffer, then we already have
957 * lock on bucket page.
958 */
959 if (buf != bucket_buf)
960 {
961 _hash_relbuf(rel, buf);
963 }
964
965 /*
966 * Clear the garbage flag from bucket after deleting the tuples that are
967 * moved by split. We purposefully clear the flag before squeeze bucket,
968 * so that after restart, vacuum shouldn't again try to delete the moved
969 * by split tuples.
970 */
971 if (split_cleanup)
972 {
974 Page page;
975
978
979 /* No ereport(ERROR) until changes are logged */
981
984
985 /* XLOG stuff */
986 if (RelationNeedsWAL(rel))
987 {
990
992 }
993 else
994 recptr = XLogGetFakeLSN(rel);
995
996 PageSetLSN(page, recptr);
997
999 }
1000
1001 /*
1002 * If we have deleted anything, try to compact free space. For squeezing
1003 * the bucket, we must have a cleanup lock, else it can impact the
1004 * ordering of tuples for a scan that has started before it.
1005 */
1008 bstrategy);
1009 else
1011}
uint32 BlockNumber
Definition block.h:31
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition block.h:71
int Buffer
Definition buf.h:23
bool IsBufferCleanupOK(Buffer buffer)
Definition bufmgr.c:6768
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3063
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:470
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:220
@ BUFFER_LOCK_UNLOCK
Definition bufmgr.h:205
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:332
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition bufpage.c:1160
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:269
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:379
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:417
PageData * Page
Definition bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:397
uint8_t uint8
Definition c.h:616
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:243
#define HashPageGetOpaque(page)
Definition hash.h:88
#define HASH_WRITE
Definition hash.h:340
#define H_HAS_DEAD_TUPLES(opaque)
Definition hash.h:93
#define LH_OVERFLOW_PAGE
Definition hash.h:54
#define InvalidBucket
Definition hash.h:37
#define XLOG_HASH_SPLIT_CLEANUP
Definition hash_xlog.h:37
#define SizeOfHashDelete
Definition hash_xlog.h:187
#define XLOG_HASH_DELETE
Definition hash_xlog.h:36
void _hash_squeezebucket(Relation rel, Bucket bucket, BlockNumber bucket_blkno, Buffer bucket_buf, BufferAccessStrategy bstrategy)
Definition hashovfl.c:843
void _hash_relbuf(Relation rel, Buffer buf)
Definition hashpage.c:266
Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, int access, int flags, BufferAccessStrategy bstrategy)
Definition hashpage.c:239
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition hashutil.c:291
Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask)
Definition hashutil.c:125
Bucket _hash_get_newbucket_from_oldbucket(Relation rel, Bucket old_bucket, uint32 lowmask, uint32 maxbucket)
Definition hashutil.c:494
IndexTupleData * IndexTuple
Definition itup.h:53
#define START_CRIT_SECTION()
Definition miscadmin.h:150
#define END_CRIT_SECTION()
Definition miscadmin.h:152
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
#define MaxOffsetNumber
Definition off.h:28
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define RelationNeedsWAL(relation)
Definition rel.h:637
BlockNumber hasho_nextblkno
Definition hash.h:80
uint16 hasho_flag
Definition hash.h:82
ItemPointerData t_tid
Definition itup.h:37
bool clear_dead_marking
Definition hash_xlog.h:181
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2431
uint64 XLogRecPtr
Definition xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:479
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
Definition xloginsert.c:410
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:369
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:246
void XLogBeginInsert(void)
Definition xloginsert.c:153
XLogRecPtr XLogGetFakeLSN(Relation rel)
Definition xloginsert.c:559
#define REGBUF_NO_CHANGE
Definition xloginsert.h:37
#define REGBUF_STANDARD
Definition xloginsert.h:35
#define REGBUF_NO_IMAGE
Definition xloginsert.h:33

References _hash_get_indextuple_hashkey(), _hash_get_newbucket_from_oldbucket(), _hash_getbuf_with_strategy(), _hash_hashkey2bucket(), _hash_relbuf(), _hash_squeezebucket(), Assert, BlockNumberIsValid(), buf, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage(), callback(), xl_hash_delete::clear_dead_marking, END_CRIT_SECTION, fb(), FirstOffsetNumber, H_HAS_DEAD_TUPLES, HASH_WRITE, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageGetOpaque, InvalidBucket, IsBufferCleanupOK(), LH_OVERFLOW_PAGE, LockBuffer(), MarkBufferDirty(), MaxOffsetNumber, OffsetNumberNext, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageIndexMultiDelete(), PageSetLSN(), PG_USED_FOR_ASSERTS_ONLY, REGBUF_NO_CHANGE, REGBUF_NO_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, SizeOfHashDelete, START_CRIT_SECTION, IndexTupleData::t_tid, vacuum_delay_point(), XLOG_HASH_DELETE, XLOG_HASH_SPLIT_CLEANUP, XLogBeginInsert(), XLogGetFakeLSN(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

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

◆ hashbuild()

IndexBuildResult * hashbuild ( Relation  heap,
Relation  index,
IndexInfo indexInfo 
)

Definition at line 135 of file hash.c.

136{
137 IndexBuildResult *result;
138 BlockNumber relpages;
139 double reltuples;
140 double allvisfrac;
144
145 /*
146 * We expect to be called exactly once for any index relation. If that's
147 * not the case, big trouble's what we have.
148 */
150 elog(ERROR, "index \"%s\" already contains data",
152
153 /* Estimate the number of rows currently present in the table */
154 estimate_rel_size(heap, NULL, &relpages, &reltuples, &allvisfrac);
155
156 /* Initialize the hash index metadata page and initial buckets */
158
159 /*
160 * If we just insert the tuples into the index in scan order, then
161 * (assuming their hash codes are pretty random) there will be no locality
162 * of access to the index, and if the index is bigger than available RAM
163 * then we'll thrash horribly. To prevent that scenario, we can sort the
164 * tuples by (expected) bucket number. However, such a sort is useless
165 * overhead when the index does fit in RAM. We choose to sort if the
166 * initial index size exceeds maintenance_work_mem, or the number of
167 * buffers usable for the index, whichever is less. (Limiting by the
168 * number of buffers should reduce thrashing between PG buffers and kernel
169 * buffers, which seems useful even if no physical I/O results. Limiting
170 * by maintenance_work_mem is useful to allow easy testing of the sort
171 * code path, and may be useful to DBAs as an additional control knob.)
172 *
173 * NOTE: this test will need adjustment if a bucket is ever different from
174 * one page. Also, "initial index size" accounting does not include the
175 * metapage, nor the first bitmap page.
176 */
178 if (index->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
180 else
182
185 else
186 buildstate.spool = NULL;
187
188 /* prepare to build the index */
189 buildstate.indtuples = 0;
190 buildstate.heapRel = heap;
191
192 /* do the heap scan */
193 reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
195 &buildstate, NULL);
197 buildstate.indtuples);
198
199 if (buildstate.spool)
200 {
201 /* sort the tuples and insert them into the index */
202 _h_indexbuild(buildstate.spool, buildstate.heapRel);
204 }
205
206 /*
207 * Return statistics
208 */
210
211 result->heap_tuples = reltuples;
212 result->index_tuples = buildstate.indtuples;
213
214 return result;
215}
void pgstat_progress_update_param(int index, int64 val)
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
#define Min(x, y)
Definition c.h:1093
uint32_t uint32
Definition c.h:618
size_t Size
Definition c.h:691
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
int NBuffers
Definition globals.c:142
int maintenance_work_mem
Definition globals.c:133
static void hashbuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition hash.c:230
uint32 _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
Definition hashpage.c:327
void _h_indexbuild(HSpool *hspool, Relation heapRel)
Definition hashsort.c:120
HSpool * _h_spoolinit(Relation heap, Relation index, uint32 num_buckets)
Definition hashsort.c:60
void _h_spooldestroy(HSpool *hspool)
Definition hashsort.c:99
int NLocBuffer
Definition localbuf.c:45
void estimate_rel_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac)
Definition plancat.c:1305
#define PROGRESS_CREATEIDX_TUPLES_TOTAL
Definition progress.h:112
#define RelationGetRelationName(relation)
Definition rel.h:548
@ MAIN_FORKNUM
Definition relpath.h:58
double heap_tuples
Definition genam.h:40
double index_tuples
Definition genam.h:41
Definition type.h:96
static double table_index_build_scan(Relation table_rel, Relation index_rel, IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition tableam.h:1765

References _h_indexbuild(), _h_spooldestroy(), _h_spoolinit(), _hash_init(), elog, ERROR, estimate_rel_size(), fb(), hashbuildCallback(), IndexBuildResult::heap_tuples, IndexBuildResult::index_tuples, MAIN_FORKNUM, maintenance_work_mem, Min, NBuffers, NLocBuffer, palloc_object, pgstat_progress_update_param(), PROGRESS_CREATEIDX_TUPLES_TOTAL, RelationGetNumberOfBlocks, RelationGetRelationName, and table_index_build_scan().

Referenced by hashhandler().

◆ hashbuildCallback()

static void hashbuildCallback ( Relation  index,
ItemPointer  tid,
Datum values,
bool isnull,
bool  tupleIsAlive,
void state 
)
static

Definition at line 230 of file hash.c.

236{
239 bool index_isnull[1];
240 IndexTuple itup;
241
242 /* convert data to a hash key; on failure, do not insert anything */
244 values, isnull,
246 return;
247
248 /* Either spool the tuple for sorting, or just put it into the index */
249 if (buildstate->spool)
251 else
252 {
253 /* form an index tuple and point it at the heap tuple */
256 itup->t_tid = *tid;
257 _hash_doinsert(index, itup, buildstate->heapRel, false);
258 pfree(itup);
259 }
260
261 buildstate->indtuples += 1;
262}
static Datum values[MAXATTR]
Definition bootstrap.c:188
void _hash_doinsert(Relation rel, IndexTuple itup, Relation heapRel, bool sorted)
Definition hashinsert.c:38
void _h_spool(HSpool *hspool, const ItemPointerData *self, const Datum *values, const bool *isnull)
Definition hashsort.c:109
bool _hash_convert_tuple(Relation index, const Datum *user_values, const bool *user_isnull, Datum *index_values, bool *index_isnull)
Definition hashutil.c:318
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition indextuple.c:44
void pfree(void *pointer)
Definition mcxt.c:1616
uint64_t Datum
Definition postgres.h:70
#define RelationGetDescr(relation)
Definition rel.h:540

References _h_spool(), _hash_convert_tuple(), _hash_doinsert(), fb(), index_form_tuple(), pfree(), RelationGetDescr, IndexTupleData::t_tid, and values.

Referenced by hashbuild().

◆ hashbuildempty()

void hashbuildempty ( Relation  index)

Definition at line 221 of file hash.c.

222{
224}
@ INIT_FORKNUM
Definition relpath.h:61

References _hash_init(), and INIT_FORKNUM.

Referenced by hashhandler().

◆ hashbulkdelete()

IndexBulkDeleteResult * hashbulkdelete ( IndexVacuumInfo info,
IndexBulkDeleteResult stats,
IndexBulkDeleteCallback  callback,
void callback_state 
)

Definition at line 498 of file hash.c.

500{
501 Relation rel = info->index;
502 double tuples_removed;
503 double num_index_tuples;
504 double orig_ntuples;
509 HashMetaPage metap;
512 ReadStream *stream = NULL;
514
515 tuples_removed = 0;
516 num_index_tuples = 0;
517
518 /*
519 * We need a copy of the metapage so that we can use its hashm_spares[]
520 * values to compute bucket page addresses, but a cached copy should be
521 * good enough. (If not, we'll detect that further down and refresh the
522 * cache as necessary.)
523 */
526
527 orig_maxbucket = cachedmetap->hashm_maxbucket;
528 orig_ntuples = cachedmetap->hashm_ntuples;
529
530 /* Scan the buckets that we know exist */
531 cur_bucket = 0;
533
534 /* Set up streaming read for primary bucket pages */
536 stream_private.next_bucket = cur_bucket;
537 stream_private.max_bucket = cur_maxbucket;
538
539 /*
540 * It is safe to use batchmode as hash_bulkdelete_read_stream_cb takes no
541 * locks.
542 */
545 info->strategy,
546 rel,
550 0);
551
553 while (cur_bucket <= cur_maxbucket)
554 {
556 BlockNumber blkno;
558 Buffer buf;
560 Page page;
561 bool split_cleanup = false;
562
563 /* Get address of bucket's start page */
565
566 blkno = bucket_blkno;
567
568 /*
569 * We need to acquire a cleanup lock on the primary bucket page to out
570 * wait concurrent scans before deleting the dead tuples.
571 */
576
577 page = BufferGetPage(buf);
579
580 /*
581 * If the bucket contains tuples that are moved by split, then we need
582 * to delete such tuples. We can't delete such tuples if the split
583 * operation on bucket is not finished as those are needed by scans.
584 */
587 {
588 split_cleanup = true;
589
590 /*
591 * This bucket might have been split since we last held a lock on
592 * the metapage. If so, hashm_maxbucket, hashm_highmask and
593 * hashm_lowmask might be old enough to cause us to fail to remove
594 * tuples left behind by the most recent split. To prevent that,
595 * now that the primary page of the target bucket has been locked
596 * (and thus can't be further split), check whether we need to
597 * update our cached metapage data.
598 */
599 Assert(bucket_opaque->hasho_prevblkno != InvalidBlockNumber);
600 if (bucket_opaque->hasho_prevblkno > cachedmetap->hashm_maxbucket)
601 {
604
605 /*
606 * Reset stream with updated metadata for remaining buckets.
607 * The BUCKET_TO_BLKNO mapping depends on hashm_spares[],
608 * which may have changed.
609 */
611 stream_private.next_bucket = cur_bucket + 1;
612 stream_private.max_bucket = cur_maxbucket;
613 read_stream_reset(stream);
614 }
615 }
616
617 bucket_buf = buf;
618
620 cachedmetap->hashm_maxbucket,
621 cachedmetap->hashm_highmask,
622 cachedmetap->hashm_lowmask, &tuples_removed,
623 &num_index_tuples, split_cleanup,
624 callback, callback_state);
625
627
628 /* Advance to next bucket */
629 cur_bucket++;
630 }
631
634
635 /* Write-lock metapage and check for split since we started */
638
639 if (cur_maxbucket != metap->hashm_maxbucket)
640 {
641 /* There's been a split, so process the additional bucket(s) */
645 cur_maxbucket = cachedmetap->hashm_maxbucket;
646
647 /* Reset stream to process additional buckets from split */
649 stream_private.next_bucket = cur_bucket;
650 stream_private.max_bucket = cur_maxbucket;
651 read_stream_reset(stream);
652 goto bucket_loop;
653 }
654
655 /* Stream should be exhausted since we processed all buckets */
657 read_stream_end(stream);
658
659 /* Okay, we're really done. Update tuple count in metapage. */
661
662 if (orig_maxbucket == metap->hashm_maxbucket &&
663 orig_ntuples == metap->hashm_ntuples)
664 {
665 /*
666 * No one has split or inserted anything since start of scan, so
667 * believe our count as gospel.
668 */
669 metap->hashm_ntuples = num_index_tuples;
670 }
671 else
672 {
673 /*
674 * Otherwise, our count is untrustworthy since we may have
675 * double-scanned tuples in split buckets. Proceed by dead-reckoning.
676 * (Note: we still return estimated_count = false, because using this
677 * count is better than not updating reltuples at all.)
678 */
679 if (metap->hashm_ntuples > tuples_removed)
680 metap->hashm_ntuples -= tuples_removed;
681 else
682 metap->hashm_ntuples = 0;
683 num_index_tuples = metap->hashm_ntuples;
684 }
685
687
688 /* XLOG stuff */
689 if (RelationNeedsWAL(rel))
690 {
692
693 xlrec.ntuples = metap->hashm_ntuples;
694
697
699
701 }
702 else
703 recptr = XLogGetFakeLSN(rel);
704
706
708
709 _hash_relbuf(rel, metabuf);
710
711 /* return statistics */
712 if (stats == NULL)
714 stats->estimated_count = false;
715 stats->num_index_tuples = num_index_tuples;
716 stats->tuples_removed += tuples_removed;
717 /* hashvacuumcleanup will fill in num_pages */
718
719 return stats;
720}
#define BufferIsInvalid(buffer)
Definition buf.h:31
void LockBufferForCleanup(Buffer buffer)
Definition bufmgr.c:6537
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:421
#define palloc0_object(type)
Definition fe_memutils.h:75
static BlockNumber hash_bulkdelete_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
Definition hash.c:473
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:767
#define HASH_NOLOCK
Definition hash.h:341
#define LH_BUCKET_PAGE
Definition hash.h:55
#define H_BUCKET_BEING_SPLIT(opaque)
Definition hash.h:91
#define LH_META_PAGE
Definition hash.h:57
#define HashPageGetMeta(page)
Definition hash.h:323
#define HASH_METAPAGE
Definition hash.h:198
#define H_NEEDS_SPLIT_CLEANUP(opaque)
Definition hash.h:90
#define XLOG_HASH_UPDATE_META_PAGE
Definition hash_xlog.h:38
#define SizeOfHashUpdateMetaPage
Definition hash_xlog.h:201
HashMetaPage _hash_getcachedmetap(Relation rel, Buffer *metabuf, bool force_refresh)
Definition hashpage.c:1505
void _hash_dropbuf(Relation rel, Buffer buf)
Definition hashpage.c:277
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition hashpage.c:70
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition hashutil.c:210
void read_stream_reset(ReadStream *stream)
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
ReadStream * read_stream_begin_relation(int flags, BufferAccessStrategy strategy, Relation rel, ForkNumber forknum, ReadStreamBlockNumberCB callback, void *callback_private_data, size_t per_buffer_data_size)
void read_stream_end(ReadStream *stream)
#define READ_STREAM_MAINTENANCE
Definition read_stream.h:28
#define READ_STREAM_USE_BATCHING
Definition read_stream.h:64
uint32 hashm_maxbucket
Definition hash.h:254
double hashm_ntuples
Definition hash.h:248
double tuples_removed
Definition genam.h:88
double num_index_tuples
Definition genam.h:87
Relation index
Definition genam.h:54
BufferAccessStrategy strategy
Definition genam.h:61

References _hash_checkpage(), _hash_dropbuf(), _hash_getbuf(), _hash_getcachedmetap(), _hash_relbuf(), Assert, BUCKET_TO_BLKNO, buf, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage(), BufferIsInvalid, BufferIsValid(), callback(), END_CRIT_SECTION, IndexBulkDeleteResult::estimated_count, fb(), H_BUCKET_BEING_SPLIT, H_NEEDS_SPLIT_CLEANUP, hash_bulkdelete_read_stream_cb(), HASH_METAPAGE, HASH_NOLOCK, hashbucketcleanup(), HashMetaPageData::hashm_maxbucket, HashMetaPageData::hashm_ntuples, HashPageGetMeta, HashPageGetOpaque, IndexVacuumInfo::index, InvalidBlockNumber, InvalidBuffer, LH_BUCKET_PAGE, LH_META_PAGE, LockBuffer(), LockBufferForCleanup(), MAIN_FORKNUM, MarkBufferDirty(), xl_hash_update_meta_page::ntuples, IndexBulkDeleteResult::num_index_tuples, PageSetLSN(), palloc0_object, read_stream_begin_relation(), read_stream_end(), READ_STREAM_MAINTENANCE, read_stream_next_buffer(), read_stream_reset(), READ_STREAM_USE_BATCHING, REGBUF_STANDARD, RelationNeedsWAL, SizeOfHashUpdateMetaPage, START_CRIT_SECTION, IndexVacuumInfo::strategy, IndexBulkDeleteResult::tuples_removed, XLOG_HASH_UPDATE_META_PAGE, XLogBeginInsert(), XLogGetFakeLSN(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by hashhandler().

◆ hashendscan()

void hashendscan ( IndexScanDesc  scan)

Definition at line 446 of file hash.c.

447{
449 Relation rel = scan->indexRelation;
450
451 if (HashScanPosIsValid(so->currPos))
452 {
453 /* Before leaving current page, deal with any killed items */
454 if (so->numKilled > 0)
455 _hash_kill_items(scan);
456 }
457
458 _hash_dropscanbuf(rel, so);
459
460 if (so->killedItems != NULL)
461 pfree(so->killedItems);
462 pfree(so);
463 scan->opaque = NULL;
464}
#define HashScanPosIsValid(scanpos)
Definition hash.h:137
void _hash_dropscanbuf(Relation rel, HashScanOpaque so)
Definition hashpage.c:289
void _hash_kill_items(IndexScanDesc scan)
Definition hashutil.c:536
Relation indexRelation
Definition relscan.h:138

References _hash_dropscanbuf(), _hash_kill_items(), fb(), HashScanPosIsValid, IndexScanDescData::indexRelation, IndexScanDescData::opaque, and pfree().

Referenced by hashhandler().

◆ hashgetbitmap()

int64 hashgetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 354 of file hash.c.

355{
357 bool res;
358 int64 ntids = 0;
360
362
363 while (res)
364 {
365 currItem = &so->currPos.items[so->currPos.itemIndex];
366
367 /*
368 * _hash_first and _hash_next handle eliminate dead index entries
369 * whenever scan->ignore_killed_tuples is true. Therefore, there's
370 * nothing to do here except add the results to the TIDBitmap.
371 */
372 tbm_add_tuples(tbm, &(currItem->heapTid), 1, true);
373 ntids++;
374
375 res = _hash_next(scan, ForwardScanDirection);
376 }
377
378 return ntids;
379}
int64_t int64
Definition c.h:615
bool _hash_first(IndexScanDesc scan, ScanDirection dir)
Definition hashsearch.c:289
bool _hash_next(IndexScanDesc scan, ScanDirection dir)
Definition hashsearch.c:49
@ ForwardScanDirection
Definition sdir.h:28
void tbm_add_tuples(TIDBitmap *tbm, const ItemPointerData *tids, int ntids, bool recheck)
Definition tidbitmap.c:367

References _hash_first(), _hash_next(), fb(), ForwardScanDirection, IndexScanDescData::opaque, and tbm_add_tuples().

Referenced by hashhandler().

◆ hashgettuple()

bool hashgettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)

Definition at line 303 of file hash.c.

304{
306 bool res;
307
308 /* Hash indexes are always lossy since we store only the hash code */
309 scan->xs_recheck = true;
310
311 /*
312 * If we've already initialized this scan, we can just advance it in the
313 * appropriate direction. If we haven't done so yet, we call a routine to
314 * get the first item in the scan.
315 */
316 if (!HashScanPosIsValid(so->currPos))
317 res = _hash_first(scan, dir);
318 else
319 {
320 /*
321 * Check to see if we should kill the previously-fetched tuple.
322 */
323 if (scan->kill_prior_tuple)
324 {
325 /*
326 * Yes, so remember it for later. (We'll deal with all such tuples
327 * at once right after leaving the index page or at end of scan.)
328 * In case if caller reverses the indexscan direction it is quite
329 * possible that the same item might get entered multiple times.
330 * But, we don't detect that; instead, we just forget any excess
331 * entries.
332 */
333 if (so->killedItems == NULL)
334 so->killedItems = palloc_array(int, MaxIndexTuplesPerPage);
335
336 if (so->numKilled < MaxIndexTuplesPerPage)
337 so->killedItems[so->numKilled++] = so->currPos.itemIndex;
338 }
339
340 /*
341 * Now continue the scan.
342 */
343 res = _hash_next(scan, dir);
344 }
345
346 return res;
347}
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define MaxIndexTuplesPerPage
Definition itup.h:181
bool kill_prior_tuple
Definition relscan.h:148

References _hash_first(), _hash_next(), fb(), HashScanPosIsValid, IndexScanDescData::kill_prior_tuple, MaxIndexTuplesPerPage, IndexScanDescData::opaque, palloc_array, and IndexScanDescData::xs_recheck.

Referenced by hashhandler().

◆ hashhandler()

Datum hashhandler ( PG_FUNCTION_ARGS  )

Definition at line 70 of file hash.c.

71{
72 static const IndexAmRoutine amroutine = {
74 .amstrategies = HTMaxStrategyNumber,
75 .amsupport = HASHNProcs,
76 .amoptsprocnum = HASHOPTIONS_PROC,
77 .amcanorder = false,
78 .amcanorderbyop = false,
79 .amcanhash = true,
80 .amconsistentequality = true,
81 .amconsistentordering = false,
82 .amcanbackward = true,
83 .amcanunique = false,
84 .amcanmulticol = false,
85 .amoptionalkey = false,
86 .amsearcharray = false,
87 .amsearchnulls = false,
88 .amstorage = false,
89 .amclusterable = false,
90 .ampredlocks = true,
91 .amcanparallel = false,
92 .amcanbuildparallel = false,
93 .amcaninclude = false,
94 .amusemaintenanceworkmem = false,
95 .amsummarizing = false,
96 .amparallelvacuumoptions =
98 .amkeytype = INT4OID,
99
100 .ambuild = hashbuild,
101 .ambuildempty = hashbuildempty,
102 .aminsert = hashinsert,
103 .aminsertcleanup = NULL,
104 .ambulkdelete = hashbulkdelete,
105 .amvacuumcleanup = hashvacuumcleanup,
106 .amcanreturn = NULL,
107 .amcostestimate = hashcostestimate,
108 .amgettreeheight = NULL,
109 .amoptions = hashoptions,
110 .amproperty = NULL,
111 .ambuildphasename = NULL,
112 .amvalidate = hashvalidate,
113 .amadjustmembers = hashadjustmembers,
114 .ambeginscan = hashbeginscan,
115 .amrescan = hashrescan,
116 .amgettuple = hashgettuple,
117 .amgetbitmap = hashgetbitmap,
118 .amendscan = hashendscan,
119 .ammarkpos = NULL,
120 .amrestrpos = NULL,
121 .amestimateparallelscan = NULL,
122 .aminitparallelscan = NULL,
123 .amparallelrescan = NULL,
124 .amtranslatestrategy = hashtranslatestrategy,
125 .amtranslatecmptype = hashtranslatecmptype,
126 };
127
129}
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition hash.c:271
IndexBulkDeleteResult * hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition hash.c:728
IndexBuildResult * hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition hash.c:135
bool hashgettuple(IndexScanDesc scan, ScanDirection dir)
Definition hash.c:303
CompareType hashtranslatestrategy(StrategyNumber strategy, Oid opfamily)
Definition hash.c:1014
void hashbuildempty(Relation index)
Definition hash.c:221
IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys)
Definition hash.c:386
StrategyNumber hashtranslatecmptype(CompareType cmptype, Oid opfamily)
Definition hash.c:1022
IndexBulkDeleteResult * hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition hash.c:498
void hashrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition hash.c:416
void hashendscan(IndexScanDesc scan)
Definition hash.c:446
int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition hash.c:354
#define HASHNProcs
Definition hash.h:358
#define HASHOPTIONS_PROC
Definition hash.h:357
bytea * hashoptions(Datum reloptions, bool validate)
Definition hashutil.c:275
void hashadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
bool hashvalidate(Oid opclassoid)
void hashcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition selfuncs.c:8162
#define HTMaxStrategyNumber
Definition stratnum.h:43
NodeTag type
Definition amapi.h:234
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition vacuum.h:47

References fb(), hashadjustmembers(), hashbeginscan(), hashbuild(), hashbuildempty(), hashbulkdelete(), hashcostestimate(), hashendscan(), hashgetbitmap(), hashgettuple(), hashinsert(), HASHNProcs, hashoptions(), HASHOPTIONS_PROC, hashrescan(), hashtranslatecmptype(), hashtranslatestrategy(), hashvacuumcleanup(), hashvalidate(), HTMaxStrategyNumber, PG_RETURN_POINTER, IndexAmRoutine::type, and VACUUM_OPTION_PARALLEL_BULKDEL.

◆ hashinsert()

bool hashinsert ( Relation  rel,
Datum values,
bool isnull,
ItemPointer  ht_ctid,
Relation  heapRel,
IndexUniqueCheck  checkUnique,
bool  indexUnchanged,
IndexInfo indexInfo 
)

Definition at line 271 of file hash.c.

276{
278 bool index_isnull[1];
279 IndexTuple itup;
280
281 /* convert data to a hash key; on failure, do not insert anything */
282 if (!_hash_convert_tuple(rel,
283 values, isnull,
285 return false;
286
287 /* form an index tuple and point it at the heap tuple */
289 itup->t_tid = *ht_ctid;
290
291 _hash_doinsert(rel, itup, heapRel, false);
292
293 pfree(itup);
294
295 return false;
296}

References _hash_convert_tuple(), _hash_doinsert(), fb(), index_form_tuple(), pfree(), RelationGetDescr, IndexTupleData::t_tid, and values.

Referenced by hashhandler().

◆ hashrescan()

void hashrescan ( IndexScanDesc  scan,
ScanKey  scankey,
int  nscankeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 416 of file hash.c.

418{
420 Relation rel = scan->indexRelation;
421
422 if (HashScanPosIsValid(so->currPos))
423 {
424 /* Before leaving current page, deal with any killed items */
425 if (so->numKilled > 0)
426 _hash_kill_items(scan);
427 }
428
429 _hash_dropscanbuf(rel, so);
430
431 /* set position invalid (this will cause _hash_first call) */
432 HashScanPosInvalidate(so->currPos);
433
434 /* Update scan key, if a new one is given */
435 if (scankey && scan->numberOfKeys > 0)
436 memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
437
438 so->hashso_buc_populated = false;
439 so->hashso_buc_split = false;
440}
struct ScanKeyData * keyData
Definition relscan.h:142

References _hash_dropscanbuf(), _hash_kill_items(), fb(), HashScanPosInvalidate, HashScanPosIsValid, IndexScanDescData::indexRelation, IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, and IndexScanDescData::opaque.

Referenced by hashhandler().

◆ hashtranslatecmptype()

StrategyNumber hashtranslatecmptype ( CompareType  cmptype,
Oid  opfamily 
)

Definition at line 1022 of file hash.c.

1023{
1024 if (cmptype == COMPARE_EQ)
1025 return HTEqualStrategyNumber;
1026 return InvalidStrategy;
1027}
@ COMPARE_EQ
Definition cmptype.h:36
#define InvalidStrategy
Definition stratnum.h:24
#define HTEqualStrategyNumber
Definition stratnum.h:41

References COMPARE_EQ, HTEqualStrategyNumber, and InvalidStrategy.

Referenced by hashhandler().

◆ hashtranslatestrategy()

CompareType hashtranslatestrategy ( StrategyNumber  strategy,
Oid  opfamily 
)

Definition at line 1014 of file hash.c.

1015{
1016 if (strategy == HTEqualStrategyNumber)
1017 return COMPARE_EQ;
1018 return COMPARE_INVALID;
1019}
@ COMPARE_INVALID
Definition cmptype.h:33

References COMPARE_EQ, COMPARE_INVALID, and HTEqualStrategyNumber.

Referenced by hashhandler().

◆ hashvacuumcleanup()

IndexBulkDeleteResult * hashvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 728 of file hash.c.

729{
730 Relation rel = info->index;
731 BlockNumber num_pages;
732
733 /* If hashbulkdelete wasn't called, return NULL signifying no change */
734 /* Note: this covers the analyze_only case too */
735 if (stats == NULL)
736 return NULL;
737
738 /* update statistics */
739 num_pages = RelationGetNumberOfBlocks(rel);
740 stats->num_pages = num_pages;
741
742 return stats;
743}
BlockNumber num_pages
Definition genam.h:85

References fb(), IndexVacuumInfo::index, IndexBulkDeleteResult::num_pages, and RelationGetNumberOfBlocks.

Referenced by hashhandler().