PostgreSQL Source Code git master
Loading...
Searching...
No Matches
dynahash.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/xact.h"
#include "common/hashfn.h"
#include "lib/ilist.h"
#include "port/pg_bitutils.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "utils/memutils.h"
Include dependency graph for dynahash.c:

Go to the source code of this file.

Data Structures

struct  FreeListData
 
struct  HASHHDR
 
struct  HTAB
 

Macros

#define HASH_SEGSIZE   256
 
#define HASH_SEGSIZE_SHIFT   8 /* must be log2(HASH_SEGSIZE) */
 
#define DEF_DIRSIZE   256
 
#define NUM_FREELISTS   32
 
#define IS_PARTITIONED(hctl)   ((hctl)->num_partitions != 0)
 
#define FREELIST_IDX(hctl, hashcode)    (IS_PARTITIONED(hctl) ? (hashcode) % NUM_FREELISTS : 0)
 
#define ELEMENTKEY(helem)   (((char *)(helem)) + MAXALIGN(sizeof(HASHELEMENT)))
 
#define ELEMENT_FROM_KEY(key)    ((HASHELEMENT *) (((char *) (key)) - MAXALIGN(sizeof(HASHELEMENT))))
 
#define MOD(x, y)   ((x) & ((y)-1))
 
#define MAX_SEQ_SCANS   100
 

Typedefs

typedef HASHELEMENTHASHBUCKET
 
typedef HASHBUCKETHASHSEGMENT
 

Functions

static voidDynaHashAlloc (Size size, void *alloc_arg)
 
static HASHSEGMENT seg_alloc (HTAB *hashp)
 
static bool element_alloc (HTAB *hashp, int nelem, int freelist_idx)
 
static bool dir_realloc (HTAB *hashp)
 
static bool expand_table (HTAB *hashp)
 
static HASHBUCKET get_hash_entry (HTAB *hashp, int freelist_idx)
 
static void hdefault (HTAB *hashp)
 
static int choose_nelem_alloc (Size entrysize)
 
static bool init_htab (HTAB *hashp, int64 nelem)
 
static pg_noreturn void hash_corrupted (HTAB *hashp)
 
static uint32 hash_initial_lookup (HTAB *hashp, uint32 hashvalue, HASHBUCKET **bucketptr)
 
static int my_log2 (int64 num)
 
static int64 next_pow2_int64 (int64 num)
 
static int next_pow2_int (int64 num)
 
static void register_seq_scan (HTAB *hashp)
 
static void deregister_seq_scan (HTAB *hashp)
 
static bool has_seq_scans (HTAB *hashp)
 
static int string_compare (const char *key1, const char *key2, Size keysize)
 
HTABhash_create (const char *tabname, int64 nelem, const HASHCTL *info, int flags)
 
Size hash_estimate_size (int64 num_entries, Size entrysize)
 
void hash_destroy (HTAB *hashp)
 
void hash_stats (const char *caller, HTAB *hashp)
 
uint32 get_hash_value (HTAB *hashp, const void *keyPtr)
 
static uint32 calc_bucket (HASHHDR *hctl, uint32 hash_val)
 
voidhash_search (HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
 
voidhash_search_with_hash_value (HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
 
bool hash_update_hash_key (HTAB *hashp, void *existingEntry, const void *newKeyPtr)
 
int64 hash_get_num_entries (HTAB *hashp)
 
void hash_seq_init (HASH_SEQ_STATUS *status, HTAB *hashp)
 
void hash_seq_init_with_hash_value (HASH_SEQ_STATUS *status, HTAB *hashp, uint32 hashvalue)
 
voidhash_seq_search (HASH_SEQ_STATUS *status)
 
void hash_seq_term (HASH_SEQ_STATUS *status)
 
void hash_freeze (HTAB *hashp)
 
void AtEOXact_HashTables (bool isCommit)
 
void AtEOSubXact_HashTables (bool isCommit, int nestDepth)
 

Variables

static HTABseq_scan_tables [MAX_SEQ_SCANS]
 
static int seq_scan_level [MAX_SEQ_SCANS]
 
static int num_seq_scans = 0
 

Macro Definition Documentation

◆ DEF_DIRSIZE

#define DEF_DIRSIZE   256

Definition at line 127 of file dynahash.c.

◆ ELEMENT_FROM_KEY

#define ELEMENT_FROM_KEY (   key)     ((HASHELEMENT *) (((char *) (key)) - MAXALIGN(sizeof(HASHELEMENT))))

Definition at line 262 of file dynahash.c.

297{
298 MemoryContext hcxt = (MemoryContext) alloc_arg;
299
302}
303
304
305/*
306 * HashCompareFunc for string keys
307 *
308 * Because we copy keys with strlcpy(), they will be truncated at keysize-1
309 * bytes, so we can only compare that many ... hence strncmp is almost but
310 * not quite the right thing.
311 */
312static int
313string_compare(const char *key1, const char *key2, Size keysize)
314{
315 return strncmp(key1, key2, keysize - 1);
316}
317
318
319/************************** CREATE ROUTINES **********************/
320
321/*
322 * hash_create -- create a new dynamic hash table
323 *
324 * tabname: a name for the table (for debugging purposes)
325 * nelem: maximum number of elements expected
326 * *info: additional table parameters, as indicated by flags
327 * flags: bitmask indicating which parameters to take from *info
328 *
329 * The flags value *must* include HASH_ELEM. (Formerly, this was nominally
330 * optional, but the default keysize and entrysize values were useless.)
331 * The flags value must also include exactly one of HASH_STRINGS, HASH_BLOBS,
332 * or HASH_FUNCTION, to define the key hashing semantics (C strings,
333 * binary blobs, or custom, respectively). Callers specifying a custom
334 * hash function will likely also want to use HASH_COMPARE, and perhaps
335 * also HASH_KEYCOPY, to control key comparison and copying.
336 * Another often-used flag is HASH_CONTEXT, to allocate the hash table
337 * under info->hcxt rather than under TopMemoryContext; the default
338 * behavior is only suitable for session-lifespan hash tables.
339 * Other flags bits are special-purpose and seldom used, except for those
340 * associated with shared-memory hash tables, for which see
341 * ShmemRequestHash().
342 *
343 * Fields in *info are read only when the associated flags bit is set.
344 * It is not necessary to initialize other fields of *info.
345 * Neither tabname nor *info need persist after the hash_create() call.
346 *
347 * Note: It is deprecated for callers of hash_create() to explicitly specify
348 * string_hash, tag_hash, uint32_hash, or oid_hash. Just set HASH_STRINGS or
349 * HASH_BLOBS. Use HASH_FUNCTION only when you want something other than
350 * one of these.
351 *
352 * Note: for a shared-memory hashtable, nelem needs to be a pretty good
353 * estimate, since we can't expand the table on the fly. But an unshared
354 * hashtable can be expanded on-the-fly, so it's better for nelem to be
355 * on the small side and let the table grow if it's exceeded. An overly
356 * large nelem will penalize hash_seq_search speed without buying much.
357 */
358HTAB *
359hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
360{
361 HTAB *hashp;
362 HASHHDR *hctl;
363 MemoryContext hcxt;
364
365 /*
366 * Hash tables now allocate space for key and data, but you have to say
367 * how much space to allocate.
368 */
369 Assert(flags & HASH_ELEM);
370 Assert(info->keysize > 0);
371 Assert(info->entrysize >= info->keysize);
372
373 /*
374 * For shared hash tables, we have a local hash header (HTAB struct) that
375 * we allocate in TopMemoryContext; all else is in shared memory.
376 *
377 * For non-shared hash tables, everything including the hash header is in
378 * a memory context created specially for the hash table --- this makes
379 * hash_destroy very simple. The memory context is made a child of either
380 * a context specified by the caller, or TopMemoryContext if nothing is
381 * specified.
382 *
383 * Note that HASH_ALLOC had better be set as well.
384 */
385 if (flags & HASH_SHARED_MEM)
386 {
387 /* Set up to allocate the hash header */
388 hcxt = TopMemoryContext;
389 }
390 else
391 {
392 /* Create the hash table's private memory context */
393 if (flags & HASH_CONTEXT)
394 hcxt = info->hcxt;
395 else
396 hcxt = TopMemoryContext;
397 hcxt = AllocSetContextCreate(hcxt, "dynahash",
399 }
400
401 /* Initialize the hash header, plus a copy of the table name */
402 hashp = (HTAB *) MemoryContextAlloc(hcxt,
403 sizeof(HTAB) + strlen(tabname) + 1);
404 MemSet(hashp, 0, sizeof(HTAB));
405
406 hashp->tabname = (char *) (hashp + 1);
407 strcpy(hashp->tabname, tabname);
408
409 /* If we have a private context, label it with hashtable's name */
410 if (!(flags & HASH_SHARED_MEM))
412
413 /*
414 * Select the appropriate hash function (see comments at head of file).
415 */
416 if (flags & HASH_FUNCTION)
417 {
418 Assert(!(flags & (HASH_BLOBS | HASH_STRINGS)));
419 hashp->hash = info->hash;
420 }
421 else if (flags & HASH_BLOBS)
422 {
423 Assert(!(flags & HASH_STRINGS));
424 /* We can optimize hashing for common key sizes */
425 if (info->keysize == sizeof(uint32))
426 hashp->hash = uint32_hash;
427 else
428 hashp->hash = tag_hash;
429 }
430 else
431 {
432 /*
433 * string_hash used to be considered the default hash method, and in a
434 * non-assert build it effectively still is. But we now consider it
435 * an assertion error to not say HASH_STRINGS explicitly. To help
436 * catch mistaken usage of HASH_STRINGS, we also insist on a
437 * reasonably long string length: if the keysize is only 4 or 8 bytes,
438 * it's almost certainly an integer or pointer not a string.
439 */
440 Assert(flags & HASH_STRINGS);
441 Assert(info->keysize > 8);
442
443 hashp->hash = string_hash;
444 }
445
446 /*
447 * If you don't specify a match function, it defaults to string_compare if
448 * you used string_hash, and to memcmp otherwise.
449 *
450 * Note: explicitly specifying string_hash is deprecated, because this
451 * might not work for callers in loadable modules on some platforms due to
452 * referencing a trampoline instead of the string_hash function proper.
453 * Specify HASH_STRINGS instead.
454 */
455 if (flags & HASH_COMPARE)
456 hashp->match = info->match;
457 else if (hashp->hash == string_hash)
459 else
460 hashp->match = memcmp;
461
462 /*
463 * Similarly, the key-copying function defaults to strlcpy or memcpy.
464 */
465 if (flags & HASH_KEYCOPY)
466 hashp->keycopy = info->keycopy;
467 else if (hashp->hash == string_hash)
468 {
469 /*
470 * The signature of keycopy is meant for memcpy(), which returns
471 * void*, but strlcpy() returns size_t. Since we never use the return
472 * value of keycopy, and size_t is pretty much always the same size as
473 * void *, this should be safe. The extra cast in the middle is to
474 * avoid warnings from -Wcast-function-type.
475 */
477 }
478 else
479 hashp->keycopy = memcpy;
480
481 /* And select the entry allocation function, too. */
482 if (flags & HASH_ALLOC)
483 {
484 hashp->alloc = info->alloc;
485 hashp->alloc_arg = info->alloc_arg;
486 }
487 else
488 {
489 hashp->alloc = DynaHashAlloc;
490 hashp->alloc_arg = hcxt;
491 }
492
493 if (flags & HASH_SHARED_MEM)
494 {
495 hashp->hcxt = NULL;
496 hashp->isshared = true;
497
498 /* hash table already exists, we're just attaching to it */
499 if (flags & HASH_ATTACH)
500 {
501 /* Caller must pass the pointer to the shared header */
502 Assert(info->hctl);
503 hashp->hctl = info->hctl;
504
505 /* make local copies of some heavily-used values */
506 hashp->dir = info->hctl->dir;
507 hashp->keysize = info->hctl->keysize;
508
509 return hashp;
510 }
511 }
512 else
513 {
514 /* setup hash table defaults */
515 hashp->hctl = NULL;
516 hashp->dir = NULL;
517 hashp->hcxt = hcxt;
518 hashp->isshared = false;
519 }
520
521 /*
522 * Allocate the header structure.
523 *
524 * XXX: In case of a shared memory hash table, other processes need the
525 * pointer to the header to re-find the hash table. There is currently no
526 * explicit way to pass it back from here, the caller relies on the fact
527 * that this is the first allocation made with the alloc function. That's
528 * a little ugly, but works for now.
529 */
530 hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR), hashp->alloc_arg);
531 if (!hashp->hctl)
534 errmsg("out of memory")));
535
536 hashp->frozen = false;
537
538 hdefault(hashp);
539
540 hctl = hashp->hctl;
541
542 if (flags & HASH_PARTITION)
543 {
544 /* Doesn't make sense to partition a local hash table */
545 Assert(flags & HASH_SHARED_MEM);
546
547 /*
548 * The number of partitions had better be a power of 2. Also, it must
549 * be less than INT_MAX (see init_htab()), so call the int version of
550 * next_pow2.
551 */
553
554 hctl->num_partitions = info->num_partitions;
555 }
556
557 /* remember the entry sizes, too */
558 hctl->keysize = info->keysize;
559 hctl->entrysize = info->entrysize;
560
561 /* make local copies of heavily-used constant fields */
562 hashp->keysize = hctl->keysize;
563
564 /* Build the hash directory structure */
565 if (!init_htab(hashp, nelem))
566 elog(ERROR, "failed to initialize hash table \"%s\"", hashp->tabname);
567
568 /*
569 * For a shared hash table, preallocate the requested number of elements.
570 * This reduces problems with run-time out-of-shared-memory conditions.
571 *
572 * For a non-shared hash table, preallocate the requested number of
573 * elements if it's less than our chosen nelem_alloc. This avoids wasting
574 * space if the caller correctly estimates a small table size.
575 */
576 if ((flags & HASH_SHARED_MEM) ||
577 nelem < hctl->nelem_alloc)
578 {
579 int i,
581 nelem_alloc,
583
584 /*
585 * If hash table is partitioned, give each freelist an equal share of
586 * the initial allocation. Otherwise only freeList[0] is used.
587 */
588 if (IS_PARTITIONED(hashp->hctl))
590 else
592
593 nelem_alloc = nelem / freelist_partitions;
594 if (nelem_alloc <= 0)
595 nelem_alloc = 1;
596
597 /*
598 * Make sure we'll allocate all the requested elements; freeList[0]
599 * gets the excess if the request isn't divisible by NUM_FREELISTS.
600 */
601 if (nelem_alloc * freelist_partitions < nelem)
603 nelem - nelem_alloc * (freelist_partitions - 1);
604 else
605 nelem_alloc_first = nelem_alloc;
606
607 for (i = 0; i < freelist_partitions; i++)
608 {
609 int temp = (i == 0) ? nelem_alloc_first : nelem_alloc;
610
611 if (!element_alloc(hashp, temp, i))
614 errmsg("out of memory")));
615 }
616 }
617
618 /* Set isfixed if requested, but not till after we build initial entries */
619 if (flags & HASH_FIXED_SIZE)
620 hctl->isfixed = true;
621
622 return hashp;
623}
624
625/*
626 * Set default HASHHDR parameters.
627 */
628static void
629hdefault(HTAB *hashp)
630{
631 HASHHDR *hctl = hashp->hctl;
632
633 MemSet(hctl, 0, sizeof(HASHHDR));
634
635 hctl->num_partitions = 0; /* not partitioned */
636
637 /* table has no fixed maximum size */
638 hctl->max_dsize = NO_MAX_DSIZE;
639
640 hctl->isfixed = false; /* can be enlarged */
641
642#ifdef HASH_STATISTICS
643 hctl->accesses = hctl->collisions = hctl->expansions = 0;
644#endif
645}
646
647/*
648 * Given the user-specified entry size, choose nelem_alloc, ie, how many
649 * elements to add to the hash table when we need more.
650 */
651static int
652choose_nelem_alloc(Size entrysize)
653{
654 int nelem_alloc;
657
658 /* Each element has a HASHELEMENT header plus user data. */
659 /* NB: this had better match element_alloc() */
660 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
661
662 /*
663 * The idea here is to choose nelem_alloc at least 32, but round up so
664 * that the allocation request will be a power of 2 or just less. This
665 * makes little difference for hash tables in shared memory, but for hash
666 * tables managed by palloc, the allocation request will be rounded up to
667 * a power of 2 anyway. If we fail to take this into account, we'll waste
668 * as much as half the allocated space.
669 */
670 allocSize = 32 * 4; /* assume elementSize at least 8 */
671 do
672 {
673 allocSize <<= 1;
674 nelem_alloc = allocSize / elementSize;
675 } while (nelem_alloc < 32);
676
677 return nelem_alloc;
678}
679
680/*
681 * Compute derived fields of hctl and build the initial directory/segment
682 * arrays
683 */
684static bool
685init_htab(HTAB *hashp, int64 nelem)
686{
687 HASHHDR *hctl = hashp->hctl;
689 int nbuckets;
690 int nsegs;
691 int i;
692
693 /*
694 * initialize mutexes if it's a partitioned table
695 */
696 if (IS_PARTITIONED(hctl))
697 for (i = 0; i < NUM_FREELISTS; i++)
698 SpinLockInit(&(hctl->freeList[i].mutex));
699
700 /*
701 * Allocate space for the next greater power of two number of buckets,
702 * assuming a desired maximum load factor of 1.
703 */
704 nbuckets = next_pow2_int(nelem);
705
706 /*
707 * In a partitioned table, nbuckets must be at least equal to
708 * num_partitions; were it less, keys with apparently different partition
709 * numbers would map to the same bucket, breaking partition independence.
710 * (Normally nbuckets will be much bigger; this is just a safety check.)
711 */
712 while (nbuckets < hctl->num_partitions)
713 nbuckets <<= 1;
714
715 hctl->max_bucket = hctl->low_mask = nbuckets - 1;
716 hctl->high_mask = (nbuckets << 1) - 1;
717
718 /*
719 * Figure number of directory segments needed, round up to a power of 2
720 */
721 nsegs = (nbuckets - 1) / HASH_SEGSIZE + 1;
722 nsegs = next_pow2_int(nsegs);
723
724 /*
725 * Make sure directory is big enough.
726 */
727 hctl->dsize = Max(DEF_DIRSIZE, nsegs);
728
729 /* SHM hash tables have a fixed directory. */
730 if (hashp->isshared)
731 hctl->max_dsize = hctl->dsize;
732
733 /* Allocate a directory */
734 hctl->dir = (HASHSEGMENT *)
735 hashp->alloc(hctl->dsize * sizeof(HASHSEGMENT), hashp->alloc_arg);
736 if (!hctl->dir)
737 return false;
738 hashp->dir = hctl->dir;
739
740 /* Allocate initial segments */
741 for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
742 {
743 *segp = seg_alloc(hashp);
744 if (*segp == NULL)
745 return false;
746 }
747
748 /* Choose number of entries to allocate at a time */
750
751 return true;
752}
753
754/*
755 * Estimate the space needed for a hashtable containing the given number
756 * of entries of given size.
757 * NOTE: this is used to estimate the footprint of hashtables in shared
758 * memory; therefore it does not count HTAB which is in local memory.
759 * NB: assumes that all hash structure parameters have default values!
760 */
761Size
762hash_estimate_size(int64 num_entries, Size entrysize)
763{
764 Size size;
766 nSegments,
771
772 /* estimate number of buckets wanted */
773 nBuckets = next_pow2_int64(num_entries);
774 /* # of segments needed for nBuckets */
776 /* directory entries */
778
779 /* fixed control info */
780 size = MAXALIGN(sizeof(HASHHDR)); /* but not HTAB, per above */
781 /* directory */
782 size = add_size(size, mul_size(nDirEntries, sizeof(HASHSEGMENT)));
783 /* segments */
784 size = add_size(size, mul_size(nSegments,
785 MAXALIGN(HASH_SEGSIZE * sizeof(HASHBUCKET))));
786 /* elements --- allocated in groups of choose_nelem_alloc() entries */
788 nElementAllocs = (num_entries - 1) / elementAllocCnt + 1;
789 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
790 size = add_size(size,
793
794 return size;
795}
796
797
798/********************** DESTROY ROUTINES ************************/
799
800void
801hash_destroy(HTAB *hashp)
802{
803 if (hashp != NULL)
804 {
805 /* allocation method must be one we know how to free, too */
806 Assert(hashp->alloc == DynaHashAlloc);
807 /* so this hashtable must have its own context */
808 Assert(hashp->hcxt != NULL);
809
810 hash_stats(__func__, hashp);
811
812 /*
813 * Free everything by destroying the hash table's memory context.
814 */
816 }
817}
818
819void
820hash_stats(const char *caller, HTAB *hashp)
821{
822#ifdef HASH_STATISTICS
823 HASHHDR *hctl = hashp->hctl;
824
825 elog(DEBUG4,
826 "hash_stats: Caller: %s Table Name: \"%s\" Accesses: " UINT64_FORMAT " Collisions: " UINT64_FORMAT " Expansions: " UINT64_FORMAT " Entries: " INT64_FORMAT " Key Size: %zu Max Bucket: %u Segment Count: " INT64_FORMAT,
827 caller != NULL ? caller : "(unknown)", hashp->tabname, hctl->accesses,
828 hctl->collisions, hctl->expansions, hash_get_num_entries(hashp),
829 hctl->keysize, hctl->max_bucket, hctl->nsegs);
830#endif
831}
832
833/*******************************SEARCH ROUTINES *****************************/
834
835
836/*
837 * get_hash_value -- exported routine to calculate a key's hash value
838 *
839 * We export this because for partitioned tables, callers need to compute
840 * the partition number (from the low-order bits of the hash value) before
841 * searching.
842 */
843uint32
844get_hash_value(HTAB *hashp, const void *keyPtr)
845{
846 return hashp->hash(keyPtr, hashp->keysize);
847}
848
849/* Convert a hash value to a bucket number */
850static inline uint32
852{
854
855 bucket = hash_val & hctl->high_mask;
856 if (bucket > hctl->max_bucket)
857 bucket = bucket & hctl->low_mask;
858
859 return bucket;
860}
861
862/*
863 * hash_search -- look up key in table and perform action
864 * hash_search_with_hash_value -- same, with key's hash value already computed
865 *
866 * action is one of:
867 * HASH_FIND: look up key in table
868 * HASH_ENTER: look up key in table, creating entry if not present
869 * HASH_ENTER_NULL: same, but return NULL if out of memory
870 * HASH_REMOVE: look up key in table, remove entry if present
871 *
872 * Return value is a pointer to the element found/entered/removed if any,
873 * or NULL if no match was found. (NB: in the case of the REMOVE action,
874 * the result is a dangling pointer that shouldn't be dereferenced!)
875 *
876 * HASH_ENTER will normally ereport a generic "out of memory" error if
877 * it is unable to create a new entry. The HASH_ENTER_NULL operation is
878 * the same except it will return NULL if out of memory.
879 *
880 * If foundPtr isn't NULL, then *foundPtr is set true if we found an
881 * existing entry in the table, false otherwise. This is needed in the
882 * HASH_ENTER case, but is redundant with the return value otherwise.
883 *
884 * For hash_search_with_hash_value, the hashvalue parameter must have been
885 * calculated with get_hash_value().
886 */
887void *
888hash_search(HTAB *hashp,
889 const void *keyPtr,
890 HASHACTION action,
891 bool *foundPtr)
892{
893 return hash_search_with_hash_value(hashp,
894 keyPtr,
895 hashp->hash(keyPtr, hashp->keysize),
896 action,
897 foundPtr);
898}
899
900void *
902 const void *keyPtr,
903 uint32 hashvalue,
904 HASHACTION action,
905 bool *foundPtr)
906{
907 HASHHDR *hctl = hashp->hctl;
908 int freelist_idx = FREELIST_IDX(hctl, hashvalue);
909 Size keysize;
912 HashCompareFunc match;
913
914#ifdef HASH_STATISTICS
915 hctl->accesses++;
916#endif
917
918 /*
919 * If inserting, check if it is time to split a bucket.
920 *
921 * NOTE: failure to expand table is not a fatal error, it just means we
922 * have to run at higher fill factor than we wanted. However, if we're
923 * using the palloc allocator then it will throw error anyway on
924 * out-of-memory, so we must do this before modifying the table.
925 */
926 if (action == HASH_ENTER || action == HASH_ENTER_NULL)
927 {
928 /*
929 * Can't split if running in partitioned mode, nor if frozen, nor if
930 * table is the subject of any active hash_seq_search scans.
931 */
932 if (hctl->freeList[0].nentries > (int64) hctl->max_bucket &&
933 !IS_PARTITIONED(hctl) && !hashp->frozen &&
934 !has_seq_scans(hashp))
935 (void) expand_table(hashp);
936 }
937
938 /*
939 * Do the initial lookup
940 */
941 (void) hash_initial_lookup(hashp, hashvalue, &prevBucketPtr);
943
944 /*
945 * Follow collision chain looking for matching key
946 */
947 match = hashp->match; /* save one fetch in inner loop */
948 keysize = hashp->keysize; /* ditto */
949
950 while (currBucket != NULL)
951 {
952 if (currBucket->hashvalue == hashvalue &&
953 match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
954 break;
955 prevBucketPtr = &(currBucket->link);
957#ifdef HASH_STATISTICS
958 hctl->collisions++;
959#endif
960 }
961
962 if (foundPtr)
963 *foundPtr = (bool) (currBucket != NULL);
964
965 /*
966 * OK, now what?
967 */
968 switch (action)
969 {
970 case HASH_FIND:
971 if (currBucket != NULL)
972 return ELEMENTKEY(currBucket);
973 return NULL;
974
975 case HASH_REMOVE:
976 if (currBucket != NULL)
977 {
978 /* if partitioned, must lock to touch nentries and freeList */
979 if (IS_PARTITIONED(hctl))
981
982 /* delete the record from the appropriate nentries counter. */
985
986 /* remove record from hash bucket's chain. */
987 *prevBucketPtr = currBucket->link;
988
989 /* add the record to the appropriate freelist. */
992
993 if (IS_PARTITIONED(hctl))
995
996 /*
997 * better hope the caller is synchronizing access to this
998 * element, because someone else is going to reuse it the next
999 * time something is added to the table
1000 */
1001 return ELEMENTKEY(currBucket);
1002 }
1003 return NULL;
1004
1005 case HASH_ENTER:
1006 case HASH_ENTER_NULL:
1007 /* Return existing element if found, else create one */
1008 if (currBucket != NULL)
1009 return ELEMENTKEY(currBucket);
1010
1011 /* disallow inserts if frozen */
1012 if (hashp->frozen)
1013 elog(ERROR, "cannot insert into frozen hashtable \"%s\"",
1014 hashp->tabname);
1015
1017 if (currBucket == NULL)
1018 {
1019 /* out of memory */
1020 if (action == HASH_ENTER_NULL)
1021 return NULL;
1022 /* report a generic message */
1023 if (hashp->isshared)
1024 ereport(ERROR,
1026 errmsg("out of shared memory")));
1027 else
1028 ereport(ERROR,
1030 errmsg("out of memory")));
1031 }
1032
1033 /* link into hashbucket chain */
1035 currBucket->link = NULL;
1036
1037 /* copy key into record */
1038 currBucket->hashvalue = hashvalue;
1039 hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize);
1040
1041 /*
1042 * Caller is expected to fill the data field on return. DO NOT
1043 * insert any code that could possibly throw error here, as doing
1044 * so would leave the table entry incomplete and hence corrupt the
1045 * caller's data structure.
1046 */
1047
1048 return ELEMENTKEY(currBucket);
1049 }
1050
1051 elog(ERROR, "unrecognized hash action code: %d", (int) action);
1052
1053 return NULL; /* keep compiler quiet */
1054}
1055
1056/*
1057 * hash_update_hash_key -- change the hash key of an existing table entry
1058 *
1059 * This is equivalent to removing the entry, making a new entry, and copying
1060 * over its data, except that the entry never goes to the table's freelist.
1061 * Therefore this cannot suffer an out-of-memory failure, even if there are
1062 * other processes operating in other partitions of the hashtable.
1063 *
1064 * Returns true if successful, false if the requested new hash key is already
1065 * present. Throws error if the specified entry pointer isn't actually a
1066 * table member.
1067 *
1068 * NB: currently, there is no special case for old and new hash keys being
1069 * identical, which means we'll report false for that situation. This is
1070 * preferable for existing uses.
1071 *
1072 * NB: for a partitioned hashtable, caller must hold lock on both relevant
1073 * partitions, if the new hash key would belong to a different partition.
1074 */
1075bool
1077 void *existingEntry,
1078 const void *newKeyPtr)
1079{
1082 Size keysize;
1083 uint32 bucket;
1088 HashCompareFunc match;
1089
1090#ifdef HASH_STATISTICS
1091 HASHHDR *hctl = hashp->hctl;
1092
1093 hctl->accesses++;
1094#endif
1095
1096 /* disallow updates if frozen */
1097 if (hashp->frozen)
1098 elog(ERROR, "cannot update in frozen hashtable \"%s\"",
1099 hashp->tabname);
1100
1101 /*
1102 * Lookup the existing element using its saved hash value. We need to do
1103 * this to be able to unlink it from its hash chain, but as a side benefit
1104 * we can verify the validity of the passed existingEntry pointer.
1105 */
1106 bucket = hash_initial_lookup(hashp, existingElement->hashvalue,
1107 &prevBucketPtr);
1109
1110 while (currBucket != NULL)
1111 {
1113 break;
1114 prevBucketPtr = &(currBucket->link);
1116 }
1117
1118 if (currBucket == NULL)
1119 elog(ERROR, "hash_update_hash_key argument is not in hashtable \"%s\"",
1120 hashp->tabname);
1121
1123
1124 /*
1125 * Now perform the equivalent of a HASH_ENTER operation to locate the hash
1126 * chain we want to put the entry into.
1127 */
1128 newhashvalue = hashp->hash(newKeyPtr, hashp->keysize);
1131
1132 /*
1133 * Follow collision chain looking for matching key
1134 */
1135 match = hashp->match; /* save one fetch in inner loop */
1136 keysize = hashp->keysize; /* ditto */
1137
1138 while (currBucket != NULL)
1139 {
1140 if (currBucket->hashvalue == newhashvalue &&
1141 match(ELEMENTKEY(currBucket), newKeyPtr, keysize) == 0)
1142 break;
1143 prevBucketPtr = &(currBucket->link);
1145#ifdef HASH_STATISTICS
1146 hctl->collisions++;
1147#endif
1148 }
1149
1150 if (currBucket != NULL)
1151 return false; /* collision with an existing entry */
1152
1154
1155 /*
1156 * If old and new hash values belong to the same bucket, we need not
1157 * change any chain links, and indeed should not since this simplistic
1158 * update will corrupt the list if currBucket is the last element. (We
1159 * cannot fall out earlier, however, since we need to scan the bucket to
1160 * check for duplicate keys.)
1161 */
1162 if (bucket != newbucket)
1163 {
1164 /* OK to remove record from old hash bucket's chain. */
1165 *oldPrevPtr = currBucket->link;
1166
1167 /* link into new hashbucket chain */
1169 currBucket->link = NULL;
1170 }
1171
1172 /* copy new key into record */
1173 currBucket->hashvalue = newhashvalue;
1174 hashp->keycopy(ELEMENTKEY(currBucket), newKeyPtr, keysize);
1175
1176 /* rest of record is untouched */
1177
1178 return true;
1179}
1180
1181/*
1182 * Allocate a new hashtable entry if possible; return NULL if out of memory.
1183 * (Or, if the underlying space allocator throws error for out-of-memory,
1184 * we won't return at all.)
1185 */
1186static HASHBUCKET
1187get_hash_entry(HTAB *hashp, int freelist_idx)
1188{
1189 HASHHDR *hctl = hashp->hctl;
1191
1192 for (;;)
1193 {
1194 /* if partitioned, must lock to touch nentries and freeList */
1195 if (IS_PARTITIONED(hctl))
1197
1198 /* try to get an entry from the freelist */
1200
1201 if (newElement != NULL)
1202 break;
1203
1204 if (IS_PARTITIONED(hctl))
1206
1207 /*
1208 * No free elements in this freelist. In a partitioned table, there
1209 * might be entries in other freelists, but to reduce contention we
1210 * prefer to first try to get another chunk of buckets from the main
1211 * shmem allocator. If that fails, though, we *MUST* root through all
1212 * the other freelists before giving up. There are multiple callers
1213 * that assume that they can allocate every element in the initially
1214 * requested table size, or that deleting an element guarantees they
1215 * can insert a new element, even if shared memory is entirely full.
1216 * Failing because the needed element is in a different freelist is
1217 * not acceptable.
1218 */
1219 if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx))
1220 {
1221 int borrow_from_idx;
1222
1223 if (!IS_PARTITIONED(hctl))
1224 return NULL; /* out of memory */
1225
1226 /* try to borrow element from another freelist */
1228 for (;;)
1229 {
1232 break; /* examined all freelists, fail */
1233
1236
1237 if (newElement != NULL)
1238 {
1241
1242 /* careful: count the new element in its proper freelist */
1246
1247 return newElement;
1248 }
1249
1251 }
1252
1253 /* no elements available to borrow either, so out of memory */
1254 return NULL;
1255 }
1256 }
1257
1258 /* remove entry from freelist, bump nentries */
1261
1262 if (IS_PARTITIONED(hctl))
1264
1265 return newElement;
1266}
1267
1268/*
1269 * hash_get_num_entries -- get the number of entries in a hashtable
1270 */
1271int64
1273{
1274 int i;
1275 int64 sum = hashp->hctl->freeList[0].nentries;
1276
1277 /*
1278 * We currently don't bother with acquiring the mutexes; it's only
1279 * sensible to call this function if you've got lock on all partitions of
1280 * the table.
1281 */
1282 if (IS_PARTITIONED(hashp->hctl))
1283 {
1284 for (i = 1; i < NUM_FREELISTS; i++)
1285 sum += hashp->hctl->freeList[i].nentries;
1286 }
1287
1288 return sum;
1289}
1290
1291/*
1292 * hash_seq_init/_search/_term
1293 * Sequentially search through hash table and return
1294 * all the elements one by one, return NULL when no more.
1295 *
1296 * hash_seq_term should be called if and only if the scan is abandoned before
1297 * completion; if hash_seq_search returns NULL then it has already done the
1298 * end-of-scan cleanup.
1299 *
1300 * NOTE: caller may delete the returned element before continuing the scan.
1301 * However, deleting any other element while the scan is in progress is
1302 * UNDEFINED (it might be the one that curIndex is pointing at!). Also,
1303 * if elements are added to the table while the scan is in progress, it is
1304 * unspecified whether they will be visited by the scan or not.
1305 *
1306 * NOTE: it is possible to use hash_seq_init/hash_seq_search without any
1307 * worry about hash_seq_term cleanup, if the hashtable is first locked against
1308 * further insertions by calling hash_freeze.
1309 *
1310 * NOTE: to use this with a partitioned hashtable, caller had better hold
1311 * at least shared lock on all partitions of the table throughout the scan!
1312 * We can cope with insertions or deletions by our own backend, but *not*
1313 * with concurrent insertions or deletions by another.
1314 */
1315void
1316hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
1317{
1318 status->hashp = hashp;
1319 status->curBucket = 0;
1320 status->curEntry = NULL;
1321 status->hasHashvalue = false;
1322 if (!hashp->frozen)
1323 register_seq_scan(hashp);
1324}
1325
1326/*
1327 * Same as above but scan by the given hash value.
1328 * See also hash_seq_search().
1329 *
1330 * NOTE: the default hash function doesn't match syscache hash function.
1331 * Thus, if you're going to use this function in syscache callback, make sure
1332 * you're using custom hash function. See relatt_cache_syshash()
1333 * for example.
1334 */
1335void
1337 uint32 hashvalue)
1338{
1340
1341 hash_seq_init(status, hashp);
1342
1343 status->hasHashvalue = true;
1344 status->hashvalue = hashvalue;
1345
1346 status->curBucket = hash_initial_lookup(hashp, hashvalue, &bucketPtr);
1347 status->curEntry = *bucketPtr;
1348}
1349
1350void *
1352{
1353 HTAB *hashp;
1354 HASHHDR *hctl;
1355 uint32 max_bucket;
1359 uint32 curBucket;
1361
1362 if (status->hasHashvalue)
1363 {
1364 /*
1365 * Scan entries only in the current bucket because only this bucket
1366 * can contain entries with the given hash value.
1367 */
1368 while ((curElem = status->curEntry) != NULL)
1369 {
1370 status->curEntry = curElem->link;
1371 if (status->hashvalue != curElem->hashvalue)
1372 continue;
1373 return (void *) ELEMENTKEY(curElem);
1374 }
1375
1376 hash_seq_term(status);
1377 return NULL;
1378 }
1379
1380 if ((curElem = status->curEntry) != NULL)
1381 {
1382 /* Continuing scan of curBucket... */
1383 status->curEntry = curElem->link;
1384 if (status->curEntry == NULL) /* end of this bucket */
1385 ++status->curBucket;
1386 return ELEMENTKEY(curElem);
1387 }
1388
1389 /*
1390 * Search for next nonempty bucket starting at curBucket.
1391 */
1392 curBucket = status->curBucket;
1393 hashp = status->hashp;
1394 hctl = hashp->hctl;
1395 max_bucket = hctl->max_bucket;
1396
1397 if (curBucket > max_bucket)
1398 {
1399 hash_seq_term(status);
1400 return NULL; /* search is done */
1401 }
1402
1403 /*
1404 * first find the right segment in the table directory.
1405 */
1406 segment_num = curBucket >> HASH_SEGSIZE_SHIFT;
1407 segment_ndx = MOD(curBucket, HASH_SEGSIZE);
1408
1409 segp = hashp->dir[segment_num];
1410
1411 /*
1412 * Pick up the first item in this bucket's chain. If chain is not empty
1413 * we can begin searching it. Otherwise we have to advance to find the
1414 * next nonempty bucket. We try to optimize that case since searching a
1415 * near-empty hashtable has to iterate this loop a lot.
1416 */
1417 while ((curElem = segp[segment_ndx]) == NULL)
1418 {
1419 /* empty bucket, advance to next */
1420 if (++curBucket > max_bucket)
1421 {
1422 status->curBucket = curBucket;
1423 hash_seq_term(status);
1424 return NULL; /* search is done */
1425 }
1426 if (++segment_ndx >= HASH_SEGSIZE)
1427 {
1428 segment_num++;
1429 segment_ndx = 0;
1430 segp = hashp->dir[segment_num];
1431 }
1432 }
1433
1434 /* Begin scan of curBucket... */
1435 status->curEntry = curElem->link;
1436 if (status->curEntry == NULL) /* end of this bucket */
1437 ++curBucket;
1438 status->curBucket = curBucket;
1439 return ELEMENTKEY(curElem);
1440}
1441
1442void
1444{
1445 if (!status->hashp->frozen)
1446 deregister_seq_scan(status->hashp);
1447}
1448
1449/*
1450 * hash_freeze
1451 * Freeze a hashtable against future insertions (deletions are
1452 * still allowed)
1453 *
1454 * The reason for doing this is that by preventing any more bucket splits,
1455 * we no longer need to worry about registering hash_seq_search scans,
1456 * and thus caller need not be careful about ensuring hash_seq_term gets
1457 * called at the right times.
1458 *
1459 * Multiple calls to hash_freeze() are allowed, but you can't freeze a table
1460 * with active scans (since hash_seq_term would then do the wrong thing).
1461 */
1462void
1463hash_freeze(HTAB *hashp)
1464{
1465 if (hashp->isshared)
1466 elog(ERROR, "cannot freeze shared hashtable \"%s\"", hashp->tabname);
1467 if (!hashp->frozen && has_seq_scans(hashp))
1468 elog(ERROR, "cannot freeze hashtable \"%s\" because it has active scans",
1469 hashp->tabname);
1470 hashp->frozen = true;
1471}
1472
1473
1474/********************************* UTILITIES ************************/
1475
1476/*
1477 * Expand the table by adding one more hash bucket.
1478 */
1479static bool
1480expand_table(HTAB *hashp)
1481{
1482 HASHHDR *hctl = hashp->hctl;
1484 new_seg;
1486 new_bucket;
1488 new_segndx;
1490 old_segndx;
1492 *newlink;
1495
1496 Assert(!IS_PARTITIONED(hctl));
1497
1498#ifdef HASH_STATISTICS
1499 hctl->expansions++;
1500#endif
1501
1502 new_bucket = hctl->max_bucket + 1;
1503 new_segnum = new_bucket >> HASH_SEGSIZE_SHIFT;
1504 new_segndx = MOD(new_bucket, HASH_SEGSIZE);
1505
1506 if (new_segnum >= hctl->nsegs)
1507 {
1508 /* Allocate new segment if necessary -- could fail if dir full */
1509 if (new_segnum >= hctl->dsize)
1510 if (!dir_realloc(hashp))
1511 return false;
1512 if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
1513 return false;
1514 hctl->nsegs++;
1515 }
1516
1517 /* OK, we created a new bucket */
1518 hctl->max_bucket++;
1519
1520 /*
1521 * *Before* changing masks, find old bucket corresponding to same hash
1522 * values; values in that bucket may need to be relocated to new bucket.
1523 * Note that new_bucket is certainly larger than low_mask at this point,
1524 * so we can skip the first step of the regular hash mask calc.
1525 */
1526 old_bucket = (new_bucket & hctl->low_mask);
1527
1528 /*
1529 * If we crossed a power of 2, readjust masks.
1530 */
1531 if ((uint32) new_bucket > hctl->high_mask)
1532 {
1533 hctl->low_mask = hctl->high_mask;
1534 hctl->high_mask = (uint32) new_bucket | hctl->low_mask;
1535 }
1536
1537 /*
1538 * Relocate records to the new bucket. NOTE: because of the way the hash
1539 * masking is done in calc_bucket, only one old bucket can need to be
1540 * split at this point. With a different way of reducing the hash value,
1541 * that might not be true!
1542 */
1545
1546 old_seg = hashp->dir[old_segnum];
1547 new_seg = hashp->dir[new_segnum];
1548
1551
1552 for (currElement = *oldlink;
1553 currElement != NULL;
1555 {
1557 if ((int64) calc_bucket(hctl, currElement->hashvalue) == old_bucket)
1558 {
1561 }
1562 else
1563 {
1566 }
1567 }
1568 /* don't forget to terminate the rebuilt hash chains... */
1569 *oldlink = NULL;
1570 *newlink = NULL;
1571
1572 return true;
1573}
1574
1575
1576static bool
1577dir_realloc(HTAB *hashp)
1578{
1579 HASHSEGMENT *p;
1584
1585 if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
1586 return false;
1587
1588 /* Reallocate directory */
1589 new_dsize = hashp->hctl->dsize << 1;
1590 old_dirsize = hashp->hctl->dsize * sizeof(HASHSEGMENT);
1591 new_dirsize = new_dsize * sizeof(HASHSEGMENT);
1592
1593 old_p = hashp->dir;
1594 p = (HASHSEGMENT *) hashp->alloc((Size) new_dirsize, hashp->alloc_arg);
1595
1596 if (p != NULL)
1597 {
1599 MemSet(((char *) p) + old_dirsize, 0, new_dirsize - old_dirsize);
1600 hashp->hctl->dir = p;
1601 hashp->dir = p;
1602 hashp->hctl->dsize = new_dsize;
1603
1604 /* XXX assume the allocator is palloc, so we know how to free */
1605 Assert(hashp->alloc == DynaHashAlloc);
1606 pfree(old_p);
1607
1608 return true;
1609 }
1610
1611 return false;
1612}
1613
1614
1615static HASHSEGMENT
1616seg_alloc(HTAB *hashp)
1617{
1619
1620 segp = (HASHSEGMENT) hashp->alloc(sizeof(HASHBUCKET) * HASH_SEGSIZE, hashp->alloc_arg);
1621
1622 if (!segp)
1623 return NULL;
1624
1625 MemSet(segp, 0, sizeof(HASHBUCKET) * HASH_SEGSIZE);
1626
1627 return segp;
1628}
1629
1630/*
1631 * allocate some new elements and link them into the indicated free list
1632 */
1633static bool
1634element_alloc(HTAB *hashp, int nelem, int freelist_idx)
1635{
1636 HASHHDR *hctl = hashp->hctl;
1639 char *allocedBlock;
1643 int i;
1644
1645 if (hctl->isfixed)
1646 return false;
1647
1648 /* Each element has a HASHELEMENT header plus user data. */
1650
1652
1653 /* Add space for slist_node list link if we need one. */
1654#ifdef USE_VALGRIND
1655 if (!hashp->isshared)
1656 requestSize += MAXALIGN(sizeof(slist_node));
1657#endif
1658
1659 /* Allocate the memory. */
1660 allocedBlock = hashp->alloc(requestSize, hashp->alloc_arg);
1661
1662 if (!allocedBlock)
1663 return false;
1664
1665 /*
1666 * If USE_VALGRIND, each allocated block of elements of a non-shared
1667 * hashtable is chained into a list, so that Valgrind won't think it's
1668 * been leaked.
1669 */
1670#ifdef USE_VALGRIND
1671 if (hashp->isshared)
1673 else
1674 {
1675 slist_push_head(&hashp->element_blocks, (slist_node *) allocedBlock);
1677 }
1678#else
1680#endif
1681
1682 /* prepare to link all the new entries into the freelist */
1683 prevElement = NULL;
1685 for (i = 0; i < nelem; i++)
1686 {
1687 tmpElement->link = prevElement;
1689 tmpElement = (HASHELEMENT *) (((char *) tmpElement) + elementSize);
1690 }
1691
1692 /* if partitioned, must lock to touch freeList */
1693 if (IS_PARTITIONED(hctl))
1695
1696 /* freelist could be nonempty if two backends did this concurrently */
1699
1700 if (IS_PARTITIONED(hctl))
1702
1703 return true;
1704}
1705
1706/*
1707 * Do initial lookup of a bucket for the given hash value, retrieving its
1708 * bucket number and its hash bucket.
1709 */
1710static inline uint32
1712{
1713 HASHHDR *hctl = hashp->hctl;
1717 uint32 bucket;
1718
1719 bucket = calc_bucket(hctl, hashvalue);
1720
1723
1724 segp = hashp->dir[segment_num];
1725
1726 if (segp == NULL)
1727 hash_corrupted(hashp);
1728
1730 return bucket;
1731}
1732
1733/* complain when we have detected a corrupted hashtable */
1734static void
1735hash_corrupted(HTAB *hashp)
1736{
1737 /*
1738 * If the corruption is in a shared hashtable, we'd better force a
1739 * systemwide restart. Otherwise, just shut down this one backend.
1740 */
1741 if (hashp->isshared)
1742 elog(PANIC, "hash table \"%s\" corrupted", hashp->tabname);
1743 else
1744 elog(FATAL, "hash table \"%s\" corrupted", hashp->tabname);
1745}
1746
1747/* calculate ceil(log base 2) of num */
1748static int
1749my_log2(int64 num)
1750{
1751 /*
1752 * guard against too-large input, which would be invalid for
1753 * pg_ceil_log2_*()
1754 */
1755 if (num > PG_INT64_MAX / 2)
1756 num = PG_INT64_MAX / 2;
1757
1758 return pg_ceil_log2_64(num);
1759}
1760
1761/* calculate first power of 2 >= num, bounded to what will fit in a int64 */
1762static int64
1764{
1765 /* my_log2's internal range check is sufficient */
1766 return 1L << my_log2(num);
1767}
1768
1769/* calculate first power of 2 >= num, bounded to what will fit in an int */
1770static int
1772{
1773 if (num > INT_MAX / 2)
1774 num = INT_MAX / 2;
1775 return 1 << my_log2(num);
1776}
1777
1778
1779/************************* SEQ SCAN TRACKING ************************/
1780
1781/*
1782 * We track active hash_seq_search scans here. The need for this mechanism
1783 * comes from the fact that a scan will get confused if a bucket split occurs
1784 * while it's in progress: it might visit entries twice, or even miss some
1785 * entirely (if it's partway through the same bucket that splits). Hence
1786 * we want to inhibit bucket splits if there are any active scans on the
1787 * table being inserted into. This is a fairly rare case in current usage,
1788 * so just postponing the split until the next insertion seems sufficient.
1789 *
1790 * Given present usages of the function, only a few scans are likely to be
1791 * open concurrently; so a finite-size stack of open scans seems sufficient,
1792 * and we don't worry that linear search is too slow. Note that we do
1793 * allow multiple scans of the same hashtable to be open concurrently.
1794 *
1795 * This mechanism can support concurrent scan and insertion in a shared
1796 * hashtable if it's the same backend doing both. It would fail otherwise,
1797 * but locking reasons seem to preclude any such scenario anyway, so we don't
1798 * worry.
1799 *
1800 * This arrangement is reasonably robust if a transient hashtable is deleted
1801 * without notifying us. The absolute worst case is we might inhibit splits
1802 * in another table created later at exactly the same address. We will give
1803 * a warning at transaction end for reference leaks, so any bugs leading to
1804 * lack of notification should be easy to catch.
1805 */
1806
1807#define MAX_SEQ_SCANS 100
1808
1809static HTAB *seq_scan_tables[MAX_SEQ_SCANS]; /* tables being scanned */
1810static int seq_scan_level[MAX_SEQ_SCANS]; /* subtransaction nest level */
1811static int num_seq_scans = 0;
1812
1813
1814/* Register a table as having an active hash_seq_search scan */
1815static void
1816register_seq_scan(HTAB *hashp)
1817{
1819 elog(ERROR, "too many active hash_seq_search scans, cannot start one on \"%s\"",
1820 hashp->tabname);
1823 num_seq_scans++;
1824}
1825
1826/* Deregister an active scan */
1827static void
1829{
1830 int i;
1831
1832 /* Search backward since it's most likely at the stack top */
1833 for (i = num_seq_scans - 1; i >= 0; i--)
1834 {
1835 if (seq_scan_tables[i] == hashp)
1836 {
1839 num_seq_scans--;
1840 return;
1841 }
1842 }
1843 elog(ERROR, "no hash_seq_search scan for hash table \"%s\"",
1844 hashp->tabname);
1845}
1846
1847/* Check if a table has any active scan */
1848static bool
1849has_seq_scans(HTAB *hashp)
1850{
1851 int i;
1852
1853 for (i = 0; i < num_seq_scans; i++)
1854 {
1855 if (seq_scan_tables[i] == hashp)
1856 return true;
1857 }
1858 return false;
1859}
1860
1861/* Clean up any open scans at end of transaction */
1862void
1864{
1865 /*
1866 * During abort cleanup, open scans are expected; just silently clean 'em
1867 * out. An open scan at commit means someone forgot a hash_seq_term()
1868 * call, so complain.
1869 *
1870 * Note: it's tempting to try to print the tabname here, but refrain for
1871 * fear of touching deallocated memory. This isn't a user-facing message
1872 * anyway, so it needn't be pretty.
1873 */
1874 if (isCommit)
1875 {
1876 int i;
1877
1878 for (i = 0; i < num_seq_scans; i++)
1879 {
1880 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1882 }
1883 }
1884 num_seq_scans = 0;
1885}
1886
1887/* Clean up any open scans at end of subtransaction */
1888void
1890{
1891 int i;
1892
1893 /*
1894 * Search backward to make cleanup easy. Note we must check all entries,
1895 * not only those at the end of the array, because deletion technique
1896 * doesn't keep them in order.
1897 */
1898 for (i = num_seq_scans - 1; i >= 0; i--)
1899 {
1900 if (seq_scan_level[i] >= nestDepth)
1901 {
1902 if (isCommit)
1903 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1907 num_seq_scans--;
1908 }
1909 }
1910}
#define MAXALIGN(LEN)
Definition c.h:896
#define Max(x, y)
Definition c.h:1085
#define INT64_FORMAT
Definition c.h:634
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
#define UINT64_FORMAT
Definition c.h:635
#define PG_INT64_MAX
Definition c.h:676
uint32_t uint32
Definition c.h:624
#define MemSet(start, val, len)
Definition c.h:1107
void(* pg_funcptr_t)(void)
Definition c.h:548
size_t Size
Definition c.h:689
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
static HTAB * seq_scan_tables[MAX_SEQ_SCANS]
Definition dynahash.c:1810
static int seq_scan_level[MAX_SEQ_SCANS]
Definition dynahash.c:1811
void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status, HTAB *hashp, uint32 hashvalue)
Definition dynahash.c:1337
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
#define ELEMENT_FROM_KEY(key)
Definition dynahash.c:262
#define DEF_DIRSIZE
Definition dynahash.c:127
static bool element_alloc(HTAB *hashp, int nelem, int freelist_idx)
Definition dynahash.c:1635
void AtEOXact_HashTables(bool isCommit)
Definition dynahash.c:1864
#define HASH_SEGSIZE_SHIFT
Definition dynahash.c:126
Size hash_estimate_size(int64 num_entries, Size entrysize)
Definition dynahash.c:763
static HASHSEGMENT seg_alloc(HTAB *hashp)
Definition dynahash.c:1617
#define MAX_SEQ_SCANS
Definition dynahash.c:1808
static int next_pow2_int(int64 num)
Definition dynahash.c:1772
static int choose_nelem_alloc(Size entrysize)
Definition dynahash.c:653
static void * DynaHashAlloc(Size size, void *alloc_arg)
Definition dynahash.c:297
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
static void register_seq_scan(HTAB *hashp)
Definition dynahash.c:1817
#define MOD(x, y)
Definition dynahash.c:268
#define IS_PARTITIONED(hctl)
Definition dynahash.c:215
void AtEOSubXact_HashTables(bool isCommit, int nestDepth)
Definition dynahash.c:1890
static HASHBUCKET get_hash_entry(HTAB *hashp, int freelist_idx)
Definition dynahash.c:1188
#define NUM_FREELISTS
Definition dynahash.c:130
void hash_destroy(HTAB *hashp)
Definition dynahash.c:802
static int string_compare(const char *key1, const char *key2, Size keysize)
Definition dynahash.c:314
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
Definition dynahash.c:902
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
static bool expand_table(HTAB *hashp)
Definition dynahash.c:1481
static void hdefault(HTAB *hashp)
Definition dynahash.c:630
static void deregister_seq_scan(HTAB *hashp)
Definition dynahash.c:1829
static int my_log2(int64 num)
Definition dynahash.c:1750
#define ELEMENTKEY(helem)
Definition dynahash.c:257
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition dynahash.c:1444
int64 hash_get_num_entries(HTAB *hashp)
Definition dynahash.c:1273
static int num_seq_scans
Definition dynahash.c:1812
static int64 next_pow2_int64(int64 num)
Definition dynahash.c:1764
#define FREELIST_IDX(hctl, hashcode)
Definition dynahash.c:217
void hash_stats(const char *caller, HTAB *hashp)
Definition dynahash.c:821
static bool init_htab(HTAB *hashp, int64 nelem)
Definition dynahash.c:686
static pg_noreturn void hash_corrupted(HTAB *hashp)
Definition dynahash.c:1736
void hash_freeze(HTAB *hashp)
Definition dynahash.c:1464
static bool dir_realloc(HTAB *hashp)
Definition dynahash.c:1578
#define HASH_SEGSIZE
Definition dynahash.c:125
bool hash_update_hash_key(HTAB *hashp, void *existingEntry, const void *newKeyPtr)
Definition dynahash.c:1077
static uint32 hash_initial_lookup(HTAB *hashp, uint32 hashvalue, HASHBUCKET **bucketptr)
Definition dynahash.c:1712
uint32 get_hash_value(HTAB *hashp, const void *keyPtr)
Definition dynahash.c:845
static uint32 calc_bucket(HASHHDR *hctl, uint32 hash_val)
Definition dynahash.c:852
static bool has_seq_scans(HTAB *hashp)
Definition dynahash.c:1850
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
HASHBUCKET * HASHSEGMENT
Definition dynahash.c:136
int errcode(int sqlerrcode)
Definition elog.c:874
#define FATAL
Definition elog.h:42
#define WARNING
Definition elog.h:37
#define PANIC
Definition elog.h:44
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define DEBUG4
Definition elog.h:28
#define MCXT_ALLOC_NO_OOM
Definition fe_memutils.h:29
uint32 tag_hash(const void *key, Size keysize)
Definition hashfn.c:677
uint32 uint32_hash(const void *key, Size keysize)
Definition hashfn.c:688
uint32 string_hash(const void *key, Size keysize)
Definition hashfn.c:660
#define HASH_KEYCOPY
Definition hsearch.h:95
#define HASH_STRINGS
Definition hsearch.h:91
int(* HashCompareFunc)(const void *key1, const void *key2, Size keysize)
Definition hsearch.h:29
HASHACTION
Definition hsearch.h:107
@ HASH_FIND
Definition hsearch.h:108
@ HASH_REMOVE
Definition hsearch.h:110
@ HASH_ENTER
Definition hsearch.h:109
@ HASH_ENTER_NULL
Definition hsearch.h:111
#define HASH_CONTEXT
Definition hsearch.h:97
#define NO_MAX_DSIZE
Definition hsearch.h:103
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_ALLOC
Definition hsearch.h:96
#define HASH_ATTACH
Definition hsearch.h:99
#define HASH_COMPARE
Definition hsearch.h:94
#define HASH_FUNCTION
Definition hsearch.h:93
#define HASH_BLOBS
Definition hsearch.h:92
#define HASH_SHARED_MEM
Definition hsearch.h:98
#define HASH_FIXED_SIZE
Definition hsearch.h:100
#define HASH_PARTITION
Definition hsearch.h:87
void *(* HashCopyFunc)(void *dest, const void *src, Size keysize)
Definition hsearch.h:37
static void slist_push_head(slist_head *head, slist_node *node)
Definition ilist.h:1006
int i
Definition isn.c:77
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void pfree(void *pointer)
Definition mcxt.c:1616
MemoryContext TopMemoryContext
Definition mcxt.c:166
void * MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
Definition mcxt.c:1289
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition mcxt.c:661
#define MemoryContextIsValid(context)
Definition memnodes.h:145
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static char * errmsg
struct MemoryContextData * MemoryContext
Definition palloc.h:36
static uint64 pg_ceil_log2_64(uint64 num)
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
static int fb(int x)
Size add_size(Size s1, Size s2)
Definition shmem.c:1048
Size mul_size(Size s1, Size s2)
Definition shmem.c:1063
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
slock_t mutex
Definition dynahash.c:157
int64 nentries
Definition dynahash.c:158
HASHELEMENT * freeList
Definition dynahash.c:159
HashAllocFunc alloc
Definition hsearch.h:78
Size keysize
Definition hsearch.h:69
HashValueFunc hash
Definition hsearch.h:72
Size entrysize
Definition hsearch.h:70
void * alloc_arg
Definition hsearch.h:79
HashCompareFunc match
Definition hsearch.h:74
HASHHDR * hctl
Definition hsearch.h:83
MemoryContext hcxt
Definition hsearch.h:81
int64 num_partitions
Definition hsearch.h:67
HashCopyFunc keycopy
Definition hsearch.h:76
struct HASHELEMENT * link
Definition hsearch.h:52
uint32 high_mask
Definition dynahash.c:189
FreeListData freeList[NUM_FREELISTS]
Definition dynahash.c:182
Size entrysize
Definition dynahash.c:194
HASHSEGMENT * dir
Definition dynahash.c:201
uint32 max_bucket
Definition dynahash.c:188
int64 dsize
Definition dynahash.c:186
int64 max_dsize
Definition dynahash.c:196
Size keysize
Definition dynahash.c:193
bool isfixed
Definition dynahash.c:198
int nelem_alloc
Definition dynahash.c:197
int64 num_partitions
Definition dynahash.c:195
uint32 low_mask
Definition dynahash.c:190
int64 nsegs
Definition dynahash.c:187
uint32 hashvalue
Definition hsearch.h:121
HASHELEMENT * curEntry
Definition hsearch.h:119
uint32 curBucket
Definition hsearch.h:118
bool hasHashvalue
Definition hsearch.h:120
bool isshared
Definition dynahash.c:235
HashCompareFunc match
Definition dynahash.c:229
char * tabname
Definition dynahash.c:234
HASHHDR * hctl
Definition dynahash.c:226
MemoryContext hcxt
Definition dynahash.c:233
HashAllocFunc alloc
Definition dynahash.c:231
HashValueFunc hash
Definition dynahash.c:228
void * alloc_arg
Definition dynahash.c:232
HASHSEGMENT * dir
Definition dynahash.c:227
Size keysize
Definition dynahash.c:241
HashCopyFunc keycopy
Definition dynahash.c:230
bool frozen
Definition dynahash.c:238
int GetCurrentTransactionNestLevel(void)
Definition xact.c:931

◆ ELEMENTKEY

#define ELEMENTKEY (   helem)    (((char *)(helem)) + MAXALIGN(sizeof(HASHELEMENT)))

Definition at line 257 of file dynahash.c.

◆ FREELIST_IDX

#define FREELIST_IDX (   hctl,
  hashcode 
)     (IS_PARTITIONED(hctl) ? (hashcode) % NUM_FREELISTS : 0)

Definition at line 217 of file dynahash.c.

218 : 0)

◆ HASH_SEGSIZE

#define HASH_SEGSIZE   256

Definition at line 125 of file dynahash.c.

◆ HASH_SEGSIZE_SHIFT

#define HASH_SEGSIZE_SHIFT   8 /* must be log2(HASH_SEGSIZE) */

Definition at line 126 of file dynahash.c.

◆ IS_PARTITIONED

#define IS_PARTITIONED (   hctl)    ((hctl)->num_partitions != 0)

Definition at line 215 of file dynahash.c.

◆ MAX_SEQ_SCANS

#define MAX_SEQ_SCANS   100

Definition at line 1808 of file dynahash.c.

◆ MOD

#define MOD (   x,
  y 
)    ((x) & ((y)-1))

Definition at line 268 of file dynahash.c.

◆ NUM_FREELISTS

#define NUM_FREELISTS   32

Definition at line 130 of file dynahash.c.

Typedef Documentation

◆ HASHBUCKET

Definition at line 133 of file dynahash.c.

◆ HASHSEGMENT

Definition at line 136 of file dynahash.c.

Function Documentation

◆ AtEOSubXact_HashTables()

void AtEOSubXact_HashTables ( bool  isCommit,
int  nestDepth 
)

Definition at line 1890 of file dynahash.c.

1891{
1892 int i;
1893
1894 /*
1895 * Search backward to make cleanup easy. Note we must check all entries,
1896 * not only those at the end of the array, because deletion technique
1897 * doesn't keep them in order.
1898 */
1899 for (i = num_seq_scans - 1; i >= 0; i--)
1900 {
1901 if (seq_scan_level[i] >= nestDepth)
1902 {
1903 if (isCommit)
1904 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1908 num_seq_scans--;
1909 }
1910 }
1911}

References elog, fb(), i, num_seq_scans, seq_scan_level, seq_scan_tables, and WARNING.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_HashTables()

void AtEOXact_HashTables ( bool  isCommit)

Definition at line 1864 of file dynahash.c.

1865{
1866 /*
1867 * During abort cleanup, open scans are expected; just silently clean 'em
1868 * out. An open scan at commit means someone forgot a hash_seq_term()
1869 * call, so complain.
1870 *
1871 * Note: it's tempting to try to print the tabname here, but refrain for
1872 * fear of touching deallocated memory. This isn't a user-facing message
1873 * anyway, so it needn't be pretty.
1874 */
1875 if (isCommit)
1876 {
1877 int i;
1878
1879 for (i = 0; i < num_seq_scans; i++)
1880 {
1881 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1883 }
1884 }
1885 num_seq_scans = 0;
1886}

References elog, fb(), i, num_seq_scans, seq_scan_tables, and WARNING.

Referenced by AbortTransaction(), AutoVacLauncherMain(), BackgroundWriterMain(), CheckpointerMain(), CommitTransaction(), pgarch_archiveXlog(), PrepareTransaction(), WalSummarizerMain(), and WalWriterMain().

◆ calc_bucket()

static uint32 calc_bucket ( HASHHDR hctl,
uint32  hash_val 
)
inlinestatic

Definition at line 852 of file dynahash.c.

853{
855
856 bucket = hash_val & hctl->high_mask;
857 if (bucket > hctl->max_bucket)
858 bucket = bucket & hctl->low_mask;
859
860 return bucket;
861}

References fb(), HASHHDR::high_mask, HASHHDR::low_mask, and HASHHDR::max_bucket.

Referenced by expand_table(), and hash_initial_lookup().

◆ choose_nelem_alloc()

static int choose_nelem_alloc ( Size  entrysize)
static

Definition at line 653 of file dynahash.c.

654{
655 int nelem_alloc;
658
659 /* Each element has a HASHELEMENT header plus user data. */
660 /* NB: this had better match element_alloc() */
661 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
662
663 /*
664 * The idea here is to choose nelem_alloc at least 32, but round up so
665 * that the allocation request will be a power of 2 or just less. This
666 * makes little difference for hash tables in shared memory, but for hash
667 * tables managed by palloc, the allocation request will be rounded up to
668 * a power of 2 anyway. If we fail to take this into account, we'll waste
669 * as much as half the allocated space.
670 */
671 allocSize = 32 * 4; /* assume elementSize at least 8 */
672 do
673 {
674 allocSize <<= 1;
675 nelem_alloc = allocSize / elementSize;
676 } while (nelem_alloc < 32);
677
678 return nelem_alloc;
679}

References fb(), and MAXALIGN.

Referenced by hash_estimate_size(), and init_htab().

◆ deregister_seq_scan()

static void deregister_seq_scan ( HTAB hashp)
static

Definition at line 1829 of file dynahash.c.

1830{
1831 int i;
1832
1833 /* Search backward since it's most likely at the stack top */
1834 for (i = num_seq_scans - 1; i >= 0; i--)
1835 {
1836 if (seq_scan_tables[i] == hashp)
1837 {
1840 num_seq_scans--;
1841 return;
1842 }
1843 }
1844 elog(ERROR, "no hash_seq_search scan for hash table \"%s\"",
1845 hashp->tabname);
1846}

References elog, ERROR, i, num_seq_scans, seq_scan_level, seq_scan_tables, and HTAB::tabname.

Referenced by hash_seq_term().

◆ dir_realloc()

static bool dir_realloc ( HTAB hashp)
static

Definition at line 1578 of file dynahash.c.

1579{
1580 HASHSEGMENT *p;
1585
1586 if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
1587 return false;
1588
1589 /* Reallocate directory */
1590 new_dsize = hashp->hctl->dsize << 1;
1591 old_dirsize = hashp->hctl->dsize * sizeof(HASHSEGMENT);
1592 new_dirsize = new_dsize * sizeof(HASHSEGMENT);
1593
1594 old_p = hashp->dir;
1595 p = (HASHSEGMENT *) hashp->alloc((Size) new_dirsize, hashp->alloc_arg);
1596
1597 if (p != NULL)
1598 {
1600 MemSet(((char *) p) + old_dirsize, 0, new_dirsize - old_dirsize);
1601 hashp->hctl->dir = p;
1602 hashp->dir = p;
1603 hashp->hctl->dsize = new_dsize;
1604
1605 /* XXX assume the allocator is palloc, so we know how to free */
1606 Assert(hashp->alloc == DynaHashAlloc);
1607 pfree(old_p);
1608
1609 return true;
1610 }
1611
1612 return false;
1613}

References HTAB::alloc, HTAB::alloc_arg, Assert, HASHHDR::dir, HTAB::dir, HASHHDR::dsize, DynaHashAlloc(), fb(), HTAB::hctl, HASHHDR::max_dsize, memcpy(), MemSet, NO_MAX_DSIZE, and pfree().

Referenced by expand_table().

◆ DynaHashAlloc()

static void * DynaHashAlloc ( Size  size,
void alloc_arg 
)
static

Definition at line 297 of file dynahash.c.

298{
299 MemoryContext hcxt = (MemoryContext) alloc_arg;
300
303}

References Assert, MCXT_ALLOC_NO_OOM, MemoryContextAllocExtended(), and MemoryContextIsValid.

Referenced by dir_realloc(), hash_create(), and hash_destroy().

◆ element_alloc()

static bool element_alloc ( HTAB hashp,
int  nelem,
int  freelist_idx 
)
static

Definition at line 1635 of file dynahash.c.

1636{
1637 HASHHDR *hctl = hashp->hctl;
1640 char *allocedBlock;
1644 int i;
1645
1646 if (hctl->isfixed)
1647 return false;
1648
1649 /* Each element has a HASHELEMENT header plus user data. */
1651
1653
1654 /* Add space for slist_node list link if we need one. */
1655#ifdef USE_VALGRIND
1656 if (!hashp->isshared)
1657 requestSize += MAXALIGN(sizeof(slist_node));
1658#endif
1659
1660 /* Allocate the memory. */
1661 allocedBlock = hashp->alloc(requestSize, hashp->alloc_arg);
1662
1663 if (!allocedBlock)
1664 return false;
1665
1666 /*
1667 * If USE_VALGRIND, each allocated block of elements of a non-shared
1668 * hashtable is chained into a list, so that Valgrind won't think it's
1669 * been leaked.
1670 */
1671#ifdef USE_VALGRIND
1672 if (hashp->isshared)
1674 else
1675 {
1676 slist_push_head(&hashp->element_blocks, (slist_node *) allocedBlock);
1678 }
1679#else
1681#endif
1682
1683 /* prepare to link all the new entries into the freelist */
1684 prevElement = NULL;
1686 for (i = 0; i < nelem; i++)
1687 {
1688 tmpElement->link = prevElement;
1690 tmpElement = (HASHELEMENT *) (((char *) tmpElement) + elementSize);
1691 }
1692
1693 /* if partitioned, must lock to touch freeList */
1694 if (IS_PARTITIONED(hctl))
1696
1697 /* freelist could be nonempty if two backends did this concurrently */
1700
1701 if (IS_PARTITIONED(hctl))
1703
1704 return true;
1705}

References HTAB::alloc, HTAB::alloc_arg, HASHHDR::entrysize, fb(), FreeListData::freeList, HASHHDR::freeList, HTAB::hctl, i, IS_PARTITIONED, HASHHDR::isfixed, HTAB::isshared, MAXALIGN, FreeListData::mutex, slist_push_head(), SpinLockAcquire(), and SpinLockRelease().

Referenced by get_hash_entry(), and hash_create().

◆ expand_table()

static bool expand_table ( HTAB hashp)
static

Definition at line 1481 of file dynahash.c.

1482{
1483 HASHHDR *hctl = hashp->hctl;
1485 new_seg;
1487 new_bucket;
1489 new_segndx;
1491 old_segndx;
1493 *newlink;
1496
1497 Assert(!IS_PARTITIONED(hctl));
1498
1499#ifdef HASH_STATISTICS
1500 hctl->expansions++;
1501#endif
1502
1503 new_bucket = hctl->max_bucket + 1;
1504 new_segnum = new_bucket >> HASH_SEGSIZE_SHIFT;
1505 new_segndx = MOD(new_bucket, HASH_SEGSIZE);
1506
1507 if (new_segnum >= hctl->nsegs)
1508 {
1509 /* Allocate new segment if necessary -- could fail if dir full */
1510 if (new_segnum >= hctl->dsize)
1511 if (!dir_realloc(hashp))
1512 return false;
1513 if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
1514 return false;
1515 hctl->nsegs++;
1516 }
1517
1518 /* OK, we created a new bucket */
1519 hctl->max_bucket++;
1520
1521 /*
1522 * *Before* changing masks, find old bucket corresponding to same hash
1523 * values; values in that bucket may need to be relocated to new bucket.
1524 * Note that new_bucket is certainly larger than low_mask at this point,
1525 * so we can skip the first step of the regular hash mask calc.
1526 */
1527 old_bucket = (new_bucket & hctl->low_mask);
1528
1529 /*
1530 * If we crossed a power of 2, readjust masks.
1531 */
1532 if ((uint32) new_bucket > hctl->high_mask)
1533 {
1534 hctl->low_mask = hctl->high_mask;
1535 hctl->high_mask = (uint32) new_bucket | hctl->low_mask;
1536 }
1537
1538 /*
1539 * Relocate records to the new bucket. NOTE: because of the way the hash
1540 * masking is done in calc_bucket, only one old bucket can need to be
1541 * split at this point. With a different way of reducing the hash value,
1542 * that might not be true!
1543 */
1546
1547 old_seg = hashp->dir[old_segnum];
1548 new_seg = hashp->dir[new_segnum];
1549
1552
1553 for (currElement = *oldlink;
1554 currElement != NULL;
1556 {
1558 if ((int64) calc_bucket(hctl, currElement->hashvalue) == old_bucket)
1559 {
1562 }
1563 else
1564 {
1567 }
1568 }
1569 /* don't forget to terminate the rebuilt hash chains... */
1570 *oldlink = NULL;
1571 *newlink = NULL;
1572
1573 return true;
1574}

References Assert, calc_bucket(), HTAB::dir, dir_realloc(), HASHHDR::dsize, fb(), HASH_SEGSIZE, HASH_SEGSIZE_SHIFT, HTAB::hctl, HASHHDR::high_mask, IS_PARTITIONED, HASHELEMENT::link, HASHHDR::low_mask, HASHHDR::max_bucket, MOD, HASHHDR::nsegs, and seg_alloc().

Referenced by hash_search_with_hash_value().

◆ get_hash_entry()

static HASHBUCKET get_hash_entry ( HTAB hashp,
int  freelist_idx 
)
static

Definition at line 1188 of file dynahash.c.

1189{
1190 HASHHDR *hctl = hashp->hctl;
1192
1193 for (;;)
1194 {
1195 /* if partitioned, must lock to touch nentries and freeList */
1196 if (IS_PARTITIONED(hctl))
1198
1199 /* try to get an entry from the freelist */
1201
1202 if (newElement != NULL)
1203 break;
1204
1205 if (IS_PARTITIONED(hctl))
1207
1208 /*
1209 * No free elements in this freelist. In a partitioned table, there
1210 * might be entries in other freelists, but to reduce contention we
1211 * prefer to first try to get another chunk of buckets from the main
1212 * shmem allocator. If that fails, though, we *MUST* root through all
1213 * the other freelists before giving up. There are multiple callers
1214 * that assume that they can allocate every element in the initially
1215 * requested table size, or that deleting an element guarantees they
1216 * can insert a new element, even if shared memory is entirely full.
1217 * Failing because the needed element is in a different freelist is
1218 * not acceptable.
1219 */
1220 if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx))
1221 {
1222 int borrow_from_idx;
1223
1224 if (!IS_PARTITIONED(hctl))
1225 return NULL; /* out of memory */
1226
1227 /* try to borrow element from another freelist */
1229 for (;;)
1230 {
1233 break; /* examined all freelists, fail */
1234
1237
1238 if (newElement != NULL)
1239 {
1242
1243 /* careful: count the new element in its proper freelist */
1247
1248 return newElement;
1249 }
1250
1252 }
1253
1254 /* no elements available to borrow either, so out of memory */
1255 return NULL;
1256 }
1257 }
1258
1259 /* remove entry from freelist, bump nentries */
1262
1263 if (IS_PARTITIONED(hctl))
1265
1266 return newElement;
1267}

References element_alloc(), fb(), FreeListData::freeList, HASHHDR::freeList, HTAB::hctl, IS_PARTITIONED, HASHELEMENT::link, FreeListData::mutex, HASHHDR::nelem_alloc, FreeListData::nentries, NUM_FREELISTS, SpinLockAcquire(), and SpinLockRelease().

Referenced by hash_search_with_hash_value().

◆ get_hash_value()

uint32 get_hash_value ( HTAB hashp,
const void keyPtr 
)

Definition at line 845 of file dynahash.c.

846{
847 return hashp->hash(keyPtr, hashp->keysize);
848}

References fb(), HTAB::hash, and HTAB::keysize.

Referenced by BufTableHashCode(), LockTagHashCode(), and lookup_type_cache().

◆ has_seq_scans()

static bool has_seq_scans ( HTAB hashp)
static

Definition at line 1850 of file dynahash.c.

1851{
1852 int i;
1853
1854 for (i = 0; i < num_seq_scans; i++)
1855 {
1856 if (seq_scan_tables[i] == hashp)
1857 return true;
1858 }
1859 return false;
1860}

References i, num_seq_scans, and seq_scan_tables.

Referenced by hash_freeze(), and hash_search_with_hash_value().

◆ hash_corrupted()

static void hash_corrupted ( HTAB hashp)
static

Definition at line 1736 of file dynahash.c.

1737{
1738 /*
1739 * If the corruption is in a shared hashtable, we'd better force a
1740 * systemwide restart. Otherwise, just shut down this one backend.
1741 */
1742 if (hashp->isshared)
1743 elog(PANIC, "hash table \"%s\" corrupted", hashp->tabname);
1744 else
1745 elog(FATAL, "hash table \"%s\" corrupted", hashp->tabname);
1746}

References elog, FATAL, HTAB::isshared, PANIC, and HTAB::tabname.

Referenced by hash_initial_lookup().

◆ hash_create()

HTAB * hash_create ( const char tabname,
int64  nelem,
const HASHCTL info,
int  flags 
)

Definition at line 360 of file dynahash.c.

361{
362 HTAB *hashp;
363 HASHHDR *hctl;
364 MemoryContext hcxt;
365
366 /*
367 * Hash tables now allocate space for key and data, but you have to say
368 * how much space to allocate.
369 */
370 Assert(flags & HASH_ELEM);
371 Assert(info->keysize > 0);
372 Assert(info->entrysize >= info->keysize);
373
374 /*
375 * For shared hash tables, we have a local hash header (HTAB struct) that
376 * we allocate in TopMemoryContext; all else is in shared memory.
377 *
378 * For non-shared hash tables, everything including the hash header is in
379 * a memory context created specially for the hash table --- this makes
380 * hash_destroy very simple. The memory context is made a child of either
381 * a context specified by the caller, or TopMemoryContext if nothing is
382 * specified.
383 *
384 * Note that HASH_ALLOC had better be set as well.
385 */
386 if (flags & HASH_SHARED_MEM)
387 {
388 /* Set up to allocate the hash header */
389 hcxt = TopMemoryContext;
390 }
391 else
392 {
393 /* Create the hash table's private memory context */
394 if (flags & HASH_CONTEXT)
395 hcxt = info->hcxt;
396 else
397 hcxt = TopMemoryContext;
398 hcxt = AllocSetContextCreate(hcxt, "dynahash",
400 }
401
402 /* Initialize the hash header, plus a copy of the table name */
403 hashp = (HTAB *) MemoryContextAlloc(hcxt,
404 sizeof(HTAB) + strlen(tabname) + 1);
405 MemSet(hashp, 0, sizeof(HTAB));
406
407 hashp->tabname = (char *) (hashp + 1);
408 strcpy(hashp->tabname, tabname);
409
410 /* If we have a private context, label it with hashtable's name */
411 if (!(flags & HASH_SHARED_MEM))
413
414 /*
415 * Select the appropriate hash function (see comments at head of file).
416 */
417 if (flags & HASH_FUNCTION)
418 {
419 Assert(!(flags & (HASH_BLOBS | HASH_STRINGS)));
420 hashp->hash = info->hash;
421 }
422 else if (flags & HASH_BLOBS)
423 {
424 Assert(!(flags & HASH_STRINGS));
425 /* We can optimize hashing for common key sizes */
426 if (info->keysize == sizeof(uint32))
427 hashp->hash = uint32_hash;
428 else
429 hashp->hash = tag_hash;
430 }
431 else
432 {
433 /*
434 * string_hash used to be considered the default hash method, and in a
435 * non-assert build it effectively still is. But we now consider it
436 * an assertion error to not say HASH_STRINGS explicitly. To help
437 * catch mistaken usage of HASH_STRINGS, we also insist on a
438 * reasonably long string length: if the keysize is only 4 or 8 bytes,
439 * it's almost certainly an integer or pointer not a string.
440 */
441 Assert(flags & HASH_STRINGS);
442 Assert(info->keysize > 8);
443
444 hashp->hash = string_hash;
445 }
446
447 /*
448 * If you don't specify a match function, it defaults to string_compare if
449 * you used string_hash, and to memcmp otherwise.
450 *
451 * Note: explicitly specifying string_hash is deprecated, because this
452 * might not work for callers in loadable modules on some platforms due to
453 * referencing a trampoline instead of the string_hash function proper.
454 * Specify HASH_STRINGS instead.
455 */
456 if (flags & HASH_COMPARE)
457 hashp->match = info->match;
458 else if (hashp->hash == string_hash)
460 else
461 hashp->match = memcmp;
462
463 /*
464 * Similarly, the key-copying function defaults to strlcpy or memcpy.
465 */
466 if (flags & HASH_KEYCOPY)
467 hashp->keycopy = info->keycopy;
468 else if (hashp->hash == string_hash)
469 {
470 /*
471 * The signature of keycopy is meant for memcpy(), which returns
472 * void*, but strlcpy() returns size_t. Since we never use the return
473 * value of keycopy, and size_t is pretty much always the same size as
474 * void *, this should be safe. The extra cast in the middle is to
475 * avoid warnings from -Wcast-function-type.
476 */
478 }
479 else
480 hashp->keycopy = memcpy;
481
482 /* And select the entry allocation function, too. */
483 if (flags & HASH_ALLOC)
484 {
485 hashp->alloc = info->alloc;
486 hashp->alloc_arg = info->alloc_arg;
487 }
488 else
489 {
490 hashp->alloc = DynaHashAlloc;
491 hashp->alloc_arg = hcxt;
492 }
493
494 if (flags & HASH_SHARED_MEM)
495 {
496 hashp->hcxt = NULL;
497 hashp->isshared = true;
498
499 /* hash table already exists, we're just attaching to it */
500 if (flags & HASH_ATTACH)
501 {
502 /* Caller must pass the pointer to the shared header */
503 Assert(info->hctl);
504 hashp->hctl = info->hctl;
505
506 /* make local copies of some heavily-used values */
507 hashp->dir = info->hctl->dir;
508 hashp->keysize = info->hctl->keysize;
509
510 return hashp;
511 }
512 }
513 else
514 {
515 /* setup hash table defaults */
516 hashp->hctl = NULL;
517 hashp->dir = NULL;
518 hashp->hcxt = hcxt;
519 hashp->isshared = false;
520 }
521
522 /*
523 * Allocate the header structure.
524 *
525 * XXX: In case of a shared memory hash table, other processes need the
526 * pointer to the header to re-find the hash table. There is currently no
527 * explicit way to pass it back from here, the caller relies on the fact
528 * that this is the first allocation made with the alloc function. That's
529 * a little ugly, but works for now.
530 */
531 hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR), hashp->alloc_arg);
532 if (!hashp->hctl)
535 errmsg("out of memory")));
536
537 hashp->frozen = false;
538
539 hdefault(hashp);
540
541 hctl = hashp->hctl;
542
543 if (flags & HASH_PARTITION)
544 {
545 /* Doesn't make sense to partition a local hash table */
546 Assert(flags & HASH_SHARED_MEM);
547
548 /*
549 * The number of partitions had better be a power of 2. Also, it must
550 * be less than INT_MAX (see init_htab()), so call the int version of
551 * next_pow2.
552 */
554
555 hctl->num_partitions = info->num_partitions;
556 }
557
558 /* remember the entry sizes, too */
559 hctl->keysize = info->keysize;
560 hctl->entrysize = info->entrysize;
561
562 /* make local copies of heavily-used constant fields */
563 hashp->keysize = hctl->keysize;
564
565 /* Build the hash directory structure */
566 if (!init_htab(hashp, nelem))
567 elog(ERROR, "failed to initialize hash table \"%s\"", hashp->tabname);
568
569 /*
570 * For a shared hash table, preallocate the requested number of elements.
571 * This reduces problems with run-time out-of-shared-memory conditions.
572 *
573 * For a non-shared hash table, preallocate the requested number of
574 * elements if it's less than our chosen nelem_alloc. This avoids wasting
575 * space if the caller correctly estimates a small table size.
576 */
577 if ((flags & HASH_SHARED_MEM) ||
578 nelem < hctl->nelem_alloc)
579 {
580 int i,
582 nelem_alloc,
584
585 /*
586 * If hash table is partitioned, give each freelist an equal share of
587 * the initial allocation. Otherwise only freeList[0] is used.
588 */
589 if (IS_PARTITIONED(hashp->hctl))
591 else
593
594 nelem_alloc = nelem / freelist_partitions;
595 if (nelem_alloc <= 0)
596 nelem_alloc = 1;
597
598 /*
599 * Make sure we'll allocate all the requested elements; freeList[0]
600 * gets the excess if the request isn't divisible by NUM_FREELISTS.
601 */
602 if (nelem_alloc * freelist_partitions < nelem)
604 nelem - nelem_alloc * (freelist_partitions - 1);
605 else
606 nelem_alloc_first = nelem_alloc;
607
608 for (i = 0; i < freelist_partitions; i++)
609 {
610 int temp = (i == 0) ? nelem_alloc_first : nelem_alloc;
611
612 if (!element_alloc(hashp, temp, i))
615 errmsg("out of memory")));
616 }
617 }
618
619 /* Set isfixed if requested, but not till after we build initial entries */
620 if (flags & HASH_FIXED_SIZE)
621 hctl->isfixed = true;
622
623 return hashp;
624}

References HTAB::alloc, HASHCTL::alloc, HTAB::alloc_arg, HASHCTL::alloc_arg, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, HASHHDR::dir, HTAB::dir, DynaHashAlloc(), element_alloc(), elog, HASHHDR::entrysize, HASHCTL::entrysize, ereport, errcode(), errmsg, ERROR, fb(), HTAB::frozen, HTAB::hash, HASHCTL::hash, HASH_ALLOC, HASH_ATTACH, HASH_BLOBS, HASH_COMPARE, HASH_CONTEXT, HASH_ELEM, HASH_FIXED_SIZE, HASH_FUNCTION, HASH_KEYCOPY, HASH_PARTITION, HASH_SHARED_MEM, HASH_STRINGS, HTAB::hctl, HASHCTL::hctl, HTAB::hcxt, HASHCTL::hcxt, hdefault(), i, init_htab(), IS_PARTITIONED, HASHHDR::isfixed, HTAB::isshared, HTAB::keycopy, HASHCTL::keycopy, HASHHDR::keysize, HTAB::keysize, HASHCTL::keysize, HTAB::match, HASHCTL::match, memcpy(), MemoryContextAlloc(), MemoryContextSetIdentifier(), MemSet, next_pow2_int(), NUM_FREELISTS, HASHHDR::num_partitions, HASHCTL::num_partitions, string_compare(), string_hash(), strlcpy(), HTAB::tabname, tag_hash(), TopMemoryContext, and uint32_hash().

Referenced by _hash_finish_split(), _PG_init(), AddEventToPendingNotifies(), AddPendingSync(), assign_record_type_typmod(), begin_heap_rewrite(), build_colinfo_names_hash(), build_guc_variables(), build_join_rel_hash(), BuildEventTriggerCache(), cfunc_hashtable_init(), CheckForSessionAndXactLocks(), CompactCheckpointerRequestQueue(), compute_array_stats(), compute_tsvector_stats(), create_seq_hashtable(), createConnHash(), CreateLocalPredicateLockHash(), CreatePartitionDirectory(), do_autovacuum(), EnablePortalManager(), ExecInitModifyTable(), ExecuteTruncateGuts(), find_all_inheritors(), find_oper_cache_entry(), find_rendezvous_variable(), get_json_object_as_hash(), get_relation_notnullatts(), GetComboCommandId(), GetConnection(), gistInitBuildBuffers(), gistInitParentMap(), init_missing_cache(), init_procedure_caches(), init_rel_sync_cache(), init_timezone_hashtable(), init_ts_config_cache(), init_uncommitted_enum_types(), init_uncommitted_enum_values(), InitializeAttoptCache(), InitializeRelfilenumberMap(), InitializeShippableCache(), InitializeTableSpaceCache(), InitLocalBuffers(), initLocalChannelTable(), InitLockManagerAccess(), initPendingListenActions(), InitQueryHashTable(), InitRecoveryTransactionEnvironment(), InitSync(), json_unique_check_init(), load_categories_hash(), log_invalid_page(), logical_begin_heap_rewrite(), logicalrep_partmap_init(), logicalrep_relmap_init(), lookup_proof_cache(), lookup_ts_dictionary_cache(), lookup_ts_parser_cache(), lookup_type_cache(), LookupOpclassInfo(), pa_allocate_worker(), pg_get_backend_memory_contexts(), plpgsql_estate_setup(), PLy_add_exceptions(), populate_recordset_object_start(), ProcessSyncingTablesForApply(), rebuild_database_list(), record_C_func(), RegisterExtensibleNodeEntry(), RelationCacheInitialize(), ReorderBufferAllocate(), ReorderBufferBuildTupleCidHash(), ReorderBufferToastInitHash(), ResetUnloggedRelationsInDbspaceDir(), ri_FastPathGetEntry(), ri_InitHashTables(), select_perl_context(), SerializePendingSyncs(), set_rtable_names(), shmem_hash_create(), smgropen(), transformGraph(), and XLogPrefetcherAllocate().

◆ hash_destroy()

◆ hash_estimate_size()

Size hash_estimate_size ( int64  num_entries,
Size  entrysize 
)

Definition at line 763 of file dynahash.c.

764{
765 Size size;
767 nSegments,
772
773 /* estimate number of buckets wanted */
774 nBuckets = next_pow2_int64(num_entries);
775 /* # of segments needed for nBuckets */
777 /* directory entries */
779
780 /* fixed control info */
781 size = MAXALIGN(sizeof(HASHHDR)); /* but not HTAB, per above */
782 /* directory */
783 size = add_size(size, mul_size(nDirEntries, sizeof(HASHSEGMENT)));
784 /* segments */
785 size = add_size(size, mul_size(nSegments,
786 MAXALIGN(HASH_SEGSIZE * sizeof(HASHBUCKET))));
787 /* elements --- allocated in groups of choose_nelem_alloc() entries */
789 nElementAllocs = (num_entries - 1) / elementAllocCnt + 1;
790 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
791 size = add_size(size,
794
795 return size;
796}

References add_size(), choose_nelem_alloc(), DEF_DIRSIZE, fb(), HASH_SEGSIZE, Max, MAXALIGN, mul_size(), and next_pow2_int64().

Referenced by InitShmemAllocator(), ShmemGetRequestedSize(), ShmemInitHash(), and ShmemRequestHashWithOpts().

◆ hash_freeze()

void hash_freeze ( HTAB hashp)

Definition at line 1464 of file dynahash.c.

1465{
1466 if (hashp->isshared)
1467 elog(ERROR, "cannot freeze shared hashtable \"%s\"", hashp->tabname);
1468 if (!hashp->frozen && has_seq_scans(hashp))
1469 elog(ERROR, "cannot freeze hashtable \"%s\" because it has active scans",
1470 hashp->tabname);
1471 hashp->frozen = true;
1472}

References elog, ERROR, HTAB::frozen, has_seq_scans(), HTAB::isshared, and HTAB::tabname.

◆ hash_get_num_entries()

int64 hash_get_num_entries ( HTAB hashp)

Definition at line 1273 of file dynahash.c.

1274{
1275 int i;
1276 int64 sum = hashp->hctl->freeList[0].nentries;
1277
1278 /*
1279 * We currently don't bother with acquiring the mutexes; it's only
1280 * sensible to call this function if you've got lock on all partitions of
1281 * the table.
1282 */
1283 if (IS_PARTITIONED(hashp->hctl))
1284 {
1285 for (i = 1; i < NUM_FREELISTS; i++)
1286 sum += hashp->hctl->freeList[i].nentries;
1287 }
1288
1289 return sum;
1290}

References HASHHDR::freeList, HTAB::hctl, i, IS_PARTITIONED, FreeListData::nentries, and NUM_FREELISTS.

Referenced by build_guc_variables(), compute_array_stats(), compute_tsvector_stats(), entry_alloc(), entry_dealloc(), entry_reset(), EstimatePendingSyncsSpace(), EstimateUncommittedEnumsSpace(), get_crosstab_tuplestore(), get_explain_guc_options(), get_guc_variables(), GetLockStatusData(), GetPredicateLockStatusData(), GetRunningTransactionLocks(), GetWaitEventCustomNames(), hash_stats(), pgss_shmem_shutdown(), ResetUnloggedRelationsInDbspaceDir(), SerializePendingSyncs(), transformGraph(), and XLogHaveInvalidPages().

◆ hash_initial_lookup()

static uint32 hash_initial_lookup ( HTAB hashp,
uint32  hashvalue,
HASHBUCKET **  bucketptr 
)
inlinestatic

Definition at line 1712 of file dynahash.c.

1713{
1714 HASHHDR *hctl = hashp->hctl;
1718 uint32 bucket;
1719
1720 bucket = calc_bucket(hctl, hashvalue);
1721
1724
1725 segp = hashp->dir[segment_num];
1726
1727 if (segp == NULL)
1728 hash_corrupted(hashp);
1729
1731 return bucket;
1732}

References calc_bucket(), HTAB::dir, fb(), hash_corrupted(), HASH_SEGSIZE, HASH_SEGSIZE_SHIFT, HTAB::hctl, and MOD.

Referenced by hash_search_with_hash_value(), hash_seq_init_with_hash_value(), and hash_update_hash_key().

◆ hash_search()

void * hash_search ( HTAB hashp,
const void keyPtr,
HASHACTION  action,
bool foundPtr 
)

Definition at line 889 of file dynahash.c.

893{
894 return hash_search_with_hash_value(hashp,
895 keyPtr,
896 hashp->hash(keyPtr, hashp->keysize),
897 action,
898 foundPtr);
899}

References fb(), HTAB::hash, hash_search_with_hash_value(), and HTAB::keysize.

Referenced by _hash_finish_split(), _hash_splitbucket(), add_guc_variable(), add_join_rel(), add_to_names_hash(), AddEnumLabel(), AddEventToPendingNotifies(), AddPendingSync(), ApplyLogicalMappingFile(), ApplyPendingListenActions(), assign_record_type_typmod(), AsyncExistsPendingNotify(), AtEOSubXact_RelationCache(), AtEOXact_RelationCache(), AttachShmemIndexEntry(), build_guc_variables(), build_join_rel_hash(), BuildEventTriggerCache(), CallShmemCallbacksAfterStartup(), cfunc_hashtable_delete(), cfunc_hashtable_insert(), cfunc_hashtable_lookup(), CheckAndPromotePredicateLockRequest(), CheckForSerializableConflictOut(), CheckForSessionAndXactLocks(), colname_is_unique(), CompactCheckpointerRequestQueue(), compile_plperl_function(), compile_pltcl_function(), compute_array_stats(), compute_tsvector_stats(), createNewConnection(), define_custom_variable(), delete_rel_type_cache_if_needed(), deleteConnection(), do_autovacuum(), DropAllPredicateLocksFromTable(), DropAllPreparedStatements(), DropPreparedStatement(), entry_alloc(), entry_dealloc(), entry_reset(), EnumTypeUncommitted(), EnumUncommitted(), EnumValuesCreate(), EventCacheLookup(), ExecInitModifyTable(), ExecLookupResultRelByOid(), ExecuteTruncateGuts(), ExtendBufferedRelLocal(), FetchPreparedStatement(), finalize_in_progress_typentries(), find_all_inheritors(), find_join_rel(), find_oper_cache_entry(), find_option(), find_relation_notnullatts(), find_rendezvous_variable(), forget_invalid_pages(), forget_invalid_pages_db(), get_attribute_options(), get_cast_hashentry(), get_rel_sync_entry(), get_relation_notnullatts(), get_tablespace(), GetComboCommandId(), GetConnection(), getConnectionByName(), GetExtensibleNodeEntry(), getmissingattr(), getState(), GetWaitEventCustomIdentifier(), gistGetNodeBuffer(), gistGetParent(), gistMemorizeParent(), gistRelocateBuildBuffersOnSplit(), hash_object_field_end(), init_sequence(), InitShmemAllocator(), InitShmemIndexEntry(), insert_rel_type_cache_if_needed(), InvalidateAttoptCacheCallback(), InvalidateLocalBuffer(), InvalidateOprCacheCallBack(), InvalidateShippableCacheCallback(), InvalidateTableSpaceCacheCallback(), is_shippable(), IsListeningOn(), JsObjectGetField(), json_unique_check_key(), LocalBufferAlloc(), LockAcquireExtended(), LockHasWaiters(), LockHeldByMe(), LockRelease(), log_invalid_page(), logical_rewrite_log_mapping(), logicalrep_partition_open(), logicalrep_rel_open(), logicalrep_relmap_update(), lookup_C_func(), lookup_proof_cache(), lookup_ts_config_cache(), lookup_ts_dictionary_cache(), lookup_ts_parser_cache(), lookup_type_cache(), LookupOpclassInfo(), make_oper_cache_entry(), MarkGUCPrefixReserved(), pa_allocate_worker(), pa_find_worker(), pa_free_worker(), PartitionDirectoryLookup(), pg_get_backend_memory_contexts(), pg_tzset(), pgss_store(), plperl_spi_exec_prepared(), plperl_spi_freeplan(), plperl_spi_prepare(), plperl_spi_query_prepared(), pltcl_fetch_interp(), PLy_commit(), PLy_generate_spi_exceptions(), PLy_procedure_get(), PLy_rollback(), PLy_spi_subtransaction_abort(), populate_recordset_object_field_end(), predicatelock_twophase_recover(), PredicateLockExists(), PredicateLockShmemInit(), PredicateLockTwoPhaseFinish(), PrefetchLocalBuffer(), PrepareTableEntriesForListen(), PrepareTableEntriesForUnlisten(), PrepareTableEntriesForUnlistenAll(), ProcessSyncingTablesForApply(), ProcessSyncRequests(), prune_element_hashtable(), prune_lexemes_hashtable(), PutMemoryContextsStatsTupleStore(), rebuild_database_list(), record_C_func(), RegisterExtensibleNodeEntry(), RegisterPredicateLockingXid(), rel_sync_cache_relation_cb(), RelationPreTruncate(), ReleaseOneSerializableXact(), RelFileLocatorSkippingWAL(), RelfilenumberMapInvalidateCallback(), RelidByRelfilenumber(), RememberSyncRequest(), RemoveLocalLock(), ReorderBufferBuildTupleCidHash(), ReorderBufferCleanupTXN(), ReorderBufferToastAppendChunk(), ReorderBufferToastReplace(), ReorderBufferTXNByXid(), ResetUnloggedRelationsInDbspaceDir(), ResolveCminCmaxDuringDecoding(), RestoreUncommittedEnums(), rewrite_heap_dead_tuple(), rewrite_heap_tuple(), ri_FastPathGetEntry(), ri_FetchPreparedPlan(), ri_HashCompareOp(), ri_HashPreparedPlan(), ri_LoadConstraintInfo(), select_perl_context(), SerializePendingSyncs(), set_rtable_names(), smgrdestroy(), smgrDoPendingSyncs(), smgropen(), smgrreleaserellocator(), StandbyAcquireAccessExclusiveLock(), StandbyReleaseAllLocks(), StandbyReleaseLocks(), StandbyReleaseOldLocks(), StandbyReleaseXidEntryLocks(), StorePreparedStatement(), table_recheck_autovac(), TypeCacheRelCallback(), WaitEventCustomNew(), XLogPrefetcherAddFilter(), XLogPrefetcherCompleteFilters(), and XLogPrefetcherIsFiltered().

◆ hash_search_with_hash_value()

void * hash_search_with_hash_value ( HTAB hashp,
const void keyPtr,
uint32  hashvalue,
HASHACTION  action,
bool foundPtr 
)

Definition at line 902 of file dynahash.c.

907{
908 HASHHDR *hctl = hashp->hctl;
909 int freelist_idx = FREELIST_IDX(hctl, hashvalue);
910 Size keysize;
913 HashCompareFunc match;
914
915#ifdef HASH_STATISTICS
916 hctl->accesses++;
917#endif
918
919 /*
920 * If inserting, check if it is time to split a bucket.
921 *
922 * NOTE: failure to expand table is not a fatal error, it just means we
923 * have to run at higher fill factor than we wanted. However, if we're
924 * using the palloc allocator then it will throw error anyway on
925 * out-of-memory, so we must do this before modifying the table.
926 */
927 if (action == HASH_ENTER || action == HASH_ENTER_NULL)
928 {
929 /*
930 * Can't split if running in partitioned mode, nor if frozen, nor if
931 * table is the subject of any active hash_seq_search scans.
932 */
933 if (hctl->freeList[0].nentries > (int64) hctl->max_bucket &&
934 !IS_PARTITIONED(hctl) && !hashp->frozen &&
935 !has_seq_scans(hashp))
936 (void) expand_table(hashp);
937 }
938
939 /*
940 * Do the initial lookup
941 */
942 (void) hash_initial_lookup(hashp, hashvalue, &prevBucketPtr);
944
945 /*
946 * Follow collision chain looking for matching key
947 */
948 match = hashp->match; /* save one fetch in inner loop */
949 keysize = hashp->keysize; /* ditto */
950
951 while (currBucket != NULL)
952 {
953 if (currBucket->hashvalue == hashvalue &&
954 match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
955 break;
956 prevBucketPtr = &(currBucket->link);
958#ifdef HASH_STATISTICS
959 hctl->collisions++;
960#endif
961 }
962
963 if (foundPtr)
964 *foundPtr = (bool) (currBucket != NULL);
965
966 /*
967 * OK, now what?
968 */
969 switch (action)
970 {
971 case HASH_FIND:
972 if (currBucket != NULL)
973 return ELEMENTKEY(currBucket);
974 return NULL;
975
976 case HASH_REMOVE:
977 if (currBucket != NULL)
978 {
979 /* if partitioned, must lock to touch nentries and freeList */
980 if (IS_PARTITIONED(hctl))
982
983 /* delete the record from the appropriate nentries counter. */
986
987 /* remove record from hash bucket's chain. */
988 *prevBucketPtr = currBucket->link;
989
990 /* add the record to the appropriate freelist. */
993
994 if (IS_PARTITIONED(hctl))
996
997 /*
998 * better hope the caller is synchronizing access to this
999 * element, because someone else is going to reuse it the next
1000 * time something is added to the table
1001 */
1002 return ELEMENTKEY(currBucket);
1003 }
1004 return NULL;
1005
1006 case HASH_ENTER:
1007 case HASH_ENTER_NULL:
1008 /* Return existing element if found, else create one */
1009 if (currBucket != NULL)
1010 return ELEMENTKEY(currBucket);
1011
1012 /* disallow inserts if frozen */
1013 if (hashp->frozen)
1014 elog(ERROR, "cannot insert into frozen hashtable \"%s\"",
1015 hashp->tabname);
1016
1018 if (currBucket == NULL)
1019 {
1020 /* out of memory */
1021 if (action == HASH_ENTER_NULL)
1022 return NULL;
1023 /* report a generic message */
1024 if (hashp->isshared)
1025 ereport(ERROR,
1027 errmsg("out of shared memory")));
1028 else
1029 ereport(ERROR,
1031 errmsg("out of memory")));
1032 }
1033
1034 /* link into hashbucket chain */
1036 currBucket->link = NULL;
1037
1038 /* copy key into record */
1039 currBucket->hashvalue = hashvalue;
1040 hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize);
1041
1042 /*
1043 * Caller is expected to fill the data field on return. DO NOT
1044 * insert any code that could possibly throw error here, as doing
1045 * so would leave the table entry incomplete and hence corrupt the
1046 * caller's data structure.
1047 */
1048
1049 return ELEMENTKEY(currBucket);
1050 }
1051
1052 elog(ERROR, "unrecognized hash action code: %d", (int) action);
1053
1054 return NULL; /* keep compiler quiet */
1055}

References Assert, ELEMENTKEY, elog, ereport, errcode(), errmsg, ERROR, expand_table(), fb(), FreeListData::freeList, HASHHDR::freeList, FREELIST_IDX, HTAB::frozen, get_hash_entry(), has_seq_scans(), HASH_ENTER, HASH_ENTER_NULL, HASH_FIND, hash_initial_lookup(), HASH_REMOVE, HTAB::hctl, IS_PARTITIONED, HTAB::isshared, HTAB::keycopy, HTAB::keysize, HTAB::match, HASHHDR::max_bucket, FreeListData::mutex, FreeListData::nentries, SpinLockAcquire(), SpinLockRelease(), and HTAB::tabname.

Referenced by BufTableDelete(), BufTableInsert(), BufTableLookup(), CheckTargetForConflictsIn(), CleanUpLock(), ClearOldPredicateLocks(), CreatePredicateLock(), DecrementParentLocks(), DeleteChildTargetLocks(), DeleteLockTarget(), DropAllPredicateLocksFromTable(), FastPathGetRelationLockEntry(), GetLockConflicts(), hash_search(), lock_twophase_recover(), LockAcquireExtended(), LockRefindAndRelease(), LockRelease(), LockWaiterCount(), PageIsPredicateLocked(), PredicateLockAcquire(), ReleaseOneSerializableXact(), RemoveScratchTarget(), RemoveTargetIfNoLongerUsed(), RestoreScratchTarget(), SetupLockInTable(), and TransferPredicateLocksToNewTarget().

◆ hash_seq_init()

void hash_seq_init ( HASH_SEQ_STATUS status,
HTAB hashp 
)

Definition at line 1317 of file dynahash.c.

1318{
1319 status->hashp = hashp;
1320 status->curBucket = 0;
1321 status->curEntry = NULL;
1322 status->hasHashvalue = false;
1323 if (!hashp->frozen)
1324 register_seq_scan(hashp);
1325}

References HASH_SEQ_STATUS::curBucket, HASH_SEQ_STATUS::curEntry, fb(), HTAB::frozen, HASH_SEQ_STATUS::hasHashvalue, HASH_SEQ_STATUS::hashp, and register_seq_scan().

Referenced by ApplyPendingListenActions(), AtAbort_Portals(), AtCleanup_Portals(), AtEOSubXact_RelationCache(), AtEOXact_RelationCache(), AtPrepare_Locks(), AtSubAbort_Portals(), AtSubCleanup_Portals(), AtSubCommit_Portals(), BeginReportingGUCOptions(), CheckForSessionAndXactLocks(), CheckTableForSerializableConflictIn(), cleanup_rel_sync_cache(), compute_array_stats(), compute_tsvector_stats(), dblink_get_connections(), DestroyPartitionDirectory(), disconnect_cached_connections(), DropAllPredicateLocksFromTable(), DropAllPreparedStatements(), end_heap_rewrite(), entry_dealloc(), entry_reset(), ExecuteTruncateGuts(), forget_invalid_pages(), forget_invalid_pages_db(), ForgetPortalSnapshots(), gc_qtexts(), get_guc_variables(), GetLockStatusData(), GetPredicateLockStatusData(), GetRunningTransactionLocks(), GetWaitEventCustomNames(), hash_seq_init_with_hash_value(), HoldPinnedPortals(), InitializeGUCOptions(), InvalidateAttoptCacheCallback(), InvalidateOprCacheCallBack(), InvalidateOprProofCacheCallBack(), InvalidateShippableCacheCallback(), InvalidateTableSpaceCacheCallback(), InvalidateTSCacheCallBack(), LockReassignCurrentOwner(), LockReleaseAll(), LockReleaseCurrentOwner(), LockReleaseSession(), logical_end_heap_rewrite(), logical_heap_rewrite_flush_mappings(), logicalrep_partmap_invalidate_cb(), logicalrep_partmap_reset_relmap(), logicalrep_relmap_invalidate_cb(), MarkGUCPrefixReserved(), packGraph(), pg_cursor(), pg_get_shmem_allocations(), pg_get_shmem_allocations_numa(), pg_listening_channels(), pg_prepared_statement(), pg_stat_statements_internal(), pgfdw_inval_callback(), pgfdw_subxact_callback(), pgfdw_xact_callback(), pgss_shmem_shutdown(), plperl_fini(), PortalErrorCleanup(), PortalHashTableDeleteAll(), postgres_fdw_get_connections_internal(), PostPrepare_Locks(), PreCommit_Notify(), PreCommit_Portals(), PrepareTableEntriesForUnlistenAll(), ProcessConfigFileInternal(), ProcessSyncRequests(), prune_element_hashtable(), prune_lexemes_hashtable(), rebuild_database_list(), rel_sync_cache_publication_cb(), rel_sync_cache_relation_cb(), RelationCacheInitializePhase3(), RelationCacheInvalidate(), RelfilenumberMapInvalidateCallback(), RememberSyncRequest(), ReorderBufferToastReset(), ri_FastPathEndBatch(), ri_FastPathTeardown(), selectColorTrigrams(), SerializePendingSyncs(), SerializeUncommittedEnums(), smgrDoPendingSyncs(), smgrreleaseall(), StandbyReleaseAllLocks(), StandbyReleaseOldLocks(), ThereAreNoReadyPortals(), TypeCacheOpcCallback(), TypeCacheRelCallback(), TypeCacheTypCallback(), write_relcache_init_file(), and XLogCheckInvalidPages().

◆ hash_seq_init_with_hash_value()

void hash_seq_init_with_hash_value ( HASH_SEQ_STATUS status,
HTAB hashp,
uint32  hashvalue 
)

Definition at line 1337 of file dynahash.c.

1339{
1341
1342 hash_seq_init(status, hashp);
1343
1344 status->hasHashvalue = true;
1345 status->hashvalue = hashvalue;
1346
1347 status->curBucket = hash_initial_lookup(hashp, hashvalue, &bucketPtr);
1348 status->curEntry = *bucketPtr;
1349}

References HASH_SEQ_STATUS::curBucket, HASH_SEQ_STATUS::curEntry, fb(), hash_initial_lookup(), hash_seq_init(), HASH_SEQ_STATUS::hasHashvalue, and HASH_SEQ_STATUS::hashvalue.

Referenced by InvalidateAttoptCacheCallback(), and TypeCacheTypCallback().

◆ hash_seq_search()

void * hash_seq_search ( HASH_SEQ_STATUS status)

Definition at line 1352 of file dynahash.c.

1353{
1354 HTAB *hashp;
1355 HASHHDR *hctl;
1356 uint32 max_bucket;
1360 uint32 curBucket;
1362
1363 if (status->hasHashvalue)
1364 {
1365 /*
1366 * Scan entries only in the current bucket because only this bucket
1367 * can contain entries with the given hash value.
1368 */
1369 while ((curElem = status->curEntry) != NULL)
1370 {
1371 status->curEntry = curElem->link;
1372 if (status->hashvalue != curElem->hashvalue)
1373 continue;
1374 return (void *) ELEMENTKEY(curElem);
1375 }
1376
1377 hash_seq_term(status);
1378 return NULL;
1379 }
1380
1381 if ((curElem = status->curEntry) != NULL)
1382 {
1383 /* Continuing scan of curBucket... */
1384 status->curEntry = curElem->link;
1385 if (status->curEntry == NULL) /* end of this bucket */
1386 ++status->curBucket;
1387 return ELEMENTKEY(curElem);
1388 }
1389
1390 /*
1391 * Search for next nonempty bucket starting at curBucket.
1392 */
1393 curBucket = status->curBucket;
1394 hashp = status->hashp;
1395 hctl = hashp->hctl;
1396 max_bucket = hctl->max_bucket;
1397
1398 if (curBucket > max_bucket)
1399 {
1400 hash_seq_term(status);
1401 return NULL; /* search is done */
1402 }
1403
1404 /*
1405 * first find the right segment in the table directory.
1406 */
1407 segment_num = curBucket >> HASH_SEGSIZE_SHIFT;
1408 segment_ndx = MOD(curBucket, HASH_SEGSIZE);
1409
1410 segp = hashp->dir[segment_num];
1411
1412 /*
1413 * Pick up the first item in this bucket's chain. If chain is not empty
1414 * we can begin searching it. Otherwise we have to advance to find the
1415 * next nonempty bucket. We try to optimize that case since searching a
1416 * near-empty hashtable has to iterate this loop a lot.
1417 */
1418 while ((curElem = segp[segment_ndx]) == NULL)
1419 {
1420 /* empty bucket, advance to next */
1421 if (++curBucket > max_bucket)
1422 {
1423 status->curBucket = curBucket;
1424 hash_seq_term(status);
1425 return NULL; /* search is done */
1426 }
1427 if (++segment_ndx >= HASH_SEGSIZE)
1428 {
1429 segment_num++;
1430 segment_ndx = 0;
1431 segp = hashp->dir[segment_num];
1432 }
1433 }
1434
1435 /* Begin scan of curBucket... */
1436 status->curEntry = curElem->link;
1437 if (status->curEntry == NULL) /* end of this bucket */
1438 ++curBucket;
1439 status->curBucket = curBucket;
1440 return ELEMENTKEY(curElem);
1441}

References HASH_SEQ_STATUS::curBucket, HASH_SEQ_STATUS::curEntry, HTAB::dir, ELEMENTKEY, fb(), HASH_SEGSIZE, HASH_SEGSIZE_SHIFT, hash_seq_term(), HASH_SEQ_STATUS::hasHashvalue, HASH_SEQ_STATUS::hashp, HASH_SEQ_STATUS::hashvalue, HTAB::hctl, HASHELEMENT::link, HASHHDR::max_bucket, and MOD.

Referenced by ApplyPendingListenActions(), AtAbort_Portals(), AtCleanup_Portals(), AtEOSubXact_RelationCache(), AtEOXact_RelationCache(), AtPrepare_Locks(), AtSubAbort_Portals(), AtSubCleanup_Portals(), AtSubCommit_Portals(), BeginReportingGUCOptions(), CheckForSessionAndXactLocks(), CheckTableForSerializableConflictIn(), cleanup_rel_sync_cache(), compute_array_stats(), compute_tsvector_stats(), dblink_get_connections(), DestroyPartitionDirectory(), disconnect_cached_connections(), DropAllPredicateLocksFromTable(), DropAllPreparedStatements(), end_heap_rewrite(), entry_dealloc(), entry_reset(), ExecuteTruncateGuts(), forget_invalid_pages(), forget_invalid_pages_db(), ForgetPortalSnapshots(), gc_qtexts(), get_guc_variables(), GetLockStatusData(), GetPredicateLockStatusData(), GetRunningTransactionLocks(), GetWaitEventCustomNames(), HoldPinnedPortals(), InitializeGUCOptions(), InvalidateAttoptCacheCallback(), InvalidateOprCacheCallBack(), InvalidateOprProofCacheCallBack(), InvalidateShippableCacheCallback(), InvalidateTableSpaceCacheCallback(), InvalidateTSCacheCallBack(), LockReassignCurrentOwner(), LockReleaseAll(), LockReleaseCurrentOwner(), LockReleaseSession(), logical_end_heap_rewrite(), logical_heap_rewrite_flush_mappings(), logicalrep_partmap_invalidate_cb(), logicalrep_partmap_reset_relmap(), logicalrep_relmap_invalidate_cb(), MarkGUCPrefixReserved(), packGraph(), pg_cursor(), pg_get_shmem_allocations(), pg_get_shmem_allocations_numa(), pg_listening_channels(), pg_prepared_statement(), pg_stat_statements_internal(), pgfdw_inval_callback(), pgfdw_subxact_callback(), pgfdw_xact_callback(), pgss_shmem_shutdown(), plperl_fini(), PortalErrorCleanup(), PortalHashTableDeleteAll(), postgres_fdw_get_connections_internal(), PostPrepare_Locks(), PreCommit_Notify(), PreCommit_Portals(), PrepareTableEntriesForUnlistenAll(), ProcessConfigFileInternal(), ProcessSyncRequests(), prune_element_hashtable(), prune_lexemes_hashtable(), rebuild_database_list(), rel_sync_cache_publication_cb(), rel_sync_cache_relation_cb(), RelationCacheInitializePhase3(), RelationCacheInvalidate(), RelfilenumberMapInvalidateCallback(), RememberSyncRequest(), ReorderBufferToastReset(), ri_FastPathEndBatch(), ri_FastPathTeardown(), selectColorTrigrams(), SerializePendingSyncs(), SerializeUncommittedEnums(), smgrDoPendingSyncs(), smgrreleaseall(), StandbyReleaseAllLocks(), StandbyReleaseOldLocks(), ThereAreNoReadyPortals(), TypeCacheOpcCallback(), TypeCacheRelCallback(), TypeCacheTypCallback(), write_relcache_init_file(), and XLogCheckInvalidPages().

◆ hash_seq_term()

◆ hash_stats()

void hash_stats ( const char caller,
HTAB hashp 
)

Definition at line 821 of file dynahash.c.

822{
823#ifdef HASH_STATISTICS
824 HASHHDR *hctl = hashp->hctl;
825
826 elog(DEBUG4,
827 "hash_stats: Caller: %s Table Name: \"%s\" Accesses: " UINT64_FORMAT " Collisions: " UINT64_FORMAT " Expansions: " UINT64_FORMAT " Entries: " INT64_FORMAT " Key Size: %zu Max Bucket: %u Segment Count: " INT64_FORMAT,
828 caller != NULL ? caller : "(unknown)", hashp->tabname, hctl->accesses,
829 hctl->collisions, hctl->expansions, hash_get_num_entries(hashp),
830 hctl->keysize, hctl->max_bucket, hctl->nsegs);
831#endif
832}

References DEBUG4, elog, fb(), hash_get_num_entries(), HTAB::hctl, INT64_FORMAT, HASHHDR::keysize, HASHHDR::max_bucket, HASHHDR::nsegs, HTAB::tabname, and UINT64_FORMAT.

Referenced by hash_destroy().

◆ hash_update_hash_key()

bool hash_update_hash_key ( HTAB hashp,
void existingEntry,
const void newKeyPtr 
)

Definition at line 1077 of file dynahash.c.

1080{
1083 Size keysize;
1084 uint32 bucket;
1089 HashCompareFunc match;
1090
1091#ifdef HASH_STATISTICS
1092 HASHHDR *hctl = hashp->hctl;
1093
1094 hctl->accesses++;
1095#endif
1096
1097 /* disallow updates if frozen */
1098 if (hashp->frozen)
1099 elog(ERROR, "cannot update in frozen hashtable \"%s\"",
1100 hashp->tabname);
1101
1102 /*
1103 * Lookup the existing element using its saved hash value. We need to do
1104 * this to be able to unlink it from its hash chain, but as a side benefit
1105 * we can verify the validity of the passed existingEntry pointer.
1106 */
1107 bucket = hash_initial_lookup(hashp, existingElement->hashvalue,
1108 &prevBucketPtr);
1110
1111 while (currBucket != NULL)
1112 {
1114 break;
1115 prevBucketPtr = &(currBucket->link);
1117 }
1118
1119 if (currBucket == NULL)
1120 elog(ERROR, "hash_update_hash_key argument is not in hashtable \"%s\"",
1121 hashp->tabname);
1122
1124
1125 /*
1126 * Now perform the equivalent of a HASH_ENTER operation to locate the hash
1127 * chain we want to put the entry into.
1128 */
1129 newhashvalue = hashp->hash(newKeyPtr, hashp->keysize);
1132
1133 /*
1134 * Follow collision chain looking for matching key
1135 */
1136 match = hashp->match; /* save one fetch in inner loop */
1137 keysize = hashp->keysize; /* ditto */
1138
1139 while (currBucket != NULL)
1140 {
1141 if (currBucket->hashvalue == newhashvalue &&
1142 match(ELEMENTKEY(currBucket), newKeyPtr, keysize) == 0)
1143 break;
1144 prevBucketPtr = &(currBucket->link);
1146#ifdef HASH_STATISTICS
1147 hctl->collisions++;
1148#endif
1149 }
1150
1151 if (currBucket != NULL)
1152 return false; /* collision with an existing entry */
1153
1155
1156 /*
1157 * If old and new hash values belong to the same bucket, we need not
1158 * change any chain links, and indeed should not since this simplistic
1159 * update will corrupt the list if currBucket is the last element. (We
1160 * cannot fall out earlier, however, since we need to scan the bucket to
1161 * check for duplicate keys.)
1162 */
1163 if (bucket != newbucket)
1164 {
1165 /* OK to remove record from old hash bucket's chain. */
1166 *oldPrevPtr = currBucket->link;
1167
1168 /* link into new hashbucket chain */
1170 currBucket->link = NULL;
1171 }
1172
1173 /* copy new key into record */
1174 currBucket->hashvalue = newhashvalue;
1175 hashp->keycopy(ELEMENTKEY(currBucket), newKeyPtr, keysize);
1176
1177 /* rest of record is untouched */
1178
1179 return true;
1180}

References ELEMENT_FROM_KEY, ELEMENTKEY, elog, ERROR, fb(), HTAB::frozen, HTAB::hash, hash_initial_lookup(), HTAB::hctl, HTAB::keycopy, HTAB::keysize, HTAB::match, and HTAB::tabname.

Referenced by PostPrepare_Locks().

◆ hdefault()

static void hdefault ( HTAB hashp)
static

Definition at line 630 of file dynahash.c.

631{
632 HASHHDR *hctl = hashp->hctl;
633
634 MemSet(hctl, 0, sizeof(HASHHDR));
635
636 hctl->num_partitions = 0; /* not partitioned */
637
638 /* table has no fixed maximum size */
639 hctl->max_dsize = NO_MAX_DSIZE;
640
641 hctl->isfixed = false; /* can be enlarged */
642
643#ifdef HASH_STATISTICS
644 hctl->accesses = hctl->collisions = hctl->expansions = 0;
645#endif
646}

References HTAB::hctl, HASHHDR::isfixed, HASHHDR::max_dsize, MemSet, NO_MAX_DSIZE, and HASHHDR::num_partitions.

Referenced by hash_create().

◆ init_htab()

static bool init_htab ( HTAB hashp,
int64  nelem 
)
static

Definition at line 686 of file dynahash.c.

687{
688 HASHHDR *hctl = hashp->hctl;
690 int nbuckets;
691 int nsegs;
692 int i;
693
694 /*
695 * initialize mutexes if it's a partitioned table
696 */
697 if (IS_PARTITIONED(hctl))
698 for (i = 0; i < NUM_FREELISTS; i++)
699 SpinLockInit(&(hctl->freeList[i].mutex));
700
701 /*
702 * Allocate space for the next greater power of two number of buckets,
703 * assuming a desired maximum load factor of 1.
704 */
705 nbuckets = next_pow2_int(nelem);
706
707 /*
708 * In a partitioned table, nbuckets must be at least equal to
709 * num_partitions; were it less, keys with apparently different partition
710 * numbers would map to the same bucket, breaking partition independence.
711 * (Normally nbuckets will be much bigger; this is just a safety check.)
712 */
713 while (nbuckets < hctl->num_partitions)
714 nbuckets <<= 1;
715
716 hctl->max_bucket = hctl->low_mask = nbuckets - 1;
717 hctl->high_mask = (nbuckets << 1) - 1;
718
719 /*
720 * Figure number of directory segments needed, round up to a power of 2
721 */
722 nsegs = (nbuckets - 1) / HASH_SEGSIZE + 1;
723 nsegs = next_pow2_int(nsegs);
724
725 /*
726 * Make sure directory is big enough.
727 */
728 hctl->dsize = Max(DEF_DIRSIZE, nsegs);
729
730 /* SHM hash tables have a fixed directory. */
731 if (hashp->isshared)
732 hctl->max_dsize = hctl->dsize;
733
734 /* Allocate a directory */
735 hctl->dir = (HASHSEGMENT *)
736 hashp->alloc(hctl->dsize * sizeof(HASHSEGMENT), hashp->alloc_arg);
737 if (!hctl->dir)
738 return false;
739 hashp->dir = hctl->dir;
740
741 /* Allocate initial segments */
742 for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
743 {
744 *segp = seg_alloc(hashp);
745 if (*segp == NULL)
746 return false;
747 }
748
749 /* Choose number of entries to allocate at a time */
751
752 return true;
753}

References HTAB::alloc, HTAB::alloc_arg, choose_nelem_alloc(), DEF_DIRSIZE, HASHHDR::dir, HTAB::dir, HASHHDR::dsize, HASHHDR::entrysize, fb(), HASHHDR::freeList, HASH_SEGSIZE, HTAB::hctl, HASHHDR::high_mask, i, IS_PARTITIONED, HTAB::isshared, HASHHDR::low_mask, Max, HASHHDR::max_bucket, HASHHDR::max_dsize, FreeListData::mutex, HASHHDR::nelem_alloc, next_pow2_int(), HASHHDR::nsegs, NUM_FREELISTS, seg_alloc(), and SpinLockInit().

Referenced by hash_create().

◆ my_log2()

static int my_log2 ( int64  num)
static

Definition at line 1750 of file dynahash.c.

1751{
1752 /*
1753 * guard against too-large input, which would be invalid for
1754 * pg_ceil_log2_*()
1755 */
1756 if (num > PG_INT64_MAX / 2)
1757 num = PG_INT64_MAX / 2;
1758
1759 return pg_ceil_log2_64(num);
1760}

References pg_ceil_log2_64(), and PG_INT64_MAX.

Referenced by next_pow2_int(), and next_pow2_int64().

◆ next_pow2_int()

static int next_pow2_int ( int64  num)
static

Definition at line 1772 of file dynahash.c.

1773{
1774 if (num > INT_MAX / 2)
1775 num = INT_MAX / 2;
1776 return 1 << my_log2(num);
1777}

References fb(), and my_log2().

Referenced by hash_create(), and init_htab().

◆ next_pow2_int64()

static int64 next_pow2_int64 ( int64  num)
static

Definition at line 1764 of file dynahash.c.

1765{
1766 /* my_log2's internal range check is sufficient */
1767 return 1L << my_log2(num);
1768}

References my_log2().

Referenced by hash_estimate_size().

◆ register_seq_scan()

static void register_seq_scan ( HTAB hashp)
static

Definition at line 1817 of file dynahash.c.

1818{
1820 elog(ERROR, "too many active hash_seq_search scans, cannot start one on \"%s\"",
1821 hashp->tabname);
1824 num_seq_scans++;
1825}

References elog, ERROR, GetCurrentTransactionNestLevel(), MAX_SEQ_SCANS, num_seq_scans, seq_scan_level, seq_scan_tables, and HTAB::tabname.

Referenced by hash_seq_init().

◆ seg_alloc()

static HASHSEGMENT seg_alloc ( HTAB hashp)
static

Definition at line 1617 of file dynahash.c.

1618{
1620
1621 segp = (HASHSEGMENT) hashp->alloc(sizeof(HASHBUCKET) * HASH_SEGSIZE, hashp->alloc_arg);
1622
1623 if (!segp)
1624 return NULL;
1625
1626 MemSet(segp, 0, sizeof(HASHBUCKET) * HASH_SEGSIZE);
1627
1628 return segp;
1629}

References HTAB::alloc, HTAB::alloc_arg, fb(), HASH_SEGSIZE, and MemSet.

Referenced by expand_table(), and init_htab().

◆ string_compare()

static int string_compare ( const char key1,
const char key2,
Size  keysize 
)
static

Definition at line 314 of file dynahash.c.

315{
316 return strncmp(key1, key2, keysize - 1);
317}

References fb().

Referenced by hash_create().

Variable Documentation

◆ num_seq_scans

int num_seq_scans = 0
static

◆ seq_scan_level

int seq_scan_level[MAX_SEQ_SCANS]
static

Definition at line 1811 of file dynahash.c.

Referenced by AtEOSubXact_HashTables(), deregister_seq_scan(), and register_seq_scan().

◆ seq_scan_tables