Expose some information about backend subxact status.
authorRobert Haas <[email protected]>
Mon, 19 Dec 2022 19:43:09 +0000 (14:43 -0500)
committerRobert Haas <[email protected]>
Mon, 19 Dec 2022 19:43:09 +0000 (14:43 -0500)
A new function pg_stat_get_backend_subxact() can be used to get
information about the number of subtransactions in the cache of
a particular backend and whether that cache has overflowed. This
can be useful for tracking down performance problems that can
result from overflowed snapshots.

Dilip Kumar, reviewed by Zhihong Yu, Nikolay Samokhvalov,
Justin Pryzby, Nathan Bossart, Ashutosh Sharma, Julien
Rouhaud. Additional design comments from Andres Freund,
Tom Lane, Bruce Momjian, and David G. Johnston.

Discussion: http://postgr.es/m/CAFiTN-ut0uwkRJDQJeDPXpVyTWD46m3gt3JDToE02hTfONEN=Q@mail.gmail.com

doc/src/sgml/monitoring.sgml
src/backend/storage/ipc/sinvaladt.c
src/backend/utils/activity/backend_status.c
src/backend/utils/adt/pgstatfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/include/storage/sinvaladt.h
src/include/utils/backend_status.h

index 11a8ebe5ec7697dbbe0c8ab22a5d8f47261155fa..363b183e5f0f02a901bb7a7bab5193a1ca2dcf0a 100644 (file)
@@ -5671,6 +5671,24 @@ FROM pg_stat_get_backend_idset() AS backendid;
        </para></entry>
       </row>
 
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>pg_stat_get_backend_subxact</primary>
+        </indexterm>
+        <function>pg_stat_get_backend_subxact</function> ( <type>integer</type> )
+        <returnvalue>record</returnvalue>
+       </para>
+       <para>
+        Returns a record of information about the subtransactions of the
+        backend with the specified ID.
+        The fields returned are <parameter>subxact_count</parameter>, which
+        is the number of subtransactions in the backend's subtransaction cache,
+        and <parameter>subxact_overflow</parameter>, which indicates whether
+        the backend's subtransaction cache is overflowed or not.
+       </para></entry>
+      </row>
+
       <row>
        <entry role="func_table_entry"><para role="func_signature">
         <indexterm>
index 59310b708fbd1f61ed7e394767b9b0389c48675e..4a20fe7ebeed6031d30a5ddd5f5ec3f081315e5b 100644 (file)
@@ -404,17 +404,20 @@ BackendIdGetProc(int backendID)
 
 /*
  * BackendIdGetTransactionIds
- *             Get the xid and xmin of the backend. The result may be out of date
- *             arbitrarily quickly, so the caller must be careful about how this
- *             information is used.
+ *             Get the xid, xmin, nsubxid and overflow status of the backend. The
+ *             result may be out of date arbitrarily quickly, so the caller must be
+ *             careful about how this information is used.
  */
 void
-BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin)
+BackendIdGetTransactionIds(int backendID, TransactionId *xid,
+                                                  TransactionId *xmin, int *nsubxid, bool *overflowed)
 {
        SISeg      *segP = shmInvalBuffer;
 
        *xid = InvalidTransactionId;
        *xmin = InvalidTransactionId;
+       *nsubxid = 0;
+       *overflowed = false;
 
        /* Need to lock out additions/removals of backends */
        LWLockAcquire(SInvalWriteLock, LW_SHARED);
@@ -428,6 +431,8 @@ BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmi
                {
                        *xid = proc->xid;
                        *xmin = proc->xmin;
+                       *nsubxid = proc->subxidStatus.count;
+                       *overflowed = proc->subxidStatus.overflowed;
                }
        }
 
index 1146a6c33cdcb7615af7a182e175e816d6e60d1e..7ecf467b8cde9245c369c8002cf3438b19639043 100644 (file)
@@ -855,7 +855,9 @@ pgstat_read_current_status(void)
                        localentry->backend_id = i;
                        BackendIdGetTransactionIds(i,
                                                                           &localentry->backend_xid,
-                                                                          &localentry->backend_xmin);
+                                                                          &localentry->backend_xmin,
+                                                                          &localentry->backend_subxact_count,
+                                                                          &localentry->backend_subxact_overflowed);
 
                        localentry++;
                        localappname += NAMEDATALEN;
index 04a5a9900256bb875a638f6290936b567582b527..46f98fd67f5ba1e299b7e006d1a60f5174105f7d 100644 (file)
@@ -687,6 +687,44 @@ pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
        PG_RETURN_OID(beentry->st_userid);
 }
 
+Datum
+pg_stat_get_backend_subxact(PG_FUNCTION_ARGS)
+{
+#define PG_STAT_GET_SUBXACT_COLS       2
+       TupleDesc       tupdesc;
+       Datum           values[PG_STAT_GET_SUBXACT_COLS];
+       bool            nulls[PG_STAT_GET_SUBXACT_COLS];
+       int32           beid = PG_GETARG_INT32(0);
+       LocalPgBackendStatus *local_beentry;
+
+       /* Initialise values and NULL flags arrays */
+       MemSet(values, 0, sizeof(values));
+       MemSet(nulls, 0, sizeof(nulls));
+
+       /* Initialise attributes information in the tuple descriptor */
+       tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBXACT_COLS);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subxact_count",
+                                          INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "subxact_overflow",
+                                          BOOLOID, -1, 0);
+
+       BlessTupleDesc(tupdesc);
+
+       if ((local_beentry = pgstat_fetch_stat_local_beentry(beid)) != NULL)
+       {
+               /* Fill values and NULLs */
+               values[0] = Int32GetDatum(local_beentry->backend_subxact_count);
+               values[1] = BoolGetDatum(local_beentry->backend_subxact_overflowed);
+       }
+       else
+       {
+               nulls[0] = true;
+               nulls[1] = true;
+       }
+
+       /* Returns the record as Datum */
+       PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
+}
 
 Datum
 pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
index 5cb12437a67e658d075c6a75d884082b509c7fc9..094f59f82db94d29b834f56d725f61330c306c5f 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202212131
+#define CATALOG_VERSION_NO     202212191
 
 #endif
index 719599649a96692ad564a9df91da52e7a8912b14..d763419c0de5e287c53ea31a061b933c6680d248 100644 (file)
   proname => 'pg_stat_get_backend_dbid', provolatile => 's', proparallel => 'r',
   prorettype => 'oid', proargtypes => 'int4',
   prosrc => 'pg_stat_get_backend_dbid' },
+{ oid => '6107', descr => 'statistics: get subtransaction status of backend',
+  proname => 'pg_stat_get_backend_subxact', provolatile => 's', proparallel => 'r',
+  prorettype => 'record', proargtypes => 'int4',
+  proallargtypes => '{int4,int4,bool}',
+  proargmodes => '{i,o,o}',
+  proargnames => '{bid,subxact_count,subxact_overflowed}',
+  prosrc => 'pg_stat_get_backend_subxact' },
 { oid => '1939', descr => 'statistics: user ID of backend',
   proname => 'pg_stat_get_backend_userid', provolatile => 's',
   proparallel => 'r', prorettype => 'oid', proargtypes => 'int4',
index 91e24189a7a63c0d686f936d7bec9d1ed6c9618b..bf739ebdba7c559fd316aa9f78c4a38b10cf6f1a 100644 (file)
@@ -32,7 +32,9 @@ extern Size SInvalShmemSize(void);
 extern void CreateSharedInvalidationState(void);
 extern void SharedInvalBackendInit(bool sendOnly);
 extern PGPROC *BackendIdGetProc(int backendID);
-extern void BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin);
+extern void BackendIdGetTransactionIds(int backendID, TransactionId *xid,
+                                                                          TransactionId *xmin, int *nsubxid,
+                                                                          bool *overflowed);
 
 extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
 extern int     SIGetDataEntries(SharedInvalidationMessage *data, int datasize);
index b582b46e9f99d61427b7ef1be5545dead0e55302..e076adcaa82cb70bfa15df145ec0d268045a56d8 100644 (file)
@@ -266,6 +266,17 @@ typedef struct LocalPgBackendStatus
         * not.
         */
        TransactionId backend_xmin;
+
+       /*
+        * Number of cached subtransactions in the current session.
+        */
+       int     backend_subxact_count;
+
+       /*
+        * The number of subtransactions in the current session exceeded the cached
+        * subtransaction limit.
+        */
+       bool backend_subxact_overflowed;
 } LocalPgBackendStatus;