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 DEF_SEGSIZE   256
 
#define DEF_SEGSIZE_SHIFT   8 /* must be log2(DEF_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)
 
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)
 
int64 hash_select_dirsize (int64 num_entries)
 
Size hash_get_shared_size (HASHCTL *info, int flags)
 
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 MemoryContext CurrentDynaHashCxt = NULL
 
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 125 of file dynahash.c.

◆ DEF_SEGSIZE

#define DEF_SEGSIZE   256

Definition at line 123 of file dynahash.c.

◆ DEF_SEGSIZE_SHIFT

#define DEF_SEGSIZE_SHIFT   8 /* must be log2(DEF_SEGSIZE) */

Definition at line 124 of file dynahash.c.

◆ ELEMENT_FROM_KEY

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

Definition at line 260 of file dynahash.c.

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

◆ ELEMENTKEY

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

Definition at line 255 of file dynahash.c.

◆ FREELIST_IDX

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

Definition at line 214 of file dynahash.c.

215 : 0)

◆ IS_PARTITIONED

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

Definition at line 212 of file dynahash.c.

◆ MAX_SEQ_SCANS

#define MAX_SEQ_SCANS   100

Definition at line 1875 of file dynahash.c.

◆ MOD

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

Definition at line 266 of file dynahash.c.

◆ NUM_FREELISTS

#define NUM_FREELISTS   32

Definition at line 128 of file dynahash.c.

Typedef Documentation

◆ HASHBUCKET

Definition at line 131 of file dynahash.c.

◆ HASHSEGMENT

Definition at line 134 of file dynahash.c.

Function Documentation

◆ AtEOSubXact_HashTables()

void AtEOSubXact_HashTables ( bool  isCommit,
int  nestDepth 
)

Definition at line 1957 of file dynahash.c.

1958{
1959 int i;
1960
1961 /*
1962 * Search backward to make cleanup easy. Note we must check all entries,
1963 * not only those at the end of the array, because deletion technique
1964 * doesn't keep them in order.
1965 */
1966 for (i = num_seq_scans - 1; i >= 0; i--)
1967 {
1968 if (seq_scan_level[i] >= nestDepth)
1969 {
1970 if (isCommit)
1971 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1975 num_seq_scans--;
1976 }
1977 }
1978}

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 1931 of file dynahash.c.

1932{
1933 /*
1934 * During abort cleanup, open scans are expected; just silently clean 'em
1935 * out. An open scan at commit means someone forgot a hash_seq_term()
1936 * call, so complain.
1937 *
1938 * Note: it's tempting to try to print the tabname here, but refrain for
1939 * fear of touching deallocated memory. This isn't a user-facing message
1940 * anyway, so it needn't be pretty.
1941 */
1942 if (isCommit)
1943 {
1944 int i;
1945
1946 for (i = 0; i < num_seq_scans; i++)
1947 {
1948 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1950 }
1951 }
1952 num_seq_scans = 0;
1953}

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 915 of file dynahash.c.

916{
918
919 bucket = hash_val & hctl->high_mask;
920 if (bucket > hctl->max_bucket)
921 bucket = bucket & hctl->low_mask;
922
923 return bucket;
924}

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 667 of file dynahash.c.

668{
669 int nelem_alloc;
672
673 /* Each element has a HASHELEMENT header plus user data. */
674 /* NB: this had better match element_alloc() */
675 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
676
677 /*
678 * The idea here is to choose nelem_alloc at least 32, but round up so
679 * that the allocation request will be a power of 2 or just less. This
680 * makes little difference for hash tables in shared memory, but for hash
681 * tables managed by palloc, the allocation request will be rounded up to
682 * a power of 2 anyway. If we fail to take this into account, we'll waste
683 * as much as half the allocated space.
684 */
685 allocSize = 32 * 4; /* assume elementSize at least 8 */
686 do
687 {
688 allocSize <<= 1;
689 nelem_alloc = allocSize / elementSize;
690 } while (nelem_alloc < 32);
691
692 return nelem_alloc;
693}

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 1896 of file dynahash.c.

1897{
1898 int i;
1899
1900 /* Search backward since it's most likely at the stack top */
1901 for (i = num_seq_scans - 1; i >= 0; i--)
1902 {
1903 if (seq_scan_tables[i] == hashp)
1904 {
1907 num_seq_scans--;
1908 return;
1909 }
1910 }
1911 elog(ERROR, "no hash_seq_search scan for hash table \"%s\"",
1912 hashp->tabname);
1913}

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 1643 of file dynahash.c.

1644{
1645 HASHSEGMENT *p;
1650
1651 if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
1652 return false;
1653
1654 /* Reallocate directory */
1655 new_dsize = hashp->hctl->dsize << 1;
1656 old_dirsize = hashp->hctl->dsize * sizeof(HASHSEGMENT);
1657 new_dirsize = new_dsize * sizeof(HASHSEGMENT);
1658
1659 old_p = hashp->dir;
1660 CurrentDynaHashCxt = hashp->hcxt;
1661 p = (HASHSEGMENT *) hashp->alloc((Size) new_dirsize);
1662
1663 if (p != NULL)
1664 {
1666 MemSet(((char *) p) + old_dirsize, 0, new_dirsize - old_dirsize);
1667 hashp->dir = p;
1668 hashp->hctl->dsize = new_dsize;
1669
1670 /* XXX assume the allocator is palloc, so we know how to free */
1671 Assert(hashp->alloc == DynaHashAlloc);
1672 pfree(old_p);
1673
1674 return true;
1675 }
1676
1677 return false;
1678}

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

Referenced by expand_table().

◆ DynaHashAlloc()

◆ element_alloc()

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

Definition at line 1701 of file dynahash.c.

1702{
1703 HASHHDR *hctl = hashp->hctl;
1706 char *allocedBlock;
1710 int i;
1711
1712 if (hctl->isfixed)
1713 return false;
1714
1715 /* Each element has a HASHELEMENT header plus user data. */
1717
1719
1720 /* Add space for slist_node list link if we need one. */
1721#ifdef USE_VALGRIND
1722 if (!hashp->isshared)
1723 requestSize += MAXALIGN(sizeof(slist_node));
1724#endif
1725
1726 /* Allocate the memory. */
1727 CurrentDynaHashCxt = hashp->hcxt;
1728 allocedBlock = hashp->alloc(requestSize);
1729
1730 if (!allocedBlock)
1731 return false;
1732
1733 /*
1734 * If USE_VALGRIND, each allocated block of elements of a non-shared
1735 * hashtable is chained into a list, so that Valgrind won't think it's
1736 * been leaked.
1737 */
1738#ifdef USE_VALGRIND
1739 if (hashp->isshared)
1741 else
1742 {
1743 slist_push_head(&hashp->element_blocks, (slist_node *) allocedBlock);
1745 }
1746#else
1748#endif
1749
1750 /* prepare to link all the new entries into the freelist */
1751 prevElement = NULL;
1753 for (i = 0; i < nelem; i++)
1754 {
1755 tmpElement->link = prevElement;
1757 tmpElement = (HASHELEMENT *) (((char *) tmpElement) + elementSize);
1758 }
1759
1760 /* if partitioned, must lock to touch freeList */
1761 if (IS_PARTITIONED(hctl))
1763
1764 /* freelist could be nonempty if two backends did this concurrently */
1767
1768 if (IS_PARTITIONED(hctl))
1770
1771 return true;
1772}

References HTAB::alloc, CurrentDynaHashCxt, HASHHDR::entrysize, fb(), FreeListData::freeList, HASHHDR::freeList, HTAB::hctl, HTAB::hcxt, 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 1546 of file dynahash.c.

1547{
1548 HASHHDR *hctl = hashp->hctl;
1550 new_seg;
1552 new_bucket;
1554 new_segndx;
1556 old_segndx;
1558 *newlink;
1561
1562 Assert(!IS_PARTITIONED(hctl));
1563
1564#ifdef HASH_STATISTICS
1565 hctl->expansions++;
1566#endif
1567
1568 new_bucket = hctl->max_bucket + 1;
1569 new_segnum = new_bucket >> hashp->sshift;
1570 new_segndx = MOD(new_bucket, hashp->ssize);
1571
1572 if (new_segnum >= hctl->nsegs)
1573 {
1574 /* Allocate new segment if necessary -- could fail if dir full */
1575 if (new_segnum >= hctl->dsize)
1576 if (!dir_realloc(hashp))
1577 return false;
1578 if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
1579 return false;
1580 hctl->nsegs++;
1581 }
1582
1583 /* OK, we created a new bucket */
1584 hctl->max_bucket++;
1585
1586 /*
1587 * *Before* changing masks, find old bucket corresponding to same hash
1588 * values; values in that bucket may need to be relocated to new bucket.
1589 * Note that new_bucket is certainly larger than low_mask at this point,
1590 * so we can skip the first step of the regular hash mask calc.
1591 */
1592 old_bucket = (new_bucket & hctl->low_mask);
1593
1594 /*
1595 * If we crossed a power of 2, readjust masks.
1596 */
1597 if ((uint32) new_bucket > hctl->high_mask)
1598 {
1599 hctl->low_mask = hctl->high_mask;
1600 hctl->high_mask = (uint32) new_bucket | hctl->low_mask;
1601 }
1602
1603 /*
1604 * Relocate records to the new bucket. NOTE: because of the way the hash
1605 * masking is done in calc_bucket, only one old bucket can need to be
1606 * split at this point. With a different way of reducing the hash value,
1607 * that might not be true!
1608 */
1609 old_segnum = old_bucket >> hashp->sshift;
1610 old_segndx = MOD(old_bucket, hashp->ssize);
1611
1612 old_seg = hashp->dir[old_segnum];
1613 new_seg = hashp->dir[new_segnum];
1614
1617
1618 for (currElement = *oldlink;
1619 currElement != NULL;
1621 {
1623 if ((int64) calc_bucket(hctl, currElement->hashvalue) == old_bucket)
1624 {
1627 }
1628 else
1629 {
1632 }
1633 }
1634 /* don't forget to terminate the rebuilt hash chains... */
1635 *oldlink = NULL;
1636 *newlink = NULL;
1637
1638 return true;
1639}

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

Referenced by hash_search_with_hash_value().

◆ get_hash_entry()

static HASHBUCKET get_hash_entry ( HTAB hashp,
int  freelist_idx 
)
static

Definition at line 1251 of file dynahash.c.

1252{
1253 HASHHDR *hctl = hashp->hctl;
1255
1256 for (;;)
1257 {
1258 /* if partitioned, must lock to touch nentries and freeList */
1259 if (IS_PARTITIONED(hctl))
1261
1262 /* try to get an entry from the freelist */
1264
1265 if (newElement != NULL)
1266 break;
1267
1268 if (IS_PARTITIONED(hctl))
1270
1271 /*
1272 * No free elements in this freelist. In a partitioned table, there
1273 * might be entries in other freelists, but to reduce contention we
1274 * prefer to first try to get another chunk of buckets from the main
1275 * shmem allocator. If that fails, though, we *MUST* root through all
1276 * the other freelists before giving up. There are multiple callers
1277 * that assume that they can allocate every element in the initially
1278 * requested table size, or that deleting an element guarantees they
1279 * can insert a new element, even if shared memory is entirely full.
1280 * Failing because the needed element is in a different freelist is
1281 * not acceptable.
1282 */
1283 if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx))
1284 {
1285 int borrow_from_idx;
1286
1287 if (!IS_PARTITIONED(hctl))
1288 return NULL; /* out of memory */
1289
1290 /* try to borrow element from another freelist */
1292 for (;;)
1293 {
1296 break; /* examined all freelists, fail */
1297
1300
1301 if (newElement != NULL)
1302 {
1305
1306 /* careful: count the new element in its proper freelist */
1310
1311 return newElement;
1312 }
1313
1315 }
1316
1317 /* no elements available to borrow either, so out of memory */
1318 return NULL;
1319 }
1320 }
1321
1322 /* remove entry from freelist, bump nentries */
1325
1326 if (IS_PARTITIONED(hctl))
1328
1329 return newElement;
1330}

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 908 of file dynahash.c.

909{
910 return hashp->hash(keyPtr, hashp->keysize);
911}

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 1917 of file dynahash.c.

1918{
1919 int i;
1920
1921 for (i = 0; i < num_seq_scans; i++)
1922 {
1923 if (seq_scan_tables[i] == hashp)
1924 return true;
1925 }
1926 return false;
1927}

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 1803 of file dynahash.c.

1804{
1805 /*
1806 * If the corruption is in a shared hashtable, we'd better force a
1807 * systemwide restart. Otherwise, just shut down this one backend.
1808 */
1809 if (hashp->isshared)
1810 elog(PANIC, "hash table \"%s\" corrupted", hashp->tabname);
1811 else
1812 elog(FATAL, "hash table \"%s\" corrupted", hashp->tabname);
1813}

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 358 of file dynahash.c.

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

References HTAB::alloc, HASHCTL::alloc, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CurrentDynaHashCxt, HTAB::dir, HASHHDR::dsize, HASHCTL::dsize, 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_DIRSIZE, HASH_ELEM, HASH_FIXED_SIZE, HASH_FUNCTION, HASH_KEYCOPY, HASH_PARTITION, HASH_SEGMENT, 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, HASHHDR::max_dsize, HASHCTL::max_dsize, MemoryContextAlloc(), MemoryContextSetIdentifier(), MemSet, my_log2(), next_pow2_int(), NUM_FREELISTS, HASHHDR::num_partitions, HASHCTL::num_partitions, HASHHDR::sshift, HTAB::sshift, HASHHDR::ssize, HTAB::ssize, HASHCTL::ssize, 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(), InitBufferManagerAccess(), 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_InitHashTables(), select_perl_context(), SerializePendingSyncs(), set_rtable_names(), ShmemInitHash(), smgropen(), transformGraph(), and XLogPrefetcherAllocate().

◆ hash_destroy()

◆ hash_estimate_size()

Size hash_estimate_size ( int64  num_entries,
Size  entrysize 
)

Definition at line 783 of file dynahash.c.

784{
785 Size size;
787 nSegments,
792
793 /* estimate number of buckets wanted */
794 nBuckets = next_pow2_int64(num_entries);
795 /* # of segments needed for nBuckets */
797 /* directory entries */
799 while (nDirEntries < nSegments)
800 nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */
801
802 /* fixed control info */
803 size = MAXALIGN(sizeof(HASHHDR)); /* but not HTAB, per above */
804 /* directory */
805 size = add_size(size, mul_size(nDirEntries, sizeof(HASHSEGMENT)));
806 /* segments */
807 size = add_size(size, mul_size(nSegments,
808 MAXALIGN(DEF_SEGSIZE * sizeof(HASHBUCKET))));
809 /* elements --- allocated in groups of choose_nelem_alloc() entries */
811 nElementAllocs = (num_entries - 1) / elementAllocCnt + 1;
812 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(entrysize);
813 size = add_size(size,
816
817 return size;
818}

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

Referenced by BufTableShmemSize(), CalculateShmemSize(), LockManagerShmemSize(), pgss_memsize(), PredicateLockShmemSize(), and WaitEventCustomShmemSize().

◆ hash_freeze()

void hash_freeze ( HTAB hashp)

Definition at line 1529 of file dynahash.c.

1530{
1531 if (hashp->isshared)
1532 elog(ERROR, "cannot freeze shared hashtable \"%s\"", hashp->tabname);
1533 if (!hashp->frozen && has_seq_scans(hashp))
1534 elog(ERROR, "cannot freeze hashtable \"%s\" because it has active scans",
1535 hashp->tabname);
1536 hashp->frozen = true;
1537}

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 1336 of file dynahash.c.

1337{
1338 int i;
1339 int64 sum = hashp->hctl->freeList[0].nentries;
1340
1341 /*
1342 * We currently don't bother with acquiring the mutexes; it's only
1343 * sensible to call this function if you've got lock on all partitions of
1344 * the table.
1345 */
1346 if (IS_PARTITIONED(hashp->hctl))
1347 {
1348 for (i = 1; i < NUM_FREELISTS; i++)
1349 sum += hashp->hctl->freeList[i].nentries;
1350 }
1351
1352 return sum;
1353}

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_get_shared_size()

Size hash_get_shared_size ( HASHCTL info,
int  flags 
)

Definition at line 854 of file dynahash.c.

855{
856 Assert(flags & HASH_DIRSIZE);
857 Assert(info->dsize == info->max_dsize);
858 return sizeof(HASHHDR) + info->dsize * sizeof(HASHSEGMENT);
859}

References Assert, HASHCTL::dsize, HASH_DIRSIZE, and HASHCTL::max_dsize.

Referenced by ShmemInitHash().

◆ hash_initial_lookup()

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

Definition at line 1779 of file dynahash.c.

1780{
1781 HASHHDR *hctl = hashp->hctl;
1785 uint32 bucket;
1786
1787 bucket = calc_bucket(hctl, hashvalue);
1788
1789 segment_num = bucket >> hashp->sshift;
1790 segment_ndx = MOD(bucket, hashp->ssize);
1791
1792 segp = hashp->dir[segment_num];
1793
1794 if (segp == NULL)
1795 hash_corrupted(hashp);
1796
1798 return bucket;
1799}

References calc_bucket(), HTAB::dir, fb(), hash_corrupted(), HTAB::hctl, MOD, HTAB::sshift, and HTAB::ssize.

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 952 of file dynahash.c.

956{
957 return hash_search_with_hash_value(hashp,
958 keyPtr,
959 hashp->hash(keyPtr, hashp->keysize),
960 action,
961 foundPtr);
962}

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(), build_guc_variables(), build_join_rel_hash(), BuildEventTriggerCache(), 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(), ForgetPrivateRefCountEntry(), get_attribute_options(), get_cast_hashentry(), get_rel_sync_entry(), get_relation_notnullatts(), get_tablespace(), GetComboCommandId(), GetConnection(), getConnectionByName(), GetExtensibleNodeEntry(), getmissingattr(), GetPrivateRefCountEntrySlow(), getState(), GetWaitEventCustomIdentifier(), gistGetNodeBuffer(), gistGetParent(), gistMemorizeParent(), gistRelocateBuildBuffersOnSplit(), hash_object_field_end(), init_sequence(), 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(), ReservePrivateRefCountEntry(), ResetUnloggedRelationsInDbspaceDir(), ResolveCminCmaxDuringDecoding(), RestoreUncommittedEnums(), rewrite_heap_dead_tuple(), rewrite_heap_tuple(), ri_FetchPreparedPlan(), ri_HashCompareOp(), ri_HashPreparedPlan(), ri_LoadConstraintInfo(), select_perl_context(), SerializePendingSyncs(), set_rtable_names(), ShmemInitStruct(), 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 965 of file dynahash.c.

970{
971 HASHHDR *hctl = hashp->hctl;
972 int freelist_idx = FREELIST_IDX(hctl, hashvalue);
973 Size keysize;
976 HashCompareFunc match;
977
978#ifdef HASH_STATISTICS
979 hctl->accesses++;
980#endif
981
982 /*
983 * If inserting, check if it is time to split a bucket.
984 *
985 * NOTE: failure to expand table is not a fatal error, it just means we
986 * have to run at higher fill factor than we wanted. However, if we're
987 * using the palloc allocator then it will throw error anyway on
988 * out-of-memory, so we must do this before modifying the table.
989 */
990 if (action == HASH_ENTER || action == HASH_ENTER_NULL)
991 {
992 /*
993 * Can't split if running in partitioned mode, nor if frozen, nor if
994 * table is the subject of any active hash_seq_search scans.
995 */
996 if (hctl->freeList[0].nentries > (int64) hctl->max_bucket &&
997 !IS_PARTITIONED(hctl) && !hashp->frozen &&
998 !has_seq_scans(hashp))
999 (void) expand_table(hashp);
1000 }
1001
1002 /*
1003 * Do the initial lookup
1004 */
1005 (void) hash_initial_lookup(hashp, hashvalue, &prevBucketPtr);
1007
1008 /*
1009 * Follow collision chain looking for matching key
1010 */
1011 match = hashp->match; /* save one fetch in inner loop */
1012 keysize = hashp->keysize; /* ditto */
1013
1014 while (currBucket != NULL)
1015 {
1016 if (currBucket->hashvalue == hashvalue &&
1017 match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
1018 break;
1019 prevBucketPtr = &(currBucket->link);
1021#ifdef HASH_STATISTICS
1022 hctl->collisions++;
1023#endif
1024 }
1025
1026 if (foundPtr)
1027 *foundPtr = (bool) (currBucket != NULL);
1028
1029 /*
1030 * OK, now what?
1031 */
1032 switch (action)
1033 {
1034 case HASH_FIND:
1035 if (currBucket != NULL)
1036 return ELEMENTKEY(currBucket);
1037 return NULL;
1038
1039 case HASH_REMOVE:
1040 if (currBucket != NULL)
1041 {
1042 /* if partitioned, must lock to touch nentries and freeList */
1043 if (IS_PARTITIONED(hctl))
1045
1046 /* delete the record from the appropriate nentries counter. */
1049
1050 /* remove record from hash bucket's chain. */
1051 *prevBucketPtr = currBucket->link;
1052
1053 /* add the record to the appropriate freelist. */
1056
1057 if (IS_PARTITIONED(hctl))
1059
1060 /*
1061 * better hope the caller is synchronizing access to this
1062 * element, because someone else is going to reuse it the next
1063 * time something is added to the table
1064 */
1065 return ELEMENTKEY(currBucket);
1066 }
1067 return NULL;
1068
1069 case HASH_ENTER:
1070 case HASH_ENTER_NULL:
1071 /* Return existing element if found, else create one */
1072 if (currBucket != NULL)
1073 return ELEMENTKEY(currBucket);
1074
1075 /* disallow inserts if frozen */
1076 if (hashp->frozen)
1077 elog(ERROR, "cannot insert into frozen hashtable \"%s\"",
1078 hashp->tabname);
1079
1081 if (currBucket == NULL)
1082 {
1083 /* out of memory */
1084 if (action == HASH_ENTER_NULL)
1085 return NULL;
1086 /* report a generic message */
1087 if (hashp->isshared)
1088 ereport(ERROR,
1090 errmsg("out of shared memory")));
1091 else
1092 ereport(ERROR,
1094 errmsg("out of memory")));
1095 }
1096
1097 /* link into hashbucket chain */
1099 currBucket->link = NULL;
1100
1101 /* copy key into record */
1102 currBucket->hashvalue = hashvalue;
1103 hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize);
1104
1105 /*
1106 * Caller is expected to fill the data field on return. DO NOT
1107 * insert any code that could possibly throw error here, as doing
1108 * so would leave the table entry incomplete and hence corrupt the
1109 * caller's data structure.
1110 */
1111
1112 return ELEMENTKEY(currBucket);
1113 }
1114
1115 elog(ERROR, "unrecognized hash action code: %d", (int) action);
1116
1117 return NULL; /* keep compiler quiet */
1118}

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_select_dirsize()

int64 hash_select_dirsize ( int64  num_entries)

Definition at line 830 of file dynahash.c.

831{
833 nSegments,
835
836 /* estimate number of buckets wanted */
837 nBuckets = next_pow2_int64(num_entries);
838 /* # of segments needed for nBuckets */
840 /* directory entries */
842 while (nDirEntries < nSegments)
843 nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */
844
845 return nDirEntries;
846}

References DEF_DIRSIZE, DEF_SEGSIZE, fb(), and next_pow2_int64().

Referenced by ShmemInitHash().

◆ hash_seq_init()

void hash_seq_init ( HASH_SEQ_STATUS status,
HTAB hashp 
)

Definition at line 1380 of file dynahash.c.

1381{
1382 status->hashp = hashp;
1383 status->curBucket = 0;
1384 status->curEntry = NULL;
1385 status->hasHashvalue = false;
1386 if (!hashp->frozen)
1387 register_seq_scan(hashp);
1388}

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(), CheckForBufferLeaks(), 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(), 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 1400 of file dynahash.c.

1402{
1404
1405 hash_seq_init(status, hashp);
1406
1407 status->hasHashvalue = true;
1408 status->hashvalue = hashvalue;
1409
1410 status->curBucket = hash_initial_lookup(hashp, hashvalue, &bucketPtr);
1411 status->curEntry = *bucketPtr;
1412}

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 1415 of file dynahash.c.

1416{
1417 HTAB *hashp;
1418 HASHHDR *hctl;
1419 uint32 max_bucket;
1420 int64 ssize;
1424 uint32 curBucket;
1426
1427 if (status->hasHashvalue)
1428 {
1429 /*
1430 * Scan entries only in the current bucket because only this bucket
1431 * can contain entries with the given hash value.
1432 */
1433 while ((curElem = status->curEntry) != NULL)
1434 {
1435 status->curEntry = curElem->link;
1436 if (status->hashvalue != curElem->hashvalue)
1437 continue;
1438 return (void *) ELEMENTKEY(curElem);
1439 }
1440
1441 hash_seq_term(status);
1442 return NULL;
1443 }
1444
1445 if ((curElem = status->curEntry) != NULL)
1446 {
1447 /* Continuing scan of curBucket... */
1448 status->curEntry = curElem->link;
1449 if (status->curEntry == NULL) /* end of this bucket */
1450 ++status->curBucket;
1451 return ELEMENTKEY(curElem);
1452 }
1453
1454 /*
1455 * Search for next nonempty bucket starting at curBucket.
1456 */
1457 curBucket = status->curBucket;
1458 hashp = status->hashp;
1459 hctl = hashp->hctl;
1460 ssize = hashp->ssize;
1461 max_bucket = hctl->max_bucket;
1462
1463 if (curBucket > max_bucket)
1464 {
1465 hash_seq_term(status);
1466 return NULL; /* search is done */
1467 }
1468
1469 /*
1470 * first find the right segment in the table directory.
1471 */
1472 segment_num = curBucket >> hashp->sshift;
1473 segment_ndx = MOD(curBucket, ssize);
1474
1475 segp = hashp->dir[segment_num];
1476
1477 /*
1478 * Pick up the first item in this bucket's chain. If chain is not empty
1479 * we can begin searching it. Otherwise we have to advance to find the
1480 * next nonempty bucket. We try to optimize that case since searching a
1481 * near-empty hashtable has to iterate this loop a lot.
1482 */
1483 while ((curElem = segp[segment_ndx]) == NULL)
1484 {
1485 /* empty bucket, advance to next */
1486 if (++curBucket > max_bucket)
1487 {
1488 status->curBucket = curBucket;
1489 hash_seq_term(status);
1490 return NULL; /* search is done */
1491 }
1492 if (++segment_ndx >= ssize)
1493 {
1494 segment_num++;
1495 segment_ndx = 0;
1496 segp = hashp->dir[segment_num];
1497 }
1498 }
1499
1500 /* Begin scan of curBucket... */
1501 status->curEntry = curElem->link;
1502 if (status->curEntry == NULL) /* end of this bucket */
1503 ++curBucket;
1504 status->curBucket = curBucket;
1505 return ELEMENTKEY(curElem);
1506}

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

Referenced by ApplyPendingListenActions(), AtAbort_Portals(), AtCleanup_Portals(), AtEOSubXact_RelationCache(), AtEOXact_RelationCache(), AtPrepare_Locks(), AtSubAbort_Portals(), AtSubCleanup_Portals(), AtSubCommit_Portals(), BeginReportingGUCOptions(), CheckForBufferLeaks(), 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(), 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 884 of file dynahash.c.

885{
886#ifdef HASH_STATISTICS
887 HASHHDR *hctl = hashp->hctl;
888
889 elog(DEBUG4,
890 "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,
891 caller != NULL ? caller : "(unknown)", hashp->tabname, hctl->accesses,
892 hctl->collisions, hctl->expansions, hash_get_num_entries(hashp),
893 hctl->keysize, hctl->max_bucket, hctl->nsegs);
894#endif
895}

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 1140 of file dynahash.c.

1143{
1146 Size keysize;
1147 uint32 bucket;
1152 HashCompareFunc match;
1153
1154#ifdef HASH_STATISTICS
1155 HASHHDR *hctl = hashp->hctl;
1156
1157 hctl->accesses++;
1158#endif
1159
1160 /* disallow updates if frozen */
1161 if (hashp->frozen)
1162 elog(ERROR, "cannot update in frozen hashtable \"%s\"",
1163 hashp->tabname);
1164
1165 /*
1166 * Lookup the existing element using its saved hash value. We need to do
1167 * this to be able to unlink it from its hash chain, but as a side benefit
1168 * we can verify the validity of the passed existingEntry pointer.
1169 */
1170 bucket = hash_initial_lookup(hashp, existingElement->hashvalue,
1171 &prevBucketPtr);
1173
1174 while (currBucket != NULL)
1175 {
1177 break;
1178 prevBucketPtr = &(currBucket->link);
1180 }
1181
1182 if (currBucket == NULL)
1183 elog(ERROR, "hash_update_hash_key argument is not in hashtable \"%s\"",
1184 hashp->tabname);
1185
1187
1188 /*
1189 * Now perform the equivalent of a HASH_ENTER operation to locate the hash
1190 * chain we want to put the entry into.
1191 */
1192 newhashvalue = hashp->hash(newKeyPtr, hashp->keysize);
1195
1196 /*
1197 * Follow collision chain looking for matching key
1198 */
1199 match = hashp->match; /* save one fetch in inner loop */
1200 keysize = hashp->keysize; /* ditto */
1201
1202 while (currBucket != NULL)
1203 {
1204 if (currBucket->hashvalue == newhashvalue &&
1205 match(ELEMENTKEY(currBucket), newKeyPtr, keysize) == 0)
1206 break;
1207 prevBucketPtr = &(currBucket->link);
1209#ifdef HASH_STATISTICS
1210 hctl->collisions++;
1211#endif
1212 }
1213
1214 if (currBucket != NULL)
1215 return false; /* collision with an existing entry */
1216
1218
1219 /*
1220 * If old and new hash values belong to the same bucket, we need not
1221 * change any chain links, and indeed should not since this simplistic
1222 * update will corrupt the list if currBucket is the last element. (We
1223 * cannot fall out earlier, however, since we need to scan the bucket to
1224 * check for duplicate keys.)
1225 */
1226 if (bucket != newbucket)
1227 {
1228 /* OK to remove record from old hash bucket's chain. */
1229 *oldPrevPtr = currBucket->link;
1230
1231 /* link into new hashbucket chain */
1233 currBucket->link = NULL;
1234 }
1235
1236 /* copy new key into record */
1237 currBucket->hashvalue = newhashvalue;
1238 hashp->keycopy(ELEMENTKEY(currBucket), newKeyPtr, keysize);
1239
1240 /* rest of record is untouched */
1241
1242 return true;
1243}

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 638 of file dynahash.c.

639{
640 HASHHDR *hctl = hashp->hctl;
641
642 MemSet(hctl, 0, sizeof(HASHHDR));
643
644 hctl->dsize = DEF_DIRSIZE;
645 hctl->nsegs = 0;
646
647 hctl->num_partitions = 0; /* not partitioned */
648
649 /* table has no fixed maximum size */
650 hctl->max_dsize = NO_MAX_DSIZE;
651
652 hctl->ssize = DEF_SEGSIZE;
654
655 hctl->isfixed = false; /* can be enlarged */
656
657#ifdef HASH_STATISTICS
658 hctl->accesses = hctl->collisions = hctl->expansions = 0;
659#endif
660}

References DEF_DIRSIZE, DEF_SEGSIZE, DEF_SEGSIZE_SHIFT, HASHHDR::dsize, HTAB::hctl, HASHHDR::isfixed, HASHHDR::max_dsize, MemSet, NO_MAX_DSIZE, HASHHDR::nsegs, HASHHDR::num_partitions, HASHHDR::sshift, and HASHHDR::ssize.

Referenced by hash_create().

◆ init_htab()

static bool init_htab ( HTAB hashp,
int64  nelem 
)
static

Definition at line 700 of file dynahash.c.

701{
702 HASHHDR *hctl = hashp->hctl;
704 int nbuckets;
705 int nsegs;
706 int i;
707
708 /*
709 * initialize mutexes if it's a partitioned table
710 */
711 if (IS_PARTITIONED(hctl))
712 for (i = 0; i < NUM_FREELISTS; i++)
713 SpinLockInit(&(hctl->freeList[i].mutex));
714
715 /*
716 * Allocate space for the next greater power of two number of buckets,
717 * assuming a desired maximum load factor of 1.
718 */
719 nbuckets = next_pow2_int(nelem);
720
721 /*
722 * In a partitioned table, nbuckets must be at least equal to
723 * num_partitions; were it less, keys with apparently different partition
724 * numbers would map to the same bucket, breaking partition independence.
725 * (Normally nbuckets will be much bigger; this is just a safety check.)
726 */
727 while (nbuckets < hctl->num_partitions)
728 nbuckets <<= 1;
729
730 hctl->max_bucket = hctl->low_mask = nbuckets - 1;
731 hctl->high_mask = (nbuckets << 1) - 1;
732
733 /*
734 * Figure number of directory segments needed, round up to a power of 2
735 */
736 nsegs = (nbuckets - 1) / hctl->ssize + 1;
737 nsegs = next_pow2_int(nsegs);
738
739 /*
740 * Make sure directory is big enough. If pre-allocated directory is too
741 * small, choke (caller screwed up).
742 */
743 if (nsegs > hctl->dsize)
744 {
745 if (!(hashp->dir))
746 hctl->dsize = nsegs;
747 else
748 return false;
749 }
750
751 /* Allocate a directory */
752 if (!(hashp->dir))
753 {
754 CurrentDynaHashCxt = hashp->hcxt;
755 hashp->dir = (HASHSEGMENT *)
756 hashp->alloc(hctl->dsize * sizeof(HASHSEGMENT));
757 if (!hashp->dir)
758 return false;
759 }
760
761 /* Allocate initial segments */
762 for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
763 {
764 *segp = seg_alloc(hashp);
765 if (*segp == NULL)
766 return false;
767 }
768
769 /* Choose number of entries to allocate at a time */
771
772 return true;
773}

References HTAB::alloc, choose_nelem_alloc(), CurrentDynaHashCxt, HTAB::dir, HASHHDR::dsize, HASHHDR::entrysize, fb(), HASHHDR::freeList, HTAB::hctl, HTAB::hcxt, HASHHDR::high_mask, i, IS_PARTITIONED, HASHHDR::low_mask, HASHHDR::max_bucket, FreeListData::mutex, HASHHDR::nelem_alloc, next_pow2_int(), HASHHDR::nsegs, NUM_FREELISTS, seg_alloc(), SpinLockInit, and HASHHDR::ssize.

Referenced by hash_create().

◆ my_log2()

static int my_log2 ( int64  num)
static

Definition at line 1817 of file dynahash.c.

1818{
1819 /*
1820 * guard against too-large input, which would be invalid for
1821 * pg_ceil_log2_*()
1822 */
1823 if (num > PG_INT64_MAX / 2)
1824 num = PG_INT64_MAX / 2;
1825
1826 return pg_ceil_log2_64(num);
1827}

References pg_ceil_log2_64(), and PG_INT64_MAX.

Referenced by hash_create(), next_pow2_int(), and next_pow2_int64().

◆ next_pow2_int()

static int next_pow2_int ( int64  num)
static

Definition at line 1839 of file dynahash.c.

1840{
1841 if (num > INT_MAX / 2)
1842 num = INT_MAX / 2;
1843 return 1 << my_log2(num);
1844}

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 1831 of file dynahash.c.

1832{
1833 /* my_log2's internal range check is sufficient */
1834 return 1L << my_log2(num);
1835}

References my_log2().

Referenced by hash_estimate_size(), and hash_select_dirsize().

◆ register_seq_scan()

static void register_seq_scan ( HTAB hashp)
static

Definition at line 1884 of file dynahash.c.

1885{
1887 elog(ERROR, "too many active hash_seq_search scans, cannot start one on \"%s\"",
1888 hashp->tabname);
1891 num_seq_scans++;
1892}

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 1682 of file dynahash.c.

1683{
1685
1686 CurrentDynaHashCxt = hashp->hcxt;
1687 segp = (HASHSEGMENT) hashp->alloc(sizeof(HASHBUCKET) * hashp->ssize);
1688
1689 if (!segp)
1690 return NULL;
1691
1692 MemSet(segp, 0, sizeof(HASHBUCKET) * hashp->ssize);
1693
1694 return segp;
1695}

References HTAB::alloc, CurrentDynaHashCxt, fb(), HTAB::hcxt, MemSet, and HTAB::ssize.

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 313 of file dynahash.c.

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

References fb().

Referenced by hash_create().

Variable Documentation

◆ CurrentDynaHashCxt

MemoryContext CurrentDynaHashCxt = NULL
static

Definition at line 294 of file dynahash.c.

Referenced by dir_realloc(), DynaHashAlloc(), element_alloc(), hash_create(), init_htab(), and seg_alloc().

◆ num_seq_scans

int num_seq_scans = 0
static

◆ seq_scan_level

int seq_scan_level[MAX_SEQ_SCANS]
static

Definition at line 1878 of file dynahash.c.

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

◆ seq_scan_tables