LCOV - differential code coverage report
Current view: top level - src/backend/storage/ipc - shm_toc.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB DCB
Current: 77aeca80249c9e640c811e80633a2e334a9320de vs 38afc3dcb25c45b744d4025029ce0a6c90b7059f Lines: 80.0 % 75 60 3 12 11 49 4 13
Current Date: 2026-07-25 19:08:27 +0900 Functions: 85.7 % 7 6 1 2 4
Baseline: lcov-20260725-baseline Branches: 47.5 % 40 19 1 20 1 18
Baseline Date: 2026-07-25 19:09:19 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 78.6 % 14 11 3 11
(30,360] days: 100.0 % 1 1 1
(360..) days: 80.0 % 60 48 12 48
Function coverage date bins:
(360..) days: 85.7 % 7 6 1 2 4
Branch coverage date bins:
(7,30] days: 50.0 % 2 1 1 1
(30,360] days: 100.0 % 2 2 2
(360..) days: 44.4 % 36 16 20 16

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * shm_toc.c
                                  4                 :                :  *    shared memory segment table of contents
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  * src/backend/storage/ipc/shm_toc.c
                                 10                 :                :  *
                                 11                 :                :  *-------------------------------------------------------------------------
                                 12                 :                :  */
                                 13                 :                : 
                                 14                 :                : #include "postgres.h"
                                 15                 :                : 
                                 16                 :                : #include "port/atomics.h"
                                 17                 :                : #include "storage/shm_toc.h"
                                 18                 :                : #include "storage/spin.h"
                                 19                 :                : 
                                 20                 :                : typedef struct shm_toc_entry
                                 21                 :                : {
                                 22                 :                :     uint64      key;            /* Arbitrary identifier */
                                 23                 :                :     Size        offset;         /* Offset, in bytes, from TOC start */
                                 24                 :                : } shm_toc_entry;
                                 25                 :                : 
                                 26                 :                : struct shm_toc
                                 27                 :                : {
                                 28                 :                :     uint64      toc_magic;      /* Magic number identifying this TOC */
                                 29                 :                :     slock_t     toc_mutex;      /* Spinlock for mutual exclusion */
                                 30                 :                :     Size        toc_total_bytes;    /* Bytes managed by this TOC */
                                 31                 :                :     Size        toc_allocated_bytes;    /* Bytes allocated of those managed */
                                 32                 :                :     uint32      toc_nentry;     /* Number of entries in TOC */
                                 33                 :                :     shm_toc_entry toc_entry[FLEXIBLE_ARRAY_MEMBER];
                                 34                 :                : };
                                 35                 :                : 
                                 36                 :                : /*
                                 37                 :                :  * Initialize a region of shared memory with a table of contents.
                                 38                 :                :  */
                                 39                 :                : shm_toc *
 4575 rhaas@postgresql.org       40                 :CBC         813 : shm_toc_create(uint64 magic, void *address, Size nbytes)
                                 41                 :                : {
 4463 bruce@momjian.us           42                 :            813 :     shm_toc    *toc = (shm_toc *) address;
                                 43                 :                : 
 4575 rhaas@postgresql.org       44         [ -  + ]:            813 :     Assert(nbytes > offsetof(shm_toc, toc_entry));
                                 45                 :            813 :     toc->toc_magic = magic;
                                 46                 :            813 :     SpinLockInit(&toc->toc_mutex);
                                 47                 :                : 
                                 48                 :                :     /*
                                 49                 :                :      * The alignment code in shm_toc_allocate() assumes that the starting
                                 50                 :                :      * value is buffer-aligned.
                                 51                 :                :      */
 3265 heikki.linnakangas@i       52                 :            813 :     toc->toc_total_bytes = BUFFERALIGN_DOWN(nbytes);
 4575 rhaas@postgresql.org       53                 :            813 :     toc->toc_allocated_bytes = 0;
                                 54                 :            813 :     toc->toc_nentry = 0;
                                 55                 :                : 
                                 56                 :            813 :     return toc;
                                 57                 :                : }
                                 58                 :                : 
                                 59                 :                : /*
                                 60                 :                :  * Attach to an existing table of contents.  If the magic number found at
                                 61                 :                :  * the target address doesn't match our expectations, return NULL.
                                 62                 :                :  */
                                 63                 :                : shm_toc *
                                 64                 :           4039 : shm_toc_attach(uint64 magic, void *address)
                                 65                 :                : {
 4463 bruce@momjian.us           66                 :           4039 :     shm_toc    *toc = (shm_toc *) address;
                                 67                 :                : 
 4575 rhaas@postgresql.org       68         [ -  + ]:           4039 :     if (toc->toc_magic != magic)
 4575 rhaas@postgresql.org       69                 :UBC           0 :         return NULL;
                                 70                 :                : 
 4575 rhaas@postgresql.org       71         [ -  + ]:CBC        4039 :     Assert(toc->toc_total_bytes >= toc->toc_allocated_bytes);
 3337 tgl@sss.pgh.pa.us          72         [ -  + ]:           4039 :     Assert(toc->toc_total_bytes > offsetof(shm_toc, toc_entry));
                                 73                 :                : 
 4575 rhaas@postgresql.org       74                 :           4039 :     return toc;
                                 75                 :                : }
                                 76                 :                : 
                                 77                 :                : /*
                                 78                 :                :  * Allocate shared memory from a segment managed by a table of contents.
                                 79                 :                :  *
                                 80                 :                :  * This is not a full-blown allocator; there's no way to free memory.  It's
                                 81                 :                :  * just a way of dividing a single physical shared memory segment into logical
                                 82                 :                :  * chunks that may be used for different purposes.
                                 83                 :                :  *
                                 84                 :                :  * We allocate backwards from the end of the segment, so that the TOC entries
                                 85                 :                :  * can grow forward from the start of the segment.
                                 86                 :                :  */
                                 87                 :                : void *
                                 88                 :          16698 : shm_toc_allocate(shm_toc *toc, Size nbytes)
                                 89                 :                : {
                                 90                 :                :     Size        total_bytes;
                                 91                 :                :     Size        allocated_bytes;
                                 92                 :                :     Size        nentry;
                                 93                 :                :     Size        toc_bytes;
                                 94                 :                : 
                                 95                 :                :     /*
                                 96                 :                :      * Make sure request is well-aligned.  XXX: MAXALIGN is not enough,
                                 97                 :                :      * because atomic ops might need a wider alignment.  We don't have a
                                 98                 :                :      * proper definition for the minimum to make atomic ops safe, but
                                 99                 :                :      * BUFFERALIGN ought to be enough.
                                100                 :                :      */
                                101                 :          16698 :     nbytes = BUFFERALIGN(nbytes);
                                102                 :                : 
                                103                 :          16698 :     SpinLockAcquire(&toc->toc_mutex);
                                104                 :                : 
   18 nathan@postgresql.or      105                 :GNC       16698 :     total_bytes = toc->toc_total_bytes;
                                106                 :          16698 :     allocated_bytes = toc->toc_allocated_bytes;
                                107                 :          16698 :     nentry = toc->toc_nentry;
 3321 tgl@sss.pgh.pa.us         108                 :CBC       16698 :     toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 4575 rhaas@postgresql.org      109                 :          16698 :         + allocated_bytes;
                                110                 :                : 
                                111                 :                :     /* Check for memory exhaustion and overflow. */
                                112   [ +  -  -  + ]:          16698 :     if (toc_bytes + nbytes > total_bytes || toc_bytes + nbytes < toc_bytes)
                                113                 :                :     {
 4575 rhaas@postgresql.org      114                 :UBC           0 :         SpinLockRelease(&toc->toc_mutex);
                                115         [ #  # ]:              0 :         ereport(ERROR,
                                116                 :                :                 (errcode(ERRCODE_OUT_OF_MEMORY),
                                117                 :                :                  errmsg("out of shared memory")));
                                118                 :                :     }
   18 nathan@postgresql.or      119                 :GNC       16698 :     toc->toc_allocated_bytes += nbytes;
                                120                 :                : 
 4575 rhaas@postgresql.org      121                 :CBC       16698 :     SpinLockRelease(&toc->toc_mutex);
                                122                 :                : 
                                123                 :          16698 :     return ((char *) toc) + (total_bytes - allocated_bytes - nbytes);
                                124                 :                : }
                                125                 :                : 
                                126                 :                : /*
                                127                 :                :  * Return the number of bytes that can still be allocated.
                                128                 :                :  */
                                129                 :                : Size
 4575 rhaas@postgresql.org      130                 :UBC           0 : shm_toc_freespace(shm_toc *toc)
                                131                 :                : {
                                132                 :                :     Size        total_bytes;
                                133                 :                :     Size        allocated_bytes;
                                134                 :                :     Size        nentry;
                                135                 :                :     Size        toc_bytes;
                                136                 :                : 
                                137                 :              0 :     SpinLockAcquire(&toc->toc_mutex);
   18 nathan@postgresql.or      138                 :UNC           0 :     total_bytes = toc->toc_total_bytes;
                                139                 :              0 :     allocated_bytes = toc->toc_allocated_bytes;
                                140                 :              0 :     nentry = toc->toc_nentry;
 4575 rhaas@postgresql.org      141                 :UBC           0 :     SpinLockRelease(&toc->toc_mutex);
                                142                 :                : 
 3321 tgl@sss.pgh.pa.us         143                 :              0 :     toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry);
 4575 rhaas@postgresql.org      144         [ #  # ]:              0 :     Assert(allocated_bytes + BUFFERALIGN(toc_bytes) <= total_bytes);
                                145                 :              0 :     return total_bytes - (allocated_bytes + BUFFERALIGN(toc_bytes));
                                146                 :                : }
                                147                 :                : 
                                148                 :                : /*
                                149                 :                :  * Insert a TOC entry.
                                150                 :                :  *
                                151                 :                :  * The idea here is that the process setting up the shared memory segment will
                                152                 :                :  * register the addresses of data structures within the segment using this
                                153                 :                :  * function.  Each data structure will be identified using a 64-bit key, which
                                154                 :                :  * is assumed to be a well-known or discoverable integer.  Other processes
                                155                 :                :  * accessing the shared memory segment can pass the same key to
                                156                 :                :  * shm_toc_lookup() to discover the addresses of those data structures.
                                157                 :                :  *
                                158                 :                :  * Since the shared memory segment may be mapped at different addresses within
                                159                 :                :  * different backends, we store relative rather than absolute pointers.
                                160                 :                :  *
                                161                 :                :  * This won't scale well to a large number of keys.  Hopefully, that isn't
                                162                 :                :  * necessary; if it proves to be, we might need to provide a more sophisticated
                                163                 :                :  * data structure here.  But the real idea here is just to give someone mapping
                                164                 :                :  * a dynamic shared memory the ability to find the bare minimum number of
                                165                 :                :  * pointers that they need to bootstrap.  If you're storing a lot of stuff in
                                166                 :                :  * the TOC, you're doing it wrong.
                                167                 :                :  */
                                168                 :                : void
 4575 rhaas@postgresql.org      169                 :CBC       16698 : shm_toc_insert(shm_toc *toc, uint64 key, void *address)
                                170                 :                : {
                                171                 :                :     Size        total_bytes;
                                172                 :                :     Size        allocated_bytes;
                                173                 :                :     Size        nentry;
                                174                 :                :     Size        toc_bytes;
                                175                 :                :     Size        offset;
                                176                 :                : 
                                177                 :                :     /* Relativize pointer. */
                                178         [ -  + ]:          16698 :     Assert(address > (void *) toc);
                                179                 :          16698 :     offset = ((char *) address) - (char *) toc;
                                180                 :                : 
                                181                 :          16698 :     SpinLockAcquire(&toc->toc_mutex);
                                182                 :                : 
   18 nathan@postgresql.or      183                 :GNC       16698 :     total_bytes = toc->toc_total_bytes;
                                184                 :          16698 :     allocated_bytes = toc->toc_allocated_bytes;
                                185                 :          16698 :     nentry = toc->toc_nentry;
                                186                 :                : 
                                187                 :                : #ifdef USE_ASSERT_CHECKING
                                188                 :                :     /* Verify no duplicate keys */
  110 melanieplageman@gmai      189         [ +  + ]:CBC      248148 :     for (Size i = 0; i < nentry; i++)
   18 nathan@postgresql.or      190         [ -  + ]:GNC      231450 :         Assert(toc->toc_entry[i].key != key);
                                191                 :                : #endif
                                192                 :                : 
 3321 tgl@sss.pgh.pa.us         193                 :CBC       16698 :     toc_bytes = offsetof(shm_toc, toc_entry) + nentry * sizeof(shm_toc_entry)
 4575 rhaas@postgresql.org      194                 :          16698 :         + allocated_bytes;
                                195                 :                : 
                                196                 :                :     /* Check for memory exhaustion and overflow. */
                                197   [ +  -  +  - ]:          16698 :     if (toc_bytes + sizeof(shm_toc_entry) > total_bytes ||
 3337 tgl@sss.pgh.pa.us         198         [ -  + ]:          16698 :         toc_bytes + sizeof(shm_toc_entry) < toc_bytes ||
                                199                 :                :         nentry >= PG_UINT32_MAX)
                                200                 :                :     {
 4575 rhaas@postgresql.org      201                 :UBC           0 :         SpinLockRelease(&toc->toc_mutex);
                                202         [ #  # ]:              0 :         ereport(ERROR,
                                203                 :                :                 (errcode(ERRCODE_OUT_OF_MEMORY),
                                204                 :                :                  errmsg("out of shared memory")));
                                205                 :                :     }
                                206                 :                : 
 4575 rhaas@postgresql.org      207         [ -  + ]:CBC       16698 :     Assert(offset < total_bytes);
   18 nathan@postgresql.or      208                 :GNC       16698 :     toc->toc_entry[nentry].key = key;
                                209                 :          16698 :     toc->toc_entry[nentry].offset = offset;
                                210                 :                : 
                                211                 :                :     /*
                                212                 :                :      * By placing a write barrier after filling in the entry and before
                                213                 :                :      * updating the number of entries, we make it safe to read the TOC
                                214                 :                :      * unlocked.
                                215                 :                :      */
 4575 rhaas@postgresql.org      216                 :CBC       16698 :     pg_write_barrier();
                                217                 :                : 
   18 nathan@postgresql.or      218                 :GNC       16698 :     toc->toc_nentry++;
                                219                 :                : 
 4575 rhaas@postgresql.org      220                 :CBC       16698 :     SpinLockRelease(&toc->toc_mutex);
                                221                 :          16698 : }
                                222                 :                : 
                                223                 :                : /*
                                224                 :                :  * Look up a TOC entry.
                                225                 :                :  *
                                226                 :                :  * If the key is not found, returns NULL if noError is true, otherwise
                                227                 :                :  * throws elog(ERROR).
                                228                 :                :  *
                                229                 :                :  * Unlike the other functions in this file, this operation acquires no lock;
                                230                 :                :  * it uses only barriers.  It probably wouldn't hurt concurrency very much even
                                231                 :                :  * if it did get a lock, but since it's reasonably likely that a group of
                                232                 :                :  * worker processes could each read a series of entries from the same TOC
                                233                 :                :  * right around the same time, there seems to be some value in avoiding it.
                                234                 :                :  */
                                235                 :                : void *
 3337 tgl@sss.pgh.pa.us         236                 :          61016 : shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
                                237                 :                : {
                                238                 :                :     uint32      nentry;
                                239                 :                :     uint32      i;
                                240                 :                : 
                                241                 :                :     /*
                                242                 :                :      * Read the number of entries before we examine any entry.  We assume that
                                243                 :                :      * reading a uint32 is atomic.
                                244                 :                :      */
 4575 rhaas@postgresql.org      245                 :          61016 :     nentry = toc->toc_nentry;
                                246                 :          61016 :     pg_read_barrier();
                                247                 :                : 
                                248                 :                :     /* Now search for a matching entry. */
                                249         [ +  + ]:         876270 :     for (i = 0; i < nentry; ++i)
                                250                 :                :     {
                                251         [ +  + ]:         869677 :         if (toc->toc_entry[i].key == key)
                                252                 :          54423 :             return ((char *) toc) + toc->toc_entry[i].offset;
                                253                 :                :     }
                                254                 :                : 
                                255                 :                :     /* No matching entry was found. */
 3337 tgl@sss.pgh.pa.us         256         [ -  + ]:           6593 :     if (!noError)
 3337 tgl@sss.pgh.pa.us         257         [ #  # ]:UBC           0 :         elog(ERROR, "could not find key " UINT64_FORMAT " in shm TOC at %p",
                                258                 :                :              key, toc);
 4575 rhaas@postgresql.org      259                 :CBC        6593 :     return NULL;
                                260                 :                : }
                                261                 :                : 
                                262                 :                : /*
                                263                 :                :  * Estimate how much shared memory will be required to store a TOC and its
                                264                 :                :  * dependent data structures.
                                265                 :                :  */
                                266                 :                : Size
                                267                 :            830 : shm_toc_estimate(shm_toc_estimator *e)
                                268                 :                : {
                                269                 :                :     Size        sz;
                                270                 :                : 
 3265 heikki.linnakangas@i      271                 :            830 :     sz = offsetof(shm_toc, toc_entry);
 2017 fujii@postgresql.org      272                 :            830 :     sz = add_size(sz, mul_size(e->number_of_keys, sizeof(shm_toc_entry)));
                                273                 :            830 :     sz = add_size(sz, e->space_for_chunks);
                                274                 :                : 
 3265 heikki.linnakangas@i      275                 :            830 :     return BUFFERALIGN(sz);
                                276                 :                : }
        

Generated by: LCOV version 2.0-1