PostgreSQL Source Code  git master
dsm_registry.c
Go to the documentation of this file.
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  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
19  * Portions Copyright (c) 1994, Regents of the University of California
20  *
21  * IDENTIFICATION
22  * src/backend/storage/ipc/dsm_registry.c
23  *
24  *-------------------------------------------------------------------------
25  */
26 
27 #include "postgres.h"
28 
29 #include "lib/dshash.h"
30 #include "storage/dsm_registry.h"
31 #include "storage/lwlock.h"
32 #include "storage/shmem.h"
33 #include "utils/memutils.h"
34 
35 typedef struct DSMRegistryCtxStruct
36 {
40 
42 
43 typedef struct DSMRegistryEntry
44 {
45  char name[64];
47  size_t size;
49 
50 static const dshash_parameters dsh_params = {
51  offsetof(DSMRegistryEntry, handle),
52  sizeof(DSMRegistryEntry),
57 };
58 
61 
62 Size
64 {
65  return MAXALIGN(sizeof(DSMRegistryCtxStruct));
66 }
67 
68 void
70 {
71  bool found;
72 
74  ShmemInitStruct("DSM Registry Data",
76  &found);
77 
78  if (!found)
79  {
82  }
83 }
84 
85 /*
86  * Initialize or attach to the dynamic shared hash table that stores the DSM
87  * registry entries, if not already done. This must be called before accessing
88  * the table.
89  */
90 static void
92 {
93  /* Quick exit if we already did this. */
95  return;
96 
97  /* Otherwise, use a lock to ensure only one process creates the table. */
98  LWLockAcquire(DSMRegistryLock, LW_EXCLUSIVE);
99 
101  {
102  /* Initialize dynamic shared hash table for registry. */
107 
108  /* Store handles in shared memory for other backends to use. */
111  }
112  else
113  {
114  /* Attach to existing dynamic shared hash table. */
118  DSMRegistryCtx->dshh, NULL);
119  }
120 
121  LWLockRelease(DSMRegistryLock);
122 }
123 
124 /*
125  * Initialize or attach a named DSM segment.
126  *
127  * This routine returns the address of the segment. init_callback is called to
128  * initialize the segment when it is first created.
129  */
130 void *
131 GetNamedDSMSegment(const char *name, size_t size,
132  void (*init_callback) (void *ptr), bool *found)
133 {
134  DSMRegistryEntry *entry;
135  MemoryContext oldcontext;
136  void *ret;
137 
138  Assert(found);
139 
140  if (!name || *name == '\0')
141  ereport(ERROR,
142  (errmsg("DSM segment name cannot be empty")));
143 
144  if (strlen(name) >= offsetof(DSMRegistryEntry, handle))
145  ereport(ERROR,
146  (errmsg("DSM segment name too long")));
147 
148  if (size == 0)
149  ereport(ERROR,
150  (errmsg("DSM segment size must be nonzero")));
151 
152  /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
154 
155  /* Connect to the registry. */
157 
159  if (!(*found))
160  {
161  /* Initialize the segment. */
162  dsm_segment *seg = dsm_create(size, 0);
163 
164  dsm_pin_segment(seg);
165  dsm_pin_mapping(seg);
166  entry->handle = dsm_segment_handle(seg);
167  entry->size = size;
168  ret = dsm_segment_address(seg);
169 
170  if (init_callback)
171  (*init_callback) (ret);
172  }
173  else if (entry->size != size)
174  {
175  ereport(ERROR,
176  (errmsg("requested DSM segment size does not match size of "
177  "existing segment")));
178  }
179  else
180  {
181  dsm_segment *seg = dsm_find_mapping(entry->handle);
182 
183  /* If the existing segment is not already attached, attach it now. */
184  if (seg == NULL)
185  {
186  seg = dsm_attach(entry->handle);
187  if (seg == NULL)
188  elog(ERROR, "could not map dynamic shared memory segment");
189 
190  dsm_pin_mapping(seg);
191  }
192 
193  ret = dsm_segment_address(seg);
194  }
195 
197  MemoryContextSwitchTo(oldcontext);
198 
199  return ret;
200 }
#define MAXALIGN(LEN)
Definition: c.h:811
#define Assert(condition)
Definition: c.h:858
size_t Size
Definition: c.h:605
dsa_area * dsa_attach(dsa_handle handle)
Definition: dsa.c:510
void dsa_pin_mapping(dsa_area *area)
Definition: dsa.c:635
dsa_handle dsa_get_handle(dsa_area *area)
Definition: dsa.c:498
void dsa_pin(dsa_area *area)
Definition: dsa.c:975
dsm_handle dsa_handle
Definition: dsa.h:136
#define DSA_HANDLE_INVALID
Definition: dsa.h:139
#define dsa_create(tranch_id)
Definition: dsa.h:117
void dshash_strcpy(void *dest, const void *src, size_t size, void *arg)
Definition: dshash.c:622
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:558
dshash_hash dshash_strhash(const void *v, size_t size, void *arg)
Definition: dshash.c:611
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:367
int dshash_strcmp(const void *a, const void *b, size_t size, void *arg)
Definition: dshash.c:599
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:433
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:270
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:206
#define DSHASH_HANDLE_INVALID
Definition: dshash.h:27
dsa_pointer dshash_table_handle
Definition: dshash.h:24
dsm_handle dsm_segment_handle(dsm_segment *seg)
Definition: dsm.c:1123
void * dsm_segment_address(dsm_segment *seg)
Definition: dsm.c:1095
dsm_segment * dsm_attach(dsm_handle h)
Definition: dsm.c:665
dsm_segment * dsm_create(Size size, int flags)
Definition: dsm.c:516
void dsm_pin_mapping(dsm_segment *seg)
Definition: dsm.c:915
void dsm_pin_segment(dsm_segment *seg)
Definition: dsm.c:955
dsm_segment * dsm_find_mapping(dsm_handle handle)
Definition: dsm.c:1076
uint32 dsm_handle
Definition: dsm_impl.h:55
void DSMRegistryShmemInit(void)
Definition: dsm_registry.c:69
static void init_dsm_registry(void)
Definition: dsm_registry.c:91
static DSMRegistryCtxStruct * DSMRegistryCtx
Definition: dsm_registry.c:41
struct DSMRegistryEntry DSMRegistryEntry
static dshash_table * dsm_registry_table
Definition: dsm_registry.c:60
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr), bool *found)
Definition: dsm_registry.c:131
static dsa_area * dsm_registry_dsa
Definition: dsm_registry.c:59
static const dshash_parameters dsh_params
Definition: dsm_registry.c:50
struct DSMRegistryCtxStruct DSMRegistryCtxStruct
Size DSMRegistryShmemSize(void)
Definition: dsm_registry.c:63
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LWTRANCHE_DSM_REGISTRY_DSA
Definition: lwlock.h:208
@ LWTRANCHE_DSM_REGISTRY_HASH
Definition: lwlock.h:209
@ LW_EXCLUSIVE
Definition: lwlock.h:114
MemoryContext TopMemoryContext
Definition: mcxt.c:149
MemoryContextSwitchTo(old_ctx)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
static pg_noinline void Size size
Definition: slab.c:607
dshash_table_handle dshh
Definition: dsm_registry.c:38
dsm_handle handle
Definition: dsm_registry.c:46
Definition: dsa.c:348
const char * name