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

Go to the source code of this file.

Data Structures

struct  InjectionPointCondition
 
struct  InjectionPointSharedState
 

Macros

#define INJ_MAX_WAIT   8
 
#define INJ_NAME_MAXLEN   64
 

Typedefs

typedef enum InjectionPointConditionType InjectionPointConditionType
 
typedef struct InjectionPointCondition InjectionPointCondition
 
typedef struct InjectionPointSharedState InjectionPointSharedState
 

Enumerations

enum  InjectionPointConditionType { INJ_CONDITION_ALWAYS = 0 , INJ_CONDITION_PID }
 

Functions

PGDLLEXPORT void injection_error (const char *name, const void *private_data)
 
PGDLLEXPORT void injection_notice (const char *name, const void *private_data)
 
PGDLLEXPORT void injection_wait (const char *name, const void *private_data)
 
static void injection_point_init_state (void *ptr)
 
static void injection_init_shmem (void)
 
static bool injection_point_allowed (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_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)
 

Variables

 PG_MODULE_MAGIC
 
static Listinj_list_local = NIL
 
static InjectionPointSharedStateinj_state = NULL
 
static bool injection_point_local = false
 

Macro Definition Documentation

◆ INJ_MAX_WAIT

#define INJ_MAX_WAIT   8

Definition at line 37 of file injection_points.c.

◆ INJ_NAME_MAXLEN

#define INJ_NAME_MAXLEN   64

Definition at line 38 of file injection_points.c.

Typedef Documentation

◆ InjectionPointCondition

◆ InjectionPointConditionType

◆ InjectionPointSharedState

Enumeration Type Documentation

◆ InjectionPointConditionType

Enumerator
INJ_CONDITION_ALWAYS 
INJ_CONDITION_PID 

Definition at line 49 of file injection_points.c.

50 {
51  INJ_CONDITION_ALWAYS = 0, /* always run */
52  INJ_CONDITION_PID, /* PID restriction */
InjectionPointConditionType
@ INJ_CONDITION_PID
@ INJ_CONDITION_ALWAYS

Function Documentation

◆ injection_error()

void injection_error ( const char *  name,
const void *  private_data 
)

Definition at line 178 of file injection_points.c.

179 {
180  InjectionPointCondition *condition = (InjectionPointCondition *) private_data;
181 
182  if (!injection_point_allowed(condition))
183  return;
184 
185  elog(ERROR, "error triggered for injection point %s", name);
186 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static bool injection_point_allowed(InjectionPointCondition *condition)
const char * name

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

◆ injection_init_shmem()

static void injection_init_shmem ( void  )
static

Definition at line 117 of file injection_points.c.

118 {
119  bool found;
120 
121  if (inj_state != NULL)
122  return;
123 
124  inj_state = GetNamedDSMSegment("injection_points",
127  &found);
128 }
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr), bool *found)
Definition: dsm_registry.c:131
static void injection_point_init_state(void *ptr)
static InjectionPointSharedState * inj_state

References 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 
)

Definition at line 189 of file injection_points.c.

190 {
191  InjectionPointCondition *condition = (InjectionPointCondition *) private_data;
192 
193  if (!injection_point_allowed(condition))
194  return;
195 
196  elog(NOTICE, "notice triggered for injection point %s", name);
197 }
#define NOTICE
Definition: elog.h:35

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

◆ injection_point_allowed()

static bool injection_point_allowed ( InjectionPointCondition condition)
static

Definition at line 137 of file injection_points.c.

138 {
139  bool result = true;
140 
141  switch (condition->type)
142  {
143  case INJ_CONDITION_PID:
144  if (MyProcPid != condition->pid)
145  result = false;
146  break;
148  break;
149  }
150 
151  return result;
152 }
int MyProcPid
Definition: globals.c:46
InjectionPointConditionType type

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

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

◆ injection_point_init_state()

static void injection_point_init_state ( void *  ptr)
static

Definition at line 103 of file injection_points.c.

104 {
106 
107  SpinLockInit(&state->lock);
108  memset(state->wait_counts, 0, sizeof(state->wait_counts));
109  memset(state->name, 0, sizeof(state->name));
110  ConditionVariableInit(&state->wait_point);
111 }
void ConditionVariableInit(ConditionVariable *cv)
#define SpinLockInit(lock)
Definition: spin.h:60
Definition: regguts.h:323

References ConditionVariableInit(), and SpinLockInit.

Referenced by injection_init_shmem().

◆ injection_points_attach()

Datum injection_points_attach ( PG_FUNCTION_ARGS  )

Definition at line 268 of file injection_points.c.

269 {
272  char *function;
273  InjectionPointCondition condition = {0};
274 
275  if (strcmp(action, "error") == 0)
276  function = "injection_error";
277  else if (strcmp(action, "notice") == 0)
278  function = "injection_notice";
279  else if (strcmp(action, "wait") == 0)
280  function = "injection_wait";
281  else
282  elog(ERROR, "incorrect action \"%s\" for injection point creation", action);
283 
285  {
286  condition.type = INJ_CONDITION_PID;
287  condition.pid = MyProcPid;
288  }
289 
290  InjectionPointAttach(name, "injection_points", function, &condition,
291  sizeof(InjectionPointCondition));
292 
294  {
295  MemoryContext oldctx;
296 
297  /* Local injection point, so track it for automated cleanup */
300  MemoryContextSwitchTo(oldctx);
301  }
302  PG_RETURN_VOID();
303 }
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
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:1696
MemoryContext TopMemoryContext
Definition: mcxt.c:149
MemoryContextSwitchTo(old_ctx)
String * makeString(char *str)
Definition: value.c:63
char * text_to_cstring(const text *t)
Definition: varlena.c:217

References generate_unaccent_rules::action, elog, ERROR, 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_cached()

Datum injection_points_cached ( PG_FUNCTION_ARGS  )

Definition at line 341 of file injection_points.c.

342 {
344 
346 
347  PG_RETURN_VOID();
348 }
#define INJECTION_POINT_CACHED(name)

References INJECTION_POINT_CACHED, name, 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 159 of file injection_points.c.

160 {
161  ListCell *lc;
162 
163  /* Leave if nothing is tracked locally */
165  return;
166 
167  /* Detach all the local points */
168  foreach(lc, inj_list_local)
169  {
170  char *name = strVal(lfirst(lc));
171 
172  (void) InjectionPointDetach(name);
173  }
174 }
bool InjectionPointDetach(const char *name)
#define lfirst(lc)
Definition: pg_list.h:172
#define strVal(v)
Definition: value.h:82

References 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 417 of file injection_points.c.

418 {
420 
422  elog(ERROR, "could not detach injection point \"%s\"", name);
423 
424  /* Remove point from local list, if required */
425  if (inj_list_local != NIL)
426  {
427  MemoryContext oldctx;
428 
431  MemoryContextSwitchTo(oldctx);
432  }
433 
434  PG_RETURN_VOID();
435 }
List * list_delete(List *list, void *datum)
Definition: list.c:853
#define NIL
Definition: pg_list.h:68

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

◆ injection_points_load()

Datum injection_points_load ( PG_FUNCTION_ARGS  )

Definition at line 310 of file injection_points.c.

311 {
313 
314  if (inj_state == NULL)
316 
318 
319  PG_RETURN_VOID();
320 }
#define INJECTION_POINT_LOAD(name)
static void injection_init_shmem(void)

References 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 327 of file injection_points.c.

328 {
330 
332 
333  PG_RETURN_VOID();
334 }
#define INJECTION_POINT(name)

References INJECTION_POINT, name, 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 395 of file injection_points.c.

396 {
397  /* Enable flag to add a runtime condition based on this process ID */
398  injection_point_local = true;
399 
400  if (inj_state == NULL)
402 
403  /*
404  * Register a before_shmem_exit callback to remove any injection points
405  * linked to this process.
406  */
408 
409  PG_RETURN_VOID();
410 }
static void injection_points_cleanup(int code, Datum arg)
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:337
uintptr_t Datum
Definition: postgres.h:64

References before_shmem_exit(), 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 355 of file injection_points.c.

356 {
358  int index = -1;
359 
360  if (inj_state == NULL)
362 
363  /* First bump the wait counter for the injection point to wake up */
365  for (int i = 0; i < INJ_MAX_WAIT; i++)
366  {
367  if (strcmp(name, inj_state->name[i]) == 0)
368  {
369  index = i;
370  break;
371  }
372  }
373  if (index < 0)
374  {
376  elog(ERROR, "could not find injection point %s to wake up", name);
377  }
380 
381  /* And broadcast the change to the waiters */
383  PG_RETURN_VOID();
384 }
void ConditionVariableBroadcast(ConditionVariable *cv)
#define INJ_MAX_WAIT
int i
Definition: isn.c:73
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
uint32 wait_counts[INJ_MAX_WAIT]
char name[INJ_MAX_WAIT][INJ_NAME_MAXLEN]
ConditionVariable wait_point
Definition: type.h:95

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

◆ injection_wait()

void injection_wait ( const char *  name,
const void *  private_data 
)

Definition at line 201 of file injection_points.c.

202 {
203  uint32 old_wait_counts = 0;
204  int index = -1;
205  uint32 injection_wait_event = 0;
206  InjectionPointCondition *condition = (InjectionPointCondition *) private_data;
207 
208  if (inj_state == NULL)
210 
211  if (!injection_point_allowed(condition))
212  return;
213 
214  /*
215  * Use the injection point name for this custom wait event. Note that
216  * this custom wait event name is not released, but we don't care much for
217  * testing as this should be short-lived.
218  */
219  injection_wait_event = WaitEventInjectionPointNew(name);
220 
221  /*
222  * Find a free slot to wait for, and register this injection point's name.
223  */
225  for (int i = 0; i < INJ_MAX_WAIT; i++)
226  {
227  if (inj_state->name[i][0] == '\0')
228  {
229  index = i;
231  old_wait_counts = inj_state->wait_counts[i];
232  break;
233  }
234  }
236 
237  if (index < 0)
238  elog(ERROR, "could not find free slot for wait of injection point %s ",
239  name);
240 
241  /* And sleep.. */
243  for (;;)
244  {
245  uint32 new_wait_counts;
246 
248  new_wait_counts = inj_state->wait_counts[index];
250 
251  if (old_wait_counts != new_wait_counts)
252  break;
253  ConditionVariableSleep(&inj_state->wait_point, injection_wait_event);
254  }
256 
257  /* Remove this injection point from the waiters. */
259  inj_state->name[index][0] = '\0';
261 }
unsigned int uint32
Definition: c.h:506
bool ConditionVariableCancelSleep(void)
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
#define INJ_NAME_MAXLEN
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
uint32 WaitEventInjectionPointNew(const char *wait_event_name)
Definition: wait_event.c:170

References ConditionVariableCancelSleep(), ConditionVariablePrepareToSleep(), ConditionVariableSleep(), elog, ERROR, i, INJ_MAX_WAIT, INJ_NAME_MAXLEN, inj_state, injection_init_shmem(), injection_point_allowed(), InjectionPointSharedState::lock, name, InjectionPointSharedState::name, SpinLockAcquire, SpinLockRelease, strlcpy(), InjectionPointSharedState::wait_counts, InjectionPointSharedState::wait_point, and WaitEventInjectionPointNew().

◆ PG_FUNCTION_INFO_V1() [1/7]

PG_FUNCTION_INFO_V1 ( injection_points_attach  )

◆ PG_FUNCTION_INFO_V1() [2/7]

PG_FUNCTION_INFO_V1 ( injection_points_cached  )

◆ PG_FUNCTION_INFO_V1() [3/7]

PG_FUNCTION_INFO_V1 ( injection_points_detach  )

◆ PG_FUNCTION_INFO_V1() [4/7]

PG_FUNCTION_INFO_V1 ( injection_points_load  )

◆ PG_FUNCTION_INFO_V1() [5/7]

PG_FUNCTION_INFO_V1 ( injection_points_run  )

◆ PG_FUNCTION_INFO_V1() [6/7]

PG_FUNCTION_INFO_V1 ( injection_points_set_local  )

◆ PG_FUNCTION_INFO_V1() [7/7]

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

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 34 of file injection_points.c.