Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * waitfuncs.c
4 : : * Functions for SQL access to syntheses of multiple contention types.
5 : : *
6 : : * Copyright (c) 2002-2025, 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"
16 : : #include "storage/predicate_internals.h"
17 : : #include "storage/proc.h"
18 : : #include "storage/procarray.h"
19 : : #include "utils/array.h"
20 : : #include "utils/fmgrprotos.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
436 noah@leadboat.com 39 :CBC 1920 : pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
40 : : {
41 : 1920 : int blocked_pid = PG_GETARG_INT32(0);
42 : 1920 : 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 : 1920 : proc = BackendPidGetProc(blocked_pid);
56 [ - + ]: 1920 : if (proc == NULL)
436 noah@leadboat.com 57 :UBC 0 : PG_RETURN_BOOL(false); /* session gone: definitely unblocked */
58 : : wait_event_type =
436 noah@leadboat.com 59 :CBC 1920 : pgstat_get_wait_event_type(UINT32_ACCESS_ONCE(proc->wait_event_info));
60 [ + + - + ]: 1920 : if (wait_event_type && strcmp("InjectionPoint", wait_event_type) == 0)
436 noah@leadboat.com 61 :UBC 0 : PG_RETURN_BOOL(true);
62 : :
63 : : /* Validate the passed-in array */
436 noah@leadboat.com 64 [ - + ]:CBC 1920 : Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
65 [ - + ]: 1920 : if (array_contains_nulls(interesting_pids_a))
436 noah@leadboat.com 66 [ # # ]:UBC 0 : elog(ERROR, "array must not contain nulls");
436 noah@leadboat.com 67 [ - + ]:CBC 1920 : interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
68 : 1920 : 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 =
29 peter@eisentraut.org 76 :GNC 1920 : DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, Int32GetDatum(blocked_pid)));
77 : :
436 noah@leadboat.com 78 [ - + ]:CBC 1920 : Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
79 [ - + ]: 1920 : Assert(!array_contains_nulls(blocking_pids_a));
80 [ - + ]: 1920 : blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
81 : 1920 : 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 [ + + ]: 1920 : for (i = 0; i < num_blocking_pids; i++)
94 [ + - ]: 1730 : for (j = 0; j < num_interesting_pids; j++)
95 : : {
96 [ + + ]: 1730 : if (blocking_pids[i] == interesting_pids[j])
97 : 1133 : 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 [ + + ]: 787 : if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
110 : 2 : PG_RETURN_BOOL(true);
111 : :
112 : 785 : PG_RETURN_BOOL(false);
113 : : }
|