LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - shmem_hash.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 66.0 % 47 31
Test Date: 2026-04-06 14:16:21 Functions: 66.7 % 6 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * shmem_hash.c
       4              :  *    hash table implementation in shared memory
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  * A shared memory hash table implementation on top of the named, fixed-size
      10              :  * shared memory areas managed by shmem.c.  Each hash table has its own free
      11              :  * list, so hash buckets can be reused when an item is deleted.
      12              :  *
      13              :  * IDENTIFICATION
      14              :  *    src/backend/storage/ipc/shmem_hash.c
      15              :  *
      16              :  *-------------------------------------------------------------------------
      17              :  */
      18              : 
      19              : #include "postgres.h"
      20              : 
      21              : #include "storage/shmem.h"
      22              : #include "storage/shmem_internal.h"
      23              : #include "utils/memutils.h"
      24              : 
      25              : /*
      26              :  * A very simple allocator used to carve out different parts of a hash table
      27              :  * from a previously allocated contiguous shared memory area.
      28              :  */
      29              : typedef struct shmem_hash_allocator
      30              : {
      31              :     char       *next;           /* start of free space in the area */
      32              :     char       *end;            /* end of the shmem area */
      33              : } shmem_hash_allocator;
      34              : 
      35              : static void *ShmemHashAlloc(Size size, void *alloc_arg);
      36              : 
      37              : /*
      38              :  * ShmemRequestHash -- Request a shared memory hash table.
      39              :  *
      40              :  * Similar to ShmemRequestStruct(), but requests a hash table instead of an
      41              :  * opaque area.
      42              :  */
      43              : void
      44         9875 : ShmemRequestHashWithOpts(const ShmemHashOpts *options)
      45              : {
      46              :     ShmemHashOpts *options_copy;
      47              : 
      48              :     Assert(options->name != NULL);
      49              : 
      50         9875 :     options_copy = MemoryContextAlloc(TopMemoryContext,
      51              :                                       sizeof(ShmemHashOpts));
      52         9875 :     memcpy(options_copy, options, sizeof(ShmemHashOpts));
      53              : 
      54              :     /* Set options for the fixed-size area holding the hash table */
      55         9875 :     options_copy->base.name = options->name;
      56         9875 :     options_copy->base.size = hash_estimate_size(options_copy->nelems,
      57              :                                                  options_copy->hash_info.entrysize);
      58              : 
      59         9875 :     ShmemRequestInternal(&options_copy->base, SHMEM_KIND_HASH);
      60         9875 : }
      61              : 
      62              : void
      63         9851 : shmem_hash_init(void *location, ShmemStructOpts *base_options)
      64              : {
      65         9851 :     ShmemHashOpts *options = (ShmemHashOpts *) base_options;
      66         9851 :     int         hash_flags = options->hash_flags;
      67              :     HTAB       *htab;
      68              : 
      69         9851 :     options->hash_info.hctl = location;
      70         9851 :     htab = shmem_hash_create(location, options->base.size, false,
      71              :                              options->name,
      72              :                              options->nelems, &options->hash_info, hash_flags);
      73              : 
      74         9851 :     if (options->ptr)
      75         9851 :         *options->ptr = htab;
      76         9851 : }
      77              : 
      78              : void
      79            0 : shmem_hash_attach(void *location, ShmemStructOpts *base_options)
      80              : {
      81            0 :     ShmemHashOpts *options = (ShmemHashOpts *) base_options;
      82            0 :     int         hash_flags = options->hash_flags;
      83              :     HTAB       *htab;
      84              : 
      85              :     /* attach to it rather than allocate and initialize new space */
      86            0 :     hash_flags |= HASH_ATTACH;
      87            0 :     options->hash_info.hctl = location;
      88              :     Assert(options->hash_info.hctl != NULL);
      89            0 :     htab = shmem_hash_create(location, options->base.size, true,
      90              :                              options->name,
      91              :                              options->nelems, &options->hash_info, hash_flags);
      92              : 
      93            0 :     if (options->ptr)
      94            0 :         *options->ptr = htab;
      95            0 : }
      96              : 
      97              : /*
      98              :  * ShmemInitHash -- Create and initialize, or attach to, a
      99              :  *      shared memory hash table.
     100              :  *
     101              :  * We assume caller is doing some kind of synchronization
     102              :  * so that two processes don't try to create/initialize the same
     103              :  * table at once.  (In practice, all creations are done in the postmaster
     104              :  * process; child processes should always be attaching to existing tables.)
     105              :  *
     106              :  * nelems is the maximum number of hashtable entries.
     107              :  *
     108              :  * *infoP and hash_flags must specify at least the entry sizes and key
     109              :  * comparison semantics (see hash_create()).  Flag bits and values specific
     110              :  * to shared-memory hash tables are added here, except that callers may
     111              :  * choose to specify HASH_PARTITION.
     112              :  *
     113              :  * Note: This is a legacy interface, kept for backwards compatibility with
     114              :  * extensions.  Use ShmemRequestHash() in new code!
     115              :  */
     116              : HTAB *
     117            0 : ShmemInitHash(const char *name,     /* table string name for shmem index */
     118              :               int64 nelems,     /* size of the table */
     119              :               HASHCTL *infoP,   /* info about key and bucket size */
     120              :               int hash_flags)   /* info about infoP */
     121              : {
     122              :     bool        found;
     123              :     size_t      size;
     124              :     void       *location;
     125              : 
     126            0 :     size = hash_estimate_size(nelems, infoP->entrysize);
     127              : 
     128              :     /*
     129              :      * Look it up in the shmem index or allocate.
     130              :      *
     131              :      * NOTE: The area is requested internally as SHMEM_KIND_STRUCT instead of
     132              :      * SHMEM_KIND_HASH.  That's correct because we do the hash table
     133              :      * initialization by calling shmem_hash_create() ourselves.  (We don't
     134              :      * expose the request kind to users; if we did, that would be confusing.)
     135              :      */
     136            0 :     location = ShmemInitStruct(name, size, &found);
     137              : 
     138            0 :     return shmem_hash_create(location, size, found,
     139              :                              name, nelems, infoP, hash_flags);
     140              : }
     141              : 
     142              : /*
     143              :  * Initialize or attach to a shared hash table in the given shmem region.
     144              :  *
     145              :  * This is exposed to allow InitShmemAllocator() to share the logic for
     146              :  * bootstrapping the ShmemIndex hash table.
     147              :  */
     148              : HTAB *
     149        11081 : shmem_hash_create(void *location, size_t size, bool found,
     150              :                   const char *name, int64 nelems, HASHCTL *infoP, int hash_flags)
     151              : {
     152              :     shmem_hash_allocator allocator;
     153              : 
     154              :     /*
     155              :      * Hash tables allocated in shared memory have a fixed directory and have
     156              :      * all elements allocated upfront.  We don't support growing because we'd
     157              :      * need to grow the underlying shmem region with it.
     158              :      *
     159              :      * The shared memory allocator must be specified too.
     160              :      */
     161        11081 :     infoP->alloc = ShmemHashAlloc;
     162        11081 :     infoP->alloc_arg = NULL;
     163        11081 :     hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_FIXED_SIZE;
     164              : 
     165              :     /*
     166              :      * if it already exists, attach to it rather than allocate and initialize
     167              :      * new space
     168              :      */
     169        11081 :     if (!found)
     170              :     {
     171        11081 :         allocator.next = (char *) location;
     172        11081 :         allocator.end = (char *) location + size;
     173        11081 :         infoP->alloc_arg = &allocator;
     174              :     }
     175              :     else
     176              :     {
     177              :         /* Pass location of hashtable header to hash_create */
     178            0 :         infoP->hctl = (HASHHDR *) location;
     179            0 :         hash_flags |= HASH_ATTACH;
     180              :     }
     181              : 
     182        11081 :     return hash_create(name, nelems, infoP, hash_flags);
     183              : }
     184              : 
     185              : /*
     186              :  * ShmemHashAlloc -- alloc callback for shared memory hash tables
     187              :  *
     188              :  * Carve out the allocation from a pre-allocated region.  All shared memory
     189              :  * hash tables are initialized with HASH_FIXED_SIZE, so all the allocations
     190              :  * happen upfront during initialization and no locking is required.
     191              :  */
     192              : static void *
     193       718260 : ShmemHashAlloc(Size size, void *alloc_arg)
     194              : {
     195       718260 :     shmem_hash_allocator *allocator = (shmem_hash_allocator *) alloc_arg;
     196              :     void       *result;
     197              : 
     198       718260 :     size = MAXALIGN(size);
     199              : 
     200       718260 :     if (allocator->end - allocator->next < size)
     201            0 :         return NULL;
     202       718260 :     result = allocator->next;
     203       718260 :     allocator->next += size;
     204              : 
     205       718260 :     return result;
     206              : }
        

Generated by: LCOV version 2.0-1