@ -517,6 +517,125 @@ pg_blocking_pids(PG_FUNCTION_ARGS)
}
/*
* pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
* given PID from getting a safe snapshot
*
* XXX this does not consider parallel - query cases ; not clear how big a
* problem that is in practice
*/
Datum
pg_safe_snapshot_blocking_pids ( PG_FUNCTION_ARGS )
{
int blocked_pid = PG_GETARG_INT32 ( 0 ) ;
int * blockers ;
int num_blockers ;
Datum * blocker_datums ;
/* A buffer big enough for any possible blocker list without truncation */
blockers = ( int * ) palloc ( MaxBackends * sizeof ( int ) ) ;
/* Collect a snapshot of processes waited for by GetSafeSnapshot */
num_blockers =
GetSafeSnapshotBlockingPids ( blocked_pid , blockers , MaxBackends ) ;
/* Convert int array to Datum array */
if ( num_blockers > 0 )
{
int i ;
blocker_datums = ( Datum * ) palloc ( num_blockers * sizeof ( Datum ) ) ;
for ( i = 0 ; i < num_blockers ; + + i )
blocker_datums [ i ] = Int32GetDatum ( blockers [ i ] ) ;
}
else
blocker_datums = NULL ;
/* Construct array, using hardwired knowledge about int4 type */
PG_RETURN_ARRAYTYPE_P ( construct_array ( blocker_datums , num_blockers ,
INT4OID ,
sizeof ( int32 ) , true , ' i ' ) ) ;
}
/*
* pg_isolation_test_session_is_blocked - support function for isolationtester
*
* Check if specified PID is blocked by any of the PIDs listed in the second
* argument . Currently , this looks for blocking caused by waiting for
* heavyweight locks or safe snapshots . We ignore blockage caused by PIDs
* not directly under the isolationtester ' s control , eg autovacuum .
*
* This is an undocumented function intended for use by the isolation tester ,
* and may change in future releases as required for testing purposes .
*/
Datum
pg_isolation_test_session_is_blocked ( PG_FUNCTION_ARGS )
{
int blocked_pid = PG_GETARG_INT32 ( 0 ) ;
ArrayType * interesting_pids_a = PG_GETARG_ARRAYTYPE_P ( 1 ) ;
ArrayType * blocking_pids_a ;
int32 * interesting_pids ;
int32 * blocking_pids ;
int num_interesting_pids ;
int num_blocking_pids ;
int dummy ;
int i ,
j ;
/* Validate the passed-in array */
Assert ( ARR_ELEMTYPE ( interesting_pids_a ) = = INT4OID ) ;
if ( array_contains_nulls ( interesting_pids_a ) )
elog ( ERROR , " array must not contain nulls " ) ;
interesting_pids = ( int32 * ) ARR_DATA_PTR ( interesting_pids_a ) ;
num_interesting_pids = ArrayGetNItems ( ARR_NDIM ( interesting_pids_a ) ,
ARR_DIMS ( interesting_pids_a ) ) ;
/*
* Get the PIDs of all sessions blocking the given session ' s attempt to
* acquire heavyweight locks .
*/
blocking_pids_a =
DatumGetArrayTypeP ( DirectFunctionCall1 ( pg_blocking_pids , blocked_pid ) ) ;
Assert ( ARR_ELEMTYPE ( blocking_pids_a ) = = INT4OID ) ;
Assert ( ! array_contains_nulls ( blocking_pids_a ) ) ;
blocking_pids = ( int32 * ) ARR_DATA_PTR ( blocking_pids_a ) ;
num_blocking_pids = ArrayGetNItems ( ARR_NDIM ( blocking_pids_a ) ,
ARR_DIMS ( blocking_pids_a ) ) ;
/*
* Check if any of these are in the list of interesting PIDs , that being
* the sessions that the isolation tester is running . We don ' t use
* " arrayoverlaps " here , because it would lead to cache lookups and one of
* our goals is to run quickly under CLOBBER_CACHE_ALWAYS . We expect
* blocking_pids to be usually empty and otherwise a very small number in
* isolation tester cases , so make that the outer loop of a naive search
* for a match .
*/
for ( i = 0 ; i < num_blocking_pids ; i + + )
for ( j = 0 ; j < num_interesting_pids ; j + + )
{
if ( blocking_pids [ i ] = = interesting_pids [ j ] )
PG_RETURN_BOOL ( true ) ;
}
/*
* Check if blocked_pid is waiting for a safe snapshot . We could in
* theory check the resulting array of blocker PIDs against the
* interesting PIDs whitelist , but since there is no danger of autovacuum
* blocking GetSafeSnapshot there seems to be no point in expending cycles
* on allocating a buffer and searching for overlap ; so it ' s presently
* sufficient for the isolation tester ' s purposes to use a single element
* buffer and check if the number of safe snapshot blockers is non - zero .
*/
if ( GetSafeSnapshotBlockingPids ( blocked_pid , & dummy , 1 ) > 0 )
PG_RETURN_BOOL ( true ) ;
PG_RETURN_BOOL ( false ) ;
}
/*
* Functions for manipulating advisory locks
*