PostgreSQL Source Code git master
dsm_registry.c File Reference
#include "postgres.h"
#include "funcapi.h"
#include "lib/dshash.h"
#include "storage/dsm_registry.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
Include dependency graph for dsm_registry.c:

Go to the source code of this file.

Data Structures

struct  DSMRegistryCtxStruct
 
struct  NamedDSMState
 
struct  NamedDSAState
 
struct  NamedDSHState
 
struct  DSMRegistryEntry
 

Typedefs

typedef struct DSMRegistryCtxStruct DSMRegistryCtxStruct
 
typedef struct NamedDSMState NamedDSMState
 
typedef struct NamedDSAState NamedDSAState
 
typedef struct NamedDSHState NamedDSHState
 
typedef enum DSMREntryType DSMREntryType
 
typedef struct DSMRegistryEntry DSMRegistryEntry
 

Enumerations

enum  DSMREntryType { DSMR_ENTRY_TYPE_DSM , DSMR_ENTRY_TYPE_DSA , DSMR_ENTRY_TYPE_DSH }
 

Functions

Size DSMRegistryShmemSize (void)
 
void DSMRegistryShmemInit (void)
 
static void init_dsm_registry (void)
 
void * GetNamedDSMSegment (const char *name, size_t size, void(*init_callback)(void *ptr), bool *found)
 
dsa_areaGetNamedDSA (const char *name, bool *found)
 
dshash_tableGetNamedDSHash (const char *name, const dshash_parameters *params, bool *found)
 
Datum pg_get_dsm_registry_allocations (PG_FUNCTION_ARGS)
 

Variables

static DSMRegistryCtxStructDSMRegistryCtx
 
static const char *const DSMREntryTypeNames []
 
static const dshash_parameters dsh_params
 
static dsa_areadsm_registry_dsa
 
static dshash_tabledsm_registry_table
 

Typedef Documentation

◆ DSMRegistryCtxStruct

◆ DSMRegistryEntry

◆ DSMREntryType

◆ NamedDSAState

typedef struct NamedDSAState NamedDSAState

◆ NamedDSHState

typedef struct NamedDSHState NamedDSHState

◆ NamedDSMState

typedef struct NamedDSMState NamedDSMState

Enumeration Type Documentation

◆ DSMREntryType

Enumerator
DSMR_ENTRY_TYPE_DSM 
DSMR_ENTRY_TYPE_DSA 
DSMR_ENTRY_TYPE_DSH 

Definition at line 78 of file dsm_registry.c.

79{
DSMREntryType
Definition: dsm_registry.c:79
@ DSMR_ENTRY_TYPE_DSM
Definition: dsm_registry.c:80
@ DSMR_ENTRY_TYPE_DSA
Definition: dsm_registry.c:81
@ DSMR_ENTRY_TYPE_DSH
Definition: dsm_registry.c:82

Function Documentation

◆ DSMRegistryShmemInit()

void DSMRegistryShmemInit ( void  )

Definition at line 124 of file dsm_registry.c.

125{
126 bool found;
127
129 ShmemInitStruct("DSM Registry Data",
131 &found);
132
133 if (!found)
134 {
137 }
138}
#define DSA_HANDLE_INVALID
Definition: dsa.h:139
#define DSHASH_HANDLE_INVALID
Definition: dshash.h:27
static DSMRegistryCtxStruct * DSMRegistryCtx
Definition: dsm_registry.c:57
Size DSMRegistryShmemSize(void)
Definition: dsm_registry.c:118
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
dshash_table_handle dshh
Definition: dsm_registry.c:54

References DSA_HANDLE_INVALID, DSMRegistryCtxStruct::dsah, DSHASH_HANDLE_INVALID, DSMRegistryCtxStruct::dshh, DSMRegistryCtx, DSMRegistryShmemSize(), and ShmemInitStruct().

Referenced by CreateOrAttachShmemStructs().

◆ DSMRegistryShmemSize()

Size DSMRegistryShmemSize ( void  )

Definition at line 118 of file dsm_registry.c.

119{
120 return MAXALIGN(sizeof(DSMRegistryCtxStruct));
121}
#define MAXALIGN(LEN)
Definition: c.h:814

References MAXALIGN.

Referenced by CalculateShmemSize(), and DSMRegistryShmemInit().

◆ GetNamedDSA()

dsa_area * GetNamedDSA ( const char *  name,
bool *  found 
)

Definition at line 282 of file dsm_registry.c.

283{
284 DSMRegistryEntry *entry;
285 MemoryContext oldcontext;
286 dsa_area *ret;
287
288 Assert(found);
289
290 if (!name || *name == '\0')
292 (errmsg("DSA name cannot be empty")));
293
294 if (strlen(name) >= offsetof(DSMRegistryEntry, type))
296 (errmsg("DSA name too long")));
297
298 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
300
301 /* Connect to the registry. */
303
305 if (!(*found))
306 {
307 NamedDSAState *state = &entry->dsa;
308
309 entry->type = DSMR_ENTRY_TYPE_DSA;
310 entry->initialized = false;
311
312 /* Initialize the LWLock tranche for the DSA. */
313 state->tranche = LWLockNewTrancheId(name);
314
315 /* Initialize the DSA. */
316 ret = dsa_create(state->tranche);
317 dsa_pin(ret);
318 dsa_pin_mapping(ret);
319
320 /* Store handle for other backends to use. */
321 state->handle = dsa_get_handle(ret);
322
323 entry->initialized = true;
324 }
325 else if (entry->type != DSMR_ENTRY_TYPE_DSA)
327 (errmsg("requested DSA \"%s\" does not match type of existing entry",
328 name)));
329 else if (!entry->initialized)
331 (errmsg("requested DSA \"%s\" failed initialization",
332 name)));
333 else
334 {
335 NamedDSAState *state = &entry->dsa;
336
337 if (dsa_is_attached(state->handle))
339 (errmsg("requested DSA already attached to current process")));
340
341 /* Attach to existing DSA. */
342 ret = dsa_attach(state->handle);
343 dsa_pin_mapping(ret);
344 }
345
347 MemoryContextSwitchTo(oldcontext);
348
349 return ret;
350}
dsa_area * dsa_attach(dsa_handle handle)
Definition: dsa.c:510
void dsa_pin_mapping(dsa_area *area)
Definition: dsa.c:650
dsa_handle dsa_get_handle(dsa_area *area)
Definition: dsa.c:498
bool dsa_is_attached(dsa_handle handle)
Definition: dsa.c:540
void dsa_pin(dsa_area *area)
Definition: dsa.c:990
#define dsa_create(tranche_id)
Definition: dsa.h:117
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:560
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:435
static void init_dsm_registry(void)
Definition: dsm_registry.c:146
static dshash_table * dsm_registry_table
Definition: dsm_registry.c:115
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
Assert(PointerIsAligned(start, uint64))
int LWLockNewTrancheId(const char *name)
Definition: lwlock.c:596
MemoryContext TopMemoryContext
Definition: mcxt.c:166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
NamedDSAState dsa
Definition: dsm_registry.c:100
DSMREntryType type
Definition: dsm_registry.c:95
Definition: dsa.c:348
Definition: regguts.h:323
const char * type
const char * name

References Assert(), DSMRegistryEntry::dsa, dsa_attach(), dsa_create, dsa_get_handle(), dsa_is_attached(), dsa_pin(), dsa_pin_mapping(), dshash_find_or_insert(), dshash_release_lock(), dsm_registry_table, DSMR_ENTRY_TYPE_DSA, ereport, errmsg(), ERROR, init_dsm_registry(), DSMRegistryEntry::initialized, LWLockNewTrancheId(), MemoryContextSwitchTo(), name, TopMemoryContext, DSMRegistryEntry::type, and type.

Referenced by tdr_attach_shmem().

◆ GetNamedDSHash()

dshash_table * GetNamedDSHash ( const char *  name,
const dshash_parameters params,
bool *  found 
)

Definition at line 362 of file dsm_registry.c.

363{
364 DSMRegistryEntry *entry;
365 MemoryContext oldcontext;
366 dshash_table *ret;
367
368 Assert(params);
369 Assert(found);
370
371 if (!name || *name == '\0')
373 (errmsg("DSHash name cannot be empty")));
374
375 if (strlen(name) >= offsetof(DSMRegistryEntry, type))
377 (errmsg("DSHash name too long")));
378
379 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
381
382 /* Connect to the registry. */
384
386 if (!(*found))
387 {
388 NamedDSHState *dsh_state = &entry->dsh;
389 dshash_parameters params_copy;
390 dsa_area *dsa;
391
392 entry->type = DSMR_ENTRY_TYPE_DSH;
393 entry->initialized = false;
394
395 /* Initialize the LWLock tranche for the hash table. */
396 dsh_state->tranche = LWLockNewTrancheId(name);
397
398 /* Initialize the DSA for the hash table. */
399 dsa = dsa_create(dsh_state->tranche);
400 dsa_pin(dsa);
401 dsa_pin_mapping(dsa);
402
403 /* Initialize the dshash table. */
404 memcpy(&params_copy, params, sizeof(dshash_parameters));
405 params_copy.tranche_id = dsh_state->tranche;
406 ret = dshash_create(dsa, &params_copy, NULL);
407
408 /* Store handles for other backends to use. */
409 dsh_state->dsa_handle = dsa_get_handle(dsa);
411
412 entry->initialized = true;
413 }
414 else if (entry->type != DSMR_ENTRY_TYPE_DSH)
416 (errmsg("requested DSHash \"%s\" does not match type of existing entry",
417 name)));
418 else if (!entry->initialized)
420 (errmsg("requested DSHash \"%s\" failed initialization",
421 name)));
422 else
423 {
424 NamedDSHState *dsh_state = &entry->dsh;
425 dsa_area *dsa;
426
427 /* XXX: Should we verify params matches what table was created with? */
428
429 if (dsa_is_attached(dsh_state->dsa_handle))
431 (errmsg("requested DSHash already attached to current process")));
432
433 /* Attach to existing DSA for the hash table. */
434 dsa = dsa_attach(dsh_state->dsa_handle);
435 dsa_pin_mapping(dsa);
436
437 /* Attach to existing dshash table. */
438 ret = dshash_attach(dsa, params, dsh_state->dsh_handle, NULL);
439 }
440
442 MemoryContextSwitchTo(oldcontext);
443
444 return ret;
445}
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:369
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:272
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:208
NamedDSHState dsh
Definition: dsm_registry.c:101
dsa_handle dsa_handle
Definition: dsm_registry.c:73
dshash_table_handle dsh_handle
Definition: dsm_registry.c:74

References Assert(), dsa_attach(), dsa_create, dsa_get_handle(), NamedDSHState::dsa_handle, dsa_is_attached(), dsa_pin(), dsa_pin_mapping(), DSMRegistryEntry::dsh, NamedDSHState::dsh_handle, dshash_attach(), dshash_create(), dshash_find_or_insert(), dshash_get_hash_table_handle(), dshash_release_lock(), dsm_registry_table, DSMR_ENTRY_TYPE_DSH, ereport, errmsg(), ERROR, init_dsm_registry(), DSMRegistryEntry::initialized, LWLockNewTrancheId(), MemoryContextSwitchTo(), name, TopMemoryContext, NamedDSHState::tranche, dshash_parameters::tranche_id, DSMRegistryEntry::type, and type.

Referenced by tdr_attach_shmem().

◆ GetNamedDSMSegment()

void * GetNamedDSMSegment ( const char *  name,
size_t  size,
void(*)(void *ptr)  init_callback,
bool *  found 
)

Definition at line 186 of file dsm_registry.c.

188{
189 DSMRegistryEntry *entry;
190 MemoryContext oldcontext;
191 void *ret;
192
193 Assert(found);
194
195 if (!name || *name == '\0')
197 (errmsg("DSM segment name cannot be empty")));
198
199 if (strlen(name) >= offsetof(DSMRegistryEntry, type))
201 (errmsg("DSM segment name too long")));
202
203 if (size == 0)
205 (errmsg("DSM segment size must be nonzero")));
206
207 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
209
210 /* Connect to the registry. */
212
214 if (!(*found))
215 {
216 NamedDSMState *state = &entry->dsm;
217 dsm_segment *seg;
218
219 entry->type = DSMR_ENTRY_TYPE_DSM;
220 entry->initialized = false;
221
222 /* Initialize the segment. */
223 seg = dsm_create(size, 0);
224
225 dsm_pin_segment(seg);
226 dsm_pin_mapping(seg);
227 state->handle = dsm_segment_handle(seg);
228 state->size = size;
229 ret = dsm_segment_address(seg);
230
231 if (init_callback)
232 (*init_callback) (ret);
233
234 entry->initialized = true;
235 }
236 else if (entry->type != DSMR_ENTRY_TYPE_DSM)
238 (errmsg("requested DSM segment \"%s\" does not match type of existing entry",
239 name)));
240 else if (!entry->initialized)
242 (errmsg("requested DSM segment \"%s\" failed initialization",
243 name)));
244 else if (entry->dsm.size != size)
246 (errmsg("requested DSM segment \"%s\" does not match size of existing entry",
247 name)));
248 else
249 {
250 NamedDSMState *state = &entry->dsm;
251 dsm_segment *seg;
252
253 /* If the existing segment is not already attached, attach it now. */
254 seg = dsm_find_mapping(state->handle);
255 if (seg == NULL)
256 {
257 seg = dsm_attach(state->handle);
258 if (seg == NULL)
259 elog(ERROR, "could not map dynamic shared memory segment");
260
261 dsm_pin_mapping(seg);
262 }
263
264 ret = dsm_segment_address(seg);
265 }
266
268 MemoryContextSwitchTo(oldcontext);
269
270 return ret;
271}
dsm_handle dsm_segment_handle(dsm_segment *seg)
Definition: dsm.c:1123
void dsm_pin_mapping(dsm_segment *seg)
Definition: dsm.c:915
void dsm_pin_segment(dsm_segment *seg)
Definition: dsm.c:955
void * dsm_segment_address(dsm_segment *seg)
Definition: dsm.c:1095
dsm_segment * dsm_create(Size size, int flags)
Definition: dsm.c:516
dsm_segment * dsm_attach(dsm_handle h)
Definition: dsm.c:665
dsm_segment * dsm_find_mapping(dsm_handle handle)
Definition: dsm.c:1076
#define elog(elevel,...)
Definition: elog.h:226
NamedDSMState dsm
Definition: dsm_registry.c:99

References Assert(), dshash_find_or_insert(), dshash_release_lock(), DSMRegistryEntry::dsm, dsm_attach(), dsm_create(), dsm_find_mapping(), dsm_pin_mapping(), dsm_pin_segment(), dsm_registry_table, dsm_segment_address(), dsm_segment_handle(), DSMR_ENTRY_TYPE_DSM, elog, ereport, errmsg(), ERROR, init_dsm_registry(), DSMRegistryEntry::initialized, MemoryContextSwitchTo(), name, NamedDSMState::size, TopMemoryContext, DSMRegistryEntry::type, and type.

Referenced by apw_init_shmem(), injection_init_shmem(), tdr_attach_shmem(), test_dsa_basic(), and test_dsa_resowners().

◆ init_dsm_registry()

static void init_dsm_registry ( void  )
static

Definition at line 146 of file dsm_registry.c.

147{
148 /* Quick exit if we already did this. */
150 return;
151
152 /* Otherwise, use a lock to ensure only one process creates the table. */
153 LWLockAcquire(DSMRegistryLock, LW_EXCLUSIVE);
154
156 {
157 /* Initialize dynamic shared hash table for registry. */
158 dsm_registry_dsa = dsa_create(LWTRANCHE_DSM_REGISTRY_DSA);
162
163 /* Store handles in shared memory for other backends to use. */
166 }
167 else
168 {
169 /* Attach to existing dynamic shared hash table. */
173 DSMRegistryCtx->dshh, NULL);
174 }
175
176 LWLockRelease(DSMRegistryLock);
177}
static dsa_area * dsm_registry_dsa
Definition: dsm_registry.c:114
static const dshash_parameters dsh_params
Definition: dsm_registry.c:105
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_EXCLUSIVE
Definition: lwlock.h:112

References dsa_attach(), dsa_create, dsa_get_handle(), dsa_pin(), dsa_pin_mapping(), DSMRegistryCtxStruct::dsah, dsh_params, dshash_attach(), dshash_create(), dshash_get_hash_table_handle(), DSHASH_HANDLE_INVALID, DSMRegistryCtxStruct::dshh, dsm_registry_dsa, dsm_registry_table, DSMRegistryCtx, LW_EXCLUSIVE, LWLockAcquire(), and LWLockRelease().

Referenced by GetNamedDSA(), GetNamedDSHash(), GetNamedDSMSegment(), and pg_get_dsm_registry_allocations().

◆ pg_get_dsm_registry_allocations()

Datum pg_get_dsm_registry_allocations ( PG_FUNCTION_ARGS  )

Definition at line 448 of file dsm_registry.c.

449{
450 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
451 DSMRegistryEntry *entry;
452 MemoryContext oldcontext;
453 dshash_seq_status status;
454
456
457 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
460 MemoryContextSwitchTo(oldcontext);
461
462 dshash_seq_init(&status, dsm_registry_table, false);
463 while ((entry = dshash_seq_next(&status)) != NULL)
464 {
465 Datum vals[3];
466 bool nulls[3] = {0};
467
468 vals[0] = CStringGetTextDatum(entry->name);
469 vals[1] = CStringGetTextDatum(DSMREntryTypeNames[entry->type]);
470
471 /*
472 * Since we can't know the size of DSA/dshash entries without first
473 * attaching to them, return NULL for those.
474 */
475 if (entry->type == DSMR_ENTRY_TYPE_DSM)
476 vals[2] = Int64GetDatum(entry->dsm.size);
477 else
478 nulls[2] = true;
479
480 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, vals, nulls);
481 }
482 dshash_seq_term(&status);
483
484 return (Datum) 0;
485}
#define CStringGetTextDatum(s)
Definition: builtins.h:97
void dshash_seq_init(dshash_seq_status *status, dshash_table *hash_table, bool exclusive)
Definition: dshash.c:640
void dshash_seq_term(dshash_seq_status *status)
Definition: dshash.c:749
void * dshash_seq_next(dshash_seq_status *status)
Definition: dshash.c:659
static const char *const DSMREntryTypeNames[]
Definition: dsm_registry.c:85
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define MAT_SRF_USE_EXPECTED_DESC
Definition: funcapi.h:296
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
uint64_t Datum
Definition: postgres.h:70
TupleDesc setDesc
Definition: execnodes.h:364
Tuplestorestate * setResult
Definition: execnodes.h:363
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784

References CStringGetTextDatum, dshash_seq_init(), dshash_seq_next(), dshash_seq_term(), dsm_registry_table, DSMR_ENTRY_TYPE_DSM, DSMREntryTypeNames, init_dsm_registry(), InitMaterializedSRF(), Int64GetDatum(), MAT_SRF_USE_EXPECTED_DESC, MemoryContextSwitchTo(), ReturnSetInfo::setDesc, ReturnSetInfo::setResult, TopMemoryContext, and tuplestore_putvalues().

Variable Documentation

◆ dsh_params

const dshash_parameters dsh_params
static
Initial value:
= {
offsetof(DSMRegistryEntry, type),
LWTRANCHE_DSM_REGISTRY_HASH
}
void dshash_strcpy(void *dest, const void *src, size_t size, void *arg)
Definition: dshash.c:624
dshash_hash dshash_strhash(const void *v, size_t size, void *arg)
Definition: dshash.c:613
int dshash_strcmp(const void *a, const void *b, size_t size, void *arg)
Definition: dshash.c:601
struct DSMRegistryEntry DSMRegistryEntry

Definition at line 105 of file dsm_registry.c.

Referenced by init_dsm_registry().

◆ dsm_registry_dsa

dsa_area* dsm_registry_dsa
static

Definition at line 114 of file dsm_registry.c.

Referenced by init_dsm_registry().

◆ dsm_registry_table

dshash_table* dsm_registry_table
static

◆ DSMRegistryCtx

DSMRegistryCtxStruct* DSMRegistryCtx
static

Definition at line 57 of file dsm_registry.c.

Referenced by DSMRegistryShmemInit(), and init_dsm_registry().

◆ DSMREntryTypeNames

const char* const DSMREntryTypeNames[]
static
Initial value:
=
{
[DSMR_ENTRY_TYPE_DSM] = "segment",
[DSMR_ENTRY_TYPE_DSA] = "area",
[DSMR_ENTRY_TYPE_DSH] = "hash",
}

Definition at line 85 of file dsm_registry.c.

Referenced by pg_get_dsm_registry_allocations().