Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+10-7
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

+17
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

+3
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

+13
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

+10
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

+14
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

+2
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)