PostgreSQL Source Code  git master
waitfuncs.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * waitfuncs.c
4  * Functions for SQL access to syntheses of multiple contention types.
5  *
6  * Copyright (c) 2002-2024, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/backend/utils/adt/waitfuncs.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "catalog/pg_type.h"
17 #include "storage/proc.h"
18 #include "storage/procarray.h"
19 #include "utils/array.h"
20 #include "utils/builtins.h"
21 #include "utils/wait_event.h"
22 
23 #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var))))
24 
25 
26 /*
27  * pg_isolation_test_session_is_blocked - support function for isolationtester
28  *
29  * Check if specified PID is blocked by any of the PIDs listed in the second
30  * argument. Currently, this looks for blocking caused by waiting for
31  * injection points, heavyweight locks, or safe snapshots. We ignore blockage
32  * caused by PIDs not directly under the isolationtester's control, eg
33  * autovacuum.
34  *
35  * This is an undocumented function intended for use by the isolation tester,
36  * and may change in future releases as required for testing purposes.
37  */
38 Datum
40 {
41  int blocked_pid = PG_GETARG_INT32(0);
42  ArrayType *interesting_pids_a = PG_GETARG_ARRAYTYPE_P(1);
43  PGPROC *proc;
44  const char *wait_event_type;
45  ArrayType *blocking_pids_a;
46  int32 *interesting_pids;
47  int32 *blocking_pids;
48  int num_interesting_pids;
49  int num_blocking_pids;
50  int dummy;
51  int i,
52  j;
53 
54  /* Check if blocked_pid is in an injection point. */
55  proc = BackendPidGetProc(blocked_pid);
56  if (proc == NULL)
57  PG_RETURN_BOOL(false); /* session gone: definitely unblocked */
58  wait_event_type =
60  if (wait_event_type && strcmp("InjectionPoint", wait_event_type) == 0)
61  PG_RETURN_BOOL(true);
62 
63  /* Validate the passed-in array */
64  Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
65  if (array_contains_nulls(interesting_pids_a))
66  elog(ERROR, "array must not contain nulls");
67  interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
68  num_interesting_pids = ArrayGetNItems(ARR_NDIM(interesting_pids_a),
69  ARR_DIMS(interesting_pids_a));
70 
71  /*
72  * Get the PIDs of all sessions blocking the given session's attempt to
73  * acquire heavyweight locks.
74  */
75  blocking_pids_a =
77 
78  Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
79  Assert(!array_contains_nulls(blocking_pids_a));
80  blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
81  num_blocking_pids = ArrayGetNItems(ARR_NDIM(blocking_pids_a),
82  ARR_DIMS(blocking_pids_a));
83 
84  /*
85  * Check if any of these are in the list of interesting PIDs, that being
86  * the sessions that the isolation tester is running. We don't use
87  * "arrayoverlaps" here, because it would lead to cache lookups and one of
88  * our goals is to run quickly with debug_discard_caches > 0. We expect
89  * blocking_pids to be usually empty and otherwise a very small number in
90  * isolation tester cases, so make that the outer loop of a naive search
91  * for a match.
92  */
93  for (i = 0; i < num_blocking_pids; i++)
94  for (j = 0; j < num_interesting_pids; j++)
95  {
96  if (blocking_pids[i] == interesting_pids[j])
97  PG_RETURN_BOOL(true);
98  }
99 
100  /*
101  * Check if blocked_pid is waiting for a safe snapshot. We could in
102  * theory check the resulting array of blocker PIDs against the
103  * interesting PIDs list, but since there is no danger of autovacuum
104  * blocking GetSafeSnapshot there seems to be no point in expending cycles
105  * on allocating a buffer and searching for overlap; so it's presently
106  * sufficient for the isolation tester's purposes to use a single element
107  * buffer and check if the number of safe snapshot blockers is non-zero.
108  */
109  if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
110  PG_RETURN_BOOL(true);
111 
112  PG_RETURN_BOOL(false);
113 }
#define ARR_NDIM(a)
Definition: array.h:290
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3755
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:57
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
int j
Definition: isn.c:74
int i
Definition: isn.c:73
Datum pg_blocking_pids(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:466
uintptr_t Datum
Definition: postgres.h:64
int GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
Definition: predicate.c:1613
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3200
Definition: proc.h:157
uint32 wait_event_info
Definition: proc.h:274
const char * pgstat_get_wait_event_type(uint32 wait_event_info)
Definition: wait_event.c:374
#define UINT32_ACCESS_ONCE(var)
Definition: waitfuncs.c:23
Datum pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
Definition: waitfuncs.c:39