LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - shmem_hash.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 66.0 % 47 31
Test Date: 2026-07-22 20:15:44 Functions: 66.7 % 6 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 37.5 % 8 3

             Branch data     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                 :       10083 : ShmemRequestHashWithOpts(const ShmemHashOpts *options)
      45                 :             : {
      46                 :             :     ShmemHashOpts *options_copy;
      47                 :             : 
      48                 :             :     Assert(options->name != NULL);
      49                 :             : 
      50                 :       10083 :     options_copy = MemoryContextAlloc(TopMemoryContext,
      51                 :             :                                       sizeof(ShmemHashOpts));
      52                 :       10083 :     memcpy(options_copy, options, sizeof(ShmemHashOpts));
      53                 :             : 
      54                 :             :     /* Set options for the fixed-size area holding the hash table */
      55                 :       10083 :     options_copy->base.name = options->name;
      56                 :       10083 :     options_copy->base.size = hash_estimate_size(options_copy->nelems,
      57                 :             :                                                  options_copy->hash_info.entrysize);
      58                 :             : 
      59                 :       10083 :     ShmemRequestInternal(&options_copy->base, SHMEM_KIND_HASH);
      60                 :       10083 : }
      61                 :             : 
      62                 :             : void
      63                 :       10059 : shmem_hash_init(void *location, ShmemStructOpts *base_options)
      64                 :             : {
      65                 :       10059 :     ShmemHashOpts *options = (ShmemHashOpts *) base_options;
      66                 :       10059 :     int         hash_flags = options->hash_flags;
      67                 :             :     HTAB       *htab;
      68                 :             : 
      69                 :       10059 :     options->hash_info.hctl = location;
      70                 :       10059 :     htab = shmem_hash_create(location, options->base.size, false,
      71                 :             :                              options->name,
      72                 :             :                              options->nelems, &options->hash_info, hash_flags);
      73                 :             : 
      74         [ +  - ]:       10059 :     if (options->ptr)
      75                 :       10059 :         *options->ptr = htab;
      76                 :       10059 : }
      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                 :       11315 : 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                 :       11315 :     infoP->alloc = ShmemHashAlloc;
     162                 :       11315 :     infoP->alloc_arg = NULL;
     163                 :       11315 :     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         [ +  - ]:       11315 :     if (!found)
     170                 :             :     {
     171                 :       11315 :         allocator.next = (char *) location;
     172                 :       11315 :         allocator.end = (char *) location + size;
     173                 :       11315 :         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                 :       11315 :     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                 :      727457 : ShmemHashAlloc(Size size, void *alloc_arg)
     194                 :             : {
     195                 :      727457 :     shmem_hash_allocator *allocator = (shmem_hash_allocator *) alloc_arg;
     196                 :             :     void       *result;
     197                 :             : 
     198                 :      727457 :     size = MAXALIGN(size);
     199                 :             : 
     200         [ -  + ]:      727457 :     if (allocator->end - allocator->next < size)
     201                 :           0 :         return NULL;
     202                 :      727457 :     result = allocator->next;
     203                 :      727457 :     allocator->next += size;
     204                 :             : 
     205                 :      727457 :     return result;
     206                 :             : }
        

Generated by: LCOV version 2.0-1