aboutsummaryrefslogtreecommitdiff
path: root/doc/src
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2024-01-22 10:15:50 +0900
committerMichael Paquier <michael@paquier.xyz>2024-01-22 10:15:50 +0900
commitd86d20f0ba79451f19782dbb5fbf206746aaffd1 (patch)
tree2475689ab3ac1ff5fec2793e69d6306cfa3c8f6b /doc/src
parentc03d91d9be378975bcdbfa3e5d40e17288e6f13f (diff)
downloadpostgresql-d86d20f0ba79451f19782dbb5fbf206746aaffd1.tar.gz
postgresql-d86d20f0ba79451f19782dbb5fbf206746aaffd1.zip
Add backend support for injection points
Injection points are a new facility that makes possible for developers to run custom code in pre-defined code paths. Its goal is to provide ways to design and run advanced tests, for cases like: - Race conditions, where processes need to do actions in a controlled ordered manner. - Forcing a state, like an ERROR, FATAL or even PANIC for OOM, to force recovery, etc. - Arbitrary sleeps. This implements some basics, and there are plans to extend it more in the future depending on what's required. Hence, this commit adds a set of routines in the backend that allows developers to attach, detach and run injection points: - A code path calling an injection point can be declared with the macro INJECTION_POINT(name). - InjectionPointAttach() and InjectionPointDetach() to respectively attach and detach a callback to/from an injection point. An injection point name is registered in a shmem hash table with a library name and a function name, which will be used to load the callback attached to an injection point when its code path is run. Injection point names are just strings, so as an injection point can be declared and run by out-of-core extensions and modules, with callbacks defined in external libraries. This facility is hidden behind a dedicated switch for ./configure and meson, disabled by default. Note that backends use a local cache to store callbacks already loaded, cleaning up their cache if a callback has found to be removed on a best-effort basis. This could be refined further but any tests but what we have here was fine with the tests I've written while implementing these backend APIs. Author: Michael Paquier, with doc suggestions from Ashutosh Bapat. Reviewed-by: Ashutosh Bapat, Nathan Bossart, Álvaro Herrera, Dilip Kumar, Amul Sul, Nazir Bilal Yavuz Discussion: https://postgr.es/m/ZTiV8tn_MIb_H2rE@paquier.xyz
Diffstat (limited to 'doc/src')
-rw-r--r--doc/src/sgml/installation.sgml30
-rw-r--r--doc/src/sgml/xfunc.sgml69
2 files changed, 99 insertions, 0 deletions
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index bb55695300c..e73902b3f8f 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1656,6 +1656,21 @@ build-postgresql:
</listitem>
</varlistentry>
+ <varlistentry id="configure-option-enable-injection-points">
+ <term><option>--enable-injection-points</option></term>
+ <listitem>
+ <para>
+ Compiles <productname>PostgreSQL</productname> with support for
+ injection points in the server. Injection points allow to run
+ user-defined code from within the server in pre-defined code paths.
+ This helps in testing and in the investigation of concurrency scenarios
+ in a controlled fashion. This option is disabled by default. See
+ <xref linkend="xfunc-addin-injection-points"/> for more details. This
+ option is intended to be used only by developers for testing.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="configure-option-with-segsize-blocks">
<term><option>--with-segsize-blocks=SEGSIZE_BLOCKS</option></term>
<listitem>
@@ -3160,6 +3175,21 @@ ninja install
</listitem>
</varlistentry>
+ <varlistentry id="configure-injection-points-meson">
+ <term><option>-Dinjection_points={ true | false }</option></term>
+ <listitem>
+ <para>
+ Compiles <productname>PostgreSQL</productname> with support for
+ injection points in the server. Injection points allow to run
+ user-defined code from within the server in pre-defined code paths.
+ This helps in testing and in the investigation of concurrency scenarios
+ in a controlled fashion. This option is disabled by default. See
+ <xref linkend="xfunc-addin-injection-points"/> for more details. This
+ option is intended to be used only by developers for testing.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="configure-segsize-blocks-meson">
<term><option>-Dsegsize_blocks=SEGSIZE_BLOCKS</option></term>
<listitem>
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 0ad9f38e902..8a79ad0943f 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3599,6 +3599,75 @@ uint32 WaitEventExtensionNew(const char *wait_event_name)
</para>
</sect2>
+ <sect2 id="xfunc-addin-injection-points">
+ <title>Injection Points</title>
+
+ <para>
+ An injection point with a given <literal>name</literal> is declared using
+ macro:
+<programlisting>
+INJECTION_POINT(name);
+</programlisting>
+
+ There are a few injection points already declared at strategic points
+ within the server code. After adding a new injection point the code needs
+ to be compiled in order for that injection point to be available in the
+ binary. Add-ins written in C-language can declare injection points in
+ their own code using the same macro.
+ </para>
+
+ <para>
+ Add-ins can attach callbacks to an already-declared injection point by
+ calling:
+<programlisting>
+extern void InjectionPointAttach(const char *name,
+ const char *library,
+ const char *function);
+</programlisting>
+
+ <literal>name</literal> is the name of the injection point, which when
+ reached during execution will execute the <literal>function</literal>
+ loaded from <literal>library</literal>.
+ </para>
+
+ <para>
+ Here is an example of callback for
+ <literal>InjectionPointCallback</literal>:
+<programlisting>
+static void
+custom_injection_callback(const char *name)
+{
+ elog(NOTICE, "%s: executed custom callback", name);
+}
+</programlisting>
+ This callback prints a message to server error log with severity
+ <literal>NOTICE</literal>, but callbacks may implement more complex
+ logic.
+ </para>
+
+ <para>
+ Optionally, it is possible to detach an injection point by calling:
+<programlisting>
+extern void InjectionPointDetach(const char *name);
+</programlisting>
+ </para>
+
+ <para>
+ A callback attached to an injection point is available across all the
+ backends including the backends started after
+ <literal>InjectionPointAttach</literal> is called. It remains attached
+ while the server is running or until the injection point is detached
+ using <literal>InjectionPointDetach</literal>.
+ </para>
+
+ <para>
+ Enabling injections points requires
+ <option>--enable-injection-points</option> with
+ <command>configure</command> or <option>-Dinjection_points=true</option>
+ with <application>Meson</application>.
+ </para>
+ </sect2>
+
<sect2 id="extend-cpp">
<title>Using C++ for Extensibility</title>