Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit511540d

Browse files
committed
Move isolationtester's is-blocked query into C code for speed.
Commit4deb413 modified isolationtester's query to see whether asession is blocked to also check for waits occurring in GetSafeSnapshot.However, it did that in a way that enormously increased the query'sruntime under CLOBBER_CACHE_ALWAYS, causing the buildfarm membersthat use that to run about four times slower than before, and in somecases fail entirely. To fix, push the entire logic into a dedicatedbackend function. This should actually reduce the CLOBBER_CACHE_ALWAYSruntime from what it was previously, though I've not checked that.In passing, expose a SQL function to check for safe-snapshot blockage,comparable to pg_blocking_pids. This is more or less free given theinfrastructure built to solve the other problem, so we might as well.Thomas MunroDiscussion:https://postgr.es/m/20170407165749.pstcakbc637opkax@alap3.anarazel.de
1 parent9cf5c31 commit511540d

File tree

8 files changed

+206
-13
lines changed

8 files changed

+206
-13
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15747,7 +15747,7 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
1574715747
<row>
1574815748
<entry><literal><function>pg_blocking_pids(<type>int</type>)</function></literal></entry>
1574915749
<entry><type>int[]</type></entry>
15750-
<entry>Process ID(s) that are blocking specified server process ID</entry>
15750+
<entry>Process ID(s) that are blocking specified server process ID from acquiring a lock</entry>
1575115751
</row>
1575215752

1575315753
<row>
@@ -15793,6 +15793,12 @@ SELECT * FROM pg_ls_dir('.') WITH ORDINALITY AS t(ls,n);
1579315793
<entry>server start time</entry>
1579415794
</row>
1579515795

15796+
<row>
15797+
<entry><literal><function>pg_safe_snapshot_blocking_pids(<type>int</type>)</function></literal></entry>
15798+
<entry><type>int[]</type></entry>
15799+
<entry>Process ID(s) that are blocking specified server process ID from acquiring a safe snapshot</entry>
15800+
</row>
15801+
1579615802
<row>
1579715803
<entry><literal><function>pg_trigger_depth()</function></literal></entry>
1579815804
<entry><type>int</type></entry>
@@ -16067,6 +16073,25 @@ SET search_path TO <replaceable>schema</> <optional>, <replaceable>schema</>, ..
1606716073
server started.
1606816074
</para>
1606916075

16076+
<indexterm>
16077+
<primary>pg_safe_snapshot_blocking_pids</primary>
16078+
</indexterm>
16079+
16080+
<para>
16081+
<function>pg_safe_snapshot_blocking_pids</function> returns an array of
16082+
the process IDs of the sessions that are blocking the server process with
16083+
the specified process ID from acquiring a safe snapshot, or an empty array
16084+
if there is no such server process or it is not blocked. A session
16085+
running a <literal>SERIALIZABLE</literal> transaction blocks
16086+
a <literal>SERIALIZABLE READ ONLY DEFERRABLE</literal> transaction from
16087+
acquiring a snapshot until the latter determines that it is safe to avoid
16088+
taking any predicate locks. See <xref linkend="xact-serializable"> for
16089+
more information about serializable and deferrable transactions. Frequent
16090+
calls to this function could have some impact on database performance,
16091+
because it needs access to the predicate lock manager's shared
16092+
state for a short time.
16093+
</para>
16094+
1607016095
<indexterm>
1607116096
<primary>version</primary>
1607216097
</indexterm>

‎src/backend/storage/lmgr/predicate.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,56 @@ GetSafeSnapshot(Snapshot origSnapshot)
15551555
returnsnapshot;
15561556
}
15571557

1558+
/*
1559+
* GetSafeSnapshotBlockingPids
1560+
*If the specified process is currently blocked in GetSafeSnapshot,
1561+
*write the process IDs of all processes that it is blocked by
1562+
*into the caller-supplied buffer output[]. The list is truncated at
1563+
*output_size, and the number of PIDs written into the buffer is
1564+
*returned. Returns zero if the given PID is not currently blocked
1565+
*in GetSafeSnapshot.
1566+
*/
1567+
int
1568+
GetSafeSnapshotBlockingPids(intblocked_pid,int*output,intoutput_size)
1569+
{
1570+
intnum_written=0;
1571+
SERIALIZABLEXACT*sxact;
1572+
1573+
LWLockAcquire(SerializableXactHashLock,LW_SHARED);
1574+
1575+
/* Find blocked_pid's SERIALIZABLEXACT by linear search. */
1576+
for (sxact=FirstPredXact();sxact!=NULL;sxact=NextPredXact(sxact))
1577+
{
1578+
if (sxact->pid==blocked_pid)
1579+
break;
1580+
}
1581+
1582+
/* Did we find it, and is it currently waiting in GetSafeSnapshot? */
1583+
if (sxact!=NULL&&SxactIsDeferrableWaiting(sxact))
1584+
{
1585+
RWConflictpossibleUnsafeConflict;
1586+
1587+
/* Traverse the list of possible unsafe conflicts collecting PIDs. */
1588+
possibleUnsafeConflict= (RWConflict)
1589+
SHMQueueNext(&sxact->possibleUnsafeConflicts,
1590+
&sxact->possibleUnsafeConflicts,
1591+
offsetof(RWConflictData,inLink));
1592+
1593+
while (possibleUnsafeConflict!=NULL&&num_written<output_size)
1594+
{
1595+
output[num_written++]=possibleUnsafeConflict->sxactOut->pid;
1596+
possibleUnsafeConflict= (RWConflict)
1597+
SHMQueueNext(&sxact->possibleUnsafeConflicts,
1598+
&possibleUnsafeConflict->inLink,
1599+
offsetof(RWConflictData,inLink));
1600+
}
1601+
}
1602+
1603+
LWLockRelease(SerializableXactHashLock);
1604+
1605+
returnnum_written;
1606+
}
1607+
15581608
/*
15591609
* Acquire a snapshot that can be used for the current transaction.
15601610
*

‎src/backend/utils/adt/lockfuncs.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,125 @@ pg_blocking_pids(PG_FUNCTION_ARGS)
517517
}
518518

519519

520+
/*
521+
* pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
522+
* given PID from getting a safe snapshot
523+
*
524+
* XXX this does not consider parallel-query cases; not clear how big a
525+
* problem that is in practice
526+
*/
527+
Datum
528+
pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
529+
{
530+
intblocked_pid=PG_GETARG_INT32(0);
531+
int*blockers;
532+
intnum_blockers;
533+
Datum*blocker_datums;
534+
535+
/* A buffer big enough for any possible blocker list without truncation */
536+
blockers= (int*)palloc(MaxBackends*sizeof(int));
537+
538+
/* Collect a snapshot of processes waited for by GetSafeSnapshot */
539+
num_blockers=
540+
GetSafeSnapshotBlockingPids(blocked_pid,blockers,MaxBackends);
541+
542+
/* Convert int array to Datum array */
543+
if (num_blockers>0)
544+
{
545+
inti;
546+
547+
blocker_datums= (Datum*)palloc(num_blockers*sizeof(Datum));
548+
for (i=0;i<num_blockers;++i)
549+
blocker_datums[i]=Int32GetDatum(blockers[i]);
550+
}
551+
else
552+
blocker_datums=NULL;
553+
554+
/* Construct array, using hardwired knowledge about int4 type */
555+
PG_RETURN_ARRAYTYPE_P(construct_array(blocker_datums,num_blockers,
556+
INT4OID,
557+
sizeof(int32), true,'i'));
558+
}
559+
560+
561+
/*
562+
* pg_isolation_test_session_is_blocked - support function for isolationtester
563+
*
564+
* Check if specified PID is blocked by any of the PIDs listed in the second
565+
* argument. Currently, this looks for blocking caused by waiting for
566+
* heavyweight locks or safe snapshots. We ignore blockage caused by PIDs
567+
* not directly under the isolationtester's control, eg autovacuum.
568+
*
569+
* This is an undocumented function intended for use by the isolation tester,
570+
* and may change in future releases as required for testing purposes.
571+
*/
572+
Datum
573+
pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
574+
{
575+
intblocked_pid=PG_GETARG_INT32(0);
576+
ArrayType*interesting_pids_a=PG_GETARG_ARRAYTYPE_P(1);
577+
ArrayType*blocking_pids_a;
578+
int32*interesting_pids;
579+
int32*blocking_pids;
580+
intnum_interesting_pids;
581+
intnum_blocking_pids;
582+
intdummy;
583+
inti,
584+
j;
585+
586+
/* Validate the passed-in array */
587+
Assert(ARR_ELEMTYPE(interesting_pids_a)==INT4OID);
588+
if (array_contains_nulls(interesting_pids_a))
589+
elog(ERROR,"array must not contain nulls");
590+
interesting_pids= (int32*)ARR_DATA_PTR(interesting_pids_a);
591+
num_interesting_pids=ArrayGetNItems(ARR_NDIM(interesting_pids_a),
592+
ARR_DIMS(interesting_pids_a));
593+
594+
/*
595+
* Get the PIDs of all sessions blocking the given session's attempt to
596+
* acquire heavyweight locks.
597+
*/
598+
blocking_pids_a=
599+
DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids,blocked_pid));
600+
601+
Assert(ARR_ELEMTYPE(blocking_pids_a)==INT4OID);
602+
Assert(!array_contains_nulls(blocking_pids_a));
603+
blocking_pids= (int32*)ARR_DATA_PTR(blocking_pids_a);
604+
num_blocking_pids=ArrayGetNItems(ARR_NDIM(blocking_pids_a),
605+
ARR_DIMS(blocking_pids_a));
606+
607+
/*
608+
* Check if any of these are in the list of interesting PIDs, that being
609+
* the sessions that the isolation tester is running. We don't use
610+
* "arrayoverlaps" here, because it would lead to cache lookups and one of
611+
* our goals is to run quickly under CLOBBER_CACHE_ALWAYS. We expect
612+
* blocking_pids to be usually empty and otherwise a very small number in
613+
* isolation tester cases, so make that the outer loop of a naive search
614+
* for a match.
615+
*/
616+
for (i=0;i<num_blocking_pids;i++)
617+
for (j=0;j<num_interesting_pids;j++)
618+
{
619+
if (blocking_pids[i]==interesting_pids[j])
620+
PG_RETURN_BOOL(true);
621+
}
622+
623+
/*
624+
* Check if blocked_pid is waiting for a safe snapshot. We could in
625+
* theory check the resulting array of blocker PIDs against the
626+
* interesting PIDs whitelist, but since there is no danger of autovacuum
627+
* blocking GetSafeSnapshot there seems to be no point in expending cycles
628+
* on allocating a buffer and searching for overlap; so it's presently
629+
* sufficient for the isolation tester's purposes to use a single element
630+
* buffer and check if the number of safe snapshot blockers is non-zero.
631+
*/
632+
if (GetSafeSnapshotBlockingPids(blocked_pid,&dummy,1)>0)
633+
PG_RETURN_BOOL(true);
634+
635+
PG_RETURN_BOOL(false);
636+
}
637+
638+
520639
/*
521640
* Functions for manipulating advisory locks
522641
*

‎src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/*yyyymmddN */
56-
#defineCATALOG_VERSION_NO201704062
56+
#defineCATALOG_VERSION_NO201704101
5757

5858
#endif

‎src/include/catalog/pg_proc.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3139,7 +3139,11 @@ DESCR("show pg_hba.conf rules");
31393139
DATA(insert OID = 1371 ( pg_lock_status PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,26,26,23,21,25,28,26,26,21,25,23,25,16,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath}" _null_ _null_ pg_lock_status _null_ _null_ _null_ ));
31403140
DESCR("view system lock information");
31413141
DATA(insert OID = 2561 ( pg_blocking_pids PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 1007 "23" _null_ _null_ _null_ _null_ _null_ pg_blocking_pids _null_ _null_ _null_ ));
3142-
DESCR("get array of PIDs of sessions blocking specified backend PID");
3142+
DESCR("get array of PIDs of sessions blocking specified backend PID from acquiring a heavyweight lock");
3143+
DATA(insert OID = 3376 ( pg_safe_snapshot_blocking_pids PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 1007 "23" _null_ _null_ _null_ _null_ _null_ pg_safe_snapshot_blocking_pids _null_ _null_ _null_ ));
3144+
DESCR("get array of PIDs of sessions blocking specified backend PID from acquiring a safe snapshot");
3145+
DATA(insert OID = 3378 ( pg_isolation_test_session_is_blocked PGNSP PGUID 12 1 0 0 0 f f f f t f v s 2 0 16 "23 1007" _null_ _null_ _null_ _null_ _null_ pg_isolation_test_session_is_blocked _null_ _null_ _null_ ));
3146+
DESCR("isolationtester support function");
31433147
DATA(insert OID = 1065 ( pg_prepared_xact PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{28,25,1184,26,26}" "{o,o,o,o,o}" "{transaction,gid,prepared,ownerid,dbid}" _null_ _null_ pg_prepared_xact _null_ _null_ _null_ ));
31443148
DESCR("view two-phase transactions");
31453149
DATA(insert OID = 3819 ( pg_get_multixact_members PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 1 0 2249 "28" "{28,28,25}" "{i,o,o}" "{multixid,xid,mode}" _null_ _null_ pg_get_multixact_members _null_ _null_ _null_ ));

‎src/include/storage/predicate_internals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,5 +474,7 @@ typedef struct TwoPhasePredicateRecord
474474
* locking internals.
475475
*/
476476
externPredicateLockData*GetPredicateLockStatusData(void);
477+
externintGetSafeSnapshotBlockingPids(intblocked_pid,
478+
int*output,intoutput_size);
477479

478480
#endif/* PREDICATE_INTERNALS_H */

‎src/test/isolation/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
/specscanner.c
88

99
# Generated subdirectories
10+
/results/
1011
/output_iso/
1112
/tmp_check_iso/

‎src/test/isolation/isolationtester.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,20 +224,12 @@ main(int argc, char **argv)
224224
*/
225225
initPQExpBuffer(&wait_query);
226226
appendPQExpBufferStr(&wait_query,
227-
"SELECT pg_catalog.pg_blocking_pids($1) && '{");
227+
"SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{");
228228
/* The spec syntax requires at least one session; assume that here. */
229229
appendPQExpBufferStr(&wait_query,backend_pids[1]);
230230
for (i=2;i<nconns;i++)
231231
appendPQExpBuffer(&wait_query,",%s",backend_pids[i]);
232-
appendPQExpBufferStr(&wait_query,"}'::integer[]");
233-
234-
/* Also detect certain wait events. */
235-
appendPQExpBufferStr(&wait_query,
236-
" OR EXISTS ("
237-
" SELECT * "
238-
" FROM pg_catalog.pg_stat_activity "
239-
" WHERE pid = $1 "
240-
" AND wait_event IN ('SafeSnapshot'))");
232+
appendPQExpBufferStr(&wait_query,"}')");
241233

242234
res=PQprepare(conns[0],PREP_WAITING,wait_query.data,0,NULL);
243235
if (PQresultStatus(res)!=PGRES_COMMAND_OK)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp