PostgreSQL Source Code git master
Loading...
Searching...
No Matches
injection_points.c File Reference
#include "postgres.h"
#include "fmgr.h"
#include "funcapi.h"
#include "injection_points.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "nodes/value.h"
#include "storage/dsm_registry.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/tuplestore.h"
#include "utils/wait_event.h"
Include dependency graph for injection_points.c:

Go to the source code of this file.

Data Structures

struct  InjectionPointSharedState
 

Macros

#define INJ_MAX_WAIT   8
 
#define INJ_NAME_MAXLEN   64
 
#define INJ_WAIT_INITIAL_US   10 /* 10us */
 
#define INJ_WAIT_MAX_US   100000 /* 100ms */
 
#define NUM_INJECTION_POINTS_LIST   3
 

Typedefs

typedef struct InjectionPointSharedState InjectionPointSharedState
 

Functions

PGDLLEXPORT void injection_error (const char *name, const void *private_data, void *arg)
 
PGDLLEXPORT void injection_notice (const char *name, const void *private_data, void *arg)
 
PGDLLEXPORT void injection_wait (const char *name, const void *private_data, void *arg)
 
static void injection_shmem_request (void *arg)
 
static void injection_shmem_init (void *arg)
 
static void injection_point_init_state (void *ptr, void *arg)
 
static void injection_init_shmem (void)
 
static bool injection_point_allowed (const InjectionPointCondition *condition)
 
static void injection_points_cleanup (int code, Datum arg)
 
 PG_FUNCTION_INFO_V1 (injection_points_attach)
 
Datum injection_points_attach (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_attach_func)
 
Datum injection_points_attach_func (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_load)
 
Datum injection_points_load (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_run)
 
Datum injection_points_run (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_cached)
 
Datum injection_points_cached (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_wakeup)
 
Datum injection_points_wakeup (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_set_local)
 
Datum injection_points_set_local (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_detach)
 
Datum injection_points_detach (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (injection_points_list)
 
Datum injection_points_list (PG_FUNCTION_ARGS)
 
void _PG_init (void)
 

Variables

 PG_MODULE_MAGIC
 
static Listinj_list_local = NIL
 
static InjectionPointSharedStateinj_state = NULL
 
static bool injection_point_local = false
 
static const ShmemCallbacks injection_shmem_callbacks
 

Macro Definition Documentation

◆ INJ_MAX_WAIT

#define INJ_MAX_WAIT   8

Definition at line 41 of file injection_points.c.

◆ INJ_NAME_MAXLEN

#define INJ_NAME_MAXLEN   64

Definition at line 42 of file injection_points.c.

◆ INJ_WAIT_INITIAL_US

#define INJ_WAIT_INITIAL_US   10 /* 10us */

Definition at line 45 of file injection_points.c.

◆ INJ_WAIT_MAX_US

#define INJ_WAIT_MAX_US   100000 /* 100ms */

Definition at line 46 of file injection_points.c.

◆ NUM_INJECTION_POINTS_LIST

#define NUM_INJECTION_POINTS_LIST   3

Typedef Documentation

◆ InjectionPointSharedState

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 561 of file injection_points.c.

562{
564 return;
565
567}
static const ShmemCallbacks injection_shmem_callbacks
bool process_shared_preload_libraries_in_progress
Definition miscinit.c:1788
void RegisterShmemCallbacks(const ShmemCallbacks *callbacks)
Definition shmem.c:873

References injection_shmem_callbacks, process_shared_preload_libraries_in_progress, and RegisterShmemCallbacks().

◆ injection_error()

void injection_error ( const char name,
const void private_data,
void arg 
)
extern

Definition at line 195 of file injection_points.c.

196{
197 const InjectionPointCondition *condition = private_data;
198 char *argstr = arg;
199
200 if (!injection_point_allowed(condition))
201 return;
202
203 if (argstr)
204 elog(ERROR, "error triggered for injection point %s (%s)",
205 name, argstr);
206 else
207 elog(ERROR, "error triggered for injection point %s", name);
208}
Datum arg
Definition elog.c:1323
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
static bool injection_point_allowed(const InjectionPointCondition *condition)
static int fb(int x)
const char * name

References arg, elog, ERROR, fb(), injection_point_allowed(), and name.

◆ injection_init_shmem()

static void injection_init_shmem ( void  )
static

Definition at line 134 of file injection_points.c.

135{
136 bool found;
137
138 if (inj_state != NULL)
139 return;
140
141 inj_state = GetNamedDSMSegment("injection_points",
144 &found, NULL);
145}
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr, void *arg), bool *found, void *arg)
static void injection_point_init_state(void *ptr, void *arg)
static InjectionPointSharedState * inj_state

References fb(), GetNamedDSMSegment(), inj_state, and injection_point_init_state().

Referenced by injection_points_load(), injection_points_set_local(), injection_points_wakeup(), and injection_wait().

◆ injection_notice()

void injection_notice ( const char name,
const void private_data,
void arg 
)
extern

Definition at line 211 of file injection_points.c.

212{
213 const InjectionPointCondition *condition = private_data;
214 char *argstr = arg;
215
216 if (!injection_point_allowed(condition))
217 return;
218
219 if (argstr)
220 elog(NOTICE, "notice triggered for injection point %s (%s)",
221 name, argstr);
222 else
223 elog(NOTICE, "notice triggered for injection point %s", name);
224}
#define NOTICE
Definition elog.h:36

References arg, elog, fb(), injection_point_allowed(), name, and NOTICE.

◆ injection_point_allowed()

static bool injection_point_allowed ( const InjectionPointCondition condition)
static

Definition at line 154 of file injection_points.c.

155{
156 bool result = true;
157
158 switch (condition->type)
159 {
161 if (MyProcPid != condition->pid)
162 result = false;
163 break;
165 break;
166 }
167
168 return result;
169}
uint32 result
int MyProcPid
Definition globals.c:49
@ INJ_CONDITION_PID
@ INJ_CONDITION_ALWAYS
InjectionPointConditionType type

References INJ_CONDITION_ALWAYS, INJ_CONDITION_PID, MyProcPid, InjectionPointCondition::pid, result, and InjectionPointCondition::type.

Referenced by injection_error(), injection_notice(), and injection_wait().

◆ injection_point_init_state()

static void injection_point_init_state ( void ptr,
void arg 
)
static

Definition at line 101 of file injection_points.c.

102{
104
105 SpinLockInit(&state->lock);
106 memset(state->name, 0, sizeof(state->name));
107 for (int i = 0; i < INJ_MAX_WAIT; i++)
108 pg_atomic_init_u32(&state->wait_counts[i], 0);
109}
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition atomics.h:214
#define INJ_MAX_WAIT
int i
Definition isn.c:77
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50

References fb(), i, INJ_MAX_WAIT, pg_atomic_init_u32(), and SpinLockInit().

Referenced by injection_init_shmem(), and injection_shmem_init().

◆ injection_points_attach()

Datum injection_points_attach ( PG_FUNCTION_ARGS  )

Definition at line 298 of file injection_points.c.

299{
302 char *function;
303 InjectionPointCondition condition = {0};
304
305 if (strcmp(action, "error") == 0)
306 function = "injection_error";
307 else if (strcmp(action, "notice") == 0)
308 function = "injection_notice";
309 else if (strcmp(action, "wait") == 0)
310 function = "injection_wait";
311 else
312 elog(ERROR, "incorrect action \"%s\" for injection point creation", action);
313
315 {
316 condition.type = INJ_CONDITION_PID;
317 condition.pid = MyProcPid;
318 }
319
320 InjectionPointAttach(name, "injection_points", function, &condition,
322
324 {
326
327 /* Local injection point, so track it for automated cleanup */
331 }
332
334}
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
void InjectionPointAttach(const char *name, const char *library, const char *function, const void *private_data, int private_data_size)
static bool injection_point_local
static List * inj_list_local
List * lappend(List *list, void *datum)
Definition list.c:339
char * pstrdup(const char *in)
Definition mcxt.c:1910
MemoryContext TopMemoryContext
Definition mcxt.c:167
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
on_exit_nicely_callback function
String * makeString(char *str)
Definition value.c:63
char * text_to_cstring(const text *t)
Definition varlena.c:217

References elog, ERROR, fb(), function, INJ_CONDITION_PID, inj_list_local, injection_point_local, InjectionPointAttach(), lappend(), makeString(), MemoryContextSwitchTo(), MyProcPid, name, PG_GETARG_TEXT_PP, PG_RETURN_VOID, InjectionPointCondition::pid, pstrdup(), text_to_cstring(), TopMemoryContext, and InjectionPointCondition::type.

◆ injection_points_attach_func()

Datum injection_points_attach_func ( PG_FUNCTION_ARGS  )

Definition at line 342 of file injection_points.c.

343{
344 char *name;
345 char *lib_name;
346 char *function;
347 bytea *private_data = NULL;
348 int private_data_size = 0;
349
350 if (PG_ARGISNULL(0))
351 elog(ERROR, "injection point name cannot be NULL");
352 if (PG_ARGISNULL(1))
353 elog(ERROR, "injection point library cannot be NULL");
354 if (PG_ARGISNULL(2))
355 elog(ERROR, "injection point function cannot be NULL");
356
360
361 if (!PG_ARGISNULL(3))
362 {
363 private_data = PG_GETARG_BYTEA_PP(3);
364 private_data_size = VARSIZE_ANY_EXHDR(private_data);
365 }
366
367 if (private_data != NULL)
370 else
372 0);
374}
#define PG_GETARG_BYTEA_PP(n)
Definition fmgr.h:309
#define PG_ARGISNULL(n)
Definition fmgr.h:209
Definition c.h:835
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486

References elog, ERROR, fb(), function, InjectionPointAttach(), name, PG_ARGISNULL, PG_GETARG_BYTEA_PP, PG_GETARG_TEXT_PP, PG_RETURN_VOID, text_to_cstring(), VARDATA_ANY(), and VARSIZE_ANY_EXHDR().

◆ injection_points_cached()

Datum injection_points_cached ( PG_FUNCTION_ARGS  )

Definition at line 420 of file injection_points.c.

421{
422 char *name;
423 char *arg = NULL;
424
425 if (PG_ARGISNULL(0))
428
429 if (!PG_ARGISNULL(1))
431
433
435}
#define INJECTION_POINT_CACHED(name, arg)

References arg, fb(), INJECTION_POINT_CACHED, name, PG_ARGISNULL, PG_GETARG_TEXT_PP, PG_RETURN_VOID, and text_to_cstring().

◆ injection_points_cleanup()

static void injection_points_cleanup ( int  code,
Datum  arg 
)
static

Definition at line 176 of file injection_points.c.

177{
178 ListCell *lc;
179
180 /* Leave if nothing is tracked locally */
182 return;
183
184 /* Detach all the local points */
185 foreach(lc, inj_list_local)
186 {
187 char *name = strVal(lfirst(lc));
188
190 }
191}
bool InjectionPointDetach(const char *name)
#define lfirst(lc)
Definition pg_list.h:172
#define strVal(v)
Definition value.h:82

References fb(), inj_list_local, injection_point_local, InjectionPointDetach(), lfirst, name, and strVal.

Referenced by injection_points_set_local().

◆ injection_points_detach()

Datum injection_points_detach ( PG_FUNCTION_ARGS  )

Definition at line 502 of file injection_points.c.

503{
505
507 elog(ERROR, "could not detach injection point \"%s\"", name);
508
509 /* Remove point from local list, if required */
510 if (inj_list_local != NIL)
511 {
513
517 }
518
520}
List * list_delete(List *list, void *datum)
Definition list.c:853
#define NIL
Definition pg_list.h:68

References elog, ERROR, fb(), inj_list_local, InjectionPointDetach(), list_delete(), makeString(), MemoryContextSwitchTo(), name, NIL, PG_GETARG_TEXT_PP, PG_RETURN_VOID, text_to_cstring(), and TopMemoryContext.

◆ injection_points_list()

Datum injection_points_list ( PG_FUNCTION_ARGS  )

Definition at line 527 of file injection_points.c.

528{
529#define NUM_INJECTION_POINTS_LIST 3
530 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
532 ListCell *lc;
533
534 /* Build a tuplestore to return our results in */
535 InitMaterializedSRF(fcinfo, 0);
536
538
539 foreach(lc, inj_points)
540 {
542 bool nulls[NUM_INJECTION_POINTS_LIST];
544
545 memset(values, 0, sizeof(values));
546 memset(nulls, 0, sizeof(nulls));
547
551
552 /* shove row into tuplestore */
553 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
554 }
555
556 return (Datum) 0;
557#undef NUM_INJECTION_POINTS_LIST
558}
static Datum values[MAXATTR]
Definition bootstrap.c:190
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
List * InjectionPointList(void)
#define NUM_INJECTION_POINTS_LIST
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
Definition pg_list.h:54
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785
text * cstring_to_text(const char *s)
Definition varlena.c:184

References cstring_to_text(), fb(), InitMaterializedSRF(), InjectionPointList(), lfirst, NUM_INJECTION_POINTS_LIST, PointerGetDatum, tuplestore_putvalues(), and values.

◆ injection_points_load()

Datum injection_points_load ( PG_FUNCTION_ARGS  )

Definition at line 381 of file injection_points.c.

382{
384
385 if (inj_state == NULL)
387
389
391}
#define INJECTION_POINT_LOAD(name)
static void injection_init_shmem(void)

References fb(), inj_state, injection_init_shmem(), INJECTION_POINT_LOAD, name, PG_GETARG_TEXT_PP, PG_RETURN_VOID, and text_to_cstring().

◆ injection_points_run()

Datum injection_points_run ( PG_FUNCTION_ARGS  )

Definition at line 398 of file injection_points.c.

399{
400 char *name;
401 char *arg = NULL;
402
403 if (PG_ARGISNULL(0))
406
407 if (!PG_ARGISNULL(1))
409
411
413}
#define INJECTION_POINT(name, arg)

References arg, fb(), INJECTION_POINT, name, PG_ARGISNULL, PG_GETARG_TEXT_PP, PG_RETURN_VOID, and text_to_cstring().

◆ injection_points_set_local()

Datum injection_points_set_local ( PG_FUNCTION_ARGS  )

Definition at line 480 of file injection_points.c.

481{
482 /* Enable flag to add a runtime condition based on this process ID */
484
485 if (inj_state == NULL)
487
488 /*
489 * Register a before_shmem_exit callback to remove any injection points
490 * linked to this process.
491 */
493
495}
static void injection_points_cleanup(int code, Datum arg)
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:344

References before_shmem_exit(), fb(), inj_state, injection_init_shmem(), injection_point_local, injection_points_cleanup(), and PG_RETURN_VOID.

◆ injection_points_wakeup()

Datum injection_points_wakeup ( PG_FUNCTION_ARGS  )

Definition at line 442 of file injection_points.c.

443{
445 int index = -1;
446
447 if (inj_state == NULL)
449
450 /* Find the injection point then bump its wait counter */
452 for (int i = 0; i < INJ_MAX_WAIT; i++)
453 {
454 if (strcmp(name, inj_state->name[i]) == 0)
455 {
456 index = i;
457 break;
458 }
459 }
460 if (index < 0)
461 {
463 elog(ERROR, "could not find injection point %s to wake up", name);
464 }
466
469}
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition atomics.h:361
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
pg_atomic_uint32 wait_counts[INJ_MAX_WAIT]
char name[INJ_MAX_WAIT][INJ_NAME_MAXLEN]
Definition type.h:97

References elog, ERROR, fb(), i, INJ_MAX_WAIT, inj_state, injection_init_shmem(), InjectionPointSharedState::lock, name, InjectionPointSharedState::name, pg_atomic_fetch_add_u32(), PG_GETARG_TEXT_PP, PG_RETURN_VOID, SpinLockAcquire(), SpinLockRelease(), text_to_cstring(), and InjectionPointSharedState::wait_counts.

◆ injection_shmem_init()

static void injection_shmem_init ( void arg)
static

Definition at line 121 of file injection_points.c.

122{
123 /*
124 * First time through, so initialize. This is shared with the dynamic
125 * initialization using a DSM.
126 */
128}

References fb(), inj_state, and injection_point_init_state().

◆ injection_shmem_request()

static void injection_shmem_request ( void arg)
static

Definition at line 112 of file injection_points.c.

113{
114 ShmemRequestStruct(.name = "injection_points",
115 .size = sizeof(InjectionPointSharedState),
116 .ptr = (void **) &inj_state,
117 );
118}
#define ShmemRequestStruct(...)
Definition shmem.h:176

References inj_state, name, and ShmemRequestStruct.

◆ injection_wait()

void injection_wait ( const char name,
const void private_data,
void arg 
)
extern

Definition at line 228 of file injection_points.c.

229{
231 int index = -1;
233 const InjectionPointCondition *condition = private_data;
234 int delay_us = 0;
235
236 if (inj_state == NULL)
238
239 if (!injection_point_allowed(condition))
240 return;
241
242 /*
243 * Use the injection point name for this custom wait event. Note that
244 * this custom wait event name is not released, but we don't care much for
245 * testing as this should be short-lived.
246 */
248
249 /*
250 * Find a free slot to wait for, and register this injection point's name.
251 */
253 for (int i = 0; i < INJ_MAX_WAIT; i++)
254 {
255 if (inj_state->name[i][0] == '\0')
256 {
257 index = i;
260 break;
261 }
262 }
264
265 if (index < 0)
266 elog(ERROR, "could not find free slot for wait of injection point %s",
267 name);
268
269 /*
270 * Wait until the counter is bumped by injection_points_wakeup().
271 *
272 * This loop starts with a short delay for responsiveness, enlarged to
273 * ease the CPU workload in slower environments.
274 */
276
279 {
284 }
286
287 /* Remove this injection point from the waiters. */
289 inj_state->name[index][0] = '\0';
291}
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition atomics.h:232
#define Min(x, y)
Definition c.h:1150
uint32_t uint32
Definition c.h:683
#define INJ_WAIT_INITIAL_US
#define INJ_NAME_MAXLEN
#define INJ_WAIT_MAX_US
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
void pg_usleep(long microsec)
Definition signal.c:53
uint32 WaitEventInjectionPointNew(const char *wait_event_name)
Definition wait_event.c:146
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition wait_event.h:67
static void pgstat_report_wait_end(void)
Definition wait_event.h:83

References CHECK_FOR_INTERRUPTS, elog, ERROR, fb(), i, INJ_MAX_WAIT, INJ_NAME_MAXLEN, inj_state, INJ_WAIT_INITIAL_US, INJ_WAIT_MAX_US, injection_init_shmem(), injection_point_allowed(), InjectionPointSharedState::lock, Min, name, InjectionPointSharedState::name, pg_atomic_read_u32(), pg_usleep(), pgstat_report_wait_end(), pgstat_report_wait_start(), SpinLockAcquire(), SpinLockRelease(), strlcpy(), InjectionPointSharedState::wait_counts, and WaitEventInjectionPointNew().

◆ PG_FUNCTION_INFO_V1() [1/9]

PG_FUNCTION_INFO_V1 ( injection_points_attach  )

◆ PG_FUNCTION_INFO_V1() [2/9]

PG_FUNCTION_INFO_V1 ( injection_points_attach_func  )

◆ PG_FUNCTION_INFO_V1() [3/9]

PG_FUNCTION_INFO_V1 ( injection_points_cached  )

◆ PG_FUNCTION_INFO_V1() [4/9]

PG_FUNCTION_INFO_V1 ( injection_points_detach  )

◆ PG_FUNCTION_INFO_V1() [5/9]

PG_FUNCTION_INFO_V1 ( injection_points_list  )

◆ PG_FUNCTION_INFO_V1() [6/9]

PG_FUNCTION_INFO_V1 ( injection_points_load  )

◆ PG_FUNCTION_INFO_V1() [7/9]

PG_FUNCTION_INFO_V1 ( injection_points_run  )

◆ PG_FUNCTION_INFO_V1() [8/9]

PG_FUNCTION_INFO_V1 ( injection_points_set_local  )

◆ PG_FUNCTION_INFO_V1() [9/9]

PG_FUNCTION_INFO_V1 ( injection_points_wakeup  )

Variable Documentation

◆ inj_list_local

List* inj_list_local = NIL
static

◆ inj_state

◆ injection_point_local

bool injection_point_local = false
static

◆ injection_shmem_callbacks

const ShmemCallbacks injection_shmem_callbacks
static
Initial value:
= {
.request_fn = injection_shmem_request,
}
static void injection_shmem_init(void *arg)
static void injection_shmem_request(void *arg)

Definition at line 91 of file injection_points.c.

91 {
92 .request_fn = injection_shmem_request,
93 .init_fn = injection_shmem_init,
94};

Referenced by _PG_init().

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 38 of file injection_points.c.