mirror of
https://github.com/postgres/postgres.git
synced 2025-12-19 17:02:53 +03:00
Add GetNamedDSA() and GetNamedDSHash().
Presently, the dynamic shared memory (DSM) registry only provides GetNamedDSMSegment(), which allocates a fixed-size segment. To use the DSM registry for more sophisticated things like dynamic shared memory areas (DSAs) or a hash table backed by a DSA (dshash), users need to create a DSM segment that stores various handles and LWLock tranche IDs and to write fairly complicated initialization code. Furthermore, there is likely little variation in this initialization code between libraries. This commit introduces functions that simplify allocating a DSA or dshash within the DSM registry. These functions are very similar to GetNamedDSMSegment(). Notable differences include the lack of an initialization callback parameter and the prohibition of calling the functions more than once for a given entry in each backend (which should be trivially avoidable in most circumstances). While at it, this commit bumps the maximum DSM registry entry name length from 63 bytes to 127 bytes. Also note that even though one could presumably detach/destroy the DSAs and dshashes created in the registry, such use-cases are not yet well-supported, if for no other reason than the associated DSM registry entries cannot be removed. Adding such support is left as a future exercise. The test_dsm_registry test module contains tests for the new functions and also serves as a complete usage example. Reviewed-by: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> Reviewed-by: Sami Imseih <samimseih@gmail.com> Reviewed-by: Florents Tselai <florents.tselai@gmail.com> Reviewed-by: Rahila Syed <rahilasyed90@gmail.com> Discussion: https://postgr.es/m/aEC8HGy2tRQjZg_8%40nathan
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user