LCOV - code coverage report
Current view: top level - src/backend/utils/adt - waitfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 91.3 % 23 21
Test Date: 2026-03-01 15:14:58 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1