From b63c28303384636699f2f514e71b62829346be4b Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Wed, 11 Oct 2023 22:07:26 -0500 Subject: [PATCH v1 1/2] add dsm registry --- src/backend/storage/ipc/Makefile | 1 + src/backend/storage/ipc/dsm_registry.c | 176 +++++++++++++++++++++++ src/backend/storage/ipc/ipci.c | 3 + src/backend/storage/ipc/meson.build | 1 + src/backend/storage/lmgr/lwlock.c | 4 + src/backend/storage/lmgr/lwlocknames.txt | 1 + src/include/storage/dsm_registry.h | 22 +++ src/include/storage/lwlock.h | 4 +- src/tools/pgindent/typedefs.list | 2 + 9 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 src/backend/storage/ipc/dsm_registry.c create mode 100644 src/include/storage/dsm_registry.h diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile index 6d5b921038..d8a1653eb6 100644 --- a/src/backend/storage/ipc/Makefile +++ b/src/backend/storage/ipc/Makefile @@ -12,6 +12,7 @@ OBJS = \ barrier.o \ dsm.o \ dsm_impl.o \ + dsm_registry.o \ ipc.o \ ipci.o \ latch.o \ diff --git a/src/backend/storage/ipc/dsm_registry.c b/src/backend/storage/ipc/dsm_registry.c new file mode 100644 index 0000000000..ea80f45716 --- /dev/null +++ b/src/backend/storage/ipc/dsm_registry.c @@ -0,0 +1,176 @@ +/*------------------------------------------------------------------------- + * + * dsm_registry.c + * + * Functions for interfacing with the dynamic shared memory registry. This + * provides a way for libraries to use shared memory without needing to + * request it at startup time via a shmem_request_hook. + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/storage/ipc/dsm_registry.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "lib/dshash.h" +#include "storage/dsm_registry.h" +#include "storage/lwlock.h" +#include "storage/shmem.h" +#include "utils/memutils.h" + +typedef struct DSMRegistryCtxStruct +{ + dsa_handle dsah; + dshash_table_handle dshh; +} DSMRegistryCtxStruct; + +static DSMRegistryCtxStruct *DSMRegistryCtx; + +typedef struct DSMRegistryEntry +{ + char key[256]; + dsm_handle handle; +} DSMRegistryEntry; + +static const dshash_parameters dsh_params = { + offsetof(DSMRegistryEntry, handle), + sizeof(DSMRegistryEntry), + dshash_memcmp, + dshash_memhash, + LWTRANCHE_DSM_REGISTRY_HASH +}; + +static dsa_area *dsm_registry_dsa; +static dshash_table *dsm_registry_table; + +static void init_dsm_registry(void); + +Size +DSMRegistryShmemSize(void) +{ + return MAXALIGN(sizeof(DSMRegistryCtxStruct)); +} + +void +DSMRegistryShmemInit(void) +{ + bool found; + + DSMRegistryCtx = (DSMRegistryCtxStruct *) + ShmemInitStruct("DSM Registry Data", + DSMRegistryShmemSize(), + &found); + + if (!found) + { + DSMRegistryCtx->dsah = DSA_HANDLE_INVALID; + DSMRegistryCtx->dshh = DSHASH_HANDLE_INVALID; + } +} + +/* + * Initialize or attach to the dynamic shared hash table that stores the DSM + * registry entries, if not already done. This must be called before accessing + * the table. + */ +static void +init_dsm_registry(void) +{ + /* Quick exit if we already did this. */ + if (dsm_registry_table) + return; + + /* Otherwise, use a lock to ensure only one process creates the table. */ + LWLockAcquire(DSMRegistryLock, LW_EXCLUSIVE); + + if (DSMRegistryCtx->dshh == DSHASH_HANDLE_INVALID) + { + /* Initialize dynamic shared hash table for registry. */ + dsm_registry_dsa = dsa_create(LWTRANCHE_DSM_REGISTRY_DSA); + dsa_pin(dsm_registry_dsa); + dsa_pin_mapping(dsm_registry_dsa); + dsm_registry_table = dshash_create(dsm_registry_dsa, &dsh_params, 0); + + /* Store handles in shared memory for other backends to use. */ + DSMRegistryCtx->dsah = dsa_get_handle(dsm_registry_dsa); + DSMRegistryCtx->dshh = dshash_get_hash_table_handle(dsm_registry_table); + } + else + { + /* Attach to existing dynamic shared hash table. */ + dsm_registry_dsa = dsa_attach(DSMRegistryCtx->dsah); + dsa_pin_mapping(dsm_registry_dsa); + dsm_registry_table = dshash_attach(dsm_registry_dsa, &dsh_params, + DSMRegistryCtx->dshh, 0); + } + + LWLockRelease(DSMRegistryLock); +} + +/* + * Initialize or attach a DSM entry. + * + * *ptr should initially be set to NULL. If it is not NULL, this routine will + * assume that the segment has already been attached to the current session. + * Otherwise, this routine will set *ptr appropriately. + * + * init_callback is called to initialize the segment when it is first created. + */ +void +dsm_registry_init_or_attach(const char *key, void **ptr, size_t size, + void (*init_callback) (void *ptr)) +{ + DSMRegistryEntry *entry; + MemoryContext oldcontext; + bool found; + char key_padded[offsetof(DSMRegistryEntry, handle)] = {0}; + + Assert(key); + Assert(ptr); + Assert(size); + + if (strlen(key) >= offsetof(DSMRegistryEntry, handle)) + elog(ERROR, "DSM registry key too long"); + + /* Quick exit if the value is already set. */ + if (*ptr) + return; + + /* Be sure any local memory allocated by DSM/DSA routines is persistent. */ + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + + /* Connect to the registry. */ + init_dsm_registry(); + + strcpy(key_padded, key); + entry = dshash_find_or_insert(dsm_registry_table, key_padded, &found); + if (!found) + { + /* Initialize DSM registry entry. */ + dsm_segment *seg = dsm_create(size, 0); + + dsm_pin_segment(seg); + dsm_pin_mapping(seg); + entry->handle = dsm_segment_handle(seg); + *ptr = dsm_segment_address(seg); + + if (init_callback) + (*init_callback) (*ptr); + } + else + { + /* Attach to existing DSM registry entry. */ + dsm_segment *seg = dsm_attach(entry->handle); + + dsm_pin_mapping(seg); + *ptr = dsm_segment_address(seg); + } + + dshash_release_lock(dsm_registry_table, entry); + MemoryContextSwitchTo(oldcontext); +} diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 2225a4a6e6..034b656115 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -38,6 +38,7 @@ #include "replication/walsender.h" #include "storage/bufmgr.h" #include "storage/dsm.h" +#include "storage/dsm_registry.h" #include "storage/ipc.h" #include "storage/pg_shmem.h" #include "storage/pmsignal.h" @@ -113,6 +114,7 @@ CalculateShmemSize(int *num_semaphores) size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE, sizeof(ShmemIndexEnt))); size = add_size(size, dsm_estimate_size()); + size = add_size(size, DSMRegistryShmemSize()); size = add_size(size, BufferShmemSize()); size = add_size(size, LockShmemSize()); size = add_size(size, PredicateLockShmemSize()); @@ -285,6 +287,7 @@ CreateOrAttachShmemStructs(void) InitShmemIndex(); dsm_shmem_init(); + DSMRegistryShmemInit(); /* * Set up xlog, clog, and buffers diff --git a/src/backend/storage/ipc/meson.build b/src/backend/storage/ipc/meson.build index 79a16d077f..88fef448be 100644 --- a/src/backend/storage/ipc/meson.build +++ b/src/backend/storage/ipc/meson.build @@ -4,6 +4,7 @@ backend_sources += files( 'barrier.c', 'dsm.c', 'dsm_impl.c', + 'dsm_registry.c', 'ipc.c', 'ipci.c', 'latch.c', diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 315a78cda9..f3faa991d1 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -190,6 +190,10 @@ static const char *const BuiltinTrancheNames[] = { "LogicalRepLauncherDSA", /* LWTRANCHE_LAUNCHER_HASH: */ "LogicalRepLauncherHash", + /* LWTRANCHE_DSM_REGISTRY_DSA: */ + "DSMRegistryDSA", + /* LWTRANCHE_DSM_REGISTRY_HASH: */ + "DSMRegistryHash", }; StaticAssertDecl(lengthof(BuiltinTrancheNames) == diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index f72f2906ce..e8f679c8ae 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -54,3 +54,4 @@ XactTruncationLock 44 WrapLimitsVacuumLock 46 NotifyQueueTailLock 47 WaitEventExtensionLock 48 +DSMRegistryLock 49 diff --git a/src/include/storage/dsm_registry.h b/src/include/storage/dsm_registry.h new file mode 100644 index 0000000000..8c311e50ae --- /dev/null +++ b/src/include/storage/dsm_registry.h @@ -0,0 +1,22 @@ +/*------------------------------------------------------------------------- + * + * dsm_registry.h + * + * + * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/storage/dsm_registry.h + * + *------------------------------------------------------------------------- + */ +#ifndef DSM_REGISTRY_H +#define DSM_REGISTRY_H + +extern void dsm_registry_init_or_attach(const char *key, void **ptr, size_t size, + void (*init_callback) (void *ptr)); + +extern Size DSMRegistryShmemSize(void); +extern void DSMRegistryShmemInit(void); + +#endif /* DSM_REGISTRY_H */ diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index b038e599c0..665d471418 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -207,7 +207,9 @@ typedef enum BuiltinTrancheIds LWTRANCHE_PGSTATS_DATA, LWTRANCHE_LAUNCHER_DSA, LWTRANCHE_LAUNCHER_HASH, - LWTRANCHE_FIRST_USER_DEFINED, + LWTRANCHE_DSM_REGISTRY_DSA, + LWTRANCHE_DSM_REGISTRY_HASH, + LWTRANCHE_FIRST_USER_DEFINED } BuiltinTrancheIds; /* diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index d659adbfd6..c89a268d9e 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -606,6 +606,8 @@ DropSubscriptionStmt DropTableSpaceStmt DropUserMappingStmt DropdbStmt +DSMRegistryCtxStruct +DSMRegistryEntry DumpComponents DumpId DumpOptions -- 2.25.1