Coverage Report

Created: 2025-06-15 06:31

/src/postgres/src/backend/utils/adt/waitfuncs.c
Line
Count
Source (jump to first uncovered line)
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
0
#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
39
pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
40
0
{
41
0
  int     blocked_pid = PG_GETARG_INT32(0);
42
0
  ArrayType  *interesting_pids_a = PG_GETARG_ARRAYTYPE_P(1);
43
0
  PGPROC     *proc;
44
0
  const char *wait_event_type;
45
0
  ArrayType  *blocking_pids_a;
46
0
  int32    *interesting_pids;
47
0
  int32    *blocking_pids;
48
0
  int     num_interesting_pids;
49
0
  int     num_blocking_pids;
50
0
  int     dummy;
51
0
  int     i,
52
0
        j;
53
54
  /* Check if blocked_pid is in an injection point. */
55
0
  proc = BackendPidGetProc(blocked_pid);
56
0
  if (proc == NULL)
57
0
    PG_RETURN_BOOL(false);  /* session gone: definitely unblocked */
58
0
  wait_event_type =
59
0
    pgstat_get_wait_event_type(UINT32_ACCESS_ONCE(proc->wait_event_info));
60
0
  if (wait_event_type && strcmp("InjectionPoint", wait_event_type) == 0)
61
0
    PG_RETURN_BOOL(true);
62
63
  /* Validate the passed-in array */
64
0
  Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
65
0
  if (array_contains_nulls(interesting_pids_a))
66
0
    elog(ERROR, "array must not contain nulls");
67
0
  interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
68
0
  num_interesting_pids = ArrayGetNItems(ARR_NDIM(interesting_pids_a),
69
0
                      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
0
  blocking_pids_a =
76
0
    DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, blocked_pid));
77
78
0
  Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
79
0
  Assert(!array_contains_nulls(blocking_pids_a));
80
0
  blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
81
0
  num_blocking_pids = ArrayGetNItems(ARR_NDIM(blocking_pids_a),
82
0
                     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
0
  for (i = 0; i < num_blocking_pids; i++)
94
0
    for (j = 0; j < num_interesting_pids; j++)
95
0
    {
96
0
      if (blocking_pids[i] == interesting_pids[j])
97
0
        PG_RETURN_BOOL(true);
98
0
    }
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
0
  if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
110
0
    PG_RETURN_BOOL(true);
111
112
0
  PG_RETURN_BOOL(false);
113
0
}