LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - dsm_registry.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 90.1 % 152 137
Test Date: 2026-07-22 21:15:44 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.0 % 100 50

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * dsm_registry.c
       4                 :             :  *    Functions for interfacing with the dynamic shared memory registry.
       5                 :             :  *
       6                 :             :  * This provides a way for libraries to use shared memory without needing
       7                 :             :  * to request it at startup time via a shmem_request_hook.  The registry
       8                 :             :  * stores dynamic shared memory (DSM) segment handles keyed by a
       9                 :             :  * library-specified string.
      10                 :             :  *
      11                 :             :  * The registry is accessed by calling GetNamedDSMSegment().  If a segment
      12                 :             :  * with the provided name does not yet exist, it is created and initialized
      13                 :             :  * with the provided init_callback callback function.  Otherwise,
      14                 :             :  * GetNamedDSMSegment() simply ensures that the segment is attached to the
      15                 :             :  * current backend.  This function guarantees that only one backend
      16                 :             :  * initializes the segment and that all other backends just attach it.
      17                 :             :  *
      18                 :             :  * A DSA can be created in or retrieved from the registry by calling
      19                 :             :  * GetNamedDSA().  As with GetNamedDSMSegment(), if a DSA with the provided
      20                 :             :  * name does not yet exist, it is created.  Otherwise, GetNamedDSA()
      21                 :             :  * ensures the DSA is attached to the current backend.  This function
      22                 :             :  * guarantees that only one backend initializes the DSA and that all other
      23                 :             :  * backends just attach it.
      24                 :             :  *
      25                 :             :  * A dshash table can be created in or retrieved from the registry by
      26                 :             :  * calling GetNamedDSHash().  As with GetNamedDSMSegment(), if a hash
      27                 :             :  * table with the provided name does not yet exist, it is created.
      28                 :             :  * Otherwise, GetNamedDSHash() ensures the hash table is attached to the
      29                 :             :  * current backend.  This function guarantees that only one backend
      30                 :             :  * initializes the table and that all other backends just attach it.
      31                 :             :  *
      32                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      33                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      34                 :             :  *
      35                 :             :  * IDENTIFICATION
      36                 :             :  *    src/backend/storage/ipc/dsm_registry.c
      37                 :             :  *
      38                 :             :  *-------------------------------------------------------------------------
      39                 :             :  */
      40                 :             : 
      41                 :             : #include "postgres.h"
      42                 :             : 
      43                 :             : #include "funcapi.h"
      44                 :             : #include "lib/dshash.h"
      45                 :             : #include "storage/dsm_registry.h"
      46                 :             : #include "storage/lwlock.h"
      47                 :             : #include "storage/shmem.h"
      48                 :             : #include "storage/subsystems.h"
      49                 :             : #include "utils/builtins.h"
      50                 :             : #include "utils/memutils.h"
      51                 :             : #include "utils/tuplestore.h"
      52                 :             : 
      53                 :             : typedef struct DSMRegistryCtxStruct
      54                 :             : {
      55                 :             :     dsa_handle  dsah;
      56                 :             :     dshash_table_handle dshh;
      57                 :             : } DSMRegistryCtxStruct;
      58                 :             : 
      59                 :             : static DSMRegistryCtxStruct *DSMRegistryCtx;
      60                 :             : 
      61                 :             : static void DSMRegistryShmemRequest(void *arg);
      62                 :             : static void DSMRegistryShmemInit(void *arg);
      63                 :             : 
      64                 :             : const ShmemCallbacks DSMRegistryShmemCallbacks = {
      65                 :             :     .request_fn = DSMRegistryShmemRequest,
      66                 :             :     .init_fn = DSMRegistryShmemInit,
      67                 :             : };
      68                 :             : 
      69                 :             : typedef struct NamedDSMState
      70                 :             : {
      71                 :             :     dsm_handle  handle;
      72                 :             :     size_t      size;
      73                 :             : } NamedDSMState;
      74                 :             : 
      75                 :             : typedef struct NamedDSAState
      76                 :             : {
      77                 :             :     dsa_handle  handle;
      78                 :             :     int         tranche;
      79                 :             : } NamedDSAState;
      80                 :             : 
      81                 :             : typedef struct NamedDSHState
      82                 :             : {
      83                 :             :     dsa_handle dsa_handle;
      84                 :             :     dshash_table_handle dsh_handle;
      85                 :             :     int         tranche;
      86                 :             : } NamedDSHState;
      87                 :             : 
      88                 :             : typedef enum DSMREntryType
      89                 :             : {
      90                 :             :     DSMR_ENTRY_TYPE_DSM,
      91                 :             :     DSMR_ENTRY_TYPE_DSA,
      92                 :             :     DSMR_ENTRY_TYPE_DSH,
      93                 :             : } DSMREntryType;
      94                 :             : 
      95                 :             : static const char *const DSMREntryTypeNames[] =
      96                 :             : {
      97                 :             :     [DSMR_ENTRY_TYPE_DSM] = "segment",
      98                 :             :     [DSMR_ENTRY_TYPE_DSA] = "area",
      99                 :             :     [DSMR_ENTRY_TYPE_DSH] = "hash",
     100                 :             : };
     101                 :             : 
     102                 :             : typedef struct DSMRegistryEntry
     103                 :             : {
     104                 :             :     char        name[NAMEDATALEN];
     105                 :             :     DSMREntryType type;
     106                 :             :     union
     107                 :             :     {
     108                 :             :         NamedDSMState dsm;
     109                 :             :         NamedDSAState dsa;
     110                 :             :         NamedDSHState dsh;
     111                 :             :     };
     112                 :             : } DSMRegistryEntry;
     113                 :             : 
     114                 :             : static const dshash_parameters dsh_params = {
     115                 :             :     offsetof(DSMRegistryEntry, type),
     116                 :             :     sizeof(DSMRegistryEntry),
     117                 :             :     dshash_strcmp,
     118                 :             :     dshash_strhash,
     119                 :             :     dshash_strcpy,
     120                 :             :     LWTRANCHE_DSM_REGISTRY_HASH
     121                 :             : };
     122                 :             : 
     123                 :             : static dsa_area *dsm_registry_dsa;
     124                 :             : static dshash_table *dsm_registry_table;
     125                 :             : 
     126                 :             : static void
     127                 :        1259 : DSMRegistryShmemRequest(void *arg)
     128                 :             : {
     129                 :        1259 :     ShmemRequestStruct(.name = "DSM Registry Data",
     130                 :             :                        .size = sizeof(DSMRegistryCtxStruct),
     131                 :             :                        .ptr = (void **) &DSMRegistryCtx,
     132                 :             :         );
     133                 :        1259 : }
     134                 :             : 
     135                 :             : static void
     136                 :        1256 : DSMRegistryShmemInit(void *arg)
     137                 :             : {
     138                 :        1256 :     DSMRegistryCtx->dsah = DSA_HANDLE_INVALID;
     139                 :        1256 :     DSMRegistryCtx->dshh = DSHASH_HANDLE_INVALID;
     140                 :        1256 : }
     141                 :             : 
     142                 :             : /*
     143                 :             :  * Initialize or attach to the dynamic shared hash table that stores the DSM
     144                 :             :  * registry entries, if not already done.  This must be called before accessing
     145                 :             :  * the table.
     146                 :             :  */
     147                 :             : static void
     148                 :         181 : init_dsm_registry(void)
     149                 :             : {
     150                 :             :     /* Quick exit if we already did this. */
     151         [ +  + ]:         181 :     if (dsm_registry_table)
     152                 :          10 :         return;
     153                 :             : 
     154                 :             :     /* Otherwise, use a lock to ensure only one process creates the table. */
     155                 :         171 :     LWLockAcquire(DSMRegistryLock, LW_EXCLUSIVE);
     156                 :             : 
     157         [ +  + ]:         171 :     if (DSMRegistryCtx->dshh == DSHASH_HANDLE_INVALID)
     158                 :             :     {
     159                 :             :         /* Initialize dynamic shared hash table for registry. */
     160                 :          25 :         dsm_registry_dsa = dsa_create(LWTRANCHE_DSM_REGISTRY_DSA);
     161                 :          25 :         dsm_registry_table = dshash_create(dsm_registry_dsa, &dsh_params, NULL);
     162                 :             : 
     163                 :          25 :         dsa_pin(dsm_registry_dsa);
     164                 :          25 :         dsa_pin_mapping(dsm_registry_dsa);
     165                 :             : 
     166                 :             :         /* Store handles in shared memory for other backends to use. */
     167                 :          25 :         DSMRegistryCtx->dsah = dsa_get_handle(dsm_registry_dsa);
     168                 :          25 :         DSMRegistryCtx->dshh = dshash_get_hash_table_handle(dsm_registry_table);
     169                 :             :     }
     170                 :             :     else
     171                 :             :     {
     172                 :             :         /* Attach to existing dynamic shared hash table. */
     173                 :         146 :         dsm_registry_dsa = dsa_attach(DSMRegistryCtx->dsah);
     174                 :         146 :         dsa_pin_mapping(dsm_registry_dsa);
     175                 :         146 :         dsm_registry_table = dshash_attach(dsm_registry_dsa, &dsh_params,
     176                 :         146 :                                            DSMRegistryCtx->dshh, NULL);
     177                 :             :     }
     178                 :             : 
     179                 :         171 :     LWLockRelease(DSMRegistryLock);
     180                 :             : }
     181                 :             : 
     182                 :             : /*
     183                 :             :  * Initialize or attach a named DSM segment.
     184                 :             :  *
     185                 :             :  * This routine returns the address of the segment.  init_callback is called to
     186                 :             :  * initialize the segment when it is first created.  'arg' is passed through to
     187                 :             :  * the initialization callback function.
     188                 :             :  */
     189                 :             : void *
     190                 :         163 : GetNamedDSMSegment(const char *name, size_t size,
     191                 :             :                    void (*init_callback) (void *ptr, void *arg),
     192                 :             :                    bool *found, void *arg)
     193                 :             : {
     194                 :             :     DSMRegistryEntry *entry;
     195                 :             :     MemoryContext oldcontext;
     196                 :             :     void       *ret;
     197                 :             :     NamedDSMState *state;
     198                 :             :     dsm_segment *seg;
     199                 :             : 
     200                 :             :     Assert(found);
     201                 :             : 
     202   [ +  -  -  + ]:         163 :     if (!name || *name == '\0')
     203         [ #  # ]:           0 :         ereport(ERROR,
     204                 :             :                 (errmsg("DSM segment name cannot be empty")));
     205                 :             : 
     206         [ -  + ]:         163 :     if (strlen(name) >= offsetof(DSMRegistryEntry, type))
     207         [ #  # ]:           0 :         ereport(ERROR,
     208                 :             :                 (errmsg("DSM segment name too long")));
     209                 :             : 
     210         [ -  + ]:         163 :     if (size == 0)
     211         [ #  # ]:           0 :         ereport(ERROR,
     212                 :             :                 (errmsg("DSM segment size must be nonzero")));
     213                 :             : 
     214                 :             :     /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
     215                 :         163 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     216                 :             : 
     217                 :             :     /* Connect to the registry. */
     218                 :         163 :     init_dsm_registry();
     219                 :             : 
     220                 :         163 :     entry = dshash_find_or_insert(dsm_registry_table, name, found);
     221                 :         163 :     state = &entry->dsm;
     222         [ +  + ]:         163 :     if (!(*found))
     223                 :             :     {
     224                 :          23 :         entry->type = DSMR_ENTRY_TYPE_DSM;
     225                 :          23 :         state->handle = DSM_HANDLE_INVALID;
     226                 :          23 :         state->size = size;
     227                 :             :     }
     228         [ -  + ]:         140 :     else if (entry->type != DSMR_ENTRY_TYPE_DSM)
     229         [ #  # ]:           0 :         ereport(ERROR,
     230                 :             :                 (errmsg("requested DSM segment does not match type of existing entry")));
     231         [ -  + ]:         140 :     else if (state->size != size)
     232         [ #  # ]:           0 :         ereport(ERROR,
     233                 :             :                 (errmsg("requested DSM segment size does not match size of existing segment")));
     234                 :             : 
     235         [ +  + ]:         163 :     if (state->handle == DSM_HANDLE_INVALID)
     236                 :             :     {
     237                 :          23 :         *found = false;
     238                 :             : 
     239                 :             :         /* Initialize the segment. */
     240                 :          23 :         seg = dsm_create(size, 0);
     241                 :             : 
     242         [ +  - ]:          23 :         if (init_callback)
     243                 :          23 :             (*init_callback) (dsm_segment_address(seg), arg);
     244                 :             : 
     245                 :          23 :         dsm_pin_segment(seg);
     246                 :          23 :         dsm_pin_mapping(seg);
     247                 :          23 :         state->handle = dsm_segment_handle(seg);
     248                 :             :     }
     249                 :             :     else
     250                 :             :     {
     251                 :             :         /* If the existing segment is not already attached, attach it now. */
     252                 :         140 :         seg = dsm_find_mapping(state->handle);
     253         [ +  + ]:         140 :         if (seg == NULL)
     254                 :             :         {
     255                 :         135 :             seg = dsm_attach(state->handle);
     256         [ -  + ]:         135 :             if (seg == NULL)
     257         [ #  # ]:           0 :                 elog(ERROR, "could not map dynamic shared memory segment");
     258                 :             : 
     259                 :         135 :             dsm_pin_mapping(seg);
     260                 :             :         }
     261                 :             :     }
     262                 :             : 
     263                 :         163 :     ret = dsm_segment_address(seg);
     264                 :         163 :     dshash_release_lock(dsm_registry_table, entry);
     265                 :         163 :     MemoryContextSwitchTo(oldcontext);
     266                 :             : 
     267                 :         163 :     return ret;
     268                 :             : }
     269                 :             : 
     270                 :             : /*
     271                 :             :  * Initialize or attach a named DSA.
     272                 :             :  *
     273                 :             :  * This routine returns a pointer to the DSA.  A new LWLock tranche ID will be
     274                 :             :  * generated if needed.  Note that the lock tranche will be registered with the
     275                 :             :  * provided name.  Also note that this should be called at most once for a
     276                 :             :  * given DSA in each backend.
     277                 :             :  */
     278                 :             : dsa_area *
     279                 :          14 : GetNamedDSA(const char *name, bool *found)
     280                 :             : {
     281                 :             :     DSMRegistryEntry *entry;
     282                 :             :     MemoryContext oldcontext;
     283                 :             :     dsa_area   *ret;
     284                 :             :     NamedDSAState *state;
     285                 :             : 
     286                 :             :     Assert(found);
     287                 :             : 
     288   [ +  -  -  + ]:          14 :     if (!name || *name == '\0')
     289         [ #  # ]:           0 :         ereport(ERROR,
     290                 :             :                 (errmsg("DSA name cannot be empty")));
     291                 :             : 
     292         [ -  + ]:          14 :     if (strlen(name) >= offsetof(DSMRegistryEntry, type))
     293         [ #  # ]:           0 :         ereport(ERROR,
     294                 :             :                 (errmsg("DSA name too long")));
     295                 :             : 
     296                 :             :     /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
     297                 :          14 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     298                 :             : 
     299                 :             :     /* Connect to the registry. */
     300                 :          14 :     init_dsm_registry();
     301                 :             : 
     302                 :          14 :     entry = dshash_find_or_insert(dsm_registry_table, name, found);
     303                 :          14 :     state = &entry->dsa;
     304         [ +  + ]:          14 :     if (!(*found))
     305                 :             :     {
     306                 :           3 :         entry->type = DSMR_ENTRY_TYPE_DSA;
     307                 :           3 :         state->handle = DSA_HANDLE_INVALID;
     308                 :           3 :         state->tranche = -1;
     309                 :             :     }
     310         [ -  + ]:          11 :     else if (entry->type != DSMR_ENTRY_TYPE_DSA)
     311         [ #  # ]:           0 :         ereport(ERROR,
     312                 :             :                 (errmsg("requested DSA does not match type of existing entry")));
     313                 :             : 
     314         [ +  + ]:          14 :     if (state->tranche == -1)
     315                 :             :     {
     316                 :           3 :         *found = false;
     317                 :             : 
     318                 :             :         /* Initialize the LWLock tranche for the DSA. */
     319                 :           3 :         state->tranche = LWLockNewTrancheId(name);
     320                 :             :     }
     321                 :             : 
     322         [ +  + ]:          14 :     if (state->handle == DSA_HANDLE_INVALID)
     323                 :             :     {
     324                 :           3 :         *found = false;
     325                 :             : 
     326                 :             :         /* Initialize the DSA. */
     327                 :           3 :         ret = dsa_create(state->tranche);
     328                 :           3 :         dsa_pin(ret);
     329                 :           3 :         dsa_pin_mapping(ret);
     330                 :             : 
     331                 :             :         /* Store handle for other backends to use. */
     332                 :           3 :         state->handle = dsa_get_handle(ret);
     333                 :             :     }
     334         [ -  + ]:          11 :     else if (dsa_is_attached(state->handle))
     335         [ #  # ]:           0 :         ereport(ERROR,
     336                 :             :                 (errmsg("requested DSA already attached to current process")));
     337                 :             :     else
     338                 :             :     {
     339                 :             :         /* Attach to existing DSA. */
     340                 :          11 :         ret = dsa_attach(state->handle);
     341                 :          11 :         dsa_pin_mapping(ret);
     342                 :             :     }
     343                 :             : 
     344                 :          14 :     dshash_release_lock(dsm_registry_table, entry);
     345                 :          14 :     MemoryContextSwitchTo(oldcontext);
     346                 :             : 
     347                 :          14 :     return ret;
     348                 :             : }
     349                 :             : 
     350                 :             : /*
     351                 :             :  * Initialize or attach a named dshash table.
     352                 :             :  *
     353                 :             :  * This routine returns the address of the table.  The tranche_id member of
     354                 :             :  * params is ignored; a new LWLock tranche ID will be generated if needed.
     355                 :             :  * Note that the lock tranche will be registered with the provided name.  Also
     356                 :             :  * note that this should be called at most once for a given table in each
     357                 :             :  * backend.
     358                 :             :  */
     359                 :             : dshash_table *
     360                 :           2 : GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
     361                 :             : {
     362                 :             :     DSMRegistryEntry *entry;
     363                 :             :     MemoryContext oldcontext;
     364                 :             :     dshash_table *ret;
     365                 :             :     NamedDSHState *dsh_state;
     366                 :             : 
     367                 :             :     Assert(params);
     368                 :             :     Assert(found);
     369                 :             : 
     370   [ +  -  -  + ]:           2 :     if (!name || *name == '\0')
     371         [ #  # ]:           0 :         ereport(ERROR,
     372                 :             :                 (errmsg("DSHash name cannot be empty")));
     373                 :             : 
     374         [ -  + ]:           2 :     if (strlen(name) >= offsetof(DSMRegistryEntry, type))
     375         [ #  # ]:           0 :         ereport(ERROR,
     376                 :             :                 (errmsg("DSHash name too long")));
     377                 :             : 
     378                 :             :     /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
     379                 :           2 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     380                 :             : 
     381                 :             :     /* Connect to the registry. */
     382                 :           2 :     init_dsm_registry();
     383                 :             : 
     384                 :           2 :     entry = dshash_find_or_insert(dsm_registry_table, name, found);
     385                 :           2 :     dsh_state = &entry->dsh;
     386         [ +  + ]:           2 :     if (!(*found))
     387                 :             :     {
     388                 :           1 :         entry->type = DSMR_ENTRY_TYPE_DSH;
     389                 :           1 :         dsh_state->dsa_handle = DSA_HANDLE_INVALID;
     390                 :           1 :         dsh_state->dsh_handle = DSHASH_HANDLE_INVALID;
     391                 :           1 :         dsh_state->tranche = -1;
     392                 :             :     }
     393         [ -  + ]:           1 :     else if (entry->type != DSMR_ENTRY_TYPE_DSH)
     394         [ #  # ]:           0 :         ereport(ERROR,
     395                 :             :                 (errmsg("requested DSHash does not match type of existing entry")));
     396                 :             : 
     397         [ +  + ]:           2 :     if (dsh_state->tranche == -1)
     398                 :             :     {
     399                 :           1 :         *found = false;
     400                 :             : 
     401                 :             :         /* Initialize the LWLock tranche for the hash table. */
     402                 :           1 :         dsh_state->tranche = LWLockNewTrancheId(name);
     403                 :             :     }
     404                 :             : 
     405         [ +  + ]:           2 :     if (dsh_state->dsa_handle == DSA_HANDLE_INVALID)
     406                 :             :     {
     407                 :             :         dshash_parameters params_copy;
     408                 :             :         dsa_area   *dsa;
     409                 :             : 
     410                 :           1 :         *found = false;
     411                 :             : 
     412                 :             :         /* Initialize the DSA for the hash table. */
     413                 :           1 :         dsa = dsa_create(dsh_state->tranche);
     414                 :             : 
     415                 :             :         /* Initialize the dshash table. */
     416                 :           1 :         memcpy(&params_copy, params, sizeof(dshash_parameters));
     417                 :           1 :         params_copy.tranche_id = dsh_state->tranche;
     418                 :           1 :         ret = dshash_create(dsa, &params_copy, NULL);
     419                 :             : 
     420                 :           1 :         dsa_pin(dsa);
     421                 :           1 :         dsa_pin_mapping(dsa);
     422                 :             : 
     423                 :             :         /* Store handles for other backends to use. */
     424                 :           1 :         dsh_state->dsa_handle = dsa_get_handle(dsa);
     425                 :           1 :         dsh_state->dsh_handle = dshash_get_hash_table_handle(ret);
     426                 :             :     }
     427         [ -  + ]:           1 :     else if (dsa_is_attached(dsh_state->dsa_handle))
     428         [ #  # ]:           0 :         ereport(ERROR,
     429                 :             :                 (errmsg("requested DSHash already attached to current process")));
     430                 :             :     else
     431                 :             :     {
     432                 :             :         dsa_area   *dsa;
     433                 :             : 
     434                 :             :         /* XXX: Should we verify params matches what table was created with? */
     435                 :             : 
     436                 :             :         /* Attach to existing DSA for the hash table. */
     437                 :           1 :         dsa = dsa_attach(dsh_state->dsa_handle);
     438                 :           1 :         dsa_pin_mapping(dsa);
     439                 :             : 
     440                 :             :         /* Attach to existing dshash table. */
     441                 :           1 :         ret = dshash_attach(dsa, params, dsh_state->dsh_handle, NULL);
     442                 :             :     }
     443                 :             : 
     444                 :           2 :     dshash_release_lock(dsm_registry_table, entry);
     445                 :           2 :     MemoryContextSwitchTo(oldcontext);
     446                 :             : 
     447                 :           2 :     return ret;
     448                 :             : }
     449                 :             : 
     450                 :             : Datum
     451                 :           2 : pg_get_dsm_registry_allocations(PG_FUNCTION_ARGS)
     452                 :             : {
     453                 :           2 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     454                 :             :     DSMRegistryEntry *entry;
     455                 :             :     MemoryContext oldcontext;
     456                 :             :     dshash_seq_status status;
     457                 :             : 
     458                 :           2 :     InitMaterializedSRF(fcinfo, MAT_SRF_USE_EXPECTED_DESC);
     459                 :             : 
     460                 :             :     /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
     461                 :           2 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     462                 :           2 :     init_dsm_registry();
     463                 :           2 :     MemoryContextSwitchTo(oldcontext);
     464                 :             : 
     465                 :           2 :     dshash_seq_init(&status, dsm_registry_table, false);
     466         [ +  + ]:           5 :     while ((entry = dshash_seq_next(&status)) != NULL)
     467                 :             :     {
     468                 :             :         Datum       vals[3];
     469                 :           3 :         bool        nulls[3] = {0};
     470                 :             : 
     471                 :           3 :         vals[0] = CStringGetTextDatum(entry->name);
     472                 :           3 :         vals[1] = CStringGetTextDatum(DSMREntryTypeNames[entry->type]);
     473                 :             : 
     474                 :             :         /* Be careful to only return the sizes of initialized entries. */
     475         [ +  + ]:           3 :         if (entry->type == DSMR_ENTRY_TYPE_DSM &&
     476         [ +  - ]:           1 :             entry->dsm.handle != DSM_HANDLE_INVALID)
     477                 :           1 :             vals[2] = Int64GetDatum(entry->dsm.size);
     478         [ +  + ]:           2 :         else if (entry->type == DSMR_ENTRY_TYPE_DSA &&
     479         [ +  - ]:           1 :                  entry->dsa.handle != DSA_HANDLE_INVALID)
     480                 :           1 :             vals[2] = Int64GetDatum(dsa_get_total_size_from_handle(entry->dsa.handle));
     481         [ +  - ]:           1 :         else if (entry->type == DSMR_ENTRY_TYPE_DSH &&
     482         [ +  - ]:           1 :                  entry->dsh.dsa_handle != DSA_HANDLE_INVALID)
     483                 :           1 :             vals[2] = Int64GetDatum(dsa_get_total_size_from_handle(entry->dsh.dsa_handle));
     484                 :             :         else
     485                 :           0 :             nulls[2] = true;
     486                 :             : 
     487                 :           3 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, vals, nulls);
     488                 :             :     }
     489                 :           2 :     dshash_seq_term(&status);
     490                 :             : 
     491                 :           2 :     return (Datum) 0;
     492                 :             : }
        

Generated by: LCOV version 2.0-1