PostgreSQL Source Code  git master
injection_points.c File Reference
#include "postgres.h"
#include "fmgr.h"
#include "miscadmin.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/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
 
#define INJ_MAX_CONDITION   4
 

Typedefs

typedef struct InjectionPointCondition InjectionPointCondition
 
typedef struct InjectionPointSharedState InjectionPointSharedState
 

Functions

PGDLLEXPORT void injection_error (const char *name)
 
PGDLLEXPORT void injection_notice (const char *name)
 
PGDLLEXPORT void injection_wait (const char *name)
 
static void injection_point_init_state (void *ptr)
 
static void injection_init_shmem (void)
 
static bool injection_point_allowed (const char *name)
 
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_run)
 
Datum injection_points_run (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 InjectionPointSharedStateinj_state = NULL
 
static bool injection_point_local = false
 

Macro Definition Documentation

◆ INJ_MAX_CONDITION

#define INJ_MAX_CONDITION   4

Definition at line 36 of file injection_points.c.

◆ INJ_MAX_WAIT

#define INJ_MAX_WAIT   8

Definition at line 34 of file injection_points.c.

◆ INJ_NAME_MAXLEN

#define INJ_NAME_MAXLEN   64

Definition at line 35 of file injection_points.c.

Typedef Documentation

◆ InjectionPointCondition

◆ InjectionPointSharedState

Function Documentation

◆ injection_error()

void injection_error ( const char *  name)

Definition at line 214 of file injection_points.c.

215 {
217  return;
218 
219  elog(ERROR, "error triggered for injection point %s", name);
220 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
static bool injection_point_allowed(const char *name)
const char * name

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

◆ injection_init_shmem()

static void injection_init_shmem ( void  )
static

Definition at line 102 of file injection_points.c.

103 {
104  bool found;
105 
106  if (inj_state != NULL)
107  return;
108 
109  inj_state = GetNamedDSMSegment("injection_points",
112  &found);
113 }
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_point_allowed(), injection_points_detach(), injection_points_set_local(), injection_points_wakeup(), and injection_wait().

◆ injection_notice()

void injection_notice ( const char *  name)

Definition at line 223 of file injection_points.c.

224 {
226  return;
227 
228  elog(NOTICE, "notice triggered for injection point %s", name);
229 }
#define NOTICE
Definition: elog.h:35

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

◆ injection_point_allowed()

static bool injection_point_allowed ( const char *  name)
static

Definition at line 123 of file injection_points.c.

124 {
125  bool result = true;
126 
127  if (inj_state == NULL)
129 
131 
132  for (int i = 0; i < INJ_MAX_CONDITION; i++)
133  {
135 
136  if (strcmp(condition->name, name) == 0)
137  {
138  /*
139  * Check if this injection point is allowed to run in this
140  * process.
141  */
142  if (MyProcPid != condition->pid)
143  {
144  result = false;
145  break;
146  }
147  }
148  }
149 
151 
152  return result;
153 }
int MyProcPid
Definition: globals.c:45
static void injection_init_shmem(void)
#define INJ_MAX_CONDITION
int i
Definition: isn.c:73
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
char name[INJ_NAME_MAXLEN]
InjectionPointCondition conditions[INJ_MAX_CONDITION]

References InjectionPointSharedState::conditions, i, INJ_MAX_CONDITION, inj_state, injection_init_shmem(), InjectionPointSharedState::lock, MyProcPid, name, InjectionPointCondition::name, InjectionPointCondition::pid, SpinLockAcquire, and SpinLockRelease.

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

88 {
90 
91  SpinLockInit(&state->lock);
92  memset(state->wait_counts, 0, sizeof(state->wait_counts));
93  memset(state->name, 0, sizeof(state->name));
94  memset(state->conditions, 0, sizeof(state->conditions));
95  ConditionVariableInit(&state->wait_point);
96 }
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 299 of file injection_points.c.

300 {
303  char *function;
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 
314  InjectionPointAttach(name, "injection_points", function);
315 
317  {
318  int index = -1;
319 
320  /*
321  * Register runtime condition to link this injection point to the
322  * current process.
323  */
325  for (int i = 0; i < INJ_MAX_CONDITION; i++)
326  {
328 
329  if (condition->name[0] == '\0')
330  {
331  index = i;
332  strlcpy(condition->name, name, INJ_NAME_MAXLEN);
333  condition->pid = MyProcPid;
334  break;
335  }
336  }
338 
339  if (index < 0)
340  elog(FATAL,
341  "could not find free slot for condition of injection point %s",
342  name);
343  }
344 
345  PG_RETURN_VOID();
346 }
#define FATAL
Definition: elog.h:41
#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)
static bool injection_point_local
#define INJ_NAME_MAXLEN
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
Definition: type.h:95
char * text_to_cstring(const text *t)
Definition: varlena.c:217

References generate_unaccent_rules::action, InjectionPointSharedState::conditions, elog, ERROR, FATAL, i, INJ_MAX_CONDITION, INJ_NAME_MAXLEN, inj_state, injection_point_local, InjectionPointAttach(), InjectionPointSharedState::lock, MyProcPid, name, InjectionPointCondition::name, PG_GETARG_TEXT_PP, PG_RETURN_VOID, InjectionPointCondition::pid, SpinLockAcquire, SpinLockRelease, strlcpy(), and text_to_cstring().

◆ injection_points_cleanup()

static void injection_points_cleanup ( int  code,
Datum  arg 
)
static

Definition at line 160 of file injection_points.c.

161 {
162  char names[INJ_MAX_CONDITION][INJ_NAME_MAXLEN] = {0};
163  int count = 0;
164 
165  /* Leave if nothing is tracked locally */
167  return;
168 
169  /*
170  * This is done in three steps: detect the points to detach, detach them
171  * and release their conditions.
172  */
174  for (int i = 0; i < INJ_MAX_CONDITION; i++)
175  {
177 
178  if (condition->name[0] == '\0')
179  continue;
180 
181  if (condition->pid != MyProcPid)
182  continue;
183 
184  /* Extract the point name to detach */
185  strlcpy(names[count], condition->name, INJ_NAME_MAXLEN);
186  count++;
187  }
189 
190  /* Detach, without holding the spinlock */
191  for (int i = 0; i < count; i++)
192  InjectionPointDetach(names[i]);
193 
194  /* Clear all the conditions */
196  for (int i = 0; i < INJ_MAX_CONDITION; i++)
197  {
199 
200  if (condition->name[0] == '\0')
201  continue;
202 
203  if (condition->pid != MyProcPid)
204  continue;
205 
206  condition->name[0] = '\0';
207  condition->pid = 0;
208  }
210 }
void InjectionPointDetach(const char *name)

References InjectionPointSharedState::conditions, i, INJ_MAX_CONDITION, INJ_NAME_MAXLEN, inj_state, injection_point_local, InjectionPointDetach(), InjectionPointSharedState::lock, MyProcPid, InjectionPointCondition::name, InjectionPointCondition::pid, SpinLockAcquire, SpinLockRelease, and strlcpy().

Referenced by injection_points_set_local().

◆ injection_points_detach()

Datum injection_points_detach ( PG_FUNCTION_ARGS  )

Definition at line 429 of file injection_points.c.

430 {
432 
434 
435  if (inj_state == NULL)
437 
438  /* Clean up any conditions associated to this injection point */
440  for (int i = 0; i < INJ_MAX_CONDITION; i++)
441  {
443 
444  if (strcmp(condition->name, name) == 0)
445  {
446  condition->pid = 0;
447  condition->name[0] = '\0';
448  }
449  }
451 
452  PG_RETURN_VOID();
453 }

References InjectionPointSharedState::conditions, i, INJ_MAX_CONDITION, inj_state, injection_init_shmem(), InjectionPointDetach(), InjectionPointSharedState::lock, name, InjectionPointCondition::name, PG_GETARG_TEXT_PP, PG_RETURN_VOID, InjectionPointCondition::pid, SpinLockAcquire, SpinLockRelease, and text_to_cstring().

◆ injection_points_run()

Datum injection_points_run ( PG_FUNCTION_ARGS  )

Definition at line 353 of file injection_points.c.

354 {
356 
358 
359  PG_RETURN_VOID();
360 }
#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 407 of file injection_points.c.

408 {
409  /* Enable flag to add a runtime condition based on this process ID */
410  injection_point_local = true;
411 
412  if (inj_state == NULL)
414 
415  /*
416  * Register a before_shmem_exit callback to remove any injection points
417  * linked to this process.
418  */
420 
421  PG_RETURN_VOID();
422 }
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 367 of file injection_points.c.

368 {
370  int index = -1;
371 
372  if (inj_state == NULL)
374 
375  /* First bump the wait counter for the injection point to wake up */
377  for (int i = 0; i < INJ_MAX_WAIT; i++)
378  {
379  if (strcmp(name, inj_state->name[i]) == 0)
380  {
381  index = i;
382  break;
383  }
384  }
385  if (index < 0)
386  {
388  elog(ERROR, "could not find injection point %s to wake up", name);
389  }
392 
393  /* And broadcast the change to the waiters */
395  PG_RETURN_VOID();
396 }
void ConditionVariableBroadcast(ConditionVariable *cv)
#define INJ_MAX_WAIT
uint32 wait_counts[INJ_MAX_WAIT]
char name[INJ_MAX_WAIT][INJ_NAME_MAXLEN]
ConditionVariable wait_point

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)

Definition at line 233 of file injection_points.c.

234 {
235  uint32 old_wait_counts = 0;
236  int index = -1;
237  uint32 injection_wait_event = 0;
238 
239  if (inj_state == NULL)
241 
243  return;
244 
245  /*
246  * Use the injection point name for this custom wait event. Note that
247  * this custom wait event name is not released, but we don't care much for
248  * testing as this should be short-lived.
249  */
250  injection_wait_event = WaitEventExtensionNew(name);
251 
252  /*
253  * Find a free slot to wait for, and register this injection point's name.
254  */
256  for (int i = 0; i < INJ_MAX_WAIT; i++)
257  {
258  if (inj_state->name[i][0] == '\0')
259  {
260  index = i;
262  old_wait_counts = inj_state->wait_counts[i];
263  break;
264  }
265  }
267 
268  if (index < 0)
269  elog(ERROR, "could not find free slot for wait of injection point %s ",
270  name);
271 
272  /* And sleep.. */
274  for (;;)
275  {
276  uint32 new_wait_counts;
277 
279  new_wait_counts = inj_state->wait_counts[index];
281 
282  if (old_wait_counts != new_wait_counts)
283  break;
284  ConditionVariableSleep(&inj_state->wait_point, injection_wait_event);
285  }
287 
288  /* Remove this injection point from the waiters. */
290  inj_state->name[index][0] = '\0';
292 }
unsigned int uint32
Definition: c.h:506
bool ConditionVariableCancelSleep(void)
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
uint32 WaitEventExtensionNew(const char *wait_event_name)
Definition: wait_event.c:162

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 WaitEventExtensionNew().

◆ PG_FUNCTION_INFO_V1() [1/5]

PG_FUNCTION_INFO_V1 ( injection_points_attach  )

◆ PG_FUNCTION_INFO_V1() [2/5]

PG_FUNCTION_INFO_V1 ( injection_points_detach  )

◆ PG_FUNCTION_INFO_V1() [3/5]

PG_FUNCTION_INFO_V1 ( injection_points_run  )

◆ PG_FUNCTION_INFO_V1() [4/5]

PG_FUNCTION_INFO_V1 ( injection_points_set_local  )

◆ PG_FUNCTION_INFO_V1() [5/5]

PG_FUNCTION_INFO_V1 ( injection_points_wakeup  )

Variable Documentation

◆ inj_state

◆ injection_point_local

bool injection_point_local = false
static

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 31 of file injection_points.c.