mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
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
This commit is contained in:
@ -3619,17 +3619,20 @@ INJECTION_POINT(name);
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
An injection point with a given <literal>name</literal> can be loaded
|
Executing an injection point can require allocating a small amount of
|
||||||
using macro:
|
memory, which can fail. If you need to have an injection point in a
|
||||||
|
critical section where dynamic allocations are not allowed, you can use
|
||||||
|
a two-step approach with the following macros:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
INJECTION_POINT_LOAD(name);
|
INJECTION_POINT_LOAD(name);
|
||||||
|
INJECTION_POINT_CACHED(name);
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
||||||
This will load the injection point callback into the process cache,
|
Before entering the critical section,
|
||||||
doing all memory allocations at this stage without running the callback.
|
call <function>INJECTION_POINT_LOAD</function>. It checks the shared
|
||||||
This is useful when an injection point is attached in a critical section
|
memory state, and loads the callback into backend-private memory if it is
|
||||||
where no memory can be allocated: load the injection point outside the
|
active. Inside the critical section, use
|
||||||
critical section, then run it in the critical section.
|
<function>INJECTION_POINT_CACHED</function> to execute the callback.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -553,3 +553,20 @@ InjectionPointRun(const char *name)
|
|||||||
elog(ERROR, "Injection points are not supported by this build");
|
elog(ERROR, "Injection points are not supported by this build");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execute an injection point directly from the cache, if defined.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
InjectionPointCached(const char *name)
|
||||||
|
{
|
||||||
|
#ifdef USE_INJECTION_POINTS
|
||||||
|
InjectionPointCacheEntry *cache_entry;
|
||||||
|
|
||||||
|
cache_entry = injection_point_cache_get(name);
|
||||||
|
if (cache_entry)
|
||||||
|
cache_entry->callback(name, cache_entry->private_data);
|
||||||
|
#else
|
||||||
|
elog(ERROR, "Injection points are not supported by this build");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -17,9 +17,11 @@
|
|||||||
#ifdef USE_INJECTION_POINTS
|
#ifdef USE_INJECTION_POINTS
|
||||||
#define INJECTION_POINT_LOAD(name) InjectionPointLoad(name)
|
#define INJECTION_POINT_LOAD(name) InjectionPointLoad(name)
|
||||||
#define INJECTION_POINT(name) InjectionPointRun(name)
|
#define INJECTION_POINT(name) InjectionPointRun(name)
|
||||||
|
#define INJECTION_POINT_CACHED(name) InjectionPointCached(name)
|
||||||
#else
|
#else
|
||||||
#define INJECTION_POINT_LOAD(name) ((void) name)
|
#define INJECTION_POINT_LOAD(name) ((void) name)
|
||||||
#define INJECTION_POINT(name) ((void) name)
|
#define INJECTION_POINT(name) ((void) name)
|
||||||
|
#define INJECTION_POINT_CACHED(name) ((void) name)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -38,6 +40,7 @@ extern void InjectionPointAttach(const char *name,
|
|||||||
int private_data_size);
|
int private_data_size);
|
||||||
extern void InjectionPointLoad(const char *name);
|
extern void InjectionPointLoad(const char *name);
|
||||||
extern void InjectionPointRun(const char *name);
|
extern void InjectionPointRun(const char *name);
|
||||||
|
extern void InjectionPointCached(const char *name);
|
||||||
extern bool InjectionPointDetach(const char *name);
|
extern bool InjectionPointDetach(const char *name);
|
||||||
|
|
||||||
#endif /* INJECTION_POINT_H */
|
#endif /* INJECTION_POINT_H */
|
||||||
|
@ -129,6 +129,12 @@ SELECT injection_points_detach('TestInjectionLog2');
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- Loading
|
-- Loading
|
||||||
|
SELECT injection_points_cached('TestInjectionLogLoad'); -- nothing in cache
|
||||||
|
injection_points_cached
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
|
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
|
||||||
injection_points_load
|
injection_points_load
|
||||||
-----------------------
|
-----------------------
|
||||||
@ -147,6 +153,13 @@ SELECT injection_points_load('TestInjectionLogLoad'); -- nothing happens
|
|||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT injection_points_cached('TestInjectionLogLoad'); -- runs from cache
|
||||||
|
NOTICE: notice triggered for injection point TestInjectionLogLoad
|
||||||
|
injection_points_cached
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT injection_points_run('TestInjectionLogLoad'); -- runs from cache
|
SELECT injection_points_run('TestInjectionLogLoad'); -- runs from cache
|
||||||
NOTICE: notice triggered for injection point TestInjectionLogLoad
|
NOTICE: notice triggered for injection point TestInjectionLogLoad
|
||||||
injection_points_run
|
injection_points_run
|
||||||
|
@ -34,6 +34,16 @@ RETURNS void
|
|||||||
AS 'MODULE_PATHNAME', 'injection_points_run'
|
AS 'MODULE_PATHNAME', 'injection_points_run'
|
||||||
LANGUAGE C STRICT PARALLEL UNSAFE;
|
LANGUAGE C STRICT PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- injection_points_cached()
|
||||||
|
--
|
||||||
|
-- Executes the action attached to the injection point, from local cache.
|
||||||
|
--
|
||||||
|
CREATE FUNCTION injection_points_cached(IN point_name TEXT)
|
||||||
|
RETURNS void
|
||||||
|
AS 'MODULE_PATHNAME', 'injection_points_cached'
|
||||||
|
LANGUAGE C STRICT PARALLEL UNSAFE;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- injection_points_wakeup()
|
-- injection_points_wakeup()
|
||||||
--
|
--
|
||||||
|
@ -333,6 +333,20 @@ injection_points_run(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SQL function for triggering an injection point from cache.
|
||||||
|
*/
|
||||||
|
PG_FUNCTION_INFO_V1(injection_points_cached);
|
||||||
|
Datum
|
||||||
|
injection_points_cached(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
||||||
|
|
||||||
|
INJECTION_POINT_CACHED(name);
|
||||||
|
|
||||||
|
PG_RETURN_VOID();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SQL function for waking up an injection point waiting in injection_wait().
|
* SQL function for waking up an injection point waiting in injection_wait().
|
||||||
*/
|
*/
|
||||||
|
@ -42,9 +42,11 @@ SELECT injection_points_run('TestInjectionLog2'); -- notice
|
|||||||
SELECT injection_points_detach('TestInjectionLog2');
|
SELECT injection_points_detach('TestInjectionLog2');
|
||||||
|
|
||||||
-- Loading
|
-- Loading
|
||||||
|
SELECT injection_points_cached('TestInjectionLogLoad'); -- nothing in cache
|
||||||
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
|
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
|
||||||
SELECT injection_points_attach('TestInjectionLogLoad', 'notice');
|
SELECT injection_points_attach('TestInjectionLogLoad', 'notice');
|
||||||
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing happens
|
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing happens
|
||||||
|
SELECT injection_points_cached('TestInjectionLogLoad'); -- runs from cache
|
||||||
SELECT injection_points_run('TestInjectionLogLoad'); -- runs from cache
|
SELECT injection_points_run('TestInjectionLogLoad'); -- runs from cache
|
||||||
SELECT injection_points_detach('TestInjectionLogLoad');
|
SELECT injection_points_detach('TestInjectionLogLoad');
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user