mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
doc: Reorganize section for shared memory and LWLocks.
Presently, this section meanders through a few different features, and the text itself is terse. This commit attempts to improve matters by splitting the section into smaller sections and by expanding the text for clarity. This is preparatory work for a follow-up commit that will introduce a way for libraries to use shared memory without needing to request it at startup time. Reviewed-by: Aleksander Alekseev, Bharath Rupireddy, Abhijit Menon-Sen Discussion: https://postgr.es/m/20240112041430.GA3557928%40nathanxps13 Discussion: https://postgr.es/m/20231205034647.GA2705267%40nathanxps13
This commit is contained in:
@ -3397,90 +3397,136 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
|
|||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="xfunc-shared-addin">
|
<sect2 id="xfunc-shared-addin">
|
||||||
<title>Shared Memory and LWLocks</title>
|
<title>Shared Memory</title>
|
||||||
|
|
||||||
<para>
|
<sect3 id="xfunc-shared-addin-at-startup">
|
||||||
Add-ins can reserve LWLocks and an allocation of shared memory on server
|
<title>Requesting Shared Memory at Startup</title>
|
||||||
startup. The add-in's shared library must be preloaded by specifying
|
|
||||||
it in
|
<para>
|
||||||
<xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>.
|
Add-ins can reserve shared memory on server startup. To do so, the
|
||||||
The shared library should register a <literal>shmem_request_hook</literal>
|
add-in's shared library must be preloaded by specifying it in
|
||||||
in its <function>_PG_init</function> function. This
|
<xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>.
|
||||||
<literal>shmem_request_hook</literal> can reserve LWLocks or shared memory.
|
The shared library should also register a
|
||||||
Shared memory is reserved by calling:
|
<literal>shmem_request_hook</literal> in its
|
||||||
|
<function>_PG_init</function> function. This
|
||||||
|
<literal>shmem_request_hook</literal> can reserve shared memory by
|
||||||
|
calling:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
void RequestAddinShmemSpace(int size)
|
void RequestAddinShmemSpace(Size size)
|
||||||
</programlisting>
|
</programlisting>
|
||||||
from your <literal>shmem_request_hook</literal>.
|
Each backend should obtain a pointer to the reserved shared memory by
|
||||||
</para>
|
calling:
|
||||||
<para>
|
<programlisting>
|
||||||
LWLocks are reserved by calling:
|
void *ShmemInitStruct(const char *name, Size size, bool *foundPtr)
|
||||||
|
</programlisting>
|
||||||
|
If this function sets <literal>foundPtr</literal> to
|
||||||
|
<literal>false</literal>, the caller should proceed to initialize the
|
||||||
|
contents of the reserved shared memory. If <literal>foundPtr</literal>
|
||||||
|
is set to <literal>true</literal>, the shared memory was already
|
||||||
|
initialized by another backend, and the caller need not initialize
|
||||||
|
further.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To avoid race conditions, each backend should use the LWLock
|
||||||
|
<function>AddinShmemInitLock</function> when initializing its allocation
|
||||||
|
of shared memory, as shown here:
|
||||||
|
<programlisting>
|
||||||
|
static mystruct *ptr = NULL;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
||||||
|
ptr = ShmemInitStruct("my struct name", size, &found);
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
... initialize contents of shared memory ...
|
||||||
|
ptr->locks = GetNamedLWLockTranche("my tranche name");
|
||||||
|
}
|
||||||
|
LWLockRelease(AddinShmemInitLock);
|
||||||
|
</programlisting>
|
||||||
|
<literal>shmem_startup_hook</literal> provides a convenient place for the
|
||||||
|
initialization code, but it is not strictly required that all such code
|
||||||
|
be placed in this hook. Each backend will execute the registered
|
||||||
|
<literal>shmem_startup_hook</literal> shortly after it attaches to shared
|
||||||
|
memory. Note that add-ins should still acquire
|
||||||
|
<function>AddinShmemInitLock</function> within this hook, as shown in the
|
||||||
|
example above.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
An example of a <literal>shmem_request_hook</literal> and
|
||||||
|
<literal>shmem_startup_hook</literal> can be found in
|
||||||
|
<filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in
|
||||||
|
the <productname>PostgreSQL</productname> source tree.
|
||||||
|
</para>
|
||||||
|
</sect3>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2 id="xfunc-addin-lwlocks">
|
||||||
|
<title>LWLocks</title>
|
||||||
|
|
||||||
|
<sect3 id="xfunc-addin-lwlocks-at-startup">
|
||||||
|
<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
|
||||||
|
<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
|
||||||
|
<function>_PG_init</function> function. This
|
||||||
|
<literal>shmem_request_hook</literal> can reserve LWLocks by calling:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
|
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
|
||||||
</programlisting>
|
</programlisting>
|
||||||
from your <literal>shmem_request_hook</literal>. This will ensure that an array of
|
This ensures that an array of <literal>num_lwlocks</literal> LWLocks is
|
||||||
<literal>num_lwlocks</literal> LWLocks is available under the name
|
available under the name <literal>tranche_name</literal>. A pointer to
|
||||||
<literal>tranche_name</literal>. Use <function>GetNamedLWLockTranche</function>
|
this array can be obtained by calling:
|
||||||
to get a pointer to this array.
|
<programlisting>
|
||||||
</para>
|
LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)
|
||||||
<para>
|
</programlisting>
|
||||||
An example of a <literal>shmem_request_hook</literal> can be found in
|
</para>
|
||||||
<filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in the
|
</sect3>
|
||||||
<productname>PostgreSQL</productname> source tree.
|
|
||||||
</para>
|
<sect3 id="xfunc-addin-lwlocks-after-startup">
|
||||||
<para>
|
<title>Requesting LWLocks After Startup</title>
|
||||||
There is another, more flexible method of obtaining LWLocks. First,
|
|
||||||
allocate a <literal>tranche_id</literal> from a shared counter by
|
<para>
|
||||||
calling:
|
There is another, more flexible method of obtaining LWLocks that can be
|
||||||
|
done after server startup and outside a
|
||||||
|
<literal>shmem_request_hook</literal>. To do so, first allocate a
|
||||||
|
<literal>tranche_id</literal> by calling:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
int LWLockNewTrancheId(void)
|
int LWLockNewTrancheId(void)
|
||||||
</programlisting>
|
</programlisting>
|
||||||
Next, each individual process using the <literal>tranche_id</literal>
|
Next, initialize each LWLock, passing the new
|
||||||
should associate it with a <literal>tranche_name</literal> by calling:
|
<literal>tranche_id</literal> as an argument:
|
||||||
<programlisting>
|
|
||||||
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
|
|
||||||
</programlisting>
|
|
||||||
It is also required to call <function>LWLockInitialize</function> once
|
|
||||||
per LWLock, passing the <literal>tranche_id</literal> as argument:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
void LWLockInitialize(LWLock *lock, int tranche_id)
|
void LWLockInitialize(LWLock *lock, int tranche_id)
|
||||||
</programlisting>
|
</programlisting>
|
||||||
A complete usage example of <function>LWLockNewTrancheId</function>,
|
Similar to shared memory, each backend should ensure that only one
|
||||||
<function>LWLockInitialize</function> and
|
process allocates a new <literal>tranche_id</literal> and initializes
|
||||||
<function>LWLockRegisterTranche</function> can be found in
|
each new LWLock. One way to do this is to only call these functions in
|
||||||
<filename>contrib/pg_prewarm/autoprewarm.c</filename> in the
|
your shared memory initialization code with the
|
||||||
<productname>PostgreSQL</productname> source tree.
|
<function>AddinShmemInitLock</function> held exclusively.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
To avoid possible race-conditions, each backend should use the LWLock
|
<para>
|
||||||
<function>AddinShmemInitLock</function> when connecting to and initializing
|
Finally, each backend using the <literal>tranche_id</literal> should
|
||||||
its allocation of shared memory, as shown here:
|
associate it with a <literal>tranche_name</literal> by calling:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
static mystruct *ptr = NULL;
|
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
|
||||||
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
bool found;
|
|
||||||
|
|
||||||
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
|
|
||||||
ptr = ShmemInitStruct("my struct name", size, &found);
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
initialize contents of shmem area;
|
|
||||||
acquire any requested LWLocks using:
|
|
||||||
ptr->locks = GetNamedLWLockTranche("my tranche name");
|
|
||||||
}
|
|
||||||
LWLockRelease(AddinShmemInitLock);
|
|
||||||
}
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
It is convenient to use <literal>shmem_startup_hook</literal> which allows
|
<para>
|
||||||
placing all the code responsible for initializing shared memory in one
|
A complete usage example of <function>LWLockNewTrancheId</function>,
|
||||||
place. When using <literal>shmem_startup_hook</literal> the extension
|
<function>LWLockInitialize</function>, and
|
||||||
still needs to acquire <function>AddinShmemInitLock</function> in order to
|
<function>LWLockRegisterTranche</function> can be found in
|
||||||
work properly on all the supported platforms.
|
<filename>contrib/pg_prewarm/autoprewarm.c</filename> in the
|
||||||
</para>
|
<productname>PostgreSQL</productname> source tree.
|
||||||
|
</para>
|
||||||
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="xfunc-addin-wait-events">
|
<sect2 id="xfunc-addin-wait-events">
|
||||||
|
Reference in New Issue
Block a user