On Fri, Dec 17, 2021 at 9:32 AM Justin Pryzby <pry...@telsasoft.com> wrote:

> On Fri, Dec 17, 2021 at 09:00:04AM +0530, Dilip Kumar wrote:
> > On Tue, Dec 14, 2021 at 3:57 AM Bossart, Nathan <bossa...@amazon.com>
> wrote:
> > >
> > > On 12/13/21, 6:30 AM, "Dilip Kumar" <dilipbal...@gmail.com> wrote:
> > > > On Tue, Dec 7, 2021 at 11:11 AM Justin Pryzby <pry...@telsasoft.com>
> wrote:
> > > >> Since I think this field is usually not interesting to most users of
> > > >> pg_stat_activity, maybe this should instead be implemented as a
> function like
> > > >> pg_backend_get_subxact_status(pid).
> > > >>
> > > >> People who want to could use it like:
> > > >> SELECT * FROM pg_stat_activity psa,
> pg_backend_get_subxact_status(pid) sub;
> > > >
> > > > I have provided two function, one for subtransaction counts and other
> > > > whether subtransaction cache is overflowed or not, we can use like
> > > > this,  if we think this is better way to do it then we can also add
> > > > another function for the lastOverflowedXid
> > >
> > > The general approach looks good to me.  I think we could have just one
> > > function for all three values, though.
> >
> > If we create just one function then the output type will be a tuple
> > then we might have to add another view on top of that.  Is there any
> > better way to do that?
>
> I don't think you'd need to add a view on top of it.
>
> Compare:
>
> postgres=# SELECT 1, pg_config() LIMIT 1;
>  ?column? |         pg_config
> ----------+----------------------------
>         1 | (BINDIR,/usr/pgsql-14/bin)
>
> postgres=# SELECT 1, c FROM pg_config() c LIMIT 1;
>  ?column? |             c
> ----------+----------------------------
>         1 | (BINDIR,/usr/pgsql-14/bin)
>
> postgres=# SELECT 1, c.* FROM pg_config() c LIMIT 1;
>  ?column? |  name  |      setting
> ----------+--------+-------------------
>         1 | BINDIR | /usr/pgsql-14/bin
>

Okay, that makes sense, I have modified it to make a single function.



-- 
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com
From 5e5dd3c6a4056b1ef821fa5d7dccf5044f1fa48c Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumar@localhost.localdomain>
Date: Sun, 12 Dec 2021 17:10:55 +0530
Subject: [PATCH v3] Add functions to show subtransaction count and overflow
 status

If there are some backends having a lot of nested subtransaction
or the subtransaction cache is overflowed there is a no way to
detect that.  So this patch is making that easy by providing
function to get that information.
---
 doc/src/sgml/monitoring.sgml                | 18 ++++++++++++++
 src/backend/storage/ipc/sinvaladt.c         | 13 +++++++---
 src/backend/utils/activity/backend_status.c |  4 ++-
 src/backend/utils/adt/pgstatfuncs.c         | 38 +++++++++++++++++++++++++++++
 src/include/catalog/pg_proc.dat             |  7 ++++++
 src/include/storage/sinvaladt.h             |  4 ++-
 src/include/utils/backend_status.h          | 11 +++++++++
 7 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 62f2a33..4388151 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -5482,6 +5482,24 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
       <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 backend's subtransactions.
+        The fields returned are <parameter>subxact_count</parameter> identifies
+        number of active subtransaction and <parameter>subxact_overflow
+        </parameter> shows whether the backend's subtransaction cache is
+        overflowed or not.
+       </para></entry>
+       </para></entry>
+      </row>
+
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
          <primary>pg_stat_get_backend_userid</primary>
         </indexterm>
         <function>pg_stat_get_backend_userid</function> ( <type>integer</type> )
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index cb3ee82..8713c88 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -395,17 +395,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 and 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);
@@ -419,6 +422,8 @@ BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmi
 		{
 			*xid = proc->xid;
 			*xmin = proc->xmin;
+			*nsubxid = proc->subxidStatus.count;
+			*overflowed = proc->subxidStatus.overflowed;
 		}
 	}
 
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 2fecf26..5349e40 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -848,7 +848,9 @@ pgstat_read_current_status(void)
 		{
 			BackendIdGetTransactionIds(i,
 									   &localentry->backend_xid,
-									   &localentry->backend_xmin);
+									   &localentry->backend_xmin,
+									   &localentry->backend_subxact_count,
+									   &localentry->backend_subxact_overflowed);
 
 			localentry++;
 			localappname += NAMEDATALEN;
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 15cb17a..850dc61 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1005,6 +1005,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)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d6bf1f3..953af32 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5398,6 +5398,13 @@
   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',
diff --git a/src/include/storage/sinvaladt.h b/src/include/storage/sinvaladt.h
index 91e2418..bf739eb 100644
--- a/src/include/storage/sinvaladt.h
+++ b/src/include/storage/sinvaladt.h
@@ -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);
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 8217d0c..01432ae 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -258,6 +258,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;
 
 
-- 
1.8.3.1

Reply via email to