@@ -129,20 +129,47 @@ injection_point_cache_remove(const char *name)
129
129
(void ) hash_search (InjectionPointCache , name , HASH_REMOVE , NULL );
130
130
}
131
131
132
+ /*
133
+ * injection_point_cache_load
134
+ *
135
+ * Load an injection point into the local cache.
136
+ */
137
+ static void
138
+ injection_point_cache_load (InjectionPointEntry * entry_by_name )
139
+ {
140
+ char path [MAXPGPATH ];
141
+ void * injection_callback_local ;
142
+
143
+ snprintf (path , MAXPGPATH , "%s/%s%s" , pkglib_path ,
144
+ entry_by_name -> library , DLSUFFIX );
145
+
146
+ if (!pg_file_exists (path ))
147
+ elog (ERROR , "could not find library \"%s\" for injection point \"%s\"" ,
148
+ path , entry_by_name -> name );
149
+
150
+ injection_callback_local = (void * )
151
+ load_external_function (path , entry_by_name -> function , false, NULL );
152
+
153
+ if (injection_callback_local == NULL )
154
+ elog (ERROR , "could not find function \"%s\" in library \"%s\" for injection point \"%s\"" ,
155
+ entry_by_name -> function , path , entry_by_name -> name );
156
+
157
+ /* add it to the local cache when found */
158
+ injection_point_cache_add (entry_by_name -> name , injection_callback_local ,
159
+ entry_by_name -> private_data );
160
+ }
161
+
132
162
/*
133
163
* injection_point_cache_get
134
164
*
135
165
* Retrieve an injection point from the local cache, if any.
136
166
*/
137
- static InjectionPointCallback
138
- injection_point_cache_get (const char * name , const void * * private_data )
167
+ static InjectionPointCacheEntry *
168
+ injection_point_cache_get (const char * name )
139
169
{
140
170
bool found ;
141
171
InjectionPointCacheEntry * entry ;
142
172
143
- if (private_data )
144
- * private_data = NULL ;
145
-
146
173
/* no callback if no cache yet */
147
174
if (InjectionPointCache == NULL )
148
175
return NULL ;
@@ -151,11 +178,7 @@ injection_point_cache_get(const char *name, const void **private_data)
151
178
hash_search (InjectionPointCache , name , HASH_FIND , & found );
152
179
153
180
if (found )
154
- {
155
- if (private_data )
156
- * private_data = entry -> private_data ;
157
- return entry -> callback ;
158
- }
181
+ return entry ;
159
182
160
183
return NULL ;
161
184
}
@@ -278,6 +301,52 @@ InjectionPointDetach(const char *name)
278
301
#endif
279
302
}
280
303
304
+ /*
305
+ * Load an injection point into the local cache.
306
+ *
307
+ * This is useful to be able to load an injection point before running it,
308
+ * especially if the injection point is called in a code path where memory
309
+ * allocations cannot happen, like critical sections.
310
+ */
311
+ void
312
+ InjectionPointLoad (const char * name )
313
+ {
314
+ #ifdef USE_INJECTION_POINTS
315
+ InjectionPointEntry * entry_by_name ;
316
+ bool found ;
317
+
318
+ LWLockAcquire (InjectionPointLock , LW_SHARED );
319
+ entry_by_name = (InjectionPointEntry * )
320
+ hash_search (InjectionPointHash , name ,
321
+ HASH_FIND , & found );
322
+
323
+ /*
324
+ * If not found, do nothing and remove it from the local cache if it
325
+ * existed there.
326
+ */
327
+ if (!found )
328
+ {
329
+ injection_point_cache_remove (name );
330
+ LWLockRelease (InjectionPointLock );
331
+ return ;
332
+ }
333
+
334
+ /* Check first the local cache, and leave if this entry exists. */
335
+ if (injection_point_cache_get (name ) != NULL )
336
+ {
337
+ LWLockRelease (InjectionPointLock );
338
+ return ;
339
+ }
340
+
341
+ /* Nothing? Then load it and leave */
342
+ injection_point_cache_load (entry_by_name );
343
+
344
+ LWLockRelease (InjectionPointLock );
345
+ #else
346
+ elog (ERROR , "Injection points are not supported by this build" );
347
+ #endif
348
+ }
349
+
281
350
/*
282
351
* Execute an injection point, if defined.
283
352
*
@@ -290,8 +359,7 @@ InjectionPointRun(const char *name)
290
359
#ifdef USE_INJECTION_POINTS
291
360
InjectionPointEntry * entry_by_name ;
292
361
bool found ;
293
- InjectionPointCallback injection_callback ;
294
- const void * private_data ;
362
+ InjectionPointCacheEntry * cache_entry ;
295
363
296
364
LWLockAcquire (InjectionPointLock , LW_SHARED );
297
365
entry_by_name = (InjectionPointEntry * )
@@ -313,37 +381,18 @@ InjectionPointRun(const char *name)
313
381
* Check if the callback exists in the local cache, to avoid unnecessary
314
382
* external loads.
315
383
*/
316
- if (injection_point_cache_get (name , NULL ) == NULL )
384
+ if (injection_point_cache_get (name ) == NULL )
317
385
{
318
- char path [MAXPGPATH ];
319
- InjectionPointCallback injection_callback_local ;
320
-
321
- /* not found in local cache, so load and register */
322
- snprintf (path , MAXPGPATH , "%s/%s%s" , pkglib_path ,
323
- entry_by_name -> library , DLSUFFIX );
324
-
325
- if (!pg_file_exists (path ))
326
- elog (ERROR , "could not find library \"%s\" for injection point \"%s\"" ,
327
- path , name );
328
-
329
- injection_callback_local = (InjectionPointCallback )
330
- load_external_function (path , entry_by_name -> function , false, NULL );
331
-
332
- if (injection_callback_local == NULL )
333
- elog (ERROR , "could not find function \"%s\" in library \"%s\" for injection point \"%s\"" ,
334
- entry_by_name -> function , path , name );
335
-
336
- /* add it to the local cache when found */
337
- injection_point_cache_add (name , injection_callback_local ,
338
- entry_by_name -> private_data );
386
+ /* not found in local cache, so load and register it */
387
+ injection_point_cache_load (entry_by_name );
339
388
}
340
389
341
390
/* Now loaded, so get it. */
342
- injection_callback = injection_point_cache_get (name , & private_data );
391
+ cache_entry = injection_point_cache_get (name );
343
392
344
393
LWLockRelease (InjectionPointLock );
345
394
346
- injection_callback (name , private_data );
395
+ cache_entry -> callback (name , cache_entry -> private_data );
347
396
#else
348
397
elog (ERROR , "Injection points are not supported by this build" );
349
398
#endif
0 commit comments