1/*-------------------------------------------------------------------------
4 * Functions for interfacing with the dynamic shared memory registry.
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.
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.
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.
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.
32 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
33 * Portions Copyright (c) 1994, Regents of the University of California
36 * src/backend/storage/ipc/dsm_registry.c
38 *-------------------------------------------------------------------------
110 LWTRANCHE_DSM_REGISTRY_HASH
140 * Initialize or attach to the dynamic shared hash table that stores the DSM
141 * registry entries, if not already done. This must be called before accessing
147 /* Quick exit if we already did this. */
151 /* Otherwise, use a lock to ensure only one process creates the table. */
156 /* Initialize dynamic shared hash table for registry. */
162 /* Store handles in shared memory for other backends to use. */
168 /* Attach to existing dynamic shared hash table. */
179 * Initialize or attach a named DSM segment.
181 * This routine returns the address of the segment. init_callback is called to
182 * initialize the segment when it is first created.
186 void (*init_callback) (
void *ptr),
bool *found)
196 (
errmsg(
"DSM segment name cannot be empty")));
200 (
errmsg(
"DSM segment name too long")));
204 (
errmsg(
"DSM segment size must be nonzero")));
206 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
209 /* Connect to the registry. */
220 /* Initialize the segment. */
230 (*init_callback) (ret);
234 (
errmsg(
"requested DSM segment does not match type of existing entry")));
235 else if (entry->
dsm.
size != size)
237 (
errmsg(
"requested DSM segment size does not match size of existing segment")));
243 /* If the existing segment is not already attached, attach it now. */
249 elog(
ERROR,
"could not map dynamic shared memory segment");
264 * Initialize or attach a named DSA.
266 * This routine returns a pointer to the DSA. A new LWLock tranche ID will be
267 * generated if needed. Note that the lock tranche will be registered with the
268 * provided name. Also note that this should be called at most once for a
269 * given DSA in each backend.
282 (
errmsg(
"DSA name cannot be empty")));
286 (
errmsg(
"DSA name too long")));
288 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
291 /* Connect to the registry. */
301 /* Initialize the LWLock tranche for the DSA. */
304 /* Initialize the DSA. */
309 /* Store handle for other backends to use. */
314 (
errmsg(
"requested DSA does not match type of existing entry")));
321 (
errmsg(
"requested DSA already attached to current process")));
323 /* Attach to existing DSA. */
335 * Initialize or attach a named dshash table.
337 * This routine returns the address of the table. The tranche_id member of
338 * params is ignored; a new LWLock tranche ID will be generated if needed.
339 * Note that the lock tranche will be registered with the provided name. Also
340 * note that this should be called at most once for a given table in each
355 (
errmsg(
"DSHash name cannot be empty")));
359 (
errmsg(
"DSHash name too long")));
361 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
364 /* Connect to the registry. */
376 /* Initialize the LWLock tranche for the hash table. */
379 /* Initialize the DSA for the hash table. */
384 /* Initialize the dshash table. */
389 /* Store handles for other backends to use. */
395 (
errmsg(
"requested DSHash does not match type of existing entry")));
401 /* XXX: Should we verify params matches what table was created with? */
405 (
errmsg(
"requested DSHash already attached to current process")));
407 /* Attach to existing DSA for the hash table. */
411 /* Attach to existing dshash table. */
431 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
446 * Since we can't know the size of DSA/dshash entries without first
447 * attaching to them, return NULL for those.
#define CStringGetTextDatum(s)
dsa_area * dsa_attach(dsa_handle handle)
void dsa_pin_mapping(dsa_area *area)
dsa_handle dsa_get_handle(dsa_area *area)
bool dsa_is_attached(dsa_handle handle)
void dsa_pin(dsa_area *area)
#define dsa_create(tranche_id)
#define DSA_HANDLE_INVALID
void dshash_strcpy(void *dest, const void *src, size_t size, void *arg)
void dshash_release_lock(dshash_table *hash_table, void *entry)
void dshash_seq_init(dshash_seq_status *status, dshash_table *hash_table, bool exclusive)
dshash_hash dshash_strhash(const void *v, size_t size, void *arg)
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
void dshash_seq_term(dshash_seq_status *status)
int dshash_strcmp(const void *a, const void *b, size_t size, void *arg)
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
void * dshash_seq_next(dshash_seq_status *status)
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
#define DSHASH_HANDLE_INVALID
dsa_pointer dshash_table_handle
dsm_handle dsm_segment_handle(dsm_segment *seg)
void dsm_pin_mapping(dsm_segment *seg)
void dsm_pin_segment(dsm_segment *seg)
void * dsm_segment_address(dsm_segment *seg)
dsm_segment * dsm_create(Size size, int flags)
dsm_segment * dsm_attach(dsm_handle h)
dsm_segment * dsm_find_mapping(dsm_handle handle)
dsa_area * GetNamedDSA(const char *name, bool *found)
Datum pg_get_dsm_registry_allocations(PG_FUNCTION_ARGS)
struct NamedDSMState NamedDSMState
void DSMRegistryShmemInit(void)
static void init_dsm_registry(void)
static const char *const DSMREntryTypeNames[]
struct NamedDSAState NamedDSAState
static DSMRegistryCtxStruct * DSMRegistryCtx
struct DSMRegistryEntry DSMRegistryEntry
static dshash_table * dsm_registry_table
dshash_table * GetNamedDSHash(const char *name, const dshash_parameters *params, bool *found)
static dsa_area * dsm_registry_dsa
static const dshash_parameters dsh_params
struct DSMRegistryCtxStruct DSMRegistryCtxStruct
struct NamedDSHState NamedDSHState
Size DSMRegistryShmemSize(void)
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr), bool *found)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
#define MAT_SRF_USE_EXPECTED_DESC
Assert(PointerIsAligned(start, uint64))
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
int LWLockNewTrancheId(const char *name)
void LWLockRelease(LWLock *lock)
MemoryContext TopMemoryContext
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
static Datum Int64GetDatum(int64 X)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
dshash_table_handle dsh_handle
Tuplestorestate * setResult
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)