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-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" 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 39 3542 : pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS) 40 : { 41 3542 : int blocked_pid = PG_GETARG_INT32(0); 42 3542 : 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 3542 : proc = BackendPidGetProc(blocked_pid); 56 3542 : if (proc == NULL) 57 0 : PG_RETURN_BOOL(false); /* session gone: definitely unblocked */ 58 : wait_event_type = 59 3542 : pgstat_get_wait_event_type(UINT32_ACCESS_ONCE(proc->wait_event_info)); 60 3542 : if (wait_event_type && strcmp("InjectionPoint", wait_event_type) == 0) 61 58 : PG_RETURN_BOOL(true); 62 : 63 : /* Validate the passed-in array */ 64 : Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID); 65 3484 : if (array_contains_nulls(interesting_pids_a)) 66 0 : elog(ERROR, "array must not contain nulls"); 67 3484 : interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a); 68 3484 : 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 = 76 3484 : DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, blocked_pid)); 77 : 78 : Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID); 79 : Assert(!array_contains_nulls(blocking_pids_a)); 80 3484 : blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a); 81 3484 : 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 3484 : for (i = 0; i < num_blocking_pids; i++) 94 3430 : for (j = 0; j < num_interesting_pids; j++) 95 : { 96 3430 : if (blocking_pids[i] == interesting_pids[j]) 97 2254 : 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 1230 : if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0) 110 4 : PG_RETURN_BOOL(true); 111 : 112 1226 : PG_RETURN_BOOL(false); 113 : }