On Tue, Jun 17, 2025 at 05:43:24PM +0530, Rahila Syed wrote:
>> Using a DSA from the registry is cumbersome.  You essentially need
>> another batch of shared memory to keep track of the pointers and do
>> locking, so it might not be tremendously useful on its own
> 
> Isn't this true while using dshash from the registry as well?

No, once you have a pointer to the dshash table, you should be able to
access it without any other special runtime-generated pointers.

> What if we make the DSM registry hash table generic so  it can be used for
> dsm segments, dsas as well as dshashs?
> 
> The DSMRegistryEntry could be modified as follows to contain a dsa_pointer
> instead of actual values.
> typedef struct DSMRegistryEntry
> {
>         char            name[64];
>         dsa_pointer value;
> } DSMRegistryEntry;
> 
> This dsa_pointer could point to a memory chunk in the same dsa that's
> created by init_dsm_registry to store the Dshash registry table.
> 
> This pointer can be cast to a structure pointer with information about
> DSMs, DSAs, or DSHASHs, based on which one we want to register in the
> registry.

I like this idea, but I took it one step further in the attached patch and
made the registry entry struct flexible enough to store any type of entry.
Specifically, I've added a new "type" enum followed by a union of the
different structs used to store the entry data.  I was originally trying to
avoid this kind of invasive change, but it's not nearly as complicated as I
feared, and there are benefits such as fewer shared memory things to juggle
and better sanity checking.  It should also be easy to extend in the
future.  WDYT?

> -static TestDSMRegistryStruct *tdr_state;
> +typedef struct TestDSMRegistryHashEntry
> +{
> +       char            key[64];
> +       dsa_handle      val;
> +} TestDSMRegistryHashEntry;
> 
> Did you mean to create val as dsa_pointer instead of dsa_handle?
> You assigned it a dsa_pointer in set_val_in_hash() function.

Yes, good catch.

-- 
nathan
>From 1bc7ab1c4ad4aa420b282cb40e09353fe9349745 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nat...@postgresql.org>
Date: Wed, 4 Jun 2025 14:21:14 -0500
Subject: [PATCH v9 1/1] simplify creating hash table in dsm registry

---
 src/backend/storage/ipc/dsm_registry.c        | 263 +++++++++++++++++-
 src/backend/utils/mmgr/dsa.c                  |  15 +
 src/include/storage/dsm_registry.h            |   7 +-
 src/include/utils/dsa.h                       |   1 +
 .../expected/test_dsm_registry.out            |  26 +-
 .../sql/test_dsm_registry.sql                 |   6 +-
 .../test_dsm_registry--1.0.sql                |  10 +-
 .../test_dsm_registry/test_dsm_registry.c     | 111 ++++++--
 src/tools/pgindent/typedefs.list              |   5 +
 9 files changed, 398 insertions(+), 46 deletions(-)

diff --git a/src/backend/storage/ipc/dsm_registry.c 
b/src/backend/storage/ipc/dsm_registry.c
index 1d4fd31ffed..136fe8b8d7d 100644
--- a/src/backend/storage/ipc/dsm_registry.c
+++ b/src/backend/storage/ipc/dsm_registry.c
@@ -15,6 +15,20 @@
  * current backend.  This function guarantees that only one backend
  * initializes the segment and that all other backends just attach it.
  *
+ * A DSA can be created in or retrieved from the registry by calling
+ * GetNamedDSA().  As with GetNamedDSMSegment(), if a DSA with the provided
+ * name does not yet exist, it is created.  Otherwise, GetNamedDSA()
+ * ensures the DSA is attached to the current backend.  This function
+ * guarantees that only one backend initializes the DSA and that all other
+ * backends just attach it.
+ *
+ * A dshash table can be created in or retrieved from the registry by
+ * calling GetNamedDSHash().  As with GetNamedDSMSegment(), if a hash
+ * table with the provided name does not yet exist, it is created.
+ * Otherwise, GetNamedDSHash() ensures the hash table is attached to the
+ * current backend.  This function guarantees that only one backend
+ * initializes the table and that all other backends just attach it.
+ *
  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -32,6 +46,12 @@
 #include "storage/shmem.h"
 #include "utils/memutils.h"
 
+#define DSMR_NAME_LEN                          128
+
+#define DSMR_DSA_TRANCHE_SUFFIX                " DSA"
+#define DSMR_DSA_TRANCHE_SUFFIX_LEN (sizeof(DSMR_DSA_TRANCHE_SUFFIX) - 1)
+#define DSMR_DSA_TRANCHE_NAME_LEN      (DSMR_NAME_LEN + 
DSMR_DSA_TRANCHE_SUFFIX_LEN)
+
 typedef struct DSMRegistryCtxStruct
 {
        dsa_handle      dsah;
@@ -40,15 +60,48 @@ typedef struct DSMRegistryCtxStruct
 
 static DSMRegistryCtxStruct *DSMRegistryCtx;
 
-typedef struct DSMRegistryEntry
+typedef struct NamedDSMState
 {
-       char            name[64];
        dsm_handle      handle;
        size_t          size;
+} NamedDSMState;
+
+typedef struct NamedDSAState
+{
+       dsa_handle      handle;
+       int                     tranche;
+       char            tranche_name[DSMR_DSA_TRANCHE_NAME_LEN];
+} NamedDSAState;
+
+typedef struct NamedDSHState
+{
+       NamedDSAState dsa;
+       dshash_table_handle handle;
+       int                     tranche;
+       char            tranche_name[DSMR_NAME_LEN];
+} NamedDSHState;
+
+typedef enum DSMREntryType
+{
+       DSMR_ENTRY_TYPE_DSM,
+       DSMR_ENTRY_TYPE_DSA,
+       DSMR_ENTRY_TYPE_DSH,
+} DSMREntryType;
+
+typedef struct DSMRegistryEntry
+{
+       char            name[DSMR_NAME_LEN];
+       DSMREntryType type;
+       union
+       {
+               NamedDSMState dsm;
+               NamedDSAState dsa;
+               NamedDSHState dsh;
+       }                       data;
 } DSMRegistryEntry;
 
 static const dshash_parameters dsh_params = {
-       offsetof(DSMRegistryEntry, handle),
+       offsetof(DSMRegistryEntry, type),
        sizeof(DSMRegistryEntry),
        dshash_strcmp,
        dshash_strhash,
@@ -141,7 +194,7 @@ GetNamedDSMSegment(const char *name, size_t size,
                ereport(ERROR,
                                (errmsg("DSM segment name cannot be empty")));
 
-       if (strlen(name) >= offsetof(DSMRegistryEntry, handle))
+       if (strlen(name) >= offsetof(DSMRegistryEntry, type))
                ereport(ERROR,
                                (errmsg("DSM segment name too long")));
 
@@ -158,32 +211,39 @@ GetNamedDSMSegment(const char *name, size_t size,
        entry = dshash_find_or_insert(dsm_registry_table, name, found);
        if (!(*found))
        {
+               NamedDSMState *state = &entry->data.dsm;
+               dsm_segment *seg;
+
+               entry->type = DSMR_ENTRY_TYPE_DSM;
+
                /* Initialize the segment. */
-               dsm_segment *seg = dsm_create(size, 0);
+               seg = dsm_create(size, 0);
 
                dsm_pin_segment(seg);
                dsm_pin_mapping(seg);
-               entry->handle = dsm_segment_handle(seg);
-               entry->size = size;
+               state->handle = dsm_segment_handle(seg);
+               state->size = size;
                ret = dsm_segment_address(seg);
 
                if (init_callback)
                        (*init_callback) (ret);
        }
-       else if (entry->size != size)
-       {
+       else if (entry->type != DSMR_ENTRY_TYPE_DSM)
                ereport(ERROR,
-                               (errmsg("requested DSM segment size does not 
match size of "
-                                               "existing segment")));
-       }
+                               (errmsg("requested DSM segment does not match 
type of existing entry")));
+       else if (entry->data.dsm.size != size)
+               ereport(ERROR,
+                               (errmsg("requested DSM segment size does not 
match size of existing segment")));
        else
        {
-               dsm_segment *seg = dsm_find_mapping(entry->handle);
+               NamedDSMState *state = &entry->data.dsm;
+               dsm_segment *seg;
 
                /* If the existing segment is not already attached, attach it 
now. */
+               seg = dsm_find_mapping(state->handle);
                if (seg == NULL)
                {
-                       seg = dsm_attach(entry->handle);
+                       seg = dsm_attach(state->handle);
                        if (seg == NULL)
                                elog(ERROR, "could not map dynamic shared 
memory segment");
 
@@ -198,3 +258,178 @@ GetNamedDSMSegment(const char *name, size_t size,
 
        return ret;
 }
+
+/*
+ * Initialize or attach a named DSA.
+ *
+ * This routine returns a pointer to the DSA.  A new LWLock tranche ID will be
+ * generated if needed.  Note that the lock tranche will be registered with the
+ * provided name.  Also note that this should be called at most once for a
+ * given DSA in each backend.
+ */
+dsa_area *
+GetNamedDSA(const char *name, bool *found)
+{
+       DSMRegistryEntry *entry;
+       MemoryContext oldcontext;
+       dsa_area   *ret;
+
+       Assert(found);
+
+       if (!name || *name == '\0')
+               ereport(ERROR,
+                               (errmsg("DSA name cannot be empty")));
+
+       if (strlen(name) >= offsetof(DSMRegistryEntry, type))
+               ereport(ERROR,
+                               (errmsg("DSA name too long")));
+
+       /* Be sure any local memory allocated by DSM/DSA routines is 
persistent. */
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+
+       /* Connect to the registry. */
+       init_dsm_registry();
+
+       entry = dshash_find_or_insert(dsm_registry_table, name, found);
+       if (!(*found))
+       {
+               NamedDSAState *state = &entry->data.dsa;
+
+               entry->type = DSMR_ENTRY_TYPE_DSA;
+
+               /* Initialize the LWLock tranche for the DSA. */
+               state->tranche = LWLockNewTrancheId();
+               strcpy(state->tranche_name, name);
+               LWLockRegisterTranche(state->tranche, state->tranche_name);
+
+               /* Initialize the DSA. */
+               ret = dsa_create(state->tranche);
+               dsa_pin(ret);
+               dsa_pin_mapping(ret);
+
+               /* Store handle for other backends to use. */
+               state->handle = dsa_get_handle(ret);
+       }
+       else if (entry->type != DSMR_ENTRY_TYPE_DSA)
+               ereport(ERROR,
+                               (errmsg("requested DSA does not match type of 
existing entry")));
+       else if (dsa_is_attached(entry->data.dsa.handle))
+               ereport(ERROR,
+                               (errmsg("requested DSA already attached to 
current process")));
+       else
+       {
+               NamedDSAState *state = &entry->data.dsa;
+
+               /* Initialize existing LWLock tranche for the DSA. */
+               LWLockRegisterTranche(state->tranche, state->tranche_name);
+
+               /* Attach to existing DSA. */
+               ret = dsa_attach(state->handle);
+               dsa_pin_mapping(ret);
+       }
+
+       dshash_release_lock(dsm_registry_table, entry);
+       MemoryContextSwitchTo(oldcontext);
+
+       return ret;
+}
+
+/*
+ * Initialize or attach a named dshash table.
+ *
+ * This routine returns the address of the table.  The tranche_id member of
+ * params is ignored; new tranche IDs will be generated if needed.  Note that
+ * the DSA lock tranche will be registered with the provided name with " DSA"
+ * appended.  The dshash lock tranche will be registered with the provided
+ * name.  Also note that this should be called at most once for a given table
+ * in each backend.
+ */
+dshash_table *
+GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
+{
+       DSMRegistryEntry *entry;
+       MemoryContext oldcontext;
+       dshash_table *ret;
+
+       Assert(params);
+       Assert(found);
+
+       if (!name || *name == '\0')
+               ereport(ERROR,
+                               (errmsg("DSHash name cannot be empty")));
+
+       if (strlen(name) >= offsetof(DSMRegistryEntry, type))
+               ereport(ERROR,
+                               (errmsg("DSHash name too long")));
+
+       /* Be sure any local memory allocated by DSM/DSA routines is 
persistent. */
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+
+       /* Connect to the registry. */
+       init_dsm_registry();
+
+       entry = dshash_find_or_insert(dsm_registry_table, name, found);
+       if (!(*found))
+       {
+               NamedDSAState *dsa_state = &entry->data.dsh.dsa;
+               NamedDSHState *dsh_state = &entry->data.dsh;
+               dshash_parameters params_copy;
+               dsa_area   *dsa;
+
+               entry->type = DSMR_ENTRY_TYPE_DSH;
+
+               /* Initialize the LWLock tranche for the DSA. */
+               dsa_state->tranche = LWLockNewTrancheId();
+               sprintf(dsa_state->tranche_name, "%s%s", name, 
DSMR_DSA_TRANCHE_SUFFIX);
+               LWLockRegisterTranche(dsa_state->tranche, 
dsa_state->tranche_name);
+
+               /* Initialize the LWLock tranche for the dshash table. */
+               dsh_state->tranche = LWLockNewTrancheId();
+               strcpy(dsh_state->tranche_name, name);
+               LWLockRegisterTranche(dsh_state->tranche, 
dsh_state->tranche_name);
+
+               /* Initialize the DSA for the hash table. */
+               dsa = dsa_create(dsa_state->tranche);
+               dsa_pin(dsa);
+               dsa_pin_mapping(dsa);
+
+               /* Initialize the dshash table. */
+               memcpy(&params_copy, params, sizeof(dshash_parameters));
+               params_copy.tranche_id = dsh_state->tranche;
+               ret = dshash_create(dsa, &params_copy, NULL);
+
+               /* Store handles in the DSM segment for other backends to use. 
*/
+               dsa_state->handle = dsa_get_handle(dsa);
+               dsh_state->handle = dshash_get_hash_table_handle(ret);
+       }
+       else if (entry->type != DSMR_ENTRY_TYPE_DSH)
+               ereport(ERROR,
+                               (errmsg("requested DSHash does not match type 
of existing entry")));
+       else if (dsa_is_attached(entry->data.dsa.handle))
+               ereport(ERROR,
+                               (errmsg("requested DSHash already attached to 
current process")));
+       else
+       {
+               NamedDSAState *dsa_state = &entry->data.dsh.dsa;
+               NamedDSHState *dsh_state = &entry->data.dsh;
+               dsa_area   *dsa;
+
+               /* XXX: Should we verify params matches what table was created 
with? */
+
+               /* Initialize existing LWLock tranches for the DSA and dshash 
table. */
+               LWLockRegisterTranche(dsa_state->tranche, 
dsa_state->tranche_name);
+               LWLockRegisterTranche(dsh_state->tranche, 
dsh_state->tranche_name);
+
+               /* Attach to existing DSA for the hash table. */
+               dsa = dsa_attach(dsa_state->handle);
+               dsa_pin_mapping(dsa);
+
+               /* Attach to existing dshash table. */
+               ret = dshash_attach(dsa, params, dsh_state->handle, NULL);
+       }
+
+       dshash_release_lock(dsm_registry_table, entry);
+       MemoryContextSwitchTo(oldcontext);
+
+       return ret;
+}
diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c
index 17d4f7a7a06..be43e9351c3 100644
--- a/src/backend/utils/mmgr/dsa.c
+++ b/src/backend/utils/mmgr/dsa.c
@@ -531,6 +531,21 @@ dsa_attach(dsa_handle handle)
        return area;
 }
 
+/*
+ * Returns whether the area with the given handle was already attached by the
+ * current process.  The area must have been created with dsa_create (not
+ * dsa_create_in_place).
+ */
+bool
+dsa_is_attached(dsa_handle handle)
+{
+       /*
+        * An area handle is really a DSM segment handle for the first segment, 
so
+        * we can just search for that.
+        */
+       return dsm_find_mapping(handle) != NULL;
+}
+
 /*
  * Attach to an area that was created with dsa_create_in_place.  The caller
  * must somehow know the location in memory that was used when the area was
diff --git a/src/include/storage/dsm_registry.h 
b/src/include/storage/dsm_registry.h
index b381e44bc9d..4871ed509eb 100644
--- a/src/include/storage/dsm_registry.h
+++ b/src/include/storage/dsm_registry.h
@@ -13,10 +13,15 @@
 #ifndef DSM_REGISTRY_H
 #define DSM_REGISTRY_H
 
+#include "lib/dshash.h"
+
 extern void *GetNamedDSMSegment(const char *name, size_t size,
                                                                void 
(*init_callback) (void *ptr),
                                                                bool *found);
-
+extern dsa_area *GetNamedDSA(const char *name, bool *found);
+extern dshash_table *GetNamedDSHash(const char *name,
+                                                                       const 
dshash_parameters *params,
+                                                                       bool 
*found);
 extern Size DSMRegistryShmemSize(void);
 extern void DSMRegistryShmemInit(void);
 
diff --git a/src/include/utils/dsa.h b/src/include/utils/dsa.h
index 9eca8788908..0a6067be628 100644
--- a/src/include/utils/dsa.h
+++ b/src/include/utils/dsa.h
@@ -145,6 +145,7 @@ extern dsa_area *dsa_create_in_place_ext(void *place, 
size_t size,
                                                                                
 size_t init_segment_size,
                                                                                
 size_t max_segment_size);
 extern dsa_area *dsa_attach(dsa_handle handle);
+extern bool dsa_is_attached(dsa_handle handle);
 extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment);
 extern void dsa_release_in_place(void *place);
 extern void dsa_on_dsm_detach_release_in_place(dsm_segment *, Datum);
diff --git a/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out 
b/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out
index 8ffbd343a05..7ee02bb51e3 100644
--- a/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out
+++ b/src/test/modules/test_dsm_registry/expected/test_dsm_registry.out
@@ -1,14 +1,26 @@
 CREATE EXTENSION test_dsm_registry;
-SELECT set_val_in_shmem(1236);
- set_val_in_shmem 
-------------------
+SELECT set_val_in_dsm(1236);
+ set_val_in_dsm 
+----------------
+ 
+(1 row)
+
+SELECT set_val_in_hash('test', '1414');
+ set_val_in_hash 
+-----------------
  
 (1 row)
 
 \c
-SELECT get_val_in_shmem();
- get_val_in_shmem 
-------------------
-             1236
+SELECT get_val_in_dsm();
+ get_val_in_dsm 
+----------------
+           1236
+(1 row)
+
+SELECT get_val_in_hash('test');
+ get_val_in_hash 
+-----------------
+ 1414
 (1 row)
 
diff --git a/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql 
b/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql
index b3351be0a16..7076f825260 100644
--- a/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql
+++ b/src/test/modules/test_dsm_registry/sql/test_dsm_registry.sql
@@ -1,4 +1,6 @@
 CREATE EXTENSION test_dsm_registry;
-SELECT set_val_in_shmem(1236);
+SELECT set_val_in_dsm(1236);
+SELECT set_val_in_hash('test', '1414');
 \c
-SELECT get_val_in_shmem();
+SELECT get_val_in_dsm();
+SELECT get_val_in_hash('test');
diff --git a/src/test/modules/test_dsm_registry/test_dsm_registry--1.0.sql 
b/src/test/modules/test_dsm_registry/test_dsm_registry--1.0.sql
index 8c55b0919b1..74ceeccfd3b 100644
--- a/src/test/modules/test_dsm_registry/test_dsm_registry--1.0.sql
+++ b/src/test/modules/test_dsm_registry/test_dsm_registry--1.0.sql
@@ -3,8 +3,14 @@
 -- complain if script is sourced in psql, rather than via CREATE EXTENSION
 \echo Use "CREATE EXTENSION test_dsm_registry" to load this file. \quit
 
-CREATE FUNCTION set_val_in_shmem(val INT) RETURNS VOID
+CREATE FUNCTION set_val_in_dsm(val INT) RETURNS VOID
        AS 'MODULE_PATHNAME' LANGUAGE C;
 
-CREATE FUNCTION get_val_in_shmem() RETURNS INT
+CREATE FUNCTION get_val_in_dsm() RETURNS INT
+       AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION set_val_in_hash(key TEXT, val TEXT) RETURNS VOID
+       AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION get_val_in_hash(key TEXT) RETURNS TEXT
        AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/src/test/modules/test_dsm_registry/test_dsm_registry.c 
b/src/test/modules/test_dsm_registry/test_dsm_registry.c
index 96a890be228..a9e60c4126b 100644
--- a/src/test/modules/test_dsm_registry/test_dsm_registry.c
+++ b/src/test/modules/test_dsm_registry/test_dsm_registry.c
@@ -15,6 +15,7 @@
 #include "fmgr.h"
 #include "storage/dsm_registry.h"
 #include "storage/lwlock.h"
+#include "utils/builtins.h"
 
 PG_MODULE_MAGIC;
 
@@ -24,15 +25,31 @@ typedef struct TestDSMRegistryStruct
        LWLock          lck;
 } TestDSMRegistryStruct;
 
-static TestDSMRegistryStruct *tdr_state;
+typedef struct TestDSMRegistryHashEntry
+{
+       char            key[64];
+       dsa_pointer val;
+} TestDSMRegistryHashEntry;
+
+static TestDSMRegistryStruct *tdr_dsm;
+static dsa_area *tdr_dsa;
+static dshash_table *tdr_hash;
+
+static const dshash_parameters dsh_params = {
+       offsetof(TestDSMRegistryHashEntry, val),
+       sizeof(TestDSMRegistryHashEntry),
+       dshash_strcmp,
+       dshash_strhash,
+       dshash_strcpy
+};
 
 static void
-tdr_init_shmem(void *ptr)
+init_tdr_dsm(void *ptr)
 {
-       TestDSMRegistryStruct *state = (TestDSMRegistryStruct *) ptr;
+       TestDSMRegistryStruct *dsm = (TestDSMRegistryStruct *) ptr;
 
-       LWLockInitialize(&state->lck, LWLockNewTrancheId());
-       state->val = 0;
+       LWLockInitialize(&dsm->lck, LWLockNewTrancheId());
+       dsm->val = 0;
 }
 
 static void
@@ -40,37 +57,91 @@ tdr_attach_shmem(void)
 {
        bool            found;
 
-       tdr_state = GetNamedDSMSegment("test_dsm_registry",
-                                                                  
sizeof(TestDSMRegistryStruct),
-                                                                  
tdr_init_shmem,
-                                                                  &found);
-       LWLockRegisterTranche(tdr_state->lck.tranche, "test_dsm_registry");
+       tdr_dsm = GetNamedDSMSegment("test_dsm_registry_dsm",
+                                                                
sizeof(TestDSMRegistryStruct),
+                                                                init_tdr_dsm,
+                                                                &found);
+       LWLockRegisterTranche(tdr_dsm->lck.tranche, "test_dsm_registry");
+
+       if (tdr_dsa == NULL)
+               tdr_dsa = GetNamedDSA("test_dsm_registry_dsa", &found);
+
+       if (tdr_hash == NULL)
+               tdr_hash = GetNamedDSHash("test_dsm_registry_hash", 
&dsh_params, &found);
 }
 
-PG_FUNCTION_INFO_V1(set_val_in_shmem);
+PG_FUNCTION_INFO_V1(set_val_in_dsm);
 Datum
-set_val_in_shmem(PG_FUNCTION_ARGS)
+set_val_in_dsm(PG_FUNCTION_ARGS)
 {
        tdr_attach_shmem();
 
-       LWLockAcquire(&tdr_state->lck, LW_EXCLUSIVE);
-       tdr_state->val = PG_GETARG_INT32(0);
-       LWLockRelease(&tdr_state->lck);
+       LWLockAcquire(&tdr_dsm->lck, LW_EXCLUSIVE);
+       tdr_dsm->val = PG_GETARG_INT32(0);
+       LWLockRelease(&tdr_dsm->lck);
 
        PG_RETURN_VOID();
 }
 
-PG_FUNCTION_INFO_V1(get_val_in_shmem);
+PG_FUNCTION_INFO_V1(get_val_in_dsm);
 Datum
-get_val_in_shmem(PG_FUNCTION_ARGS)
+get_val_in_dsm(PG_FUNCTION_ARGS)
 {
        int                     ret;
 
        tdr_attach_shmem();
 
-       LWLockAcquire(&tdr_state->lck, LW_SHARED);
-       ret = tdr_state->val;
-       LWLockRelease(&tdr_state->lck);
+       LWLockAcquire(&tdr_dsm->lck, LW_SHARED);
+       ret = tdr_dsm->val;
+       LWLockRelease(&tdr_dsm->lck);
 
        PG_RETURN_INT32(ret);
 }
+
+PG_FUNCTION_INFO_V1(set_val_in_hash);
+Datum
+set_val_in_hash(PG_FUNCTION_ARGS)
+{
+       TestDSMRegistryHashEntry *entry;
+       char       *key = TextDatumGetCString(PG_GETARG_DATUM(0));
+       char       *val = TextDatumGetCString(PG_GETARG_DATUM(1));
+       bool            found;
+
+       if (strlen(key) >= offsetof(TestDSMRegistryHashEntry, val))
+               ereport(ERROR,
+                               (errmsg("key too long")));
+
+       tdr_attach_shmem();
+
+       entry = dshash_find_or_insert(tdr_hash, key, &found);
+       if (found)
+               dsa_free(tdr_dsa, entry->val);
+
+       entry->val = dsa_allocate(tdr_dsa, strlen(val) + 1);
+       strcpy(dsa_get_address(tdr_dsa, entry->val), val);
+
+       dshash_release_lock(tdr_hash, entry);
+
+       PG_RETURN_VOID();
+}
+
+PG_FUNCTION_INFO_V1(get_val_in_hash);
+Datum
+get_val_in_hash(PG_FUNCTION_ARGS)
+{
+       TestDSMRegistryHashEntry *entry;
+       char       *key = TextDatumGetCString(PG_GETARG_DATUM(0));
+       text       *val = NULL;
+
+       tdr_attach_shmem();
+
+       entry = dshash_find(tdr_hash, key, false);
+       if (entry == NULL)
+               PG_RETURN_NULL();
+
+       val = cstring_to_text(dsa_get_address(tdr_dsa, entry->val));
+
+       dshash_release_lock(tdr_hash, entry);
+
+       PG_RETURN_TEXT_P(val);
+}
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 32d6e718adc..651e4e4f741 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -601,6 +601,7 @@ DR_intorel
 DR_printtup
 DR_sqlfunction
 DR_transientrel
+DSMREntryType
 DSMRegistryCtxStruct
 DSMRegistryEntry
 DWORD
@@ -1736,6 +1737,9 @@ Name
 NameData
 NameHashEntry
 NamedArgExpr
+NamedDSAState
+NamedDSHState
+NamedDSMState
 NamedLWLockTranche
 NamedLWLockTrancheRequest
 NamedTuplestoreScan
@@ -3006,6 +3010,7 @@ Tcl_Obj
 Tcl_Size
 Tcl_Time
 TempNamespaceStatus
+TestDSMRegistryHashEntry
 TestDSMRegistryStruct
 TestDecodingData
 TestDecodingTxnData
-- 
2.39.5 (Apple Git-154)

Reply via email to