Skip to content

Commit a0a5869

Browse files
committed
Add INJECTION_POINT_CACHED() to run injection points directly from cache
This new macro is able to perform a direct lookup from the local cache of injection points (refreshed each time a point is loaded or run), without touching the shared memory state of injection points at all. This works in combination with INJECTION_POINT_LOAD(), and it is better than INJECTION_POINT() in a critical section due to the fact that it would avoid all memory allocations should a concurrent detach happen since a LOAD(), as it retrieves a callback from the backend-private memory. The documentation is updated to describe in more details how to use this new macro with a load. Some tests are added to the module injection_points based on a new SQL function that acts as a wrapper of INJECTION_POINT_CACHED(). Based on a suggestion from Heikki Linnakangas. Author: Heikki Linnakangas, Michael Paquier Discussion: https://postgr.es/m/58d588d0-e63f-432f-9181-bed29313dece@iki.fi
1 parent 6159331 commit a0a5869

File tree

7 files changed

+69
-7
lines changed

7 files changed

+69
-7
lines changed

doc/src/sgml/xfunc.sgml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3619,17 +3619,20 @@ INJECTION_POINT(name);
36193619
</para>
36203620

36213621
<para>
3622-
An injection point with a given <literal>name</literal> can be loaded
3623-
using macro:
3622+
Executing an injection point can require allocating a small amount of
3623+
memory, which can fail. If you need to have an injection point in a
3624+
critical section where dynamic allocations are not allowed, you can use
3625+
a two-step approach with the following macros:
36243626
<programlisting>
36253627
INJECTION_POINT_LOAD(name);
3628+
INJECTION_POINT_CACHED(name);
36263629
</programlisting>
36273630

3628-
This will load the injection point callback into the process cache,
3629-
doing all memory allocations at this stage without running the callback.
3630-
This is useful when an injection point is attached in a critical section
3631-
where no memory can be allocated: load the injection point outside the
3632-
critical section, then run it in the critical section.
3631+
Before entering the critical section,
3632+
call <function>INJECTION_POINT_LOAD</function>. It checks the shared
3633+
memory state, and loads the callback into backend-private memory if it is
3634+
active. Inside the critical section, use
3635+
<function>INJECTION_POINT_CACHED</function> to execute the callback.
36333636
</para>
36343637

36353638
<para>

src/backend/utils/misc/injection_point.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,3 +553,20 @@ InjectionPointRun(const char *name)
553553
elog(ERROR, "Injection points are not supported by this build");
554554
#endif
555555
}
556+
557+
/*
558+
* Execute an injection point directly from the cache, if defined.
559+
*/
560+
void
561+
InjectionPointCached(const char *name)
562+
{
563+
#ifdef USE_INJECTION_POINTS
564+
InjectionPointCacheEntry *cache_entry;
565+
566+
cache_entry = injection_point_cache_get(name);
567+
if (cache_entry)
568+
cache_entry->callback(name, cache_entry->private_data);
569+
#else
570+
elog(ERROR, "Injection points are not supported by this build");
571+
#endif
572+
}

src/include/utils/injection_point.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
#ifdef USE_INJECTION_POINTS
1818
#define INJECTION_POINT_LOAD(name) InjectionPointLoad(name)
1919
#define INJECTION_POINT(name) InjectionPointRun(name)
20+
#define INJECTION_POINT_CACHED(name) InjectionPointCached(name)
2021
#else
2122
#define INJECTION_POINT_LOAD(name) ((void) name)
2223
#define INJECTION_POINT(name) ((void) name)
24+
#define INJECTION_POINT_CACHED(name) ((void) name)
2325
#endif
2426

2527
/*
@@ -38,6 +40,7 @@ extern void InjectionPointAttach(const char *name,
3840
int private_data_size);
3941
extern void InjectionPointLoad(const char *name);
4042
extern void InjectionPointRun(const char *name);
43+
extern void InjectionPointCached(const char *name);
4144
extern bool InjectionPointDetach(const char *name);
4245

4346
#endif /* INJECTION_POINT_H */

src/test/modules/injection_points/expected/injection_points.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ SELECT injection_points_detach('TestInjectionLog2');
129129
(1 row)
130130

131131
-- Loading
132+
SELECT injection_points_cached('TestInjectionLogLoad'); -- nothing in cache
133+
injection_points_cached
134+
-------------------------
135+
136+
(1 row)
137+
132138
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
133139
injection_points_load
134140
-----------------------
@@ -147,6 +153,13 @@ SELECT injection_points_load('TestInjectionLogLoad'); -- nothing happens
147153

148154
(1 row)
149155

156+
SELECT injection_points_cached('TestInjectionLogLoad'); -- runs from cache
157+
NOTICE: notice triggered for injection point TestInjectionLogLoad
158+
injection_points_cached
159+
-------------------------
160+
161+
(1 row)
162+
150163
SELECT injection_points_run('TestInjectionLogLoad'); -- runs from cache
151164
NOTICE: notice triggered for injection point TestInjectionLogLoad
152165
injection_points_run

src/test/modules/injection_points/injection_points--1.0.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ RETURNS void
3434
AS 'MODULE_PATHNAME', 'injection_points_run'
3535
LANGUAGE C STRICT PARALLEL UNSAFE;
3636

37+
--
38+
-- injection_points_cached()
39+
--
40+
-- Executes the action attached to the injection point, from local cache.
41+
--
42+
CREATE FUNCTION injection_points_cached(IN point_name TEXT)
43+
RETURNS void
44+
AS 'MODULE_PATHNAME', 'injection_points_cached'
45+
LANGUAGE C STRICT PARALLEL UNSAFE;
46+
3747
--
3848
-- injection_points_wakeup()
3949
--

src/test/modules/injection_points/injection_points.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,20 @@ injection_points_run(PG_FUNCTION_ARGS)
333333
PG_RETURN_VOID();
334334
}
335335

336+
/*
337+
* SQL function for triggering an injection point from cache.
338+
*/
339+
PG_FUNCTION_INFO_V1(injection_points_cached);
340+
Datum
341+
injection_points_cached(PG_FUNCTION_ARGS)
342+
{
343+
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
344+
345+
INJECTION_POINT_CACHED(name);
346+
347+
PG_RETURN_VOID();
348+
}
349+
336350
/*
337351
* SQL function for waking up an injection point waiting in injection_wait().
338352
*/

src/test/modules/injection_points/sql/injection_points.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ SELECT injection_points_run('TestInjectionLog2'); -- notice
4242
SELECT injection_points_detach('TestInjectionLog2');
4343

4444
-- Loading
45+
SELECT injection_points_cached('TestInjectionLogLoad'); -- nothing in cache
4546
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
4647
SELECT injection_points_attach('TestInjectionLogLoad', 'notice');
4748
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing happens
49+
SELECT injection_points_cached('TestInjectionLogLoad'); -- runs from cache
4850
SELECT injection_points_run('TestInjectionLogLoad'); -- runs from cache
4951
SELECT injection_points_detach('TestInjectionLogLoad');
5052

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy