mirror of https://github.com/postgres/postgres
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:
parent
6159331acf
commit
a0a5869a85
|
@ -3619,17 +3619,20 @@ INJECTION_POINT(name);
|
|||
</para>
|
||||
|
||||
<para>
|
||||
An injection point with a given <literal>name</literal> can be loaded
|
||||
using macro:
|
||||
Executing an injection point can require allocating a small amount of
|
||||
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>
|
||||
INJECTION_POINT_LOAD(name);
|
||||
INJECTION_POINT_CACHED(name);
|
||||
</programlisting>
|
||||
|
||||
This will load the injection point callback into the process cache,
|
||||
doing all memory allocations at this stage without running the callback.
|
||||
This is useful when an injection point is attached in a critical section
|
||||
where no memory can be allocated: load the injection point outside the
|
||||
critical section, then run it in the critical section.
|
||||
Before entering the critical section,
|
||||
call <function>INJECTION_POINT_LOAD</function>. It checks the shared
|
||||
memory state, and loads the callback into backend-private memory if it is
|
||||
active. Inside the critical section, use
|
||||
<function>INJECTION_POINT_CACHED</function> to execute the callback.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
|
|
@ -553,3 +553,20 @@ InjectionPointRun(const char *name)
|
|||
elog(ERROR, "Injection points are not supported by this build");
|
||||
#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
|
||||
#define INJECTION_POINT_LOAD(name) InjectionPointLoad(name)
|
||||
#define INJECTION_POINT(name) InjectionPointRun(name)
|
||||
#define INJECTION_POINT_CACHED(name) InjectionPointCached(name)
|
||||
#else
|
||||
#define INJECTION_POINT_LOAD(name) ((void) name)
|
||||
#define INJECTION_POINT(name) ((void) name)
|
||||
#define INJECTION_POINT_CACHED(name) ((void) name)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -38,6 +40,7 @@ extern void InjectionPointAttach(const char *name,
|
|||
int private_data_size);
|
||||
extern void InjectionPointLoad(const char *name);
|
||||
extern void InjectionPointRun(const char *name);
|
||||
extern void InjectionPointCached(const char *name);
|
||||
extern bool InjectionPointDetach(const char *name);
|
||||
|
||||
#endif /* INJECTION_POINT_H */
|
||||
|
|
|
@ -129,6 +129,12 @@ SELECT injection_points_detach('TestInjectionLog2');
|
|||
(1 row)
|
||||
|
||||
-- Loading
|
||||
SELECT injection_points_cached('TestInjectionLogLoad'); -- nothing in cache
|
||||
injection_points_cached
|
||||
-------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
|
||||
injection_points_load
|
||||
-----------------------
|
||||
|
@ -147,6 +153,13 @@ SELECT injection_points_load('TestInjectionLogLoad'); -- nothing happens
|
|||
|
||||
(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
|
||||
NOTICE: notice triggered for injection point TestInjectionLogLoad
|
||||
injection_points_run
|
||||
|
|
|
@ -34,6 +34,16 @@ RETURNS void
|
|||
AS 'MODULE_PATHNAME', 'injection_points_run'
|
||||
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()
|
||||
--
|
||||
|
|
|
@ -333,6 +333,20 @@ injection_points_run(PG_FUNCTION_ARGS)
|
|||
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().
|
||||
*/
|
||||
|
|
|
@ -42,9 +42,11 @@ SELECT injection_points_run('TestInjectionLog2'); -- notice
|
|||
SELECT injection_points_detach('TestInjectionLog2');
|
||||
|
||||
-- Loading
|
||||
SELECT injection_points_cached('TestInjectionLogLoad'); -- nothing in cache
|
||||
SELECT injection_points_load('TestInjectionLogLoad'); -- nothing
|
||||
SELECT injection_points_attach('TestInjectionLogLoad', 'notice');
|
||||
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_detach('TestInjectionLogLoad');
|
||||
|
||||
|
|
Loading…
Reference in New Issue