1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Introduce the dynamic shared memory registry.

Presently, the most straightforward way for a shared library to use
shared memory is to request it at server startup via a
shmem_request_hook, which requires specifying the library in
shared_preload_libraries.  Alternatively, the library can create a
dynamic shared memory (DSM) segment, but absent a shared location
to store the segment's handle, other backends cannot use it.  This
commit introduces a registry for DSM segments so that these other
backends can look up existing segments with a library-specified
string.  This allows libraries to easily use shared memory without
needing to request it at server startup.

The registry is accessed via the new GetNamedDSMSegment() function.
This function handles allocating the segment and initializing it
via a provided callback.  If another backend already created and
initialized the segment, it simply attaches the segment.
GetNamedDSMSegment() locks the registry appropriately to ensure
that only one backend initializes the segment and that all other
backends just attach it.

The registry itself is comprised of a dshash table that stores the
DSM segment handles keyed by a library-specified string.

Reviewed-by: Michael Paquier, Andrei Lepikhov, Nikita Malakhov, Robert Haas, Bharath Rupireddy, Zhang Mingli, Amul Sul
Discussion: https://postgr.es/m/20231205034647.GA2705267%40nathanxps13
This commit is contained in:
Nathan Bossart
2024-01-19 14:24:36 -06:00
parent 964152c476
commit 8b2bcf3f28
21 changed files with 455 additions and 3 deletions

View File

@ -3460,6 +3460,45 @@ LWLockRelease(AddinShmemInitLock);
the <productname>PostgreSQL</productname> source tree.
</para>
</sect3>
<sect3 id="xfunc-shared-addin-after-startup">
<title>Requesting Shared Memory After Startup</title>
<para>
There is another, more flexible method of reserving shared memory that
can be done after server startup and outside a
<literal>shmem_request_hook</literal>. To do so, each backend that will
use the shared memory should obtain a pointer to it by calling:
<programlisting>
void *GetNamedDSMSegment(const char *name, size_t size,
void (*init_callback) (void *ptr),
bool *found)
</programlisting>
If a dynamic shared memory segment with the given name does not yet
exist, this function will allocate it and initialize it with the provided
<function>init_callback</function> callback function. If the segment has
already been allocated and initialized by another backend, this function
simply attaches the existing dynamic shared memory segment to the current
backend.
</para>
<para>
Unlike shared memory reserved at server startup, there is no need to
acquire <function>AddinShmemInitLock</function> or otherwise take action
to avoid race conditions when reserving shared memory with
<function>GetNamedDSMSegment</function>. This function ensures that only
one backend allocates and initializes the segment and that all other
backends receive a pointer to the fully allocated and initialized
segment.
</para>
<para>
A complete usage example of <function>GetNamedDSMSegment</function> can
be found in
<filename>src/test/modules/test_dsm_registry/test_dsm_registry.c</filename>
in the <productname>PostgreSQL</productname> source tree.
</para>
</sect3>
</sect2>
<sect2 id="xfunc-addin-lwlocks">
@ -3469,8 +3508,9 @@ LWLockRelease(AddinShmemInitLock);
<title>Requesting LWLocks at Startup</title>
<para>
Add-ins can reserve LWLocks on server startup. As with shared memory,
the add-in's shared library must be preloaded by specifying it in
Add-ins can reserve LWLocks on server startup. As with shared memory
reserved at server startup, the add-in's shared library must be preloaded
by specifying it in
<xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>,
and the shared library should register a
<literal>shmem_request_hook</literal> in its
@ -3508,7 +3548,10 @@ void LWLockInitialize(LWLock *lock, int tranche_id)
process allocates a new <literal>tranche_id</literal> and initializes
each new LWLock. One way to do this is to only call these functions in
your shared memory initialization code with the
<function>AddinShmemInitLock</function> held exclusively.
<function>AddinShmemInitLock</function> held exclusively. If using
<function>GetNamedDSMSegment</function>, calling these functions in the
<function>init_callback</function> callback function is sufficient to
avoid race conditions.
</para>
<para>