mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +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