Re: exposing wait events for non-backends (was: Tracking wait event for latches)

Started by Robert Haasabout 9 years ago42 messages
#1Robert Haas
robertmhaas@gmail.com

On Tue, Oct 4, 2016 at 11:59 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 3, 2016 at 8:43 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

The rest looks good to me. Thanks for the feedback and the time!

Thanks for the fixes. I committed this with an additional compile
fix, but the buildfarm turned up a few more problems that my 'make
check-world' didn't find. Hopefully those are fixed now, but we'll
see.

So, one of the problems in this patch as committed is that for any
process that doesn't show up in pg_stat_activity, there's no way to
see the wait event information. That sucks. I think there are
basically two ways to fix this:

1. Show all processes that have a PGPROC in pg_stat_activity,
including auxiliary processes and whatnot, and use some new field in
pg_stat_activity to indicate the process type.

2. Add a second view, say pg_stat_system_activity, to show the
processes that don't appear in pg_stat_activity. A bunch of columns
could likely be omitted, but there would be some duplication, too.

Preferences?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#1)

Robert Haas wrote:

So, one of the problems in this patch as committed is that for any
process that doesn't show up in pg_stat_activity, there's no way to
see the wait event information. That sucks. I think there are
basically two ways to fix this:

1. Show all processes that have a PGPROC in pg_stat_activity,
including auxiliary processes and whatnot, and use some new field in
pg_stat_activity to indicate the process type.

2. Add a second view, say pg_stat_system_activity, to show the
processes that don't appear in pg_stat_activity. A bunch of columns
could likely be omitted, but there would be some duplication, too.

Preferences?

I vote 1.

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#2)

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

Robert Haas wrote:

So, one of the problems in this patch as committed is that for any
process that doesn't show up in pg_stat_activity, there's no way to
see the wait event information. That sucks. I think there are
basically two ways to fix this:

1. Show all processes that have a PGPROC in pg_stat_activity,
including auxiliary processes and whatnot, and use some new field in
pg_stat_activity to indicate the process type.

2. Add a second view, say pg_stat_system_activity, to show the
processes that don't appear in pg_stat_activity. A bunch of columns
could likely be omitted, but there would be some duplication, too.

Preferences?

I vote 1.

If we go with #2, there would immediately be a need for a union view,
which would end up being exactly the same thing as the expanded display
proposed in #1. Seems like the hard way, so I agree with Alvaro.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Andres Freund
andres@anarazel.de
In reply to: Alvaro Herrera (#2)

On 2016-12-12 13:26:32 -0300, Alvaro Herrera wrote:

Robert Haas wrote:

So, one of the problems in this patch as committed is that for any
process that doesn't show up in pg_stat_activity, there's no way to
see the wait event information. That sucks. I think there are
basically two ways to fix this:

1. Show all processes that have a PGPROC in pg_stat_activity,
including auxiliary processes and whatnot, and use some new field in
pg_stat_activity to indicate the process type.

2. Add a second view, say pg_stat_system_activity, to show the
processes that don't appear in pg_stat_activity. A bunch of columns
could likely be omitted, but there would be some duplication, too.

Preferences?

I vote 1.

+1

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5David G. Johnston
david.g.johnston@gmail.com
In reply to: Robert Haas (#1)

On Mon, Dec 12, 2016 at 9:19 AM, Robert Haas <robertmhaas@gmail.com> wrote:

So, one of the problems in this patch as committed is that for any
process that doesn't show up in pg_stat_activity, there's no way to
see the wait event information. That sucks. I think there are
basically two ways to fix this:

1. Show all processes that have a PGPROC in pg_stat_activity,
including auxiliary processes and whatnot, and use some new field in
pg_stat_activity to indicate the process type.

2. Add a second view, say pg_stat_system_activity, to show the
processes that don't appear in pg_stat_activity. A bunch of columns
could likely be omitted, but there would be some duplication, too.

Preferences?

​I'm inclined toward option 2.

A view over both that involves just the shared columns would give you the
benefits from option 1.

Question: is there a parent-child relationship involved here? Given a
record in today's pg_stat_activity is it useful/possible to link in all of
the pg_stat_system_activity​ process that are working to fulfill the
client-initiated task?

Even with "system" we'd probably want to distinguish between background
workers and true system maintenance processes. Or am I mis-interpreting
the scope of this feature?

David J.

#6Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#1)

On Mon, Dec 12, 2016 at 11:19 AM, Robert Haas <robertmhaas@gmail.com> wrote:

So, one of the problems in this patch as committed is that for any
process that doesn't show up in pg_stat_activity, there's no way to
see the wait event information. That sucks. I think there are
basically two ways to fix this:

1. Show all processes that have a PGPROC in pg_stat_activity,
including auxiliary processes and whatnot, and use some new field in
pg_stat_activity to indicate the process type.

2. Add a second view, say pg_stat_system_activity, to show the
processes that don't appear in pg_stat_activity. A bunch of columns
could likely be omitted, but there would be some duplication, too.

Preferences?

And now I'm noticing that Michael Paquier previously started a thread
on this problem which I failed to note before starting this one:

/messages/by-id/CAB7nPqSYN05rGsYCTahxTz+2hBikh7=m+hr2JTXaZv_Ei=qJAg@mail.gmail.com

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Kevin Grittner
kgrittn@gmail.com
In reply to: Andres Freund (#4)

On Mon, Dec 12, 2016 at 10:33 AM, Andres Freund <andres@anarazel.de> wrote:

On 2016-12-12 13:26:32 -0300, Alvaro Herrera wrote:

Robert Haas wrote:

1. Show all processes that have a PGPROC in pg_stat_activity,

2. Add a second view, say pg_stat_system_activity,

I vote 1.

+1

+1

--
Kevin Grittner
EDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#6)

On Tue, Dec 13, 2016 at 1:45 AM, Robert Haas <robertmhaas@gmail.com> wrote:

And now I'm noticing that Michael Paquier previously started a thread
on this problem which I failed to note before starting this one:

/messages/by-id/CAB7nPqSYN05rGsYCTahxTz+2hBikh7=m+hr2JTXaZv_Ei=qJAg@mail.gmail.com

Yes. I already had a look at what could be done to expose the
auxiliary processes in a system view with a set of proposals, though I
am not sure what would be better. It would be better to move the
discussion on this thread in my opinion, we are tracking down a
solution for a new problem.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Craig Ringer
craig@2ndquadrant.com
In reply to: Kevin Grittner (#7)

On 13 December 2016 at 01:45, Kevin Grittner <kgrittn@gmail.com> wrote:

On Mon, Dec 12, 2016 at 10:33 AM, Andres Freund <andres@anarazel.de> wrote:

On 2016-12-12 13:26:32 -0300, Alvaro Herrera wrote:

Robert Haas wrote:

1. Show all processes that have a PGPROC in pg_stat_activity,

2. Add a second view, say pg_stat_system_activity,

I vote 1.

+1

+1

I've long wanted the ability to see auxillary process state in
pg_stat_activity, so +1.

Right now pg_stat_replication is a join over pg_stat_get_activity()
and pg_stat_get_wal_senders() filtered for walsenders, and
pg_stat_activity is a view over pg_stat_get_activity() filtered for
processes with a user id. I'd really like to see walsenders in
pg_stat_activity now that logical decoding makes them more than dumb
I/O channels, as well as other auxillary processes.

We should probably expose a proc_type or something, with types:

* client_backend
* bgworker
* walsender
* autovacuum
* checkpointer
* bgwriter

for simpler filtering.

I don't think existing user code is likely to get upset by more
processes appearing in pg_stat_activity, and it'll be very handy.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Michael Paquier
michael.paquier@gmail.com
In reply to: Craig Ringer (#9)

On Tue, Dec 13, 2016 at 10:05 AM, Craig Ringer <craig@2ndquadrant.com> wrote:

We should probably expose a proc_type or something, with types:

* client_backend
* bgworker
* walsender
* autovacuum
* checkpointer
* bgwriter

A text field is adapted then, more than a single character.

for simpler filtering.

I don't think existing user code is likely to get upset by more
processes appearing in pg_stat_activity, and it'll be very handy.

Indeed, for WAL senders now abusing of the query field is definitely
not consistent. Even if having this information is useful, adding such
a column would make sense. Still, one thing that is important to keep
with pg_stat_activity is the ability to count the number of
connections that are part of max_connections for monitoring purposes.
The docs definitely would need an example of such a query counting
only client_backend and WAL senders and tell users that this can be
used to count how many active connections there are.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Craig Ringer
craig@2ndquadrant.com
In reply to: Michael Paquier (#10)

On 13 December 2016 at 09:13, Michael Paquier <michael.paquier@gmail.com> wrote:

On Tue, Dec 13, 2016 at 10:05 AM, Craig Ringer <craig@2ndquadrant.com> wrote:

We should probably expose a proc_type or something, with types:

* client_backend
* bgworker
* walsender
* autovacuum
* checkpointer
* bgwriter

A text field is adapted then, more than a single character.

for simpler filtering.

I don't think existing user code is likely to get upset by more
processes appearing in pg_stat_activity, and it'll be very handy.

Indeed, for WAL senders now abusing of the query field is definitely
not consistent. Even if having this information is useful, adding such
a column would make sense. Still, one thing that is important to keep
with pg_stat_activity is the ability to count the number of
connections that are part of max_connections for monitoring purposes.
The docs definitely would need an example of such a query counting
only client_backend and WAL senders and tell users that this can be
used to count how many active connections there are.

Good point.

No need for a new field, since a non-null client_port should be
sufficient. But definitely documented.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Robert Haas
robertmhaas@gmail.com
In reply to: Michael Paquier (#10)

On Mon, Dec 12, 2016 at 8:13 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Tue, Dec 13, 2016 at 10:05 AM, Craig Ringer <craig@2ndquadrant.com> wrote:

We should probably expose a proc_type or something, with types:

* client_backend
* bgworker
* walsender
* autovacuum
* checkpointer
* bgwriter

A text field is adapted then, more than a single character.

Sure.

for simpler filtering.

I don't think existing user code is likely to get upset by more
processes appearing in pg_stat_activity, and it'll be very handy.

Indeed, for WAL senders now abusing of the query field is definitely
not consistent. Even if having this information is useful, adding such
a column would make sense. Still, one thing that is important to keep
with pg_stat_activity is the ability to count the number of
connections that are part of max_connections for monitoring purposes.
The docs definitely would need an example of such a query counting
only client_backend and WAL senders and tell users that this can be
used to count how many active connections there are.

Let's confine ourselves to fixing one problem at a time. I think we
can get where we want to be in this case by adding one new column and
some new rows to pg_stat_activity. Michael, is that something you're
going to do? If not, one of my esteemed colleagues here at
EnterpriseDB will have a try.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Magnus Hagander
magnus@hagander.net
In reply to: Kevin Grittner (#7)

On Mon, Dec 12, 2016 at 6:45 PM, Kevin Grittner <kgrittn@gmail.com> wrote:

On Mon, Dec 12, 2016 at 10:33 AM, Andres Freund <andres@anarazel.de>
wrote:

On 2016-12-12 13:26:32 -0300, Alvaro Herrera wrote:

Robert Haas wrote:

1. Show all processes that have a PGPROC in pg_stat_activity,

2. Add a second view, say pg_stat_system_activity,

I vote 1.

+1

+1

+1 more, if we're still counting.

--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/

#14Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#12)

On Tue, Dec 13, 2016 at 11:40:54AM -0500, Robert Haas wrote:

Let's confine ourselves to fixing one problem at a time. I think we
can get where we want to be in this case by adding one new column and
some new rows to pg_stat_activity.

Agreed. Let's also remove the abuse of WAL senders with the query field
at the same time.

Michael, is that something you're
going to do? If not, one of my esteemed colleagues here at
EnterpriseDB will have a try.

If I had received feedback on the other thread, I would have coded a
proposal of patch already. But as long as SCRAM is not done I will
restrain from taking an extra project. I am fine to do reviews as I already
looked at ways to solve the problem though. So if anybody has room to do
it please be my guest.

Regarding the way to solve things, I think that having in ProcGlobal an
array of PGPROC entries for each auxiliary process is the way to go, the
position of each entry in the array defining what the process type is.
That would waste some shared memory, but we are not talking about that
much here. That would as well remove the need of having checkpointerLatch,
walWriteLatch and the startup fields in ProcGlobal.
--
Michael

#15Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Michael Paquier (#14)
4 attachment(s)

Hello everyone,

As discussed in this thread, I've attached a set of patches to show
auxiliary processes, autovacuum launcher and bgworker along with other
backends in pg_stat_activity. For now, I've extended
BackendStatusArray to store auxiliary processes. Backends use slots
indexed in the range from 1 to MaxBackends (inclusive), so we use
MaxBackends + AuxProcType + 1 as the index of the slot for an
auxiliary process. However, BackendStatusArray should be renamed to
something like 'ProcStatusArray' along with many others in pgstat.c
and pgstatfuncs.c(Ex: LocalPgBackendStatus etc). But, that needs a
major code refactoring. I can do the changes if we agree with that.

I've also kept a local array, named localBackendStatusIndex, which
stores the index of currently active backends from BackendStatusArray.
It assigns ids to currently active backend from 1 to the number of
active backends.(It is required in some pgstat_* functions, for
example: pg_stat_get_backend_idset). Hence, we are not affecting the
outputs of other sql functions apart from pg_stat_activity and
pg_stat_get_activity.

I've also added an extra column, named proc_type (suggested by Craig
and Robert), to indicate the type of process in pg_stat_activity view.
proc_type includes:

* client backend
* autovacuum launcher
* wal sender
* bgworker
* writer
* checkpointer
* wal writer
* wal receiver

Here is the present output with the relevant columns. (Didn't show
backend_start since it takes too long space)

postgres=# select pid, usesysid, application_name, wait_event_type,
wait_event, state, proc_type from pg_stat_activity;
pid | usesysid | application_name | wait_event_type |
wait_event | state | proc_type
--------+----------+------------------------------+-----------------+---------------------+--------+---------------------
109945 | | | Activity |
AutoVacuumMain | idle | autovacuum launcher
109947 | | logical replication launcher | Activity |
LogicalLauncherMain | idle | bgworker
109962 | 10 | walreceiver | Activity |
WalSenderMain | idle | wal sender
109976 | 10 | psql | |
| active | client backend
109943 | | | Activity |
BgWriterMain | idle | writer
109942 | | | Activity |
CheckpointerMain | idle | checkpointer
109944 | | | Activity |
WalWriterMain | idle | wal writer
(7 rows)

Whereas, the output of other pgstat_* functions remains unchanged. For example,

postgres=# SELECT pg_stat_get_backend_pid(s.backendid) AS procpid,
pg_stat_get_backend_activity(s.backendid) AS current_query
FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;
procpid | current_query
---------+-------------------------------------------------------------------
120713 | SELECT pg_stat_get_backend_pid(s.backendid) AS procpid, +
| pg_stat_get_backend_activity(s.backendid) AS current_query+
| FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;

Thoughts?

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Infra-to-expose-non-backend-processes-in-pg_stat_get.patchapplication/x-download; name=0001-Infra-to-expose-non-backend-processes-in-pg_stat_get.patchDownload
From 1e47895422410a9de9200c7dc17f767d85c29752 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 15:34:18 +0530
Subject: [PATCH] Infra to expose non-backend processes in pg_stat_get_activity

This patch implements the infrastructure required to expose
non-backend processes in pg_stat_activity. BackendStatusArray
is extended to store auxiliary processes as well. Backends use slots
indexed in the range from 1 to MaxBackends (inclusive), so we use
MaxBackends + AuxProcType + 1 as the index of the slot for an
auxiliary process.
---
 src/backend/postmaster/pgstat.c     | 304 ++++++++++++++++++++++++++++++------
 src/backend/storage/lmgr/proc.c     |  27 ++++
 src/backend/utils/adt/pgstatfuncs.c | 120 ++++++++------
 src/backend/utils/init/postinit.c   |   4 +-
 src/include/pgstat.h                |  35 ++++-
 src/include/storage/proc.h          |   1 +
 6 files changed, 392 insertions(+), 99 deletions(-)

diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7176cf1..069e390 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -212,7 +213,17 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
-static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Status for backends and auxiliary processes */
+static LocalPgBackendStatus *localProcStatusTable = NULL;
+
+/* Total number of processes including backends and auxiliary */
+static int	localNumProcs = 0;
+
+/* Index to backends in localProcStatusTable */
+static int *localBackendStatusIndex = NULL;
+
+/* Total number of backend processes */
 static int	localNumBackends = 0;
 
 /*
@@ -2404,7 +2415,29 @@ pgstat_fetch_stat_beentry(int beid)
 	if (beid < 1 || beid > localNumBackends)
 		return NULL;
 
-	return &localBackendStatusTable[beid - 1].backendStatus;
+	return &localProcStatusTable[localBackendStatusIndex[beid - 1]].backendStatus;
+}
+
+
+/* ----------
+ * pgstat_fetch_stat_procentry() -
+ *
+ *	Support function for the SQL-callable pgstat* functions. Returns
+ *	our local copy of the current-activity entry for one process.
+ *
+ *	NB: caller is responsible for a check if the user is permitted to see
+ *	this info (especially the querystring).
+ * ----------
+ */
+PgBackendStatus *
+pgstat_fetch_stat_procentry(int procid)
+{
+	pgstat_read_current_status();
+
+	if (procid < 1 || procid > localNumProcs)
+		return NULL;
+
+	return &localProcStatusTable[procid - 1].backendStatus;
 }
 
 
@@ -2426,7 +2459,29 @@ pgstat_fetch_stat_local_beentry(int beid)
 	if (beid < 1 || beid > localNumBackends)
 		return NULL;
 
-	return &localBackendStatusTable[beid - 1];
+	return &localProcStatusTable[localBackendStatusIndex[beid - 1]];
+}
+
+
+/* ----------
+ * pgstat_fetch_stat_local_procentry() -
+ *
+ *	Like pgstat_fetch_stat_procentry() but with locally computed additions (like
+ *	xid and xmin values of the backend)
+ *
+ *	NB: caller is responsible for a check if the user is permitted to see
+ *	this info (especially the querystring).
+ * ----------
+ */
+LocalPgBackendStatus *
+pgstat_fetch_stat_local_procentry(int procid)
+{
+	pgstat_read_current_status();
+
+	if (procid < 1 || procid > localNumProcs)
+		return NULL;
+
+	return &localProcStatusTable[procid - 1];
 }
 
 
@@ -2445,6 +2500,22 @@ pgstat_fetch_stat_numbackends(void)
 	return localNumBackends;
 }
 
+
+/* ----------
+ * pgstat_fetch_stat_numprocs() -
+ *
+ *	Support function for the SQL-callable pgstat* functions. Returns
+ *	the maximum current process id.
+ * ----------
+ */
+int
+pgstat_fetch_stat_numprocs(void)
+{
+	pgstat_read_current_status();
+
+	return localNumProcs;
+}
+
 /*
  * ---------
  * pgstat_fetch_stat_archiver() -
@@ -2504,20 +2575,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumProcStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumProcStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumProcStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+				mul_size(pgstat_track_activity_query_size, NumProcStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+					mul_size(sizeof(PgBackendSSLStatus), NumProcStatSlots));
 #endif
 	return size;
 }
@@ -2535,7 +2606,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumProcStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2558,7 +2629,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2576,7 +2647,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2585,7 +2656,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumProcStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2597,7 +2668,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2606,7 +2677,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumProcStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2618,7 +2689,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2632,7 +2703,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2642,27 +2714,47 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		/* Just a backend process */
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxProcType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
 }
 
 /* ----------
- * pgstat_bestart() -
+ * pgstat_procstart() -
+ *
+ *	Initialize this process's entry in the PgBackendStatus array.
+ *	Called from InitPostgres and AuxiliaryProcessMain.
  *
- *	Initialize this backend's entry in the PgBackendStatus array.
- *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *	For a backend process, MyDatabaseId, session userid,
+ *	and application_name must be set (hence, this cannot be combined
+ *	with pgstat_initialize).
  * ----------
  */
 void
-pgstat_bestart(void)
+pgstat_procstart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2677,7 +2769,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2696,6 +2787,55 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		/* Must be a backend process */
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_procType = PROC_AUTOVAC_LAUNCHER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_procType = PROC_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_procType = PROC_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_procType = PROC_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case BgWriterProcess:
+				beentry->st_procType = PROC_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_procType = PROC_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_procType = PROC_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_procType = PROC_WAL_RECEIVER;
+				break;
+			default:
+				elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2707,8 +2847,15 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends and wal-sender processes */
+	if (beentry->st_procType == PROC_BACKEND || beentry->st_procType == PROC_WAL_SENDER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
+
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
 				NAMEDATALEN);
@@ -3027,7 +3174,7 @@ pgstat_report_xact_timestamp(TimestampTz tstamp)
 static void
 pgstat_read_current_status(void)
 {
-	volatile PgBackendStatus *beentry;
+	volatile PgBackendStatus *procentry;
 	LocalPgBackendStatus *localtable;
 	LocalPgBackendStatus *localentry;
 	char	   *localappname,
@@ -3038,31 +3185,31 @@ pgstat_read_current_status(void)
 	int			i;
 
 	Assert(!pgStatRunningInCollector);
-	if (localBackendStatusTable)
+	if (localProcStatusTable && localBackendStatusIndex)
 		return;					/* already done */
 
 	pgstat_setup_memcxt();
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						   sizeof(LocalPgBackendStatus) * NumProcStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumProcStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					   pgstat_track_activity_query_size * NumProcStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumProcStatSlots);
 #endif
 
-	localNumBackends = 0;
+	localNumProcs = 0;
 
-	beentry = BackendStatusArray;
+	procentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumProcStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3076,32 +3223,32 @@ pgstat_read_current_status(void)
 			int			before_changecount;
 			int			after_changecount;
 
-			pgstat_save_changecount_before(beentry, before_changecount);
+			pgstat_save_changecount_before(procentry, before_changecount);
 
-			localentry->backendStatus.st_procpid = beentry->st_procpid;
+			localentry->backendStatus.st_procpid = procentry->st_procpid;
 			if (localentry->backendStatus.st_procpid > 0)
 			{
-				memcpy(&localentry->backendStatus, (char *) beentry, sizeof(PgBackendStatus));
+				memcpy(&localentry->backendStatus, (char *) procentry, sizeof(PgBackendStatus));
 
 				/*
 				 * strcpy is safe even if the string is modified concurrently,
 				 * because there's always a \0 at the end of the buffer.
 				 */
-				strcpy(localappname, (char *) beentry->st_appname);
+				strcpy(localappname, (char *) procentry->st_appname);
 				localentry->backendStatus.st_appname = localappname;
-				strcpy(localactivity, (char *) beentry->st_activity);
+				strcpy(localactivity, (char *) procentry->st_activity);
 				localentry->backendStatus.st_activity = localactivity;
-				localentry->backendStatus.st_ssl = beentry->st_ssl;
+				localentry->backendStatus.st_ssl = procentry->st_ssl;
 #ifdef USE_SSL
-				if (beentry->st_ssl)
+				if (procentry->st_ssl)
 				{
-					memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
+					memcpy(localsslstatus, procentry->st_sslstatus, sizeof(PgBackendSSLStatus));
 					localentry->backendStatus.st_sslstatus = localsslstatus;
 				}
 #endif
 			}
 
-			pgstat_save_changecount_after(beentry, after_changecount);
+			pgstat_save_changecount_after(procentry, after_changecount);
 			if (before_changecount == after_changecount &&
 				(before_changecount & 1) == 0)
 				break;
@@ -3110,7 +3257,7 @@ pgstat_read_current_status(void)
 			CHECK_FOR_INTERRUPTS();
 		}
 
-		beentry++;
+		procentry++;
 		/* Only valid entries get included into the local array */
 		if (localentry->backendStatus.st_procpid > 0)
 		{
@@ -3124,12 +3271,35 @@ pgstat_read_current_status(void)
 #ifdef USE_SSL
 			localsslstatus++;
 #endif
-			localNumBackends++;
+			localNumProcs++;
 		}
 	}
 
 	/* Set the pointer only after completion of a valid table */
-	localBackendStatusTable = localtable;
+	localProcStatusTable = localtable;
+
+	/*
+	 * In localBackendStatusIndex, we store the backend indices from
+	 * localProcStatusTable. We need this information since there are
+	 * user-defined functions which expects ids of backends starting from 1 to
+	 * the number of active backends. Hence, we don't want to surprise the
+	 * end-user by including auxiliary processes in the result.
+	 *
+	 * See pg_stat_get_backend_idset for further info.
+	 */
+	localBackendStatusIndex = (int *)
+		MemoryContextAlloc(pgStatLocalContext,
+						   sizeof(int) * NumProcStatSlots);
+
+	localNumBackends = 0;
+	for (i = 0; i < localNumProcs; i++)
+	{
+		if (localProcStatusTable[i].backendStatus.st_procType == PROC_BACKEND)
+		{
+			localBackendStatusIndex[localNumBackends] = i;
+			localNumBackends++;
+		}
+	}
 }
 
 /* ----------
@@ -3584,7 +3754,41 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_proctype_desc(ProcType procType)
+{
+	const char *procDesc = "unknown process type";
+
+	switch (procType)
+	{
+		case PROC_BACKEND:
+			procDesc = "client backend";
+			break;
+		case PROC_AUTOVAC_LAUNCHER:
+			procDesc = "autovacuum launcher";
+			break;
+		case PROC_WAL_SENDER:
+			procDesc = "wal sender";
+			break;
+		case PROC_BG_WORKER:
+			procDesc = "bgworker";
+			break;
+		case PROC_BG_WRITER:
+			procDesc = "writer";
+			break;
+		case PROC_CHECKPOINTER:
+			procDesc = "checkpointer";
+			break;
+		case PROC_WAL_WRITER:
+			procDesc = "wal writer";
+			break;
+		case PROC_WAL_RECEIVER:
+			procDesc = "wal receiver";
+			break;
+	}
 
+	return procDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
@@ -5048,7 +5252,9 @@ pgstat_clear_snapshot(void)
 	/* Reset variables */
 	pgStatLocalContext = NULL;
 	pgStatDBHash = NULL;
-	localBackendStatusTable = NULL;
+	localProcStatusTable = NULL;
+	localNumProcs = 0;
+	localBackendStatusIndex = NULL;
 	localNumBackends = 0;
 }
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..021c9b0 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..e858e4d 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -533,14 +534,14 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 }
 
 /*
- * Returns activity of PG backends.
+ * Returns activity of PG processes.
  */
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
 #define PG_STAT_GET_ACTIVITY_COLS	23
-	int			num_backends = pgstat_fetch_stat_numbackends();
-	int			curr_backend;
+	int			num_procs = pgstat_fetch_stat_numprocs();
+	int			curr_proc;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	TupleDesc	tupdesc;
@@ -574,13 +575,13 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 	MemoryContextSwitchTo(oldcontext);
 
 	/* 1-based index */
-	for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
+	for (curr_proc = 1; curr_proc <= num_procs; curr_proc++)
 	{
 		/* for each row */
 		Datum		values[PG_STAT_GET_ACTIVITY_COLS];
 		bool		nulls[PG_STAT_GET_ACTIVITY_COLS];
-		LocalPgBackendStatus *local_beentry;
-		PgBackendStatus *beentry;
+		LocalPgBackendStatus *local_procentry;
+		PgBackendStatus *procentry;
 		PGPROC	   *proc;
 		const char *wait_event_type;
 		const char *wait_event;
@@ -589,8 +590,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		MemSet(nulls, 0, sizeof(nulls));
 
 		/* Get the next one in the list */
-		local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
-		if (!local_beentry)
+		local_procentry = pgstat_fetch_stat_local_procentry(curr_proc);
+		if (!local_procentry)
 		{
 			int			i;
 
@@ -608,39 +609,48 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 		}
 
-		beentry = &local_beentry->backendStatus;
+		procentry = &local_procentry->backendStatus;
 
 		/* If looking for specific PID, ignore all the others */
-		if (pid != -1 && beentry->st_procpid != pid)
+		if (pid != -1 && procentry->st_procpid != pid)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
-		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
-		if (beentry->st_appname)
-			values[3] = CStringGetTextDatum(beentry->st_appname);
+		if (procentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(procentry->st_databaseid);
+		else
+			nulls[0] = true;
+
+		values[1] = Int32GetDatum(procentry->st_procpid);
+
+		if (procentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(procentry->st_userid);
+		else
+			nulls[2] = true;
+
+		if (procentry->st_appname)
+			values[3] = CStringGetTextDatum(procentry->st_appname);
 		else
 			nulls[3] = true;
 
-		if (TransactionIdIsValid(local_beentry->backend_xid))
-			values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
+		if (TransactionIdIsValid(local_procentry->backend_xid))
+			values[15] = TransactionIdGetDatum(local_procentry->backend_xid);
 		else
 			nulls[15] = true;
 
-		if (TransactionIdIsValid(local_beentry->backend_xmin))
-			values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
+		if (TransactionIdIsValid(local_procentry->backend_xmin))
+			values[16] = TransactionIdGetDatum(local_procentry->backend_xmin);
 		else
 			nulls[16] = true;
 
-		if (beentry->st_ssl)
+		if (procentry->st_ssl)
 		{
 			values[17] = BoolGetDatum(true);	/* ssl */
-			values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
-			values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
-			values[20] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
-			values[21] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
-			values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
+			values[18] = CStringGetTextDatum(procentry->st_sslstatus->ssl_version);
+			values[19] = CStringGetTextDatum(procentry->st_sslstatus->ssl_cipher);
+			values[20] = Int32GetDatum(procentry->st_sslstatus->ssl_bits);
+			values[21] = BoolGetDatum(procentry->st_sslstatus->ssl_compression);
+			values[22] = CStringGetTextDatum(procentry->st_sslstatus->ssl_clientdn);
 		}
 		else
 		{
@@ -649,11 +659,11 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		}
 
 		/* Values only available to role member */
-		if (has_privs_of_role(GetUserId(), beentry->st_userid))
+		if (has_privs_of_role(GetUserId(), procentry->st_userid))
 		{
 			SockAddr	zero_clientaddr;
 
-			switch (beentry->st_state)
+			switch (procentry->st_state)
 			{
 				case STATE_IDLE:
 					values[4] = CStringGetTextDatum("idle");
@@ -678,9 +688,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					break;
 			}
 
-			values[5] = CStringGetTextDatum(beentry->st_activity);
+			values[5] = CStringGetTextDatum(procentry->st_activity);
 
-			proc = BackendPidGetProc(beentry->st_procpid);
+			proc = BackendPidGetProc(procentry->st_procpid);
 			if (proc != NULL)
 			{
 				uint32		raw_wait_event;
@@ -690,6 +700,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
+			else if (procentry->st_procType != PROC_BACKEND)
+			{
+				uint32		raw_wait_event;
+
+				/*
+				 * For auxiliary process, retrieve proc info from
+				 * AuxiliaryProcs stored in shared-mem.
+				 */
+				proc = AuxiliaryPidGetProc(procentry->st_procpid);
+
+				/* Check whether this is indeed an auxiliary process */
+				Assert(proc != NULL);
+				raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+				wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+				wait_event = pgstat_get_wait_event(raw_wait_event);
+			}
 			else
 			{
 				wait_event_type = NULL;
@@ -706,29 +732,29 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			else
 				nulls[7] = true;
 
-			if (beentry->st_xact_start_timestamp != 0)
-				values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+			if (procentry->st_xact_start_timestamp != 0)
+				values[8] = TimestampTzGetDatum(procentry->st_xact_start_timestamp);
 			else
 				nulls[8] = true;
 
-			if (beentry->st_activity_start_timestamp != 0)
-				values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+			if (procentry->st_activity_start_timestamp != 0)
+				values[9] = TimestampTzGetDatum(procentry->st_activity_start_timestamp);
 			else
 				nulls[9] = true;
 
-			if (beentry->st_proc_start_timestamp != 0)
-				values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+			if (procentry->st_proc_start_timestamp != 0)
+				values[10] = TimestampTzGetDatum(procentry->st_proc_start_timestamp);
 			else
 				nulls[10] = true;
 
-			if (beentry->st_state_start_timestamp != 0)
-				values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+			if (procentry->st_state_start_timestamp != 0)
+				values[11] = TimestampTzGetDatum(procentry->st_state_start_timestamp);
 			else
 				nulls[11] = true;
 
 			/* A zeroed client addr means we don't know */
 			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
-			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
+			if (memcmp(&(procentry->st_clientaddr), &zero_clientaddr,
 					   sizeof(zero_clientaddr)) == 0)
 			{
 				nulls[12] = true;
@@ -737,9 +763,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			}
 			else
 			{
-				if (beentry->st_clientaddr.addr.ss_family == AF_INET
+				if (procentry->st_clientaddr.addr.ss_family == AF_INET
 #ifdef HAVE_IPV6
-					|| beentry->st_clientaddr.addr.ss_family == AF_INET6
+					|| procentry->st_clientaddr.addr.ss_family == AF_INET6
 #endif
 					)
 				{
@@ -749,19 +775,19 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 					remote_host[0] = '\0';
 					remote_port[0] = '\0';
-					ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
-											 beentry->st_clientaddr.salen,
+					ret = pg_getnameinfo_all(&procentry->st_clientaddr.addr,
+											 procentry->st_clientaddr.salen,
 											 remote_host, sizeof(remote_host),
 											 remote_port, sizeof(remote_port),
 											 NI_NUMERICHOST | NI_NUMERICSERV);
 					if (ret == 0)
 					{
-						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
+						clean_ipv6_addr(procentry->st_clientaddr.addr.ss_family, remote_host);
 						values[12] = DirectFunctionCall1(inet_in,
 											   CStringGetDatum(remote_host));
-						if (beentry->st_clienthostname &&
-							beentry->st_clienthostname[0])
-							values[13] = CStringGetTextDatum(beentry->st_clienthostname);
+						if (procentry->st_clienthostname &&
+							procentry->st_clienthostname[0])
+							values[13] = CStringGetTextDatum(procentry->st_clienthostname);
 						else
 							nulls[13] = true;
 						values[14] = Int32GetDatum(atoi(remote_port));
@@ -773,7 +799,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 						nulls[14] = true;
 					}
 				}
-				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
+				else if (procentry->st_clientaddr.addr.ss_family == AF_UNIX)
 				{
 					/*
 					 * Unix sockets always reports NULL for host and -1 for
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..f8c36c0 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -809,7 +809,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		InitializeClientEncoding();
 
 		/* report this backend in the PgBackendStatus array */
-		pgstat_bestart();
+		pgstat_procstart();
 
 		/* close the transaction we started above */
 		CommitTransactionCommand();
@@ -1021,7 +1021,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* report this backend in the PgBackendStatus array */
 	if (!bootstrap)
-		pgstat_bestart();
+		pgstat_procstart();
 
 	/* close the transaction we started above */
 	if (!bootstrap)
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index de8225b..80a1f36 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -41,6 +41,9 @@ typedef enum TrackFunctionsLevel
 	TRACK_FUNC_ALL
 }	TrackFunctionsLevel;
 
+/* Total number of PG processes */
+#define NumProcStatSlots	(MaxBackends + NUM_AUXPROCTYPES)
+
 /* ----------
  * The types of backend -> collector messages
  * ----------
@@ -696,6 +699,23 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Process types
+ * ----------
+ */
+typedef enum ProcType
+{
+	PROC_BACKEND,
+	PROC_AUTOVAC_LAUNCHER,
+	PROC_WAL_SENDER,
+	PROC_BG_WORKER,
+	PROC_BG_WRITER,
+	PROC_CHECKPOINTER,
+	PROC_WAL_WRITER,
+	PROC_WAL_RECEIVER
+} ProcType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -845,6 +865,12 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
+ *
+ * Each auxliliary process also maintains a PgBackendStatus struct in shared
+ * memory.
+ * XXX: PgBackendStatus should be renamed as PgProcStatus since it is used for
+ * backends as well as auxiliary process. But, to avoid massive code refactoring,
+ * we've kept it this way for now.
  * ----------
  */
 typedef struct PgBackendStatus
@@ -869,6 +895,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of process */
+	ProcType	st_procType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1056,7 +1085,7 @@ extern void pgstat_report_recovery_conflict(int reason);
 extern void pgstat_report_deadlock(void);
 
 extern void pgstat_initialize(void);
-extern void pgstat_bestart(void);
+extern void pgstat_procstart(void);
 
 extern void pgstat_report_activity(BackendState state, const char *cmd_str);
 extern void pgstat_report_tempfile(size_t filesize);
@@ -1067,6 +1096,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_proctype_desc(ProcType procType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
@@ -1210,8 +1240,11 @@ extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
 extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
 extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
 extern LocalPgBackendStatus *pgstat_fetch_stat_local_beentry(int beid);
+extern PgBackendStatus *pgstat_fetch_stat_procentry(int procid);
+extern LocalPgBackendStatus *pgstat_fetch_stat_local_procentry(int procid);
 extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
 extern int	pgstat_fetch_stat_numbackends(void);
+extern int	pgstat_fetch_stat_numprocs(void);
 extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
 extern PgStat_GlobalStats *pgstat_fetch_global(void);
 
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 5f38fa6..be3bd01 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -262,6 +262,7 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
 
 /* configurable options */
 extern int	DeadlockTimeout;
-- 
1.8.3.1

0002-Expose-stats-for-auxiliary-processes-in-pg_stat_get_.patchapplication/x-download; name=0002-Expose-stats-for-auxiliary-processes-in-pg_stat_get_.patchDownload
From 231368248b0e4addc236a8e6be84148289731319 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 16:26:20 +0530
Subject: [PATCH] Expose stats for auxiliary processes in pg_stat_get_activity

---
 src/backend/bootstrap/bootstrap.c     |  3 +++
 src/backend/postmaster/bgwriter.c     |  6 ++++++
 src/backend/postmaster/checkpointer.c |  7 +++++++
 src/backend/postmaster/walwriter.c    |  7 +++++++
 src/backend/replication/walreceiver.c | 14 ++++++++++++++
 src/backend/replication/walsender.c   |  7 +++++++
 6 files changed, 44 insertions(+)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..f56e229 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,9 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize stats collection */
+		pgstat_initialize();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..5c89444 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
 	 */
 	prev_hibernate = false;
 
+	/* report walwriter process in the PgBackendStatus array */
+	pgstat_procstart();
+
 	/*
 	 * Loop forever
 	 */
@@ -284,6 +287,7 @@ BackgroundWriterMain(void)
 		 * Send off activity statistics to the stats collector
 		 */
 		pgstat_send_bgwriter();
+		pgstat_report_activity(STATE_RUNNING, NULL);
 
 		if (FirstCallSinceLastCheckpoint())
 		{
@@ -345,6 +349,8 @@ BackgroundWriterMain(void)
 		 * down with latch events that are likely to happen frequently during
 		 * normal operation.
 		 */
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   BgWriterDelay /* ms */, WAIT_EVENT_BGWRITER_MAIN);
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..62a3f7c 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -345,6 +345,9 @@ CheckpointerMain(void)
 	 */
 	ProcGlobal->checkpointerLatch = &MyProc->procLatch;
 
+	/* report checkpointer proc in the PgBackendStatus array */
+	pgstat_procstart();
+
 	/*
 	 * Loop forever
 	 */
@@ -365,6 +368,8 @@ CheckpointerMain(void)
 		 */
 		AbsorbFsyncRequests();
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		if (got_SIGHUP)
 		{
 			got_SIGHUP = false;
@@ -556,6 +561,8 @@ CheckpointerMain(void)
 			cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
 		}
 
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   cur_timeout * 1000L /* convert to ms */,
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..dfb641b 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -231,6 +231,9 @@ WalWriterMain(void)
 	 */
 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
 
+	/* report walwriter proc in the PgBackendStatus array */
+	pgstat_procstart();
+
 	/*
 	 * Loop forever
 	 */
@@ -257,6 +260,8 @@ WalWriterMain(void)
 		/* Clear any already-pending wakeups */
 		ResetLatch(MyLatch);
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/*
 		 * Process any requests or signals received recently.
 		 */
@@ -290,6 +295,8 @@ WalWriterMain(void)
 		else
 			cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
 
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   cur_timeout,
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 5c2e72b..e94842e 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -316,6 +316,10 @@ WalReceiverMain(void)
 	SpinLockRelease(&walrcv->mutex);
 
 	first_stream = true;
+
+	/* report walreceiver proc in the PgBackendStatus array */
+	pgstat_procstart();
+
 	for (;;)
 	{
 		char	   *primary_sysid;
@@ -323,6 +327,8 @@ WalReceiverMain(void)
 		int			server_version;
 		WalRcvStreamOptions options;
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/*
 		 * Check that we're connected to a valid server using the
 		 * IDENTIFY_SYSTEM replication command.
@@ -423,6 +429,8 @@ WalReceiverMain(void)
 				/* Process any requests or signals received recently */
 				ProcessWalRcvInterrupts();
 
+				pgstat_report_activity(STATE_RUNNING, NULL);
+
 				if (got_SIGHUP)
 				{
 					got_SIGHUP = false;
@@ -491,6 +499,8 @@ WalReceiverMain(void)
 				 * could add and remove just the socket each time, potentially
 				 * avoiding some system calls.
 				 */
+				pgstat_report_activity(STATE_IDLE, NULL);
+
 				Assert(wait_fd != PGINVALID_SOCKET);
 				rc = WaitLatchOrSocket(walrcv->latch,
 								   WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
@@ -663,6 +673,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
 	{
 		ResetLatch(walrcv->latch);
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/*
 		 * Emergency bailout if postmaster has died.  This is to avoid the
 		 * necessity for manual cleanup of all postmaster children.
@@ -696,6 +708,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
 		}
 		SpinLockRelease(&walrcv->mutex);
 
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
 				  WAIT_EVENT_WAL_RECEIVER_WAIT_START);
 	}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index ba506e2..3304408 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -244,6 +244,9 @@ InitWalSender(void)
 	 */
 	MarkPostmasterChildWalSender();
 	SendPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE);
+
+	/* report walsender proc in the PgBackendStatus array */
+	pgstat_procstart();
 }
 
 /*
@@ -1774,6 +1777,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
 
 		CHECK_FOR_INTERRUPTS();
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/* Process any requests or signals received recently */
 		if (got_SIGHUP)
 		{
@@ -1868,6 +1873,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
 				wakeEvents |= WL_SOCKET_WRITEABLE;
 
 			/* Sleep until something happens or we time out */
+			pgstat_report_activity(STATE_IDLE, NULL);
+
 			WaitLatchOrSocket(MyLatch, wakeEvents,
 							  MyProcPort->sock, sleeptime,
 							  WAIT_EVENT_WAL_SENDER_MAIN);
-- 
1.8.3.1

0003-Expose-stats-for-autovacuum-launcher-and-bgworker.patchapplication/x-download; name=0003-Expose-stats-for-autovacuum-launcher-and-bgworker.patchDownload
From 1b96d656fae4c038e7fdac9a252b3b86bbea94ee Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 17:18:32 +0530
Subject: [PATCH] Expose stats for autovacuum launcher and bgworker

---
 src/backend/postmaster/autovacuum.c        |  4 ++++
 src/backend/replication/logical/launcher.c |  4 ++++
 src/backend/utils/init/postinit.c          | 16 +++++++++++++++-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0c5ffa0..f6132bc 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -597,6 +597,8 @@ AutoVacLauncherMain(int argc, char *argv[])
 		 * Wait until naptime expires or we get some type of signal (all the
 		 * signal handlers will wake us by calling SetLatch).
 		 */
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
@@ -614,6 +616,8 @@ AutoVacLauncherMain(int argc, char *argv[])
 		if (rc & WL_POSTMASTER_DEATH)
 			proc_exit(1);
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/* the normal shutdown case */
 		if (got_SIGTERM)
 			break;
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 39530f96..2f927c8 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -590,6 +590,8 @@ ApplyLauncherMain(Datum main_arg)
 
 		now = GetCurrentTimestamp();
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/* Limit the start retry to once a wal_retrieve_retry_interval */
 		if (TimestampDifferenceExceeds(last_start_time, now,
 									   wal_retrieve_retry_interval))
@@ -647,6 +649,8 @@ ApplyLauncherMain(Datum main_arg)
 		}
 
 		/* Wait for more work. */
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(&MyProc->procLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   wait_time,
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index f8c36c0..b831cf9 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -665,7 +665,14 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* The autovacuum launcher is done here */
 	if (IsAutoVacuumLauncherProcess())
+	{
+		/*
+		 * Before returning, report autovacuum launcher process in the
+		 * PgBackendStatus array.
+		 */
+		pgstat_procstart();
 		return;
+	}
 
 	/*
 	 * Start a new transaction here before first access to db, and get a
@@ -808,7 +815,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		/* initialize client encoding */
 		InitializeClientEncoding();
 
-		/* report this backend in the PgBackendStatus array */
+		/* report walsender process in the PgBackendStatus array */
 		pgstat_procstart();
 
 		/* close the transaction we started above */
@@ -875,6 +882,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		 */
 		if (!bootstrap)
 			CommitTransactionCommand();
+
+		/*
+		 * Before returning, report the background worker process in the
+		 * PgBackendStatus array.
+		 */
+		if (!bootstrap)
+			pgstat_procstart();
 		return;
 	}
 
-- 
1.8.3.1

0004-Add-proc_type-column-in-pg_stat_get_activity.patchapplication/x-download; name=0004-Add-proc_type-column-in-pg_stat_get_activity.patchDownload
From a6bbbf6a3f3ff739f362f4b3722d060051f6591e Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 17:41:08 +0530
Subject: [PATCH] Add proc_type column in pg_stat_get_activity

proc_type indicates the type of process in the stat table.
---
 src/backend/catalog/system_views.sql | 3 ++-
 src/backend/utils/adt/pgstatfuncs.c  | 5 ++++-
 src/include/catalog/pg_proc.h        | 2 +-
 src/test/regress/expected/rules.out  | 9 +++++----
 4 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 38be9cf..dfa6430 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.proc_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index e858e4d..cb2109a 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -539,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_procs = pgstat_fetch_stat_numprocs();
 	int			curr_proc;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -819,6 +819,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					nulls[14] = true;
 				}
 			}
+			/* Add process type */
+			values[23] = CStringGetTextDatum(pgstat_get_proctype_desc(procentry->st_procType));
 		}
 		else
 		{
@@ -834,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[12] = true;
 			nulls[13] = true;
 			nulls[14] = true;
+			nulls[23] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 41c12af..27aa552 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2768,7 +2768,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,proc_type}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index c661f1d..69d61c6 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.proc_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, proc_type)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1833,7 +1834,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, proc_type)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1843,7 +1844,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, proc_type);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
-- 
1.8.3.1

#16Amit Langote
Langote_Amit_f8@lab.ntt.co.jp
In reply to: Kuntal Ghosh (#15)

Hi Kuntal,

Patches apply and compile fine. Works as advertised.

Some minor comments on the patches themselves.

In 0001:

- * pgstat_bestart() -
+ * pgstat_procstart() -
+ *
+ *  Initialize this process's entry in the PgBackendStatus array.
+ *  Called from InitPostgres and AuxiliaryProcessMain.

Not being called from AuxiliaryProcessMain(). Maybe leftover comment from
a previous version. Actually I see that in patch 0002, Main() functions
of various auxiliary processes call pgstat_procstart, not
AuxiliaryProcessMain.

+ * user-defined functions which expects ids of backends starting from
1 to

s/expects/expect/g

+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+    PGPROC     *result;

Initialize to NULL so that the comment above is true. :)

In 0002:

@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
*/
prev_hibernate = false;

+    /* report walwriter process in the PgBackendStatus array */
+    pgstat_procstart();
+

s/walwriter/writer/g

Patch 0004 should update monitoring.sgml.

Thanks,
Amit

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Amit Langote (#16)
4 attachment(s)

Hello Amit,

On Tue, Mar 7, 2017 at 4:24 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:

Hi Kuntal,

Patches apply and compile fine. Works as advertised.

Some minor comments on the patches themselves.

Thanks for the review.

In 0001:

- * pgstat_bestart() -
+ * pgstat_procstart() -
+ *
+ *  Initialize this process's entry in the PgBackendStatus array.
+ *  Called from InitPostgres and AuxiliaryProcessMain.

Not being called from AuxiliaryProcessMain(). Maybe leftover comment from
a previous version. Actually I see that in patch 0002, Main() functions
of various auxiliary processes call pgstat_procstart, not
AuxiliaryProcessMain.

Fixed.

+ * user-defined functions which expects ids of backends starting from
1 to

s/expects/expect/g

Fixed.

+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+    PGPROC     *result;

Initialize to NULL so that the comment above is true. :)

Fixed.

In 0002:

@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
*/
prev_hibernate = false;

+    /* report walwriter process in the PgBackendStatus array */
+    pgstat_procstart();
+

s/walwriter/writer/g

Fixed.

Patch 0004 should update monitoring.sgml.

Added.

I've attached the updated patches. PFA.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Infra-to-expose-non-backend-processes-in-pg_stat_get.patchbinary/octet-stream; name=0001-Infra-to-expose-non-backend-processes-in-pg_stat_get.patchDownload
From 3e5cd604d729e5f8fb68cc7458fadcd3331f6e8c Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 15:34:18 +0530
Subject: [PATCH] Infra to expose non-backend processes in pg_stat_get_activity

This patch implements the infrastructure required to expose
non-backend processes in pg_stat_activity. BackendStatusArray
is extended to store auxiliary processes as well. Backends use slots
indexed in the range from 1 to MaxBackends (inclusive), so we use
MaxBackends + AuxProcType + 1 as the index of the slot for an
auxiliary process.
---
 src/backend/postmaster/pgstat.c     | 302 ++++++++++++++++++++++++++++++------
 src/backend/storage/lmgr/proc.c     |  27 ++++
 src/backend/utils/adt/pgstatfuncs.c | 120 ++++++++------
 src/backend/utils/init/postinit.c   |   4 +-
 src/include/pgstat.h                |  35 ++++-
 src/include/storage/proc.h          |   1 +
 6 files changed, 391 insertions(+), 98 deletions(-)

diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7cacb1e..a530c3b 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -212,7 +213,17 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
-static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Status for backends and auxiliary processes */
+static LocalPgBackendStatus *localProcStatusTable = NULL;
+
+/* Total number of processes including backends and auxiliary */
+static int	localNumProcs = 0;
+
+/* Index to backends in localProcStatusTable */
+static int *localBackendStatusIndex = NULL;
+
+/* Total number of backend processes */
 static int	localNumBackends = 0;
 
 /*
@@ -2404,7 +2415,29 @@ pgstat_fetch_stat_beentry(int beid)
 	if (beid < 1 || beid > localNumBackends)
 		return NULL;
 
-	return &localBackendStatusTable[beid - 1].backendStatus;
+	return &localProcStatusTable[localBackendStatusIndex[beid - 1]].backendStatus;
+}
+
+
+/* ----------
+ * pgstat_fetch_stat_procentry() -
+ *
+ *	Support function for the SQL-callable pgstat* functions. Returns
+ *	our local copy of the current-activity entry for one process.
+ *
+ *	NB: caller is responsible for a check if the user is permitted to see
+ *	this info (especially the querystring).
+ * ----------
+ */
+PgBackendStatus *
+pgstat_fetch_stat_procentry(int procid)
+{
+	pgstat_read_current_status();
+
+	if (procid < 1 || procid > localNumProcs)
+		return NULL;
+
+	return &localProcStatusTable[procid - 1].backendStatus;
 }
 
 
@@ -2426,7 +2459,29 @@ pgstat_fetch_stat_local_beentry(int beid)
 	if (beid < 1 || beid > localNumBackends)
 		return NULL;
 
-	return &localBackendStatusTable[beid - 1];
+	return &localProcStatusTable[localBackendStatusIndex[beid - 1]];
+}
+
+
+/* ----------
+ * pgstat_fetch_stat_local_procentry() -
+ *
+ *	Like pgstat_fetch_stat_procentry() but with locally computed additions (like
+ *	xid and xmin values of the backend)
+ *
+ *	NB: caller is responsible for a check if the user is permitted to see
+ *	this info (especially the querystring).
+ * ----------
+ */
+LocalPgBackendStatus *
+pgstat_fetch_stat_local_procentry(int procid)
+{
+	pgstat_read_current_status();
+
+	if (procid < 1 || procid > localNumProcs)
+		return NULL;
+
+	return &localProcStatusTable[procid - 1];
 }
 
 
@@ -2445,6 +2500,22 @@ pgstat_fetch_stat_numbackends(void)
 	return localNumBackends;
 }
 
+
+/* ----------
+ * pgstat_fetch_stat_numprocs() -
+ *
+ *	Support function for the SQL-callable pgstat* functions. Returns
+ *	the maximum current process id.
+ * ----------
+ */
+int
+pgstat_fetch_stat_numprocs(void)
+{
+	pgstat_read_current_status();
+
+	return localNumProcs;
+}
+
 /*
  * ---------
  * pgstat_fetch_stat_archiver() -
@@ -2504,20 +2575,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumProcStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumProcStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumProcStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+				mul_size(pgstat_track_activity_query_size, NumProcStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+					mul_size(sizeof(PgBackendSSLStatus), NumProcStatSlots));
 #endif
 	return size;
 }
@@ -2535,7 +2606,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumProcStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2558,7 +2629,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2576,7 +2647,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2585,7 +2656,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumProcStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2597,7 +2668,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2606,7 +2677,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumProcStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2618,7 +2689,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumProcStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2632,7 +2703,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2642,27 +2714,47 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		/* Just a backend process */
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxProcType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
 }
 
 /* ----------
- * pgstat_bestart() -
+ * pgstat_procstart() -
  *
- *	Initialize this backend's entry in the PgBackendStatus array.
+ *	Initialize this process's entry in the PgBackendStatus array.
  *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *
+ *	For a backend process, MyDatabaseId, session userid,
+ *	and application_name must be set (hence, this cannot be combined
+ *	with pgstat_initialize).
  * ----------
  */
 void
-pgstat_bestart(void)
+pgstat_procstart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2677,7 +2769,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2696,6 +2787,55 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		/* Must be a backend process */
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_procType = PROC_AUTOVAC_LAUNCHER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_procType = PROC_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_procType = PROC_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_procType = PROC_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case BgWriterProcess:
+				beentry->st_procType = PROC_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_procType = PROC_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_procType = PROC_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_procType = PROC_WAL_RECEIVER;
+				break;
+			default:
+				elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2707,8 +2847,15 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends and wal-sender processes */
+	if (beentry->st_procType == PROC_BACKEND || beentry->st_procType == PROC_WAL_SENDER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
+
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
 				NAMEDATALEN);
@@ -3027,7 +3174,7 @@ pgstat_report_xact_timestamp(TimestampTz tstamp)
 static void
 pgstat_read_current_status(void)
 {
-	volatile PgBackendStatus *beentry;
+	volatile PgBackendStatus *procentry;
 	LocalPgBackendStatus *localtable;
 	LocalPgBackendStatus *localentry;
 	char	   *localappname,
@@ -3038,31 +3185,31 @@ pgstat_read_current_status(void)
 	int			i;
 
 	Assert(!pgStatRunningInCollector);
-	if (localBackendStatusTable)
+	if (localProcStatusTable && localBackendStatusIndex)
 		return;					/* already done */
 
 	pgstat_setup_memcxt();
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						   sizeof(LocalPgBackendStatus) * NumProcStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumProcStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					   pgstat_track_activity_query_size * NumProcStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumProcStatSlots);
 #endif
 
-	localNumBackends = 0;
+	localNumProcs = 0;
 
-	beentry = BackendStatusArray;
+	procentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumProcStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3076,32 +3223,32 @@ pgstat_read_current_status(void)
 			int			before_changecount;
 			int			after_changecount;
 
-			pgstat_save_changecount_before(beentry, before_changecount);
+			pgstat_save_changecount_before(procentry, before_changecount);
 
-			localentry->backendStatus.st_procpid = beentry->st_procpid;
+			localentry->backendStatus.st_procpid = procentry->st_procpid;
 			if (localentry->backendStatus.st_procpid > 0)
 			{
-				memcpy(&localentry->backendStatus, (char *) beentry, sizeof(PgBackendStatus));
+				memcpy(&localentry->backendStatus, (char *) procentry, sizeof(PgBackendStatus));
 
 				/*
 				 * strcpy is safe even if the string is modified concurrently,
 				 * because there's always a \0 at the end of the buffer.
 				 */
-				strcpy(localappname, (char *) beentry->st_appname);
+				strcpy(localappname, (char *) procentry->st_appname);
 				localentry->backendStatus.st_appname = localappname;
-				strcpy(localactivity, (char *) beentry->st_activity);
+				strcpy(localactivity, (char *) procentry->st_activity);
 				localentry->backendStatus.st_activity = localactivity;
-				localentry->backendStatus.st_ssl = beentry->st_ssl;
+				localentry->backendStatus.st_ssl = procentry->st_ssl;
 #ifdef USE_SSL
-				if (beentry->st_ssl)
+				if (procentry->st_ssl)
 				{
-					memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
+					memcpy(localsslstatus, procentry->st_sslstatus, sizeof(PgBackendSSLStatus));
 					localentry->backendStatus.st_sslstatus = localsslstatus;
 				}
 #endif
 			}
 
-			pgstat_save_changecount_after(beentry, after_changecount);
+			pgstat_save_changecount_after(procentry, after_changecount);
 			if (before_changecount == after_changecount &&
 				(before_changecount & 1) == 0)
 				break;
@@ -3110,7 +3257,7 @@ pgstat_read_current_status(void)
 			CHECK_FOR_INTERRUPTS();
 		}
 
-		beentry++;
+		procentry++;
 		/* Only valid entries get included into the local array */
 		if (localentry->backendStatus.st_procpid > 0)
 		{
@@ -3124,12 +3271,35 @@ pgstat_read_current_status(void)
 #ifdef USE_SSL
 			localsslstatus++;
 #endif
-			localNumBackends++;
+			localNumProcs++;
 		}
 	}
 
 	/* Set the pointer only after completion of a valid table */
-	localBackendStatusTable = localtable;
+	localProcStatusTable = localtable;
+
+	/*
+	 * In localBackendStatusIndex, we store the backend indices from
+	 * localProcStatusTable. We need this information since there are
+	 * user-defined functions which expect ids of backends starting from 1 to
+	 * the number of active backends. Hence, we don't want to surprise the
+	 * end-user by including auxiliary processes in the result.
+	 *
+	 * See pg_stat_get_backend_idset for further info.
+	 */
+	localBackendStatusIndex = (int *)
+		MemoryContextAlloc(pgStatLocalContext,
+						   sizeof(int) * NumProcStatSlots);
+
+	localNumBackends = 0;
+	for (i = 0; i < localNumProcs; i++)
+	{
+		if (localProcStatusTable[i].backendStatus.st_procType == PROC_BACKEND)
+		{
+			localBackendStatusIndex[localNumBackends] = i;
+			localNumBackends++;
+		}
+	}
 }
 
 /* ----------
@@ -3590,7 +3760,41 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_proctype_desc(ProcType procType)
+{
+	const char *procDesc = "unknown process type";
+
+	switch (procType)
+	{
+		case PROC_BACKEND:
+			procDesc = "client backend";
+			break;
+		case PROC_AUTOVAC_LAUNCHER:
+			procDesc = "autovacuum launcher";
+			break;
+		case PROC_WAL_SENDER:
+			procDesc = "wal sender";
+			break;
+		case PROC_BG_WORKER:
+			procDesc = "bgworker";
+			break;
+		case PROC_BG_WRITER:
+			procDesc = "writer";
+			break;
+		case PROC_CHECKPOINTER:
+			procDesc = "checkpointer";
+			break;
+		case PROC_WAL_WRITER:
+			procDesc = "wal writer";
+			break;
+		case PROC_WAL_RECEIVER:
+			procDesc = "wal receiver";
+			break;
+	}
 
+	return procDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
@@ -5054,7 +5258,9 @@ pgstat_clear_snapshot(void)
 	/* Reset variables */
 	pgStatLocalContext = NULL;
 	pgStatDBHash = NULL;
-	localBackendStatusTable = NULL;
+	localProcStatusTable = NULL;
+	localNumProcs = 0;
+	localBackendStatusIndex = NULL;
 	localNumBackends = 0;
 }
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..3e716b1 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result = NULL;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..8bb9b7e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -533,14 +534,14 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 }
 
 /*
- * Returns activity of PG backends.
+ * Returns activity of PG processes.
  */
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
 #define PG_STAT_GET_ACTIVITY_COLS	23
-	int			num_backends = pgstat_fetch_stat_numbackends();
-	int			curr_backend;
+	int			num_procs = pgstat_fetch_stat_numprocs();
+	int			curr_proc;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	TupleDesc	tupdesc;
@@ -574,13 +575,13 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 	MemoryContextSwitchTo(oldcontext);
 
 	/* 1-based index */
-	for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
+	for (curr_proc = 1; curr_proc <= num_procs; curr_proc++)
 	{
 		/* for each row */
 		Datum		values[PG_STAT_GET_ACTIVITY_COLS];
 		bool		nulls[PG_STAT_GET_ACTIVITY_COLS];
-		LocalPgBackendStatus *local_beentry;
-		PgBackendStatus *beentry;
+		LocalPgBackendStatus *local_procentry;
+		PgBackendStatus *procentry;
 		PGPROC	   *proc;
 		const char *wait_event_type;
 		const char *wait_event;
@@ -589,8 +590,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		MemSet(nulls, 0, sizeof(nulls));
 
 		/* Get the next one in the list */
-		local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
-		if (!local_beentry)
+		local_procentry = pgstat_fetch_stat_local_procentry(curr_proc);
+		if (!local_procentry)
 		{
 			int			i;
 
@@ -608,39 +609,48 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 		}
 
-		beentry = &local_beentry->backendStatus;
+		procentry = &local_procentry->backendStatus;
 
 		/* If looking for specific PID, ignore all the others */
-		if (pid != -1 && beentry->st_procpid != pid)
+		if (pid != -1 && procentry->st_procpid != pid)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
-		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
-		if (beentry->st_appname)
-			values[3] = CStringGetTextDatum(beentry->st_appname);
+		if (procentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(procentry->st_databaseid);
+		else
+			nulls[0] = true;
+
+		values[1] = Int32GetDatum(procentry->st_procpid);
+
+		if (procentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(procentry->st_userid);
+		else
+			nulls[2] = true;
+
+		if (procentry->st_appname)
+			values[3] = CStringGetTextDatum(procentry->st_appname);
 		else
 			nulls[3] = true;
 
-		if (TransactionIdIsValid(local_beentry->backend_xid))
-			values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
+		if (TransactionIdIsValid(local_procentry->backend_xid))
+			values[15] = TransactionIdGetDatum(local_procentry->backend_xid);
 		else
 			nulls[15] = true;
 
-		if (TransactionIdIsValid(local_beentry->backend_xmin))
-			values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
+		if (TransactionIdIsValid(local_procentry->backend_xmin))
+			values[16] = TransactionIdGetDatum(local_procentry->backend_xmin);
 		else
 			nulls[16] = true;
 
-		if (beentry->st_ssl)
+		if (procentry->st_ssl)
 		{
 			values[17] = BoolGetDatum(true);	/* ssl */
-			values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
-			values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
-			values[20] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
-			values[21] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
-			values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
+			values[18] = CStringGetTextDatum(procentry->st_sslstatus->ssl_version);
+			values[19] = CStringGetTextDatum(procentry->st_sslstatus->ssl_cipher);
+			values[20] = Int32GetDatum(procentry->st_sslstatus->ssl_bits);
+			values[21] = BoolGetDatum(procentry->st_sslstatus->ssl_compression);
+			values[22] = CStringGetTextDatum(procentry->st_sslstatus->ssl_clientdn);
 		}
 		else
 		{
@@ -649,11 +659,11 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		}
 
 		/* Values only available to role member */
-		if (has_privs_of_role(GetUserId(), beentry->st_userid))
+		if (has_privs_of_role(GetUserId(), procentry->st_userid))
 		{
 			SockAddr	zero_clientaddr;
 
-			switch (beentry->st_state)
+			switch (procentry->st_state)
 			{
 				case STATE_IDLE:
 					values[4] = CStringGetTextDatum("idle");
@@ -678,9 +688,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					break;
 			}
 
-			values[5] = CStringGetTextDatum(beentry->st_activity);
+			values[5] = CStringGetTextDatum(procentry->st_activity);
 
-			proc = BackendPidGetProc(beentry->st_procpid);
+			proc = BackendPidGetProc(procentry->st_procpid);
 			if (proc != NULL)
 			{
 				uint32		raw_wait_event;
@@ -690,6 +700,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
+			else if (procentry->st_procType != PROC_BACKEND)
+			{
+				uint32		raw_wait_event;
+
+				/*
+				 * For auxiliary process, retrieve proc info from
+				 * AuxiliaryProcs stored in shared-mem.
+				 */
+				proc = AuxiliaryPidGetProc(procentry->st_procpid);
+
+				/* Check whether this is indeed an auxiliary process */
+				Assert(proc != NULL);
+				raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+				wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+				wait_event = pgstat_get_wait_event(raw_wait_event);
+			}
 			else
 			{
 				wait_event_type = NULL;
@@ -706,29 +732,29 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			else
 				nulls[7] = true;
 
-			if (beentry->st_xact_start_timestamp != 0)
-				values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+			if (procentry->st_xact_start_timestamp != 0)
+				values[8] = TimestampTzGetDatum(procentry->st_xact_start_timestamp);
 			else
 				nulls[8] = true;
 
-			if (beentry->st_activity_start_timestamp != 0)
-				values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+			if (procentry->st_activity_start_timestamp != 0)
+				values[9] = TimestampTzGetDatum(procentry->st_activity_start_timestamp);
 			else
 				nulls[9] = true;
 
-			if (beentry->st_proc_start_timestamp != 0)
-				values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+			if (procentry->st_proc_start_timestamp != 0)
+				values[10] = TimestampTzGetDatum(procentry->st_proc_start_timestamp);
 			else
 				nulls[10] = true;
 
-			if (beentry->st_state_start_timestamp != 0)
-				values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+			if (procentry->st_state_start_timestamp != 0)
+				values[11] = TimestampTzGetDatum(procentry->st_state_start_timestamp);
 			else
 				nulls[11] = true;
 
 			/* A zeroed client addr means we don't know */
 			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
-			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
+			if (memcmp(&(procentry->st_clientaddr), &zero_clientaddr,
 					   sizeof(zero_clientaddr)) == 0)
 			{
 				nulls[12] = true;
@@ -737,9 +763,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			}
 			else
 			{
-				if (beentry->st_clientaddr.addr.ss_family == AF_INET
+				if (procentry->st_clientaddr.addr.ss_family == AF_INET
 #ifdef HAVE_IPV6
-					|| beentry->st_clientaddr.addr.ss_family == AF_INET6
+					|| procentry->st_clientaddr.addr.ss_family == AF_INET6
 #endif
 					)
 				{
@@ -749,19 +775,19 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 					remote_host[0] = '\0';
 					remote_port[0] = '\0';
-					ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
-											 beentry->st_clientaddr.salen,
+					ret = pg_getnameinfo_all(&procentry->st_clientaddr.addr,
+											 procentry->st_clientaddr.salen,
 											 remote_host, sizeof(remote_host),
 											 remote_port, sizeof(remote_port),
 											 NI_NUMERICHOST | NI_NUMERICSERV);
 					if (ret == 0)
 					{
-						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
+						clean_ipv6_addr(procentry->st_clientaddr.addr.ss_family, remote_host);
 						values[12] = DirectFunctionCall1(inet_in,
 											   CStringGetDatum(remote_host));
-						if (beentry->st_clienthostname &&
-							beentry->st_clienthostname[0])
-							values[13] = CStringGetTextDatum(beentry->st_clienthostname);
+						if (procentry->st_clienthostname &&
+							procentry->st_clienthostname[0])
+							values[13] = CStringGetTextDatum(procentry->st_clienthostname);
 						else
 							nulls[13] = true;
 						values[14] = Int32GetDatum(atoi(remote_port));
@@ -773,7 +799,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 						nulls[14] = true;
 					}
 				}
-				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
+				else if (procentry->st_clientaddr.addr.ss_family == AF_UNIX)
 				{
 					/*
 					 * Unix sockets always reports NULL for host and -1 for
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..f8c36c0 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -809,7 +809,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		InitializeClientEncoding();
 
 		/* report this backend in the PgBackendStatus array */
-		pgstat_bestart();
+		pgstat_procstart();
 
 		/* close the transaction we started above */
 		CommitTransactionCommand();
@@ -1021,7 +1021,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* report this backend in the PgBackendStatus array */
 	if (!bootstrap)
-		pgstat_bestart();
+		pgstat_procstart();
 
 	/* close the transaction we started above */
 	if (!bootstrap)
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 60c78d1..440e78d 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -41,6 +41,9 @@ typedef enum TrackFunctionsLevel
 	TRACK_FUNC_ALL
 }	TrackFunctionsLevel;
 
+/* Total number of PG processes */
+#define NumProcStatSlots	(MaxBackends + NUM_AUXPROCTYPES)
+
 /* ----------
  * The types of backend -> collector messages
  * ----------
@@ -696,6 +699,23 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Process types
+ * ----------
+ */
+typedef enum ProcType
+{
+	PROC_BACKEND,
+	PROC_AUTOVAC_LAUNCHER,
+	PROC_WAL_SENDER,
+	PROC_BG_WORKER,
+	PROC_BG_WRITER,
+	PROC_CHECKPOINTER,
+	PROC_WAL_WRITER,
+	PROC_WAL_RECEIVER
+} ProcType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -847,6 +867,12 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
+ *
+ * Each auxliliary process also maintains a PgBackendStatus struct in shared
+ * memory.
+ * XXX: PgBackendStatus should be renamed as PgProcStatus since it is used for
+ * backends as well as auxiliary process. But, to avoid massive code refactoring,
+ * we've kept it this way for now.
  * ----------
  */
 typedef struct PgBackendStatus
@@ -871,6 +897,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of process */
+	ProcType	st_procType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1058,7 +1087,7 @@ extern void pgstat_report_recovery_conflict(int reason);
 extern void pgstat_report_deadlock(void);
 
 extern void pgstat_initialize(void);
-extern void pgstat_bestart(void);
+extern void pgstat_procstart(void);
 
 extern void pgstat_report_activity(BackendState state, const char *cmd_str);
 extern void pgstat_report_tempfile(size_t filesize);
@@ -1069,6 +1098,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_proctype_desc(ProcType procType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
@@ -1212,8 +1242,11 @@ extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
 extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
 extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
 extern LocalPgBackendStatus *pgstat_fetch_stat_local_beentry(int beid);
+extern PgBackendStatus *pgstat_fetch_stat_procentry(int procid);
+extern LocalPgBackendStatus *pgstat_fetch_stat_local_procentry(int procid);
 extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
 extern int	pgstat_fetch_stat_numbackends(void);
+extern int	pgstat_fetch_stat_numprocs(void);
 extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
 extern PgStat_GlobalStats *pgstat_fetch_global(void);
 
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 5f38fa6..be3bd01 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -262,6 +262,7 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
 
 /* configurable options */
 extern int	DeadlockTimeout;
-- 
1.8.3.1

0002-Expose-stats-for-auxiliary-processes-in-pg_stat_get_.patchbinary/octet-stream; name=0002-Expose-stats-for-auxiliary-processes-in-pg_stat_get_.patchDownload
From e1ee0a536b38540ff2251277b424590f5c392c9a Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 16:26:20 +0530
Subject: [PATCH] Expose stats for auxiliary processes in pg_stat_get_activity

---
 src/backend/bootstrap/bootstrap.c     |  3 +++
 src/backend/postmaster/bgwriter.c     |  6 ++++++
 src/backend/postmaster/checkpointer.c |  7 +++++++
 src/backend/postmaster/pgstat.c       |  3 ++-
 src/backend/postmaster/walwriter.c    |  7 +++++++
 src/backend/replication/walreceiver.c | 14 ++++++++++++++
 src/backend/replication/walsender.c   |  7 +++++++
 7 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..f56e229 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,9 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize stats collection */
+		pgstat_initialize();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..1e8bbc3 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
 	 */
 	prev_hibernate = false;
 
+	/* report writer process in the PgBackendStatus array */
+	pgstat_procstart();
+
 	/*
 	 * Loop forever
 	 */
@@ -284,6 +287,7 @@ BackgroundWriterMain(void)
 		 * Send off activity statistics to the stats collector
 		 */
 		pgstat_send_bgwriter();
+		pgstat_report_activity(STATE_RUNNING, NULL);
 
 		if (FirstCallSinceLastCheckpoint())
 		{
@@ -345,6 +349,8 @@ BackgroundWriterMain(void)
 		 * down with latch events that are likely to happen frequently during
 		 * normal operation.
 		 */
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   BgWriterDelay /* ms */, WAIT_EVENT_BGWRITER_MAIN);
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..62a3f7c 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -345,6 +345,9 @@ CheckpointerMain(void)
 	 */
 	ProcGlobal->checkpointerLatch = &MyProc->procLatch;
 
+	/* report checkpointer proc in the PgBackendStatus array */
+	pgstat_procstart();
+
 	/*
 	 * Loop forever
 	 */
@@ -365,6 +368,8 @@ CheckpointerMain(void)
 		 */
 		AbsorbFsyncRequests();
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		if (got_SIGHUP)
 		{
 			got_SIGHUP = false;
@@ -556,6 +561,8 @@ CheckpointerMain(void)
 			cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
 		}
 
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   cur_timeout * 1000L /* convert to ms */,
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index a530c3b..166c351 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2744,7 +2744,8 @@ pgstat_initialize(void)
  * pgstat_procstart() -
  *
  *	Initialize this process's entry in the PgBackendStatus array.
- *	Called from InitPostgres.
+ *	Called from InitPostgres and other main entrypoints for
+ *	auxiliary processes.
  *
  *	For a backend process, MyDatabaseId, session userid,
  *	and application_name must be set (hence, this cannot be combined
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..dfb641b 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -231,6 +231,9 @@ WalWriterMain(void)
 	 */
 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
 
+	/* report walwriter proc in the PgBackendStatus array */
+	pgstat_procstart();
+
 	/*
 	 * Loop forever
 	 */
@@ -257,6 +260,8 @@ WalWriterMain(void)
 		/* Clear any already-pending wakeups */
 		ResetLatch(MyLatch);
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/*
 		 * Process any requests or signals received recently.
 		 */
@@ -290,6 +295,8 @@ WalWriterMain(void)
 		else
 			cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
 
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   cur_timeout,
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 18d9d7e..9232790 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -316,6 +316,10 @@ WalReceiverMain(void)
 	SpinLockRelease(&walrcv->mutex);
 
 	first_stream = true;
+
+	/* report walreceiver proc in the PgBackendStatus array */
+	pgstat_procstart();
+
 	for (;;)
 	{
 		char	   *primary_sysid;
@@ -323,6 +327,8 @@ WalReceiverMain(void)
 		int			server_version;
 		WalRcvStreamOptions options;
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/*
 		 * Check that we're connected to a valid server using the
 		 * IDENTIFY_SYSTEM replication command.
@@ -423,6 +429,8 @@ WalReceiverMain(void)
 				/* Process any requests or signals received recently */
 				ProcessWalRcvInterrupts();
 
+				pgstat_report_activity(STATE_RUNNING, NULL);
+
 				if (got_SIGHUP)
 				{
 					got_SIGHUP = false;
@@ -491,6 +499,8 @@ WalReceiverMain(void)
 				 * could add and remove just the socket each time, potentially
 				 * avoiding some system calls.
 				 */
+				pgstat_report_activity(STATE_IDLE, NULL);
+
 				Assert(wait_fd != PGINVALID_SOCKET);
 				rc = WaitLatchOrSocket(walrcv->latch,
 								   WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
@@ -663,6 +673,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
 	{
 		ResetLatch(walrcv->latch);
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/*
 		 * Emergency bailout if postmaster has died.  This is to avoid the
 		 * necessity for manual cleanup of all postmaster children.
@@ -696,6 +708,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
 		}
 		SpinLockRelease(&walrcv->mutex);
 
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
 				  WAIT_EVENT_WAL_RECEIVER_WAIT_START);
 	}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index dd3a936..8204e1c 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -244,6 +244,9 @@ InitWalSender(void)
 	 */
 	MarkPostmasterChildWalSender();
 	SendPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE);
+
+	/* report walsender proc in the PgBackendStatus array */
+	pgstat_procstart();
 }
 
 /*
@@ -1778,6 +1781,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
 
 		CHECK_FOR_INTERRUPTS();
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/* Process any requests or signals received recently */
 		if (got_SIGHUP)
 		{
@@ -1872,6 +1877,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
 				wakeEvents |= WL_SOCKET_WRITEABLE;
 
 			/* Sleep until something happens or we time out */
+			pgstat_report_activity(STATE_IDLE, NULL);
+
 			WaitLatchOrSocket(MyLatch, wakeEvents,
 							  MyProcPort->sock, sleeptime,
 							  WAIT_EVENT_WAL_SENDER_MAIN);
-- 
1.8.3.1

0003-Expose-stats-for-autovacuum-launcher-and-bgworker.patchbinary/octet-stream; name=0003-Expose-stats-for-autovacuum-launcher-and-bgworker.patchDownload
From 1b96d656fae4c038e7fdac9a252b3b86bbea94ee Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 17:18:32 +0530
Subject: [PATCH] Expose stats for autovacuum launcher and bgworker

---
 src/backend/postmaster/autovacuum.c        |  4 ++++
 src/backend/replication/logical/launcher.c |  4 ++++
 src/backend/utils/init/postinit.c          | 16 +++++++++++++++-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0c5ffa0..f6132bc 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -597,6 +597,8 @@ AutoVacLauncherMain(int argc, char *argv[])
 		 * Wait until naptime expires or we get some type of signal (all the
 		 * signal handlers will wake us by calling SetLatch).
 		 */
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
@@ -614,6 +616,8 @@ AutoVacLauncherMain(int argc, char *argv[])
 		if (rc & WL_POSTMASTER_DEATH)
 			proc_exit(1);
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/* the normal shutdown case */
 		if (got_SIGTERM)
 			break;
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 39530f96..2f927c8 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -590,6 +590,8 @@ ApplyLauncherMain(Datum main_arg)
 
 		now = GetCurrentTimestamp();
 
+		pgstat_report_activity(STATE_RUNNING, NULL);
+
 		/* Limit the start retry to once a wal_retrieve_retry_interval */
 		if (TimestampDifferenceExceeds(last_start_time, now,
 									   wal_retrieve_retry_interval))
@@ -647,6 +649,8 @@ ApplyLauncherMain(Datum main_arg)
 		}
 
 		/* Wait for more work. */
+		pgstat_report_activity(STATE_IDLE, NULL);
+
 		rc = WaitLatch(&MyProc->procLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
 					   wait_time,
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index f8c36c0..b831cf9 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -665,7 +665,14 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* The autovacuum launcher is done here */
 	if (IsAutoVacuumLauncherProcess())
+	{
+		/*
+		 * Before returning, report autovacuum launcher process in the
+		 * PgBackendStatus array.
+		 */
+		pgstat_procstart();
 		return;
+	}
 
 	/*
 	 * Start a new transaction here before first access to db, and get a
@@ -808,7 +815,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		/* initialize client encoding */
 		InitializeClientEncoding();
 
-		/* report this backend in the PgBackendStatus array */
+		/* report walsender process in the PgBackendStatus array */
 		pgstat_procstart();
 
 		/* close the transaction we started above */
@@ -875,6 +882,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		 */
 		if (!bootstrap)
 			CommitTransactionCommand();
+
+		/*
+		 * Before returning, report the background worker process in the
+		 * PgBackendStatus array.
+		 */
+		if (!bootstrap)
+			pgstat_procstart();
 		return;
 	}
 
-- 
1.8.3.1

0004-Add-proc_type-column-in-pg_stat_get_activity.patchbinary/octet-stream; name=0004-Add-proc_type-column-in-pg_stat_get_activity.patchDownload
From c751597a2fd168995fa2cb531f0bc2bf69b5f268 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Feb 2017 17:41:08 +0530
Subject: [PATCH] Add proc_type column in pg_stat_get_activity

proc_type indicates the type of process in the stat table.
---
 doc/src/sgml/monitoring.sgml         | 11 +++++++++--
 src/backend/catalog/system_views.sql |  3 ++-
 src/backend/utils/adt/pgstatfuncs.c  |  5 ++++-
 src/include/catalog/pg_proc.h        |  2 +-
 src/test/regress/expected/rules.out  |  9 +++++----
 5 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4d03531..059bb1e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -620,8 +620,7 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
     <row>
      <entry><structfield>backend_start</></entry>
      <entry><type>timestamp with time zone</></entry>
-     <entry>Time when this process was started, i.e., when the
-      client connected to the server
+     <entry>Time when this process was started.
      </entry>
     </row>
     <row>
@@ -791,6 +790,14 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <xref linkend="guc-track-activity-query-size">.
      </entry>
     </row>
+    <row>
+     <entry><structfield>proc_type</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Type of the current server process. Possible types are:
+      autovacuum launcher, bgworker, checkpointer, client backend,
+      wal receiver, wal sender, wal writer and writer.
+     </entry>
+    </row>
    </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ba980de..9108445 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.proc_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 8bb9b7e..e1099ab 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -539,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_procs = pgstat_fetch_stat_numprocs();
 	int			curr_proc;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -819,6 +819,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					nulls[14] = true;
 				}
 			}
+			/* Add process type */
+			values[23] = CStringGetTextDatum(pgstat_get_proctype_desc(procentry->st_procType));
 		}
 		else
 		{
@@ -834,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[12] = true;
 			nulls[13] = true;
 			nulls[14] = true;
+			nulls[23] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ec4aedb..1c747fe 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2768,7 +2768,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,proc_type}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index c661f1d..69d61c6 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.proc_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, proc_type)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1833,7 +1834,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, proc_type)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1843,7 +1844,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, proc_type);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
-- 
1.8.3.1

#18Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Kuntal Ghosh (#17)

Perhaps I'm confused by the title of this thread/CF entry, but
background workers already do show up in pg_stat_activity. (You can
verify that by testing the background sessions patch.) So which
additional things are we aiming to see with this?

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.
(You always see your own session, but that's easy to eyeball.) If we
add all the various background processes by default, that will make
things harder, especially if there is no straightforward way to filter
them out.

Perhaps a pg_stat_user_* and pg_stat_system_* split like we have for
some of the statistics tables would be useful?

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#18)

On Thu, Mar 9, 2017 at 2:30 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

Perhaps I'm confused by the title of this thread/CF entry, but
background workers already do show up in pg_stat_activity. (You can
verify that by testing the background sessions patch.) So which
additional things are we aiming to see with this?

All the processes that don't normally show up in pg_stat_activity,
such as auxiliary processes.

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.
(You always see your own session, but that's easy to eyeball.) If we
add all the various background processes by default, that will make
things harder, especially if there is no straightforward way to filter
them out.

Perhaps a pg_stat_user_* and pg_stat_system_* split like we have for
some of the statistics tables would be useful?

I thought of the same kind of thing, and it was discussed upthread.
There seemed to be more votes for keeping it all in one view, but that
could change if more people vote.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Andres Freund
andres@anarazel.de
In reply to: Peter Eisentraut (#18)

Hi,

On 2017-03-09 14:30:21 -0500, Peter Eisentraut wrote:

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.

(You always see your own session, but that's easy to eyeball.) If we
add all the various background processes by default, that will make
things harder, especially if there is no straightforward way to filter
them out.

A good chunk of those still apply to database attached background
workers (say dropping a database, using it as a template) - so I'm not
really convinced that's an issue.

- Andres

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#19)

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Mar 9, 2017 at 2:30 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.

I thought of the same kind of thing, and it was discussed upthread.
There seemed to be more votes for keeping it all in one view, but that
could change if more people vote.

I've not been paying much attention to this thread, but it seems like
something that would help Peter's use-case and have other uses as well
is a new column that distinguishes different process types --- user
session, background worker, autovacuum worker, etc.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#22Andres Freund
andres@anarazel.de
In reply to: Tom Lane (#21)

On 2017-03-09 16:37:29 -0500, Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Mar 9, 2017 at 2:30 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.

I thought of the same kind of thing, and it was discussed upthread.
There seemed to be more votes for keeping it all in one view, but that
could change if more people vote.

I've not been paying much attention to this thread, but it seems like
something that would help Peter's use-case and have other uses as well
is a new column that distinguishes different process types --- user
session, background worker, autovacuum worker, etc.

The patches upthread add precisely such a column.

Andres

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Andres Freund (#22)

On Fri, Mar 10, 2017 at 3:11 AM, Andres Freund <andres@anarazel.de> wrote:

On 2017-03-09 16:37:29 -0500, Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Mar 9, 2017 at 2:30 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.

I thought of the same kind of thing, and it was discussed upthread.
There seemed to be more votes for keeping it all in one view, but that
could change if more people vote.

I've not been paying much attention to this thread, but it seems like
something that would help Peter's use-case and have other uses as well
is a new column that distinguishes different process types --- user
session, background worker, autovacuum worker, etc.

The patches upthread add precisely such a column.

The patch exposes auxiliary processes, autovacuum launcher and
bgworker along with other backends in pg_stat_activity. It also adds
an extra column, named proc_type (suggested by Craig
and Robert), to indicate the type of process in pg_stat_activity view.
proc_type includes:

* client backend
* autovacuum launcher
* wal sender
* bgworker
* writer
* checkpointer
* wal writer
* wal receiver

Here is the present output with the relevant columns.
postgres=# SELECT wait_event_type, wait_event, state, proc_type FROM
pg_stat_activity;
wait_event_type | wait_event | state | proc_type
-----------------+---------------------+--------+---------------------
Activity | AutoVacuumMain | idle | autovacuum launcher
Activity | LogicalLauncherMain | idle | bgworker
Activity | WalSenderMain | idle | wal sender
| | active | client backend
Activity | BgWriterMain | idle | writer
Activity | CheckpointerMain | idle | checkpointer
Activity | WalWriterMain | idle | wal writer
(7 rows)

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Michael Paquier
michael.paquier@gmail.com
In reply to: Kuntal Ghosh (#23)

On Fri, Mar 10, 2017 at 2:36 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

On Fri, Mar 10, 2017 at 3:11 AM, Andres Freund <andres@anarazel.de> wrote:

On 2017-03-09 16:37:29 -0500, Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Thu, Mar 9, 2017 at 2:30 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

In practice, I think it's common to do a quick select * from
pg_stat_activity to determine whether a database instance is in use.

I thought of the same kind of thing, and it was discussed upthread.
There seemed to be more votes for keeping it all in one view, but that
could change if more people vote.

I've not been paying much attention to this thread, but it seems like
something that would help Peter's use-case and have other uses as well
is a new column that distinguishes different process types --- user
session, background worker, autovacuum worker, etc.

The patches upthread add precisely such a column.

The patch exposes auxiliary processes, autovacuum launcher and
bgworker along with other backends in pg_stat_activity. It also adds
an extra column, named proc_type (suggested by Craig
and Robert), to indicate the type of process in pg_stat_activity view.
proc_type includes:

* client backend
* autovacuum launcher
* wal sender
* bgworker
* writer
* checkpointer
* wal writer
* wal receiver

"writer" would be better if defined as "background writer" instead?
You are forgetting in this list autovacuum workers and the startup
process, the latter is important for nodes in recovery.

Here is the present output with the relevant columns.
postgres=# SELECT wait_event_type, wait_event, state, proc_type FROM
pg_stat_activity;
wait_event_type | wait_event | state | proc_type
-----------------+---------------------+--------+---------------------
Activity | AutoVacuumMain | idle | autovacuum launcher
Activity | LogicalLauncherMain | idle | bgworker
Activity | WalSenderMain | idle | wal sender
| | active | client backend
Activity | BgWriterMain | idle | writer
Activity | CheckpointerMain | idle | checkpointer
Activity | WalWriterMain | idle | wal writer
(7 rows)

Here is a first pass on this patch.

+     <entry>Type of the current server process. Possible types are:
+      autovacuum launcher, bgworker, checkpointer, client backend,
+      wal receiver, wal sender, wal writer and writer.
+     </entry>
There should be markups around those terms. Shouldn't "wal writer" and
"wal sender" and "wal receiver" not use any space? On HEAD a WAL
sender is defined as "walsender".
+ * Each auxliliary process also maintains a PgBackendStatus struct in shared
+ * memory.
s/auxliliary/auxiliary/.

void
-pgstat_bestart(void)
+pgstat_procstart(void)
I would not have thought that this patch justifies potentially
breaking extensions.

For WAL senders, the "query" field is still filled with "walsender".
This should be removed.

@@ -365,6 +368,8 @@ CheckpointerMain(void)
*/
AbsorbFsyncRequests();

+       pgstat_report_activity(STATE_RUNNING, NULL);
+
        if (got_SIGHUP)
It seems to me that what we want to know here are only the wait
events, so I think that you had better drop this portion of the patch.
It is hard to decide if an auxiliary process is idle or running, and
this routine is a concept that applies to database backends running
queries.
-static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Status for backends and auxiliary processes */
+static LocalPgBackendStatus *localProcStatusTable = NULL;
I don't quite understand why you need to have two layers here,
wouldn't it be more simple to just extend localBackendStatusTable with
enough slots for the system processes? That would be also less
bug-prone. You need to be careful to have a correct mapping to
include:
- auxiliary processes, up to 4 slots used.
- bgworker processes, decided by GUC.
- autovacuum workers, decided by GUC.
+PgBackendStatus *
+pgstat_fetch_stat_procentry(int procid)
+{
+   pgstat_read_current_status();
This function is used nowhere.
-- 
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Michael Paquier (#24)

On Tue, Mar 14, 2017 at 1:50 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Here is a first pass on this patch.

Thanks Michael for the review.

void
-pgstat_bestart(void)
+pgstat_procstart(void)
I would not have thought that this patch justifies potentially
breaking extensions.

Since I'm using this method to start all kind of processes including
client backends, auxiliary procs etc., I thought of changing the name
as above. But, this surely doesn't justify breaking extensions. So,
I'll change it back to pgstat_bestart.

@@ -365,6 +368,8 @@ CheckpointerMain(void)
*/
AbsorbFsyncRequests();

+       pgstat_report_activity(STATE_RUNNING, NULL);
+
if (got_SIGHUP)
It seems to me that what we want to know here are only the wait
events, so I think that you had better drop this portion of the patch.
It is hard to decide if an auxiliary process is idle or running, and
this routine is a concept that applies to database backends running
queries.

I see your point. I'll remove this part.

-static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Status for backends and auxiliary processes */
+static LocalPgBackendStatus *localProcStatusTable = NULL;
I don't quite understand why you need to have two layers here,
wouldn't it be more simple to just extend localBackendStatusTable with
enough slots for the system processes? That would be also less
bug-prone. You need to be careful to have a correct mapping to
include:
- auxiliary processes, up to 4 slots used.
- bgworker processes, decided by GUC.
- autovacuum workers, decided by GUC.

I do have extended localBackendStatusTable with slots for non-backend
processes. But, I've renamed it as localProcStatusTable since it
includes all processes. I'll keep the variable name as
localBackendStatusTable in the updated patch to avoid any confusion.
I've extended BackendStatusArray to store auxiliary processes.
Backends use slots indexed in the range from 1 to MaxBackends
(inclusive), so we use MaxBackends + AuxProcType + 1 as the index of
the slot for an auxiliary process.

Additionally, to store the index of currently active client backends
from localBackendStatusTable, I've added an array named
localBackendStatusIndex. This is useful for generating a set of
currently active client backend ID numbers (from 1 to the number of
active client backends). These IDs are used for some pgstat_*
functions relevant to client processes, e.g.,
pg_stat_get_backend_activity, pg_stat_get_backend_client_port etc.

Any suggestions?

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#26Robert Haas
robertmhaas@gmail.com
In reply to: Kuntal Ghosh (#25)

On Tue, Mar 14, 2017 at 7:22 AM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

I do have extended localBackendStatusTable with slots for non-backend
processes. But, I've renamed it as localProcStatusTable since it
includes all processes. I'll keep the variable name as
localBackendStatusTable in the updated patch to avoid any confusion.
I've extended BackendStatusArray to store auxiliary processes.
Backends use slots indexed in the range from 1 to MaxBackends
(inclusive), so we use MaxBackends + AuxProcType + 1 as the index of
the slot for an auxiliary process.

I think the subject of this the thread, for which I'm probably to
blame, is bad terminology. The processes we're talking about exposing
in pg_stat_activity here are really backends, too, I think. They're
just ... special backends. So I would tend to avoid any backend ->
process type of renaming.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#26)

On Wed, Mar 15, 2017 at 4:52 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Mar 14, 2017 at 7:22 AM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

I do have extended localBackendStatusTable with slots for non-backend
processes. But, I've renamed it as localProcStatusTable since it
includes all processes. I'll keep the variable name as
localBackendStatusTable in the updated patch to avoid any confusion.
I've extended BackendStatusArray to store auxiliary processes.
Backends use slots indexed in the range from 1 to MaxBackends
(inclusive), so we use MaxBackends + AuxProcType + 1 as the index of
the slot for an auxiliary process.

I think the subject of this the thread, for which I'm probably to
blame, is bad terminology. The processes we're talking about exposing
in pg_stat_activity here are really backends, too, I think. They're
just ... special backends. So I would tend to avoid any backend ->
process type of renaming.

FWIW, my impression on the matter matches what is written in this paragraph.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#28Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Michael Paquier (#24)
3 attachment(s)

On Tue, Mar 14, 2017 at 1:50 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

"writer" would be better if defined as "background writer" instead?
You are forgetting in this list autovacuum workers and the startup
process, the latter is important for nodes in recovery.

Modified "writer" as "background writer". Included autovacuum workers
and startup process.

+     <entry>Type of the current server process. Possible types are:
+      autovacuum launcher, bgworker, checkpointer, client backend,
+      wal receiver, wal sender, wal writer and writer.
+     </entry>
There should be markups around those terms. Shouldn't "wal writer" and
"wal sender" and "wal receiver" not use any space? On HEAD a WAL
sender is defined as "walsender".

Enclosed each type in <literal/>. Removed space from "wal sender" and
"wal receiver".

For WAL senders, the "query" field is still filled with "walsender".
This should be removed.

Fixed.

@@ -365,6 +368,8 @@ CheckpointerMain(void)
*/
AbsorbFsyncRequests();

+       pgstat_report_activity(STATE_RUNNING, NULL);
+
if (got_SIGHUP)
It seems to me that what we want to know here are only the wait
events, so I think that you had better drop this portion of the patch.
It is hard to decide if an auxiliary process is idle or running, and
this routine is a concept that applies to database backends running
queries.

Removed this part as suggested.

I've attached the updated patches.
In 0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patch,
I've extended BackendStatusArray to to store auxiliary processes.
Backends
use slots indexed in the range from 1 to MaxBackends (inclusive), so
we can use MaxBackends + AuxBackendType + 1 as the index of the slot
for an auxiliary process. Also, I've added a backend_type to describe
the type of the backend process. The type includes:
* autovacuum launcher
* autovacuum worker
* background writer
* bgworker
* client backend
* checkpointer
* startup
* walreceiver
* walsender
* walwriter
In 0002-Expose-stats-for-all-backends.patch, I've added the required
code for reporting activity of different auxiliary processes,
autovacuum launcher and bgworker processes.
In 0003-Add-backend_type-column-in-pg_stat_get_activity.patch, I've
added a column named backend_type in pg_stat_get_activity to show the
type of the process to user.

There are some pg_stat_* functions where showing all the backends
doesn't make much sense. For example,
postgres=# SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
pg_stat_get_backend_activity(s.backendid) AS query
FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;
pid | query
-------+------------------------------------------------------------------
17300 | SELECT pg_stat_get_backend_pid(s.backendid) AS pid, +
| pg_stat_get_backend_activity(s.backendid) AS query +
| FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;
16925 | <command string not enabled>
16927 | <command string not enabled>
16926 | <command string not enabled>
16929 | <command string not enabled>
IMHO, this scenario can be easily avoided by filtering backends using
backend_type. I'm not sure whether we should add any logic in the code
for handling such cases. Thoughts?

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0003-Add-backend_type-column-in-pg_stat_get_activity.patchbinary/octet-stream; name=0003-Add-backend_type-column-in-pg_stat_get_activity.patchDownload
From e06a4a0e415190971dcbb21ef107fab5944ca5e7 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 12:53:11 +0530
Subject: [PATCH 3/3] Add backend_type column in pg_stat_get_activity

backend_type indicates the type of process in the stat table.
---
 doc/src/sgml/monitoring.sgml         | 14 ++++++++++++--
 src/backend/catalog/system_views.sql |  3 ++-
 src/backend/utils/adt/pgstatfuncs.c  |  5 ++++-
 src/include/catalog/pg_proc.h        |  2 +-
 src/test/regress/expected/rules.out  |  9 +++++----
 5 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9eaf43a..695928f 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -620,8 +620,7 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
     <row>
      <entry><structfield>backend_start</></entry>
      <entry><type>timestamp with time zone</></entry>
-     <entry>Time when this process was started, i.e., when the
-      client connected to the server
+     <entry>Time when this process was started.
      </entry>
     </row>
     <row>
@@ -791,6 +790,17 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <xref linkend="guc-track-activity-query-size">.
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_type</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Type of current backend. Possible types are 
+      <literal>autovacuum launcher</>, <literal>autovacuum worker</>,
+      <literal>bgworker</>, <literal>background writer</>,
+      <literal>client backend</>, <literal>checkpointer</>,
+      <literal>startup</>, <literal>walreceiver</>,
+      <literal>walsender</> and <literal>walwriter</>.
+     </entry>
+    </row>
    </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 0bce209..67351f9 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.backend_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 96a1188..02a164b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -539,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_backends = pgstat_fetch_stat_numbackends();
 	int			curr_backend;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -819,6 +819,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					nulls[14] = true;
 				}
 			}
+			/* Add process type */
+			values[23] = CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType));
 		}
 		else
 		{
@@ -834,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[12] = true;
 			nulls[13] = true;
 			nulls[14] = true;
+			nulls[23] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ec4aedb..6d37484 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2768,7 +2768,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,backend_type}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index bd13ae6..a317bff 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.backend_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1833,7 +1834,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1843,7 +1844,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
-- 
1.8.3.1

0002-Expose-stats-for-all-backends.patchbinary/octet-stream; name=0002-Expose-stats-for-all-backends.patchDownload
From 13b82c63aae4f0a0529abca65cd1f570ebcdfd12 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 12:27:00 +0530
Subject: [PATCH 2/3] Expose stats for all backends

All backends include auxiliary procs, autovacuum launcher and
bgworkers.
---
 src/backend/bootstrap/bootstrap.c     |  3 +++
 src/backend/postmaster/bgwriter.c     |  3 +++
 src/backend/postmaster/checkpointer.c |  3 +++
 src/backend/postmaster/pgstat.c       |  3 ++-
 src/backend/postmaster/startup.c      |  4 ++++
 src/backend/postmaster/walwriter.c    |  3 +++
 src/backend/replication/walreceiver.c |  4 ++++
 src/backend/replication/walsender.c   |  5 ++++-
 src/backend/utils/init/postinit.c     | 16 +++++++++++++++-
 9 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..f56e229 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,9 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize stats collection */
+		pgstat_initialize();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..6ba2e2e 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
 	 */
 	prev_hibernate = false;
 
+	/* report bgwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..8eb0a2a 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -345,6 +345,9 @@ CheckpointerMain(void)
 	 */
 	ProcGlobal->checkpointerLatch = &MyProc->procLatch;
 
+	/* report checkpointer process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 34cca73..215df08 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2677,7 +2677,8 @@ pgstat_initialize(void)
  * pgstat_bestart() -
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
- *	Called from InitPostgres.
+ *	Called from InitPostgres and other main entry points for
+ *	auxiliary processes.
  *
  *	Apart from auxiliary processes, MyDatabaseId, session userid,
  *	and application_name must be set for a backend (hence, this
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index b172b5e..56ff042 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -25,6 +25,7 @@
 #include "access/xlog.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/startup.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
@@ -210,6 +211,9 @@ StartupProcessMain(void)
 	 */
 	PG_SETMASK(&UnBlockSig);
 
+	/* report startup process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Do what we came for.
 	 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..9056652 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -231,6 +231,9 @@ WalWriterMain(void)
 	 */
 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
 
+	/* report walwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 18d9d7e..3265d03 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -316,6 +316,10 @@ WalReceiverMain(void)
 	SpinLockRelease(&walrcv->mutex);
 
 	first_stream = true;
+
+	/* report walreceiver process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	for (;;)
 	{
 		char	   *primary_sysid;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 127efec..9b80284 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -245,6 +245,9 @@ InitWalSender(void)
 	 */
 	MarkPostmasterChildWalSender();
 	SendPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE);
+
+	/* report walsender process in the PgBackendStatus array */
+	pgstat_bestart();
 }
 
 /*
@@ -1806,7 +1809,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
 	waiting_for_ping_response = false;
 
 	/* Report to pgstat that this process is a WAL sender */
-	pgstat_report_activity(STATE_RUNNING, "walsender");
+	pgstat_report_activity(STATE_RUNNING, NULL);
 
 	/*
 	 * Loop until we reach the end of this timeline or the client requests to
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..6f88b0f 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -665,7 +665,14 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* The autovacuum launcher is done here */
 	if (IsAutoVacuumLauncherProcess())
+	{
+		/*
+		 * Before returning, report autovacuum launcher process in the
+		 * PgBackendStatus array.
+		 */
+		pgstat_bestart();
 		return;
+	}
 
 	/*
 	 * Start a new transaction here before first access to db, and get a
@@ -808,7 +815,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		/* initialize client encoding */
 		InitializeClientEncoding();
 
-		/* report this backend in the PgBackendStatus array */
+		/* report walsender process in the PgBackendStatus array */
 		pgstat_bestart();
 
 		/* close the transaction we started above */
@@ -875,6 +882,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		 */
 		if (!bootstrap)
 			CommitTransactionCommand();
+
+		/*
+		 * Before returning, report the background worker process in the
+		 * PgBackendStatus array.
+		 */
+		if (!bootstrap)
+			pgstat_bestart();
 		return;
 	}
 
-- 
1.8.3.1

0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchbinary/octet-stream; name=0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchDownload
From 586019bd39fa5a0665b1e3bd76e1968e4228d626 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 11:32:49 +0530
Subject: [PATCH 1/3] Infra to expose all backend processes in
 pg_stat_get_activity

This patch implements the infrastructure required to expose
all backend processes including auxiliary procs in pg_stat_activity.
BackendStatusArray is extended to store auxiliary processes. Backends
use slots indexed in the range from 1 to MaxBackends (inclusive),
so we use MaxBackends + AuxBackendType + 1 as the index of the slot for an
auxiliary process.
---
 src/backend/postmaster/pgstat.c     | 176 +++++++++++++++++++++++++++++++-----
 src/backend/storage/lmgr/proc.c     |  27 ++++++
 src/backend/utils/adt/pgstatfuncs.c |  30 +++++-
 src/include/pgstat.h                |  30 +++++-
 src/include/storage/proc.h          |   1 +
 5 files changed, 236 insertions(+), 28 deletions(-)

diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7cacb1e..34cca73 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -212,7 +213,11 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
+
+/* Status for backends including auxiliary */
 static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Total number of backends including auxiliary */
 static int	localNumBackends = 0;
 
 /*
@@ -2504,20 +2509,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+			mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+				  mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
 #endif
 	return size;
 }
@@ -2535,7 +2540,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2558,7 +2563,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2576,7 +2581,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2585,7 +2590,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumBackendStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2597,7 +2602,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2606,7 +2611,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2618,7 +2623,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2632,7 +2637,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2642,8 +2648,26 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxBackendType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -2654,15 +2678,16 @@ pgstat_initialize(void)
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
  *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *
+ *	Apart from auxiliary processes, MyDatabaseId, session userid,
+ *	and application_name must be set for a backend (hence, this
+ *	cannot be combined with pgstat_initialize).
  * ----------
  */
 void
 pgstat_bestart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2677,7 +2702,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2696,6 +2720,62 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_backendType = B_AUTOVAC_LAUNCHER;
+		}
+		else if (IsAutoVacuumWorkerProcess())
+		{
+			/* Autovacuum Worker */
+			beentry->st_backendType = B_AUTOVAC_WORKER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_backendType = B_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_backendType = B_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_backendType = B_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case StartupProcess:
+				beentry->st_backendType = B_STARTUP;
+				break;
+			case BgWriterProcess:
+				beentry->st_backendType = B_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_backendType = B_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_backendType = B_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_backendType = B_WAL_RECEIVER;
+				break;
+			default:
+				elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2707,7 +2787,13 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends and wal-sender processes */
+	if (beentry->st_backendType == B_BACKEND || beentry->st_backendType == B_WAL_SENDER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
@@ -3045,24 +3131,24 @@ pgstat_read_current_status(void)
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						 sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumBackendStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					 pgstat_track_activity_query_size * NumBackendStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
 #endif
 
 	localNumBackends = 0;
 
 	beentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumBackendStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3590,7 +3676,47 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_backend_desc(BackendType backendType)
+{
+	const char *backendDesc = "unknown process type";
+
+	switch (backendType)
+	{
+		case B_AUTOVAC_LAUNCHER:
+			backendDesc = "autovacuum launcher";
+			break;
+		case B_AUTOVAC_WORKER:
+			backendDesc = "autovacuum worker";
+			break;
+		case B_BACKEND:
+			backendDesc = "client backend";
+			break;
+		case B_BG_WORKER:
+			backendDesc = "bgworker";
+			break;
+		case B_BG_WRITER:
+			backendDesc = "background writer";
+			break;
+		case B_CHECKPOINTER:
+			backendDesc = "checkpointer";
+			break;
+		case B_STARTUP:
+			backendDesc = "startup";
+			break;
+		case B_WAL_RECEIVER:
+			backendDesc = "walreceiver";
+			break;
+		case B_WAL_SENDER:
+			backendDesc = "walsender";
+			break;
+		case B_WAL_WRITER:
+			backendDesc = "walwriter";
+			break;
+	}
 
+	return backendDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..3e716b1 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result = NULL;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..96a1188 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -615,9 +616,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		if (beentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		else
+			nulls[0] = true;
+
 		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
+
+		if (beentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(beentry->st_userid);
+		else
+			nulls[2] = true;
+
 		if (beentry->st_appname)
 			values[3] = CStringGetTextDatum(beentry->st_appname);
 		else
@@ -690,6 +700,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
+			else if (beentry->st_backendType != B_BACKEND)
+			{
+				uint32		raw_wait_event;
+
+				/*
+				 * For an auxiliary process, retrieve process info from
+				 * AuxiliaryProcs stored in shared-memory.
+				 */
+				proc = AuxiliaryPidGetProc(beentry->st_procpid);
+
+				/* Check whether this is indeed an auxiliary process */
+				Assert(proc != NULL);
+				raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+				wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+				wait_event = pgstat_get_wait_event(raw_wait_event);
+			}
 			else
 			{
 				wait_event_type = NULL;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 60c78d1..a1a0193 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -41,6 +41,9 @@ typedef enum TrackFunctionsLevel
 	TRACK_FUNC_ALL
 }	TrackFunctionsLevel;
 
+/* Total number of backends including auxiliary */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
 /* ----------
  * The types of backend -> collector messages
  * ----------
@@ -696,6 +699,25 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Backend types
+ * ----------
+ */
+typedef enum BackendType
+{
+	B_AUTOVAC_LAUNCHER,
+	B_AUTOVAC_WORKER,
+	B_BACKEND,
+	B_BG_WORKER,
+	B_BG_WRITER,
+	B_CHECKPOINTER,
+	B_STARTUP,
+	B_WAL_RECEIVER,
+	B_WAL_SENDER,
+	B_WAL_WRITER
+} BackendType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -847,7 +869,9 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
- * ----------
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
  */
 typedef struct PgBackendStatus
 {
@@ -871,6 +895,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of backends */
+	BackendType st_backendType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1069,6 +1096,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_backend_desc(BackendType backendType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 5f38fa6..be3bd01 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -262,6 +262,7 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
 
 /* configurable options */
 extern int	DeadlockTimeout;
-- 
1.8.3.1

#29Michael Paquier
michael.paquier@gmail.com
In reply to: Kuntal Ghosh (#28)

On Wed, Mar 15, 2017 at 9:14 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

I've attached the updated patches.

Thanks for the new versions. This begins to look really clear.

In 0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patch,
I've extended BackendStatusArray to to store auxiliary processes.
Backends
use slots indexed in the range from 1 to MaxBackends (inclusive), so
we can use MaxBackends + AuxBackendType + 1 as the index of the slot
for an auxiliary process. Also, I've added a backend_type to describe
the type of the backend process. The type includes:
* autovacuum launcher
* autovacuum worker
* background writer
* bgworker
* client backend
* checkpointer
* startup
* walreceiver
* walsender
* walwriter
In 0002-Expose-stats-for-all-backends.patch, I've added the required
code for reporting activity of different auxiliary processes,
autovacuum launcher and bgworker processes.
In 0003-Add-backend_type-column-in-pg_stat_get_activity.patch, I've
added a column named backend_type in pg_stat_get_activity to show the
type of the process to user.

There are some pg_stat_* functions where showing all the backends
doesn't make much sense. For example,
postgres=# SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
pg_stat_get_backend_activity(s.backendid) AS query
FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;
pid | query
-------+------------------------------------------------------------------
17300 | SELECT pg_stat_get_backend_pid(s.backendid) AS pid, +
| pg_stat_get_backend_activity(s.backendid) AS query +
| FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;
16925 | <command string not enabled>
16927 | <command string not enabled>
16926 | <command string not enabled>
16929 | <command string not enabled>
IMHO, this scenario can be easily avoided by filtering backends using
backend_type. I'm not sure whether we should add any logic in the code
for handling such cases. Thoughts?

Having some activity really depends on the backend type (see
autovacuum workers for example which fill in the query field), so my
2c here is that we let things as your patch proposes. If at some point
it makes sense to add something in the query field, we could always
discuss it separately and patch it accordingly.

+/* Total number of backends including auxiliary */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
This variable remains localized in pgstat.c, so let's define it there.

+ <literal>bgworker</>, <literal>background writer</>,
That's really bike-shedding, but we could say here "background worker"
and be consistent with the rest.

+/* Total number of backends including auxiliary */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
This could be a bit more precise, telling as well that MaxBackends
includes autovacuum workers and background workers.
- * ----------
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
  */
Better to not delete this line, this prevents pgindent to touch this
comment block.

Did you try if this patch worked with EXEC_BACKEND? Sorry I don't have
a Windows workstation at hand now, but as AuxiliaryProcs is
NON_EXEC_STATIC...

+   /* We have userid for client-backends and wal-sender processes */
+   if (beentry->st_backendType == B_BACKEND ||
beentry->st_backendType == B_WAL_SENDER)
+       beentry->st_userid = GetSessionUserId();
+   else
+       beentry->st_userid = InvalidOid;
This can be true as well for bgworkers defining a role OID when
connecting with BackgroundWorkerInitializeConnection().
+       /*
+        * Before returning, report autovacuum launcher process in the
+        * PgBackendStatus array.
+        */
+       pgstat_bestart();
        return;
Wouldn't that be better in AutoVacLauncherMain()?
+       /*
+        * Before returning, report the background worker process in the
+        * PgBackendStatus array.
+        */
+       if (!bootstrap)
+           pgstat_bestart();
Ditto with BackgroundWriterMain().

@@ -808,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[23] = true;
}
That's not possible to have backend_type set as NULL, no?
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Michael Paquier (#29)
3 attachment(s)

On Thu, Mar 16, 2017 at 1:18 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Wed, Mar 15, 2017 at 9:14 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

I've attached the updated patches.

Thanks for the new versions. This begins to look really clear.

Thanks again for the review.

Having some activity really depends on the backend type (see
autovacuum workers for example which fill in the query field), so my
2c here is that we let things as your patch proposes. If at some point
it makes sense to add something in the query field, we could always
discuss it separately and patch it accordingly.

+1.

+/* Total number of backends including auxiliary */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
This variable remains localized in pgstat.c, so let's define it there.

Done.

+ <literal>bgworker</>, <literal>background writer</>,
That's really bike-shedding, but we could say here "background worker"
and be consistent with the rest.

Done.

+/* Total number of backends including auxiliary */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
This could be a bit more precise, telling as well that MaxBackends
includes autovacuum workers and background workers.

Done.

- * ----------
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
*/
Better to not delete this line, this prevents pgindent to touch this
comment block.

Good to know. Fixed.

Did you try if this patch worked with EXEC_BACKEND? Sorry I don't have
a Windows workstation at hand now, but as AuxiliaryProcs is
NON_EXEC_STATIC...

Thanks to Ashutosh for testing the patches on Windows. It's working fine.

+   /* We have userid for client-backends and wal-sender processes */
+   if (beentry->st_backendType == B_BACKEND ||
beentry->st_backendType == B_WAL_SENDER)
+       beentry->st_userid = GetSessionUserId();
+   else
+       beentry->st_userid = InvalidOid;
This can be true as well for bgworkers defining a role OID when
connecting with BackgroundWorkerInitializeConnection().

Fixed.

+       /*
+        * Before returning, report autovacuum launcher process in the
+        * PgBackendStatus array.
+        */
+       pgstat_bestart();
return;
Wouldn't that be better in AutoVacLauncherMain()?

Agreed and done that way.

+       /*
+        * Before returning, report the background worker process in the
+        * PgBackendStatus array.
+        */
+       if (!bootstrap)
+           pgstat_bestart();
Ditto with BackgroundWriterMain().

Perhaps you meant BackgroundWorkerInitializeConnection and
BackgroundWorkerInitializeConnectionByOid. Done.

@@ -808,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[23] = true;
}
That's not possible to have backend_type set as NULL, no?

Yes, backend_type can't be null. But, I'm not sure whether it should
be visible to a user with insufficient privileges. Anyway, I've made
it visible to all user for now.

Please find the updated patches in the attachment.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchbinary/octet-stream; name=0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchDownload
From 99c0aca7e7cdc683c05a3dd831d12a82e4f7db34 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 11:32:49 +0530
Subject: [PATCH 1/3] Infra to expose all backend processes in
 pg_stat_get_activity

This patch implements the infrastructure required to expose
all backend processes including auxiliary procs in pg_stat_activity.
BackendStatusArray is extended to store auxiliary processes. Backends
use slots indexed in the range from 1 to MaxBackends (inclusive),
so we use MaxBackends + AuxBackendType + 1 as the index of the slot for an
auxiliary process.
---
 src/backend/postmaster/pgstat.c     | 190 +++++++++++++++++++++++++++++++-----
 src/backend/storage/lmgr/proc.c     |  27 +++++
 src/backend/utils/adt/pgstatfuncs.c |  30 +++++-
 src/include/pgstat.h                |  26 +++++
 src/include/storage/proc.h          |   1 +
 5 files changed, 247 insertions(+), 27 deletions(-)

diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7cacb1e..5b7804a 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -103,6 +104,18 @@
 
 
 /* ----------
+ * Total number of backends including auxiliary
+ *
+ * We reserve a slot for each possible BackendId, plus one for each
+ * possible auxiliary process type.  (This scheme assumes there is not
+ * more than one of any auxiliary process type at a time.) MaxBackends
+ * includes autovacuum workers and background workers as well.
+ * ----------
+ */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
+
+/* ----------
  * GUC parameters
  * ----------
  */
@@ -212,7 +225,11 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
+
+/* Status for backends including auxiliary */
 static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Total number of backends including auxiliary */
 static int	localNumBackends = 0;
 
 /*
@@ -2504,20 +2521,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+			mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+				  mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
 #endif
 	return size;
 }
@@ -2535,7 +2552,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2558,7 +2575,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2576,7 +2593,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2585,7 +2602,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumBackendStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2597,7 +2614,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2606,7 +2623,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2618,7 +2635,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2632,7 +2649,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2642,8 +2660,26 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxBackendType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -2654,15 +2690,16 @@ pgstat_initialize(void)
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
  *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *
+ *	Apart from auxiliary processes, MyDatabaseId, session userid,
+ *	and application_name must be set for a backend (hence, this
+ *	cannot be combined with pgstat_initialize).
  * ----------
  */
 void
 pgstat_bestart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2677,7 +2714,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2696,6 +2732,62 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_backendType = B_AUTOVAC_LAUNCHER;
+		}
+		else if (IsAutoVacuumWorkerProcess())
+		{
+			/* Autovacuum Worker */
+			beentry->st_backendType = B_AUTOVAC_WORKER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_backendType = B_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_backendType = B_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_backendType = B_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case StartupProcess:
+				beentry->st_backendType = B_STARTUP;
+				break;
+			case BgWriterProcess:
+				beentry->st_backendType = B_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_backendType = B_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_backendType = B_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_backendType = B_WAL_RECEIVER;
+				break;
+			default:
+				elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2707,7 +2799,15 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends, wal-sender and bgworker processes */
+	if (beentry->st_backendType == B_BACKEND
+			|| beentry->st_backendType == B_WAL_SENDER
+			|| beentry->st_backendType == B_BG_WORKER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
@@ -3045,24 +3145,24 @@ pgstat_read_current_status(void)
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						 sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumBackendStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					 pgstat_track_activity_query_size * NumBackendStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
 #endif
 
 	localNumBackends = 0;
 
 	beentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumBackendStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3590,7 +3690,47 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_backend_desc(BackendType backendType)
+{
+	const char *backendDesc = "unknown process type";
 
+	switch (backendType)
+	{
+		case B_AUTOVAC_LAUNCHER:
+			backendDesc = "autovacuum launcher";
+			break;
+		case B_AUTOVAC_WORKER:
+			backendDesc = "autovacuum worker";
+			break;
+		case B_BACKEND:
+			backendDesc = "client backend";
+			break;
+		case B_BG_WORKER:
+			backendDesc = "background worker";
+			break;
+		case B_BG_WRITER:
+			backendDesc = "background writer";
+			break;
+		case B_CHECKPOINTER:
+			backendDesc = "checkpointer";
+			break;
+		case B_STARTUP:
+			backendDesc = "startup";
+			break;
+		case B_WAL_RECEIVER:
+			backendDesc = "walreceiver";
+			break;
+		case B_WAL_SENDER:
+			backendDesc = "walsender";
+			break;
+		case B_WAL_WRITER:
+			backendDesc = "walwriter";
+			break;
+	}
+
+	return backendDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..3e716b1 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result = NULL;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..96a1188 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -615,9 +616,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		if (beentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		else
+			nulls[0] = true;
+
 		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
+
+		if (beentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(beentry->st_userid);
+		else
+			nulls[2] = true;
+
 		if (beentry->st_appname)
 			values[3] = CStringGetTextDatum(beentry->st_appname);
 		else
@@ -690,6 +700,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
+			else if (beentry->st_backendType != B_BACKEND)
+			{
+				uint32		raw_wait_event;
+
+				/*
+				 * For an auxiliary process, retrieve process info from
+				 * AuxiliaryProcs stored in shared-memory.
+				 */
+				proc = AuxiliaryPidGetProc(beentry->st_procpid);
+
+				/* Check whether this is indeed an auxiliary process */
+				Assert(proc != NULL);
+				raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+				wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+				wait_event = pgstat_get_wait_event(raw_wait_event);
+			}
 			else
 			{
 				wait_event_type = NULL;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 60c78d1..217df45 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -696,6 +696,25 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Backend types
+ * ----------
+ */
+typedef enum BackendType
+{
+	B_AUTOVAC_LAUNCHER,
+	B_AUTOVAC_WORKER,
+	B_BACKEND,
+	B_BG_WORKER,
+	B_BG_WRITER,
+	B_CHECKPOINTER,
+	B_STARTUP,
+	B_WAL_RECEIVER,
+	B_WAL_SENDER,
+	B_WAL_WRITER
+} BackendType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -847,6 +866,9 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
  * ----------
  */
 typedef struct PgBackendStatus
@@ -871,6 +893,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of backends */
+	BackendType st_backendType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1069,6 +1094,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_backend_desc(BackendType backendType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 5f38fa6..be3bd01 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -262,6 +262,7 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
 
 /* configurable options */
 extern int	DeadlockTimeout;
-- 
1.8.3.1

0002-Expose-stats-for-all-backends.patchbinary/octet-stream; name=0002-Expose-stats-for-all-backends.patchDownload
From 191f6daebabcccb50a363801cb93edae71c12504 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 12:27:00 +0530
Subject: [PATCH 2/3] Expose stats for all backends

All backends include auxiliary procs, autovacuum launcher and
bgworkers.
---
 src/backend/bootstrap/bootstrap.c     | 3 +++
 src/backend/postmaster/autovacuum.c   | 3 +++
 src/backend/postmaster/bgwriter.c     | 3 +++
 src/backend/postmaster/checkpointer.c | 3 +++
 src/backend/postmaster/pgstat.c       | 1 -
 src/backend/postmaster/postmaster.c   | 6 ++++++
 src/backend/postmaster/startup.c      | 4 ++++
 src/backend/postmaster/walwriter.c    | 3 +++
 src/backend/replication/walreceiver.c | 4 ++++
 src/backend/replication/walsender.c   | 5 ++++-
 src/backend/utils/init/postinit.c     | 5 ++++-
 11 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..f56e229 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,9 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize stats collection */
+		pgstat_initialize();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index fa8de13..550a731 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -453,6 +453,9 @@ AutoVacLauncherMain(int argc, char *argv[])
 
 	InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
 
+	/* report autovacuum launcher process in the  PgBackendStatus array */
+	pgstat_bestart();
+
 	SetProcessingMode(NormalProcessing);
 
 	/*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..6ba2e2e 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
 	 */
 	prev_hibernate = false;
 
+	/* report bgwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..8eb0a2a 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -345,6 +345,9 @@ CheckpointerMain(void)
 	 */
 	ProcGlobal->checkpointerLatch = &MyProc->procLatch;
 
+	/* report checkpointer process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 5b7804a..1b01b53 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2689,7 +2689,6 @@ pgstat_initialize(void)
  * pgstat_bestart() -
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
- *	Called from InitPostgres.
  *
  *	Apart from auxiliary processes, MyDatabaseId, session userid,
  *	and application_name must be set for a backend (hence, this
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6831342..7d78bff 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -5461,6 +5461,9 @@ BackgroundWorkerInitializeConnection(char *dbname, char *username)
 
 	InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
 
+	/* report the background worker process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/* it had better not gotten out of "init" mode yet */
 	if (!IsInitProcessingMode())
 		ereport(ERROR,
@@ -5484,6 +5487,9 @@ BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid)
 
 	InitPostgres(NULL, dboid, NULL, useroid, NULL);
 
+	/* report the background worker process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/* it had better not gotten out of "init" mode yet */
 	if (!IsInitProcessingMode())
 		ereport(ERROR,
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index b172b5e..56ff042 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -25,6 +25,7 @@
 #include "access/xlog.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/startup.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
@@ -210,6 +211,9 @@ StartupProcessMain(void)
 	 */
 	PG_SETMASK(&UnBlockSig);
 
+	/* report startup process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Do what we came for.
 	 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..9056652 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -231,6 +231,9 @@ WalWriterMain(void)
 	 */
 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
 
+	/* report walwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 18d9d7e..3265d03 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -316,6 +316,10 @@ WalReceiverMain(void)
 	SpinLockRelease(&walrcv->mutex);
 
 	first_stream = true;
+
+	/* report walreceiver process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	for (;;)
 	{
 		char	   *primary_sysid;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 127efec..9b80284 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -245,6 +245,9 @@ InitWalSender(void)
 	 */
 	MarkPostmasterChildWalSender();
 	SendPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE);
+
+	/* report walsender process in the PgBackendStatus array */
+	pgstat_bestart();
 }
 
 /*
@@ -1806,7 +1809,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
 	waiting_for_ping_response = false;
 
 	/* Report to pgstat that this process is a WAL sender */
-	pgstat_report_activity(STATE_RUNNING, "walsender");
+	pgstat_report_activity(STATE_RUNNING, NULL);
 
 	/*
 	 * Loop until we reach the end of this timeline or the client requests to
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..cbe9b49 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -665,7 +665,9 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* The autovacuum launcher is done here */
 	if (IsAutoVacuumLauncherProcess())
+	{
 		return;
+	}
 
 	/*
 	 * Start a new transaction here before first access to db, and get a
@@ -808,7 +810,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		/* initialize client encoding */
 		InitializeClientEncoding();
 
-		/* report this backend in the PgBackendStatus array */
+		/* report walsender process in the PgBackendStatus array */
 		pgstat_bestart();
 
 		/* close the transaction we started above */
@@ -875,6 +877,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		 */
 		if (!bootstrap)
 			CommitTransactionCommand();
+
 		return;
 	}
 
-- 
1.8.3.1

0003-Add-backend_type-column-in-pg_stat_get_activity.patchbinary/octet-stream; name=0003-Add-backend_type-column-in-pg_stat_get_activity.patchDownload
From 19c3a51356ccf01cc6f1e396518af360e104b648 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 12:53:11 +0530
Subject: [PATCH 3/3] Add backend_type column in pg_stat_get_activity

backend_type indicates the type of process in the stat table.
---
 doc/src/sgml/monitoring.sgml         | 14 ++++++++++++--
 src/backend/catalog/system_views.sql |  3 ++-
 src/backend/utils/adt/pgstatfuncs.c  |  4 +++-
 src/include/catalog/pg_proc.h        |  2 +-
 src/test/regress/expected/rules.out  |  9 +++++----
 5 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9eaf43a..320cec3 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -620,8 +620,7 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
     <row>
      <entry><structfield>backend_start</></entry>
      <entry><type>timestamp with time zone</></entry>
-     <entry>Time when this process was started, i.e., when the
-      client connected to the server
+     <entry>Time when this process was started.
      </entry>
     </row>
     <row>
@@ -791,6 +790,17 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <xref linkend="guc-track-activity-query-size">.
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_type</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Type of current backend. Possible types are 
+      <literal>autovacuum launcher</>, <literal>autovacuum worker</>,
+      <literal>background worker</>, <literal>background writer</>,
+      <literal>client backend</>, <literal>checkpointer</>,
+      <literal>startup</>, <literal>walreceiver</>,
+      <literal>walsender</> and <literal>walwriter</>.
+     </entry>
+    </row>
    </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index b6552da..bdbb5b8 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.backend_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 96a1188..eafb0bf 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -539,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_backends = pgstat_fetch_stat_numbackends();
 	int			curr_backend;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -835,6 +835,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[13] = true;
 			nulls[14] = true;
 		}
+		/* Add backend type */
+		values[23] = CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType));
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
 
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 836d6ff..8494648 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2797,7 +2797,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,backend_type}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index bd13ae6..a317bff 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.backend_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1833,7 +1834,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1843,7 +1844,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
-- 
1.8.3.1

#31Michael Paquier
michael.paquier@gmail.com
In reply to: Kuntal Ghosh (#30)

On Fri, Mar 17, 2017 at 6:19 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

On Thu, Mar 16, 2017 at 1:18 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

+   /* We have userid for client-backends and wal-sender processes */
+   if (beentry->st_backendType == B_BACKEND ||
beentry->st_backendType == B_WAL_SENDER)
+       beentry->st_userid = GetSessionUserId();
+   else
+       beentry->st_userid = InvalidOid;
This can be true as well for bgworkers defining a role OID when
connecting with BackgroundWorkerInitializeConnection().

Fixed.

And so you have the following thing to initialize the statistics:
@@ -5484,6 +5487,9 @@ BackgroundWorkerInitializeConnectionByOid(Oid
dboid, Oid useroid)

InitPostgres(NULL, dboid, NULL, useroid, NULL);

+   /* report the background worker process in the PgBackendStatus array */
+   pgstat_bestart();
And that bit as well:
+   if (beentry->st_backendType == B_BACKEND
+           || beentry->st_backendType == B_WAL_SENDER
+           || beentry->st_backendType == B_BG_WORKER)
+       beentry->st_userid = GetSessionUserId();
Unfortunately this is true only for background workers that connect to
a database. And this would break for bgworkers that do not do that.
The point to fix is here:
+   if (MyBackendId != InvalidBackendId)
+   {
[...]
+       else if (IsBackgroundWorker)
+       {
+           /* bgworker */
+           beentry->st_backendType = B_BG_WORKER;
+       }
Your code is assuming that a bgworker will always be setting
MyBackendId which is not necessarily true, and you would trigger the
assertion down:
Assert(MyAuxProcType != NotAnAuxProcess);
So you need to rely on IsBackgroundWorker in priority I think. I would
suggest as well to give up calling pgstat_bestart() in
BackgroundWorkerInitializeConnection[ByOid] and let the workers do
this work by themselves. This gives more flexibility. You would need
to update the logical replication worker and worker_spi for that as
well.

If you want to test this configuration, feel free to use this background worker:
https://github.com/michaelpq/pg_plugins/tree/master/hello_world
This just prints an entry to the logs every 10s, and does not connect
to any database. Adding a call to pgstat_bestart() in hello_main
triggers the assertion.

@@ -808,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[23] = true;
}
That's not possible to have backend_type set as NULL, no?

Yes, backend_type can't be null. But, I'm not sure whether it should
be visible to a user with insufficient privileges. Anyway, I've made
it visible to all user for now.

Please find the updated patches in the attachment.

Yeah, hiding it may make sense...

Thanks for the updated versions/

/* The autovacuum launcher is done here */
if (IsAutoVacuumLauncherProcess())
+ {
return;
+ }
Unnecessary noise here.

Except for the two issues pointed out in this email, I am pretty cool
with this patch. Nice work.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#32Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Michael Paquier (#31)
3 attachment(s)

On Tue, Mar 21, 2017 at 10:52 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
Thank you for the review.

Unfortunately this is true only for background workers that connect to
a database. And this would break for bgworkers that do not do that.
The point to fix is here:
+   if (MyBackendId != InvalidBackendId)
+   {
[...]
+       else if (IsBackgroundWorker)
+       {
+           /* bgworker */
+           beentry->st_backendType = B_BG_WORKER;
+       }
Your code is assuming that a bgworker will always be setting
MyBackendId which is not necessarily true, and you would trigger the
assertion down:
Assert(MyAuxProcType != NotAnAuxProcess);
So you need to rely on IsBackgroundWorker in priority I think. I would
suggest as well to give up calling pgstat_bestart() in
BackgroundWorkerInitializeConnection[ByOid] and let the workers do
this work by themselves. This gives more flexibility. You would need
to update the logical replication worker and worker_spi for that as
well.

We reserve a slot for each possible BackendId, plus one for each
possible auxiliary process type. For a non-auxiliary process,
BackendId is used to refer the backend status in PgBackendStatus
array. So, a bgworker without any BackendId can't initialize its'
entry in PgBackendStatus array. In simple terms, it will not be shown
in pg_stat_activity. I've added some comments regarding this in
pgstat_bestart().
And, any bgworker having valid BackendId will have either a valid
userid or BOOTSTRAP_SUPERUSERID.

If you want to test this configuration, feel free to use this background worker:
https://github.com/michaelpq/pg_plugins/tree/master/hello_world
This just prints an entry to the logs every 10s, and does not connect
to any database. Adding a call to pgstat_bestart() in hello_main
triggers the assertion.

In this case, pgstat_bestart() shouldn't be called from this module as
the spawned bgworker will have invalid BackendId. By the way, thanks
for sharing the repo link. Found a lot of interesting things to
explore and learn. :)

@@ -808,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[12] = true;
nulls[13] = true;
nulls[14] = true;
+ nulls[23] = true;
}
That's not possible to have backend_type set as NULL, no?

Yes, backend_type can't be null. But, I'm not sure whether it should
be visible to a user with insufficient privileges. Anyway, I've made
it visible to all user for now.

Please find the updated patches in the attachment.

Yeah, hiding it may make sense...

Modified.

/* The autovacuum launcher is done here */
if (IsAutoVacuumLauncherProcess())
+ {
return;
+ }
Unnecessary noise here.

Fixed.

Except for the two issues pointed out in this email, I am pretty cool
with this patch. Nice work.

Thank you. :)

Please find the updated patches.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchapplication/x-download; name=0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchDownload
From 9b83396077a4b5847621cd572f626507accf77e6 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 11:32:49 +0530
Subject: [PATCH 1/3] Infra to expose all backend processes in
 pg_stat_get_activity

This patch implements the infrastructure required to expose
all backend processes including auxiliary procs in pg_stat_activity.
BackendStatusArray is extended to store auxiliary processes. Backends
use slots indexed in the range from 1 to MaxBackends (inclusive),
so we use MaxBackends + AuxBackendType + 1 as the index of the slot for an
auxiliary process.
---
 src/backend/postmaster/pgstat.c     | 193 +++++++++++++++++++++++++++++++-----
 src/backend/storage/lmgr/proc.c     |  27 +++++
 src/backend/utils/adt/pgstatfuncs.c |  30 +++++-
 src/include/pgstat.h                |  26 +++++
 src/include/storage/proc.h          |   1 +
 5 files changed, 250 insertions(+), 27 deletions(-)

diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 3a50488..a2b9bbf 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -103,6 +104,18 @@
 
 
 /* ----------
+ * Total number of backends including auxiliary
+ *
+ * We reserve a slot for each possible BackendId, plus one for each
+ * possible auxiliary process type.  (This scheme assumes there is not
+ * more than one of any auxiliary process type at a time.) MaxBackends
+ * includes autovacuum workers and background workers as well.
+ * ----------
+ */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
+
+/* ----------
  * GUC parameters
  * ----------
  */
@@ -212,7 +225,11 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
+
+/* Status for backends including auxiliary */
 static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Total number of backends including auxiliary */
 static int	localNumBackends = 0;
 
 /*
@@ -2505,20 +2522,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+			mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+				  mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
 #endif
 	return size;
 }
@@ -2536,7 +2553,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2559,7 +2576,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2577,7 +2594,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2586,7 +2603,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumBackendStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2598,7 +2615,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2607,7 +2624,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2619,7 +2636,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2633,7 +2650,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2643,8 +2661,26 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxBackendType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -2655,15 +2691,16 @@ pgstat_initialize(void)
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
  *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *
+ *	Apart from auxiliary processes, MyBackendId, MyDatabaseId,
+ *	session userid, and application_name must be set for a
+ *	backend (hence, this cannot be combined with pgstat_initialize).
  * ----------
  */
 void
 pgstat_bestart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2678,7 +2715,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2697,6 +2733,65 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	/* pgstats state must be initialized from pgstat_initialize() */
+	Assert(beentry != NULL);
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_backendType = B_AUTOVAC_LAUNCHER;
+		}
+		else if (IsAutoVacuumWorkerProcess())
+		{
+			/* Autovacuum Worker */
+			beentry->st_backendType = B_AUTOVAC_WORKER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_backendType = B_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_backendType = B_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_backendType = B_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case StartupProcess:
+				beentry->st_backendType = B_STARTUP;
+				break;
+			case BgWriterProcess:
+				beentry->st_backendType = B_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_backendType = B_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_backendType = B_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_backendType = B_WAL_RECEIVER;
+				break;
+			default:
+				elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2708,7 +2803,15 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends, wal-sender and bgworker processes */
+	if (beentry->st_backendType == B_BACKEND
+			|| beentry->st_backendType == B_WAL_SENDER
+			|| beentry->st_backendType == B_BG_WORKER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
@@ -3046,24 +3149,24 @@ pgstat_read_current_status(void)
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						 sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumBackendStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					 pgstat_track_activity_query_size * NumBackendStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
 #endif
 
 	localNumBackends = 0;
 
 	beentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumBackendStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3823,7 +3926,47 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_backend_desc(BackendType backendType)
+{
+	const char *backendDesc = "unknown process type";
+
+	switch (backendType)
+	{
+		case B_AUTOVAC_LAUNCHER:
+			backendDesc = "autovacuum launcher";
+			break;
+		case B_AUTOVAC_WORKER:
+			backendDesc = "autovacuum worker";
+			break;
+		case B_BACKEND:
+			backendDesc = "client backend";
+			break;
+		case B_BG_WORKER:
+			backendDesc = "background worker";
+			break;
+		case B_BG_WRITER:
+			backendDesc = "background writer";
+			break;
+		case B_CHECKPOINTER:
+			backendDesc = "checkpointer";
+			break;
+		case B_STARTUP:
+			backendDesc = "startup";
+			break;
+		case B_WAL_RECEIVER:
+			backendDesc = "walreceiver";
+			break;
+		case B_WAL_SENDER:
+			backendDesc = "walsender";
+			break;
+		case B_WAL_WRITER:
+			backendDesc = "walwriter";
+			break;
+	}
 
+	return backendDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..3e716b1 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result = NULL;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..96a1188 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -615,9 +616,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		if (beentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		else
+			nulls[0] = true;
+
 		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
+
+		if (beentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(beentry->st_userid);
+		else
+			nulls[2] = true;
+
 		if (beentry->st_appname)
 			values[3] = CStringGetTextDatum(beentry->st_appname);
 		else
@@ -690,6 +700,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
+			else if (beentry->st_backendType != B_BACKEND)
+			{
+				uint32		raw_wait_event;
+
+				/*
+				 * For an auxiliary process, retrieve process info from
+				 * AuxiliaryProcs stored in shared-memory.
+				 */
+				proc = AuxiliaryPidGetProc(beentry->st_procpid);
+
+				/* Check whether this is indeed an auxiliary process */
+				Assert(proc != NULL);
+				raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+				wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+				wait_event = pgstat_get_wait_event(raw_wait_event);
+			}
 			else
 			{
 				wait_event_type = NULL;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index f2daf32..14562d5 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -696,6 +696,25 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Backend types
+ * ----------
+ */
+typedef enum BackendType
+{
+	B_AUTOVAC_LAUNCHER,
+	B_AUTOVAC_WORKER,
+	B_BACKEND,
+	B_BG_WORKER,
+	B_BG_WRITER,
+	B_CHECKPOINTER,
+	B_STARTUP,
+	B_WAL_RECEIVER,
+	B_WAL_SENDER,
+	B_WAL_WRITER
+} BackendType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -925,6 +944,9 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
  * ----------
  */
 typedef struct PgBackendStatus
@@ -949,6 +971,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of backends */
+	BackendType st_backendType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1147,6 +1172,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_backend_desc(BackendType backendType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 5f38fa6..be3bd01 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -262,6 +262,7 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
 
 /* configurable options */
 extern int	DeadlockTimeout;
-- 
1.8.3.1

0002-Expose-stats-for-all-backends.patchapplication/x-download; name=0002-Expose-stats-for-all-backends.patchDownload
From d9328739f9fab8ca4d9919085af45f711bfce90a Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Tue, 21 Mar 2017 18:18:22 +0530
Subject: [PATCH 2/3] Expose stats for all backends

All backends include auxiliary procs, autovacuum launcher and
bgworkers having valid BackendIds.
---
 src/backend/access/transam/parallel.c      | 3 +++
 src/backend/bootstrap/bootstrap.c          | 3 +++
 src/backend/postmaster/autovacuum.c        | 3 +++
 src/backend/postmaster/bgwriter.c          | 3 +++
 src/backend/postmaster/checkpointer.c      | 3 +++
 src/backend/postmaster/pgstat.c            | 1 -
 src/backend/postmaster/startup.c           | 4 ++++
 src/backend/postmaster/walwriter.c         | 3 +++
 src/backend/replication/logical/launcher.c | 3 +++
 src/backend/replication/logical/worker.c   | 3 +++
 src/backend/replication/walreceiver.c      | 4 ++++
 src/backend/replication/walsender.c        | 5 ++++-
 src/backend/utils/init/postinit.c          | 3 ++-
 src/test/modules/worker_spi/worker_spi.c   | 3 +++
 14 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 3e0ee87..ed2ac47 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -1044,6 +1044,9 @@ ParallelWorkerMain(Datum main_arg)
 	BackgroundWorkerInitializeConnectionByOid(fps->database_id,
 											  fps->authenticated_user_id);
 
+	/* report the parallel worker process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Set the client encoding to the database encoding, since that is what
 	 * the leader will expect.
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..f56e229 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,9 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize stats collection */
+		pgstat_initialize();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 33ca749..0dd8ccc 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -453,6 +453,9 @@ AutoVacLauncherMain(int argc, char *argv[])
 
 	InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
 
+	/* report autovacuum launcher process in the  PgBackendStatus array */
+	pgstat_bestart();
+
 	SetProcessingMode(NormalProcessing);
 
 	/*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..6ba2e2e 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
 	 */
 	prev_hibernate = false;
 
+	/* report bgwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..8eb0a2a 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -345,6 +345,9 @@ CheckpointerMain(void)
 	 */
 	ProcGlobal->checkpointerLatch = &MyProc->procLatch;
 
+	/* report checkpointer process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index a2b9bbf..ff565a3 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2690,7 +2690,6 @@ pgstat_initialize(void)
  * pgstat_bestart() -
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
- *	Called from InitPostgres.
  *
  *	Apart from auxiliary processes, MyBackendId, MyDatabaseId,
  *	session userid, and application_name must be set for a
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index b172b5e..56ff042 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -25,6 +25,7 @@
 #include "access/xlog.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/startup.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
@@ -210,6 +211,9 @@ StartupProcessMain(void)
 	 */
 	PG_SETMASK(&UnBlockSig);
 
+	/* report startup process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Do what we came for.
 	 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..9056652 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -231,6 +231,9 @@ WalWriterMain(void)
 	 */
 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
 
+	/* report walwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 20b4362..221adb0 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -571,6 +571,9 @@ ApplyLauncherMain(Datum main_arg)
 	 */
 	BackgroundWorkerInitializeConnection(NULL, NULL);
 
+	/* report the apply launcher process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/* Enter main loop */
 	while (!got_SIGTERM)
 	{
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index c3e54af..db09540 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1376,6 +1376,9 @@ ApplyWorkerMain(Datum main_arg)
 	BackgroundWorkerInitializeConnectionByOid(MyLogicalRepWorker->dbid,
 											  MyLogicalRepWorker->userid);
 
+	/* report the apply worker process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/* Load the subscription into persistent memory context. */
 	CreateCacheMemoryContext();
 	ApplyCacheContext = AllocSetContextCreate(CacheMemoryContext,
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 18d9d7e..3265d03 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -316,6 +316,10 @@ WalReceiverMain(void)
 	SpinLockRelease(&walrcv->mutex);
 
 	first_stream = true;
+
+	/* report walreceiver process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	for (;;)
 	{
 		char	   *primary_sysid;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 0f6b828..de1edc6 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -245,6 +245,9 @@ InitWalSender(void)
 	 */
 	MarkPostmasterChildWalSender();
 	SendPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE);
+
+	/* report walsender process in the PgBackendStatus array */
+	pgstat_bestart();
 }
 
 /*
@@ -1808,7 +1811,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
 	waiting_for_ping_response = false;
 
 	/* Report to pgstat that this process is a WAL sender */
-	pgstat_report_activity(STATE_RUNNING, "walsender");
+	pgstat_report_activity(STATE_RUNNING, NULL);
 
 	/*
 	 * Loop until we reach the end of this timeline or the client requests to
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..cc4a639 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -808,7 +808,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		/* initialize client encoding */
 		InitializeClientEncoding();
 
-		/* report this backend in the PgBackendStatus array */
+		/* report walsender process in the PgBackendStatus array */
 		pgstat_bestart();
 
 		/* close the transaction we started above */
@@ -875,6 +875,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		 */
 		if (!bootstrap)
 			CommitTransactionCommand();
+
 		return;
 	}
 
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 72ab846..bea6aa63 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -181,6 +181,9 @@ worker_spi_main(Datum main_arg)
 	/* Connect to our database */
 	BackgroundWorkerInitializeConnection("postgres", NULL);
 
+	/* report the worker spi process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	elog(LOG, "%s initialized with %s.%s",
 		 MyBgworkerEntry->bgw_name, table->schema, table->name);
 	initialize_worker_spi(table);
-- 
1.8.3.1

0003-Add-backend_type-column-in-pg_stat_get_activity.patchapplication/x-download; name=0003-Add-backend_type-column-in-pg_stat_get_activity.patchDownload
From c59011315e90b8558ca80e835068e9c5f8cc1ac2 Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 12:53:11 +0530
Subject: [PATCH 3/3] Add backend_type column in pg_stat_get_activity

backend_type indicates the type of process in the stat table.
---
 doc/src/sgml/monitoring.sgml         | 14 ++++++++++++--
 src/backend/catalog/system_views.sql |  3 ++-
 src/backend/utils/adt/pgstatfuncs.c  |  5 ++++-
 src/include/catalog/pg_proc.h        |  2 +-
 src/test/regress/expected/rules.out  |  9 +++++----
 5 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index dcb2d33..f77c5a7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -620,8 +620,7 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
     <row>
      <entry><structfield>backend_start</></entry>
      <entry><type>timestamp with time zone</></entry>
-     <entry>Time when this process was started, i.e., when the
-      client connected to the server
+     <entry>Time when this process was started.
      </entry>
     </row>
     <row>
@@ -797,6 +796,17 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <xref linkend="guc-track-activity-query-size">.
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_type</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Type of current backend. Possible types are 
+      <literal>autovacuum launcher</>, <literal>autovacuum worker</>,
+      <literal>background worker</>, <literal>background writer</>,
+      <literal>client backend</>, <literal>checkpointer</>,
+      <literal>startup</>, <literal>walreceiver</>,
+      <literal>walsender</> and <literal>walwriter</>.
+     </entry>
+    </row>
    </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index b6552da..bdbb5b8 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.backend_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 96a1188..0085335 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -539,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_backends = pgstat_fetch_stat_numbackends();
 	int			curr_backend;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -819,6 +819,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					nulls[14] = true;
 				}
 			}
+			/* Add backend type */
+			values[23] = CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType));
 		}
 		else
 		{
@@ -834,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[12] = true;
 			nulls[13] = true;
 			nulls[14] = true;
+			nulls[23] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 836d6ff..8494648 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2797,7 +2797,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,backend_type}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index bd13ae6..a317bff 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.backend_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1833,7 +1834,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1843,7 +1844,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
-- 
1.8.3.1

#33Michael Paquier
michael.paquier@gmail.com
In reply to: Kuntal Ghosh (#32)

On Tue, Mar 21, 2017 at 10:37 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

On Tue, Mar 21, 2017 at 10:52 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
We reserve a slot for each possible BackendId, plus one for each
possible auxiliary process type. For a non-auxiliary process,
BackendId is used to refer the backend status in PgBackendStatus
array. So, a bgworker without any BackendId can't initialize its'
entry in PgBackendStatus array. In simple terms, it will not be shown
in pg_stat_activity. I've added some comments regarding this in
pgstat_bestart().

- * Called from InitPostgres.
- * MyDatabaseId, session userid, and application_name must be set
- * (hence, this cannot be combined with pgstat_initialize).
+ *
+ * Apart from auxiliary processes, MyBackendId, MyDatabaseId,
+ * session userid, and application_name must be set for a
+ * backend (hence, this cannot be combined with pgstat_initialize).
That looks right.

And, any bgworker having valid BackendId will have either a valid
userid or BOOTSTRAP_SUPERUSERID.

So looking at the area of the code in more details, my memories have
failed me a bit. InitPostgres() is setting up MyBackendId via
SharedInvalBackendInit(), something that will never be called for
backend processes not connected to a database. The bgworker for
logical replication does not do that.

If you want to test this configuration, feel free to use this background worker:
https://github.com/michaelpq/pg_plugins/tree/master/hello_world
This just prints an entry to the logs every 10s, and does not connect
to any database. Adding a call to pgstat_bestart() in hello_main
triggers the assertion.

In this case, pgstat_bestart() shouldn't be called from this module as
the spawned bgworker will have invalid BackendId. By the way, thanks
for sharing the repo link. Found a lot of interesting things to
explore and learn. :)

RIP to this process. Not sure if that's worth the documentation. I
imagine that people usually implement bgworkers by deleting lines in
worker_spi and keeping its structure.

Except for the two issues pointed out in this email, I am pretty cool
with this patch. Nice work.

Thank you. :)

Please find the updated patches.

Okay, switched as ready for committer. One note for the committer
though: keeping the calls of pgstat_bestart() out of
BackgroundWorkerInitializeConnection() and
BackgroundWorkerInitializeConnectionByOid() keeps users the
possibility to not have backends connected to the database show up in
pg_stat_activity. This may matter for some users (cloud deployment for
example). I am as well in favor in keeping the work of those routines
minimal, without touching at pgstat.

if (!bootstrap)
CommitTransactionCommand();
+
return;
Some useless noise here.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#34Robert Haas
robertmhaas@gmail.com
In reply to: Michael Paquier (#33)

On Wed, Mar 22, 2017 at 1:31 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Okay, switched as ready for committer. One note for the committer
though: keeping the calls of pgstat_bestart() out of
BackgroundWorkerInitializeConnection() and
BackgroundWorkerInitializeConnectionByOid() keeps users the
possibility to not have backends connected to the database show up in
pg_stat_activity. This may matter for some users (cloud deployment for
example). I am as well in favor in keeping the work of those routines
minimal, without touching at pgstat.

I think that's just inviting bugs of omission, in both core and
extension code. I think it'd be much better to do this in a
centralized place.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#35Robert Haas
robertmhaas@gmail.com
In reply to: Robert Haas (#34)

On Wed, Mar 22, 2017 at 12:20 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Mar 22, 2017 at 1:31 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Okay, switched as ready for committer. One note for the committer
though: keeping the calls of pgstat_bestart() out of
BackgroundWorkerInitializeConnection() and
BackgroundWorkerInitializeConnectionByOid() keeps users the
possibility to not have backends connected to the database show up in
pg_stat_activity. This may matter for some users (cloud deployment for
example). I am as well in favor in keeping the work of those routines
minimal, without touching at pgstat.

I think that's just inviting bugs of omission, in both core and
extension code. I think it'd be much better to do this in a
centralized place.

I mean, your argument boils down to "somebody might want to
deliberately hide things from pg_stat_activity". But that's not
really a mode we support in general, and supporting it only for
certain cases doesn't seem like something that this patch should be
about. We could add an option to BackgroundWorkerInitializeConnection
and BackgroundWorkerInitializeConnectionByOid to suppress it, if it's
something that somebody wants, but actually I'd be more inclined to
think that everybody (who has a shared memory connection) should go
into the machinery and then security-filtering should be left to some
higher-level facility that can make policy decisions rather than being
hard-coded in the individual modules.

But I'm slightly confused as to how this even arises. Background
workers already show up in pg_stat_activity output, or at least I sure
think they do. So why does this patch need to make any change to that
case at all?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#36Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#35)

On Thu, Mar 23, 2017 at 1:24 AM, Robert Haas <robertmhaas@gmail.com> wrote:

I mean, your argument boils down to "somebody might want to
deliberately hide things from pg_stat_activity". But that's not
really a mode we support in general, and supporting it only for
certain cases doesn't seem like something that this patch should be
about. We could add an option to BackgroundWorkerInitializeConnection
and BackgroundWorkerInitializeConnectionByOid to suppress it, if it's
something that somebody wants, but actually I'd be more inclined to
think that everybody (who has a shared memory connection) should go
into the machinery and then security-filtering should be left to some
higher-level facility that can make policy decisions rather than being
hard-coded in the individual modules.

But I'm slightly confused as to how this even arises. Background
workers already show up in pg_stat_activity output, or at least I sure
think they do. So why does this patch need to make any change to that
case at all?

When working on a couple of bgworkers some time ago, I recalled that
they only showed up in pg_stat_activity only if calling
pgstat_report_activity() in them. Just looking again, visibly I was
mistaken, they do indeed show up when if WaitLatch() or
pgstat_report_activity() are not used. Please let me discard that
remark.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#37Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Robert Haas (#35)
3 attachment(s)

On Wed, Mar 22, 2017 at 9:54 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Mar 22, 2017 at 12:20 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Mar 22, 2017 at 1:31 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Okay, switched as ready for committer. One note for the committer
though: keeping the calls of pgstat_bestart() out of
BackgroundWorkerInitializeConnection() and
BackgroundWorkerInitializeConnectionByOid() keeps users the
possibility to not have backends connected to the database show up in
pg_stat_activity. This may matter for some users (cloud deployment for
example). I am as well in favor in keeping the work of those routines
minimal, without touching at pgstat.

I think that's just inviting bugs of omission, in both core and
extension code. I think it'd be much better to do this in a
centralized place.

I mean, your argument boils down to "somebody might want to
deliberately hide things from pg_stat_activity". But that's not
really a mode we support in general, and supporting it only for
certain cases doesn't seem like something that this patch should be
about. We could add an option to BackgroundWorkerInitializeConnection
and BackgroundWorkerInitializeConnectionByOid to suppress it, if it's
something that somebody wants, but actually I'd be more inclined to
think that everybody (who has a shared memory connection) should go
into the machinery and then security-filtering should be left to some
higher-level facility that can make policy decisions rather than being
hard-coded in the individual modules.

But I'm slightly confused as to how this even arises. Background
workers already show up in pg_stat_activity output, or at least I sure
think they do. So why does this patch need to make any change to that
case at all?

When we initialize a process through InitPostgres, the control returns
from the method at different locations based on the process's type(as
soon as its relevant information is initialized). Following is the
order of returning a process from InitPostgres:

IsAutoVacuumLauncherProcess
walsender not connected to a DB
bgworker not connected to a DB
Other processes using InitPostgres

Before the patch, not all the processes are shown in pg_stat_activity.
Hence, only at two locations in InitPostgres, we need to call
pgstat_bestart() to initialize the entry for the respective process.
But, since we're increasing the types of a process shown in
pg_stat_activity, it seems to be reasonable to move the
pgstat_bestart() call to a proc's main entry point. I've followed the
same approach for auxiliary processes as well.

AutovacuumLauncher - AutoVacLauncherMain()
bgwriter BackgroundWriterMain()
checkpointer CheckpointerMain()
startup StartupProcessMain()
walwriter WalWriterMain()
walreceiver WalReceiverMain()
walsender InitWalSender()

Hence, to be consistent with others, bgworker processes can be
initialized from BackgroundWorkerInitializeConnectionBy[Oid].

I've attached the updated patches which reflect the above change. PFA.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchbinary/octet-stream; name=0001-Infra-to-expose-all-backend-processes-in-pg_stat_get.patchDownload
From 207cd2047902e6d82d02de081347b52b711dc58a Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 11:32:49 +0530
Subject: [PATCH 1/3] Infra to expose all backend processes in
 pg_stat_get_activity

This patch implements the infrastructure required to expose
all backend processes including auxiliary procs in pg_stat_activity.
BackendStatusArray is extended to store auxiliary processes. Backends
use slots indexed in the range from 1 to MaxBackends (inclusive),
so we use MaxBackends + AuxBackendType + 1 as the index of the slot for an
auxiliary process.
---
 src/backend/postmaster/pgstat.c     | 193 +++++++++++++++++++++++++++++++-----
 src/backend/storage/lmgr/proc.c     |  27 +++++
 src/backend/utils/adt/pgstatfuncs.c |  30 +++++-
 src/include/pgstat.h                |  26 +++++
 src/include/storage/proc.h          |   1 +
 5 files changed, 250 insertions(+), 27 deletions(-)

diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 3a50488..a2b9bbf 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -103,6 +104,18 @@
 
 
 /* ----------
+ * Total number of backends including auxiliary
+ *
+ * We reserve a slot for each possible BackendId, plus one for each
+ * possible auxiliary process type.  (This scheme assumes there is not
+ * more than one of any auxiliary process type at a time.) MaxBackends
+ * includes autovacuum workers and background workers as well.
+ * ----------
+ */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
+
+/* ----------
  * GUC parameters
  * ----------
  */
@@ -212,7 +225,11 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
+
+/* Status for backends including auxiliary */
 static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Total number of backends including auxiliary */
 static int	localNumBackends = 0;
 
 /*
@@ -2505,20 +2522,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+			mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+				  mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
 #endif
 	return size;
 }
@@ -2536,7 +2553,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2559,7 +2576,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2577,7 +2594,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2586,7 +2603,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumBackendStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2598,7 +2615,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2607,7 +2624,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2619,7 +2636,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2633,7 +2650,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2643,8 +2661,26 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxBackendType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -2655,15 +2691,16 @@ pgstat_initialize(void)
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
  *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *
+ *	Apart from auxiliary processes, MyBackendId, MyDatabaseId,
+ *	session userid, and application_name must be set for a
+ *	backend (hence, this cannot be combined with pgstat_initialize).
  * ----------
  */
 void
 pgstat_bestart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2678,7 +2715,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2697,6 +2733,65 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	/* pgstats state must be initialized from pgstat_initialize() */
+	Assert(beentry != NULL);
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_backendType = B_AUTOVAC_LAUNCHER;
+		}
+		else if (IsAutoVacuumWorkerProcess())
+		{
+			/* Autovacuum Worker */
+			beentry->st_backendType = B_AUTOVAC_WORKER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_backendType = B_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_backendType = B_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_backendType = B_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case StartupProcess:
+				beentry->st_backendType = B_STARTUP;
+				break;
+			case BgWriterProcess:
+				beentry->st_backendType = B_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_backendType = B_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_backendType = B_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_backendType = B_WAL_RECEIVER;
+				break;
+			default:
+				elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2708,7 +2803,15 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends, wal-sender and bgworker processes */
+	if (beentry->st_backendType == B_BACKEND
+			|| beentry->st_backendType == B_WAL_SENDER
+			|| beentry->st_backendType == B_BG_WORKER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
@@ -3046,24 +3149,24 @@ pgstat_read_current_status(void)
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						 sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumBackendStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					 pgstat_track_activity_query_size * NumBackendStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
 #endif
 
 	localNumBackends = 0;
 
 	beentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumBackendStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3823,7 +3926,47 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_backend_desc(BackendType backendType)
+{
+	const char *backendDesc = "unknown process type";
+
+	switch (backendType)
+	{
+		case B_AUTOVAC_LAUNCHER:
+			backendDesc = "autovacuum launcher";
+			break;
+		case B_AUTOVAC_WORKER:
+			backendDesc = "autovacuum worker";
+			break;
+		case B_BACKEND:
+			backendDesc = "client backend";
+			break;
+		case B_BG_WORKER:
+			backendDesc = "background worker";
+			break;
+		case B_BG_WRITER:
+			backendDesc = "background writer";
+			break;
+		case B_CHECKPOINTER:
+			backendDesc = "checkpointer";
+			break;
+		case B_STARTUP:
+			backendDesc = "startup";
+			break;
+		case B_WAL_RECEIVER:
+			backendDesc = "walreceiver";
+			break;
+		case B_WAL_SENDER:
+			backendDesc = "walsender";
+			break;
+		case B_WAL_WRITER:
+			backendDesc = "walwriter";
+			break;
+	}
 
+	return backendDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..3e716b1 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result = NULL;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..96a1188 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -615,9 +616,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		if (beentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		else
+			nulls[0] = true;
+
 		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
+
+		if (beentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(beentry->st_userid);
+		else
+			nulls[2] = true;
+
 		if (beentry->st_appname)
 			values[3] = CStringGetTextDatum(beentry->st_appname);
 		else
@@ -690,6 +700,22 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
+			else if (beentry->st_backendType != B_BACKEND)
+			{
+				uint32		raw_wait_event;
+
+				/*
+				 * For an auxiliary process, retrieve process info from
+				 * AuxiliaryProcs stored in shared-memory.
+				 */
+				proc = AuxiliaryPidGetProc(beentry->st_procpid);
+
+				/* Check whether this is indeed an auxiliary process */
+				Assert(proc != NULL);
+				raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+				wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+				wait_event = pgstat_get_wait_event(raw_wait_event);
+			}
 			else
 			{
 				wait_event_type = NULL;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index f2daf32..14562d5 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -696,6 +696,25 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Backend types
+ * ----------
+ */
+typedef enum BackendType
+{
+	B_AUTOVAC_LAUNCHER,
+	B_AUTOVAC_WORKER,
+	B_BACKEND,
+	B_BG_WORKER,
+	B_BG_WRITER,
+	B_CHECKPOINTER,
+	B_STARTUP,
+	B_WAL_RECEIVER,
+	B_WAL_SENDER,
+	B_WAL_WRITER
+} BackendType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -925,6 +944,9 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
  * ----------
  */
 typedef struct PgBackendStatus
@@ -949,6 +971,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of backends */
+	BackendType st_backendType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1147,6 +1172,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_backend_desc(BackendType backendType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 945dd1d..7ad3094 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -267,6 +267,7 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
 
 /* configurable options */
 extern int	DeadlockTimeout;
-- 
1.8.3.1

0002-Expose-stats-for-all-backends.patchbinary/octet-stream; name=0002-Expose-stats-for-all-backends.patchDownload
From aacedd4fca9dc52367a250c67459605849c7291e Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Thu, 23 Mar 2017 16:39:05 +0530
Subject: [PATCH 2/3] Expose stats for all backends

All backends include auxiliary procs, autovacuum launcher and
bgworkers having valid BackendIds.
---
 src/backend/bootstrap/bootstrap.c     | 3 +++
 src/backend/postmaster/autovacuum.c   | 3 +++
 src/backend/postmaster/bgwriter.c     | 3 +++
 src/backend/postmaster/checkpointer.c | 3 +++
 src/backend/postmaster/pgstat.c       | 1 -
 src/backend/postmaster/postmaster.c   | 6 ++++++
 src/backend/postmaster/startup.c      | 4 ++++
 src/backend/postmaster/walwriter.c    | 3 +++
 src/backend/replication/walreceiver.c | 4 ++++
 src/backend/replication/walsender.c   | 5 ++++-
 src/backend/utils/init/postinit.c     | 3 ---
 11 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..f56e229 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,9 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize stats collection */
+		pgstat_initialize();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 33ca749..0dd8ccc 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -453,6 +453,9 @@ AutoVacLauncherMain(int argc, char *argv[])
 
 	InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
 
+	/* report autovacuum launcher process in the  PgBackendStatus array */
+	pgstat_bestart();
+
 	SetProcessingMode(NormalProcessing);
 
 	/*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..6ba2e2e 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -248,6 +248,9 @@ BackgroundWriterMain(void)
 	 */
 	prev_hibernate = false;
 
+	/* report bgwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..8eb0a2a 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -345,6 +345,9 @@ CheckpointerMain(void)
 	 */
 	ProcGlobal->checkpointerLatch = &MyProc->procLatch;
 
+	/* report checkpointer process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index a2b9bbf..ff565a3 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2690,7 +2690,6 @@ pgstat_initialize(void)
  * pgstat_bestart() -
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
- *	Called from InitPostgres.
  *
  *	Apart from auxiliary processes, MyBackendId, MyDatabaseId,
  *	session userid, and application_name must be set for a
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6831342..4f62b99 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -5461,6 +5461,9 @@ BackgroundWorkerInitializeConnection(char *dbname, char *username)
 
 	InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
 
+	/* report the parallel worker process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/* it had better not gotten out of "init" mode yet */
 	if (!IsInitProcessingMode())
 		ereport(ERROR,
@@ -5484,6 +5487,9 @@ BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid)
 
 	InitPostgres(NULL, dboid, NULL, useroid, NULL);
 
+	/* report the parallel worker process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/* it had better not gotten out of "init" mode yet */
 	if (!IsInitProcessingMode())
 		ereport(ERROR,
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index b172b5e..56ff042 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -25,6 +25,7 @@
 #include "access/xlog.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/startup.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
@@ -210,6 +211,9 @@ StartupProcessMain(void)
 	 */
 	PG_SETMASK(&UnBlockSig);
 
+	/* report startup process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Do what we came for.
 	 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..9056652 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -231,6 +231,9 @@ WalWriterMain(void)
 	 */
 	ProcGlobal->walwriterLatch = &MyProc->procLatch;
 
+	/* report walwriter process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	/*
 	 * Loop forever
 	 */
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 31c567b..cdd35e2 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -316,6 +316,10 @@ WalReceiverMain(void)
 	SpinLockRelease(&walrcv->mutex);
 
 	first_stream = true;
+
+	/* report walreceiver process in the PgBackendStatus array */
+	pgstat_bestart();
+
 	for (;;)
 	{
 		char	   *primary_sysid;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 7561770..f79d4a5 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -246,6 +246,9 @@ InitWalSender(void)
 	 */
 	MarkPostmasterChildWalSender();
 	SendPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE);
+
+	/* report walsender process in the PgBackendStatus array */
+	pgstat_bestart();
 }
 
 /*
@@ -1811,7 +1814,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
 	waiting_for_ping_response = false;
 
 	/* Report to pgstat that this process is a WAL sender */
-	pgstat_report_activity(STATE_RUNNING, "walsender");
+	pgstat_report_activity(STATE_RUNNING, NULL);
 
 	/*
 	 * Loop until we reach the end of this timeline or the client requests to
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..2470f24 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -808,9 +808,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		/* initialize client encoding */
 		InitializeClientEncoding();
 
-		/* report this backend in the PgBackendStatus array */
-		pgstat_bestart();
-
 		/* close the transaction we started above */
 		CommitTransactionCommand();
 
-- 
1.8.3.1

0003-Add-backend_type-column-in-pg_stat_get_activity.patchbinary/octet-stream; name=0003-Add-backend_type-column-in-pg_stat_get_activity.patchDownload
From 29cc1ce9eee41840cc4f3023f9ae3a6812ed614d Mon Sep 17 00:00:00 2001
From: Kuntal Ghosh <kuntal.ghosh@enterprisedb.com>
Date: Wed, 15 Mar 2017 12:53:11 +0530
Subject: [PATCH 3/3] Add backend_type column in pg_stat_get_activity

backend_type indicates the type of process in the stat table.
---
 doc/src/sgml/monitoring.sgml         | 14 ++++++++++++--
 src/backend/catalog/system_views.sql |  3 ++-
 src/backend/utils/adt/pgstatfuncs.c  |  5 ++++-
 src/include/catalog/pg_proc.h        |  2 +-
 src/test/regress/expected/rules.out  |  9 +++++----
 5 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index dcb2d33..f77c5a7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -620,8 +620,7 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
     <row>
      <entry><structfield>backend_start</></entry>
      <entry><type>timestamp with time zone</></entry>
-     <entry>Time when this process was started, i.e., when the
-      client connected to the server
+     <entry>Time when this process was started.
      </entry>
     </row>
     <row>
@@ -797,6 +796,17 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <xref linkend="guc-track-activity-query-size">.
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_type</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Type of current backend. Possible types are 
+      <literal>autovacuum launcher</>, <literal>autovacuum worker</>,
+      <literal>background worker</>, <literal>background writer</>,
+      <literal>client backend</>, <literal>checkpointer</>,
+      <literal>startup</>, <literal>walreceiver</>,
+      <literal>walsender</> and <literal>walwriter</>.
+     </entry>
+    </row>
    </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c2b0bed..c0974db 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.backend_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 96a1188..0085335 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -539,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_backends = pgstat_fetch_stat_numbackends();
 	int			curr_backend;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -819,6 +819,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					nulls[14] = true;
 				}
 			}
+			/* Add backend type */
+			values[23] = CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType));
 		}
 		else
 		{
@@ -834,6 +836,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[12] = true;
 			nulls[13] = true;
 			nulls[14] = true;
+			nulls[23] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 2263565..5dcc93d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2797,7 +2797,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,backend_type}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index bd13ae6..a317bff 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.backend_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1833,7 +1834,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1843,7 +1844,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn, backend_type);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
-- 
1.8.3.1

#38Michael Paquier
michael.paquier@gmail.com
In reply to: Kuntal Ghosh (#37)

On Thu, Mar 23, 2017 at 8:19 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

Hence, to be consistent with others, bgworker processes can be
initialized from BackgroundWorkerInitializeConnectionBy[Oid].

Yeah, I am fine with that. Thanks for the updated versions.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39Robert Haas
robertmhaas@gmail.com
In reply to: Michael Paquier (#38)
1 attachment(s)

On Thu, Mar 23, 2017 at 7:29 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Thu, Mar 23, 2017 at 8:19 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

Hence, to be consistent with others, bgworker processes can be
initialized from BackgroundWorkerInitializeConnectionBy[Oid].

Yeah, I am fine with that. Thanks for the updated versions.

I think this is still not good. The places where pgstat_bestart() has
been added are not even correct. For example, the call added to
BackgroundWriterMain() occurs after the section that does
error-recovery, so it would get repeated every time the background
writer recovers from an error. There are similar problems elsewhere.
Furthermore, although in theory there's an idea here that we're making
it no longer the responsibility of InitPostgres() to call
pgstat_bestart(), the patch as proposed only removes one of the two
calls, so we really don't even have a consistent practice. I think
it's better to go with the idea of having InitPostgres() be
responsible for calling this for regular backends, and
AuxiliaryProcessMain() for auxiliary backends. That involves
substantially fewer calls to pgstat_bestart() and they are spread
across only two functions, which IMHO makes fewer bugs of omission a
lot less likely.

Updated patch with that change attached. In addition to that
modification, I made some other alterations:

- I changed the elog() for the can't-happen case in pgstat_bestart()
from PANIC to FATAL. The contents of shared memory aren't corrupted,
so I think PANIC is overkill.

- I tweaked the comment in WalSndLoop() just before the
pgstat_report_activity() call to accurately reflect what the effect of
that call now is.

- I changed the column ordering in pg_stat_get_activity() to put
backend_type with the other columns that appear in pg_stat_activity,
rather than (as the patch did) grouping it with the ones that appear
in pg_stat_ssl.

- I modified the code to tolerate a NULL return from
AuxiliaryPidGetProc(). I am pretty sure that without that there's a
race condition that could lead to a crash if somebody tried to call
this function just as an auxiliary process was terminating.

- I updated the documentation slightly.

- I rebased over some conflicting commits.

If there aren't objections, I plan to commit this version.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

more-pg-stat-activity.patchapplication/octet-stream; name=more-pg-stat-activity.patchDownload
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e930731..9856968 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -620,8 +620,8 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
     <row>
      <entry><structfield>backend_start</></entry>
      <entry><type>timestamp with time zone</></entry>
-     <entry>Time when this process was started, i.e., when the
-      client connected to the server
+     <entry>Time when this process was started.  For client backends,
+      this is the time the client connected to the server.
      </entry>
     </row>
     <row>
@@ -797,6 +797,17 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <xref linkend="guc-track-activity-query-size">.
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_type</structfield></entry>
+     <entry><type>text</type></entry>
+     <entry>Type of current backend. Possible types are 
+      <literal>autovacuum launcher</>, <literal>autovacuum worker</>,
+      <literal>background worker</>, <literal>background writer</>,
+      <literal>client backend</>, <literal>checkpointer</>,
+      <literal>startup</>, <literal>walreceiver</>,
+      <literal>walsender</> and <literal>walwriter</>.
+     </entry>
+    </row>
    </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6511c60..6b5feaf 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -387,6 +387,10 @@ AuxiliaryProcessMain(int argc, char *argv[])
 		/* finish setting up bufmgr.c */
 		InitBufferPoolBackend();
 
+		/* Initialize backend status information */
+		pgstat_initialize();
+		pgstat_bestart();
+
 		/* register a before-shutdown callback for LWLock cleanup */
 		before_shmem_exit(ShutdownAuxiliaryProcess, 0);
 	}
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 80d1429..bab76df 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -684,7 +684,8 @@ CREATE VIEW pg_stat_activity AS
             S.state,
             S.backend_xid,
             s.backend_xmin,
-            S.query
+            S.query,
+            S.backend_type
     FROM pg_stat_get_activity(NULL) AS S
         LEFT JOIN pg_database AS D ON (S.datid = D.oid)
         LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index b704788..869afd4 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -50,6 +50,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "replication/walsender.h"
 #include "storage/backendid.h"
 #include "storage/dsm.h"
 #include "storage/fd.h"
@@ -103,6 +104,18 @@
 
 
 /* ----------
+ * Total number of backends including auxiliary
+ *
+ * We reserve a slot for each possible BackendId, plus one for each
+ * possible auxiliary process type.  (This scheme assumes there is not
+ * more than one of any auxiliary process type at a time.) MaxBackends
+ * includes autovacuum workers and background workers as well.
+ * ----------
+ */
+#define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
+
+
+/* ----------
  * GUC parameters
  * ----------
  */
@@ -212,7 +225,11 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
+
+/* Status for backends including auxiliary */
 static LocalPgBackendStatus *localBackendStatusTable = NULL;
+
+/* Total number of backends including auxiliary */
 static int	localNumBackends = 0;
 
 /*
@@ -2505,20 +2522,20 @@ BackendStatusShmemSize(void)
 	Size		size;
 
 	/* BackendStatusArray: */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	/* BackendAppnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendClientHostnameBuffer: */
 	size = add_size(size,
-					mul_size(NAMEDATALEN, MaxBackends));
+					mul_size(NAMEDATALEN, NumBackendStatSlots));
 	/* BackendActivityBuffer: */
 	size = add_size(size,
-					mul_size(pgstat_track_activity_query_size, MaxBackends));
+			mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
 #ifdef USE_SSL
 	/* BackendSslStatusBuffer: */
 	size = add_size(size,
-					mul_size(sizeof(PgBackendSSLStatus), MaxBackends));
+				  mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
 #endif
 	return size;
 }
@@ -2536,7 +2553,7 @@ CreateSharedBackendStatus(void)
 	char	   *buffer;
 
 	/* Create or attach to the shared array */
-	size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
 	BackendStatusArray = (PgBackendStatus *)
 		ShmemInitStruct("Backend Status Array", size, &found);
 
@@ -2559,7 +2576,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_appname pointers. */
 		buffer = BackendAppnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_appname = buffer;
 			buffer += NAMEDATALEN;
@@ -2577,7 +2594,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_clienthostname pointers. */
 		buffer = BackendClientHostnameBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_clienthostname = buffer;
 			buffer += NAMEDATALEN;
@@ -2586,7 +2603,7 @@ CreateSharedBackendStatus(void)
 
 	/* Create or attach to the shared activity buffer */
 	BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
-										 MaxBackends);
+										 NumBackendStatSlots);
 	BackendActivityBuffer = (char *)
 		ShmemInitStruct("Backend Activity Buffer",
 						BackendActivityBufferSize,
@@ -2598,7 +2615,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_activity pointers. */
 		buffer = BackendActivityBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_activity = buffer;
 			buffer += pgstat_track_activity_query_size;
@@ -2607,7 +2624,7 @@ CreateSharedBackendStatus(void)
 
 #ifdef USE_SSL
 	/* Create or attach to the shared SSL status buffer */
-	size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
+	size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
 	BackendSslStatusBuffer = (PgBackendSSLStatus *)
 		ShmemInitStruct("Backend SSL Status Buffer", size, &found);
 
@@ -2619,7 +2636,7 @@ CreateSharedBackendStatus(void)
 
 		/* Initialize st_sslstatus pointers. */
 		ptr = BackendSslStatusBuffer;
-		for (i = 0; i < MaxBackends; i++)
+		for (i = 0; i < NumBackendStatSlots; i++)
 		{
 			BackendStatusArray[i].st_sslstatus = ptr;
 			ptr++;
@@ -2633,7 +2650,8 @@ CreateSharedBackendStatus(void)
  * pgstat_initialize() -
  *
  *	Initialize pgstats state, and set up our on-proc-exit hook.
- *	Called from InitPostgres.  MyBackendId must be set,
+ *	Called from InitPostgres and AuxiliaryProcessMain. For auxiliary process,
+ *	MyBackendId is invalid. Otherwise, MyBackendId must be set,
  *	but we must not have started any transaction yet (since the
  *	exit hook must run after the last transaction exit).
  *	NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
@@ -2643,8 +2661,26 @@ void
 pgstat_initialize(void)
 {
 	/* Initialize MyBEEntry */
-	Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
-	MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	if (MyBackendId != InvalidBackendId)
+	{
+		Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+		MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+
+		/*
+		 * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
+		 * have a BackendId, the slot is statically allocated based on the
+		 * auxiliary process type (MyAuxProcType).  Backends use slots indexed
+		 * in the range from 1 to MaxBackends (inclusive), so we use
+		 * MaxBackends + AuxBackendType + 1 as the index of the slot for an
+		 * auxiliary process.
+		 */
+		MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
+	}
 
 	/* Set up a process-exit hook to clean up */
 	on_shmem_exit(pgstat_beshutdown_hook, 0);
@@ -2655,15 +2691,16 @@ pgstat_initialize(void)
  *
  *	Initialize this backend's entry in the PgBackendStatus array.
  *	Called from InitPostgres.
- *	MyDatabaseId, session userid, and application_name must be set
- *	(hence, this cannot be combined with pgstat_initialize).
+ *
+ *	Apart from auxiliary processes, MyBackendId, MyDatabaseId,
+ *	session userid, and application_name must be set for a
+ *	backend (hence, this cannot be combined with pgstat_initialize).
  * ----------
  */
 void
 pgstat_bestart(void)
 {
 	TimestampTz proc_start_timestamp;
-	Oid			userid;
 	SockAddr	clientaddr;
 	volatile PgBackendStatus *beentry;
 
@@ -2678,7 +2715,6 @@ pgstat_bestart(void)
 		proc_start_timestamp = MyProcPort->SessionStartTime;
 	else
 		proc_start_timestamp = GetCurrentTimestamp();
-	userid = GetSessionUserId();
 
 	/*
 	 * We may not have a MyProcPort (eg, if this is the autovacuum process).
@@ -2697,6 +2733,66 @@ pgstat_bestart(void)
 	 * cute.
 	 */
 	beentry = MyBEEntry;
+
+	/* pgstats state must be initialized from pgstat_initialize() */
+	Assert(beentry != NULL);
+
+	if (MyBackendId != InvalidBackendId)
+	{
+		if (IsAutoVacuumLauncherProcess())
+		{
+			/* Autovacuum Launcher */
+			beentry->st_backendType = B_AUTOVAC_LAUNCHER;
+		}
+		else if (IsAutoVacuumWorkerProcess())
+		{
+			/* Autovacuum Worker */
+			beentry->st_backendType = B_AUTOVAC_WORKER;
+		}
+		else if (am_walsender)
+		{
+			/* Wal sender */
+			beentry->st_backendType = B_WAL_SENDER;
+		}
+		else if (IsBackgroundWorker)
+		{
+			/* bgworker */
+			beentry->st_backendType = B_BG_WORKER;
+		}
+		else
+		{
+			/* client-backend */
+			beentry->st_backendType = B_BACKEND;
+		}
+	}
+	else
+	{
+		/* Must be an auxiliary process */
+		Assert(MyAuxProcType != NotAnAuxProcess);
+		switch (MyAuxProcType)
+		{
+			case StartupProcess:
+				beentry->st_backendType = B_STARTUP;
+				break;
+			case BgWriterProcess:
+				beentry->st_backendType = B_BG_WRITER;
+				break;
+			case CheckpointerProcess:
+				beentry->st_backendType = B_CHECKPOINTER;
+				break;
+			case WalWriterProcess:
+				beentry->st_backendType = B_WAL_WRITER;
+				break;
+			case WalReceiverProcess:
+				beentry->st_backendType = B_WAL_RECEIVER;
+				break;
+			default:
+				elog(FATAL, "unrecognized process type: %d",
+					(int) MyAuxProcType);
+				proc_exit(1);
+		}
+	}
+
 	do
 	{
 		pgstat_increment_changecount_before(beentry);
@@ -2708,7 +2804,15 @@ pgstat_bestart(void)
 	beentry->st_state_start_timestamp = 0;
 	beentry->st_xact_start_timestamp = 0;
 	beentry->st_databaseid = MyDatabaseId;
-	beentry->st_userid = userid;
+
+	/* We have userid for client-backends, wal-sender and bgworker processes */
+	if (beentry->st_backendType == B_BACKEND
+			|| beentry->st_backendType == B_WAL_SENDER
+			|| beentry->st_backendType == B_BG_WORKER)
+		beentry->st_userid = GetSessionUserId();
+	else
+		beentry->st_userid = InvalidOid;
+
 	beentry->st_clientaddr = clientaddr;
 	if (MyProcPort && MyProcPort->remote_hostname)
 		strlcpy(beentry->st_clienthostname, MyProcPort->remote_hostname,
@@ -3046,24 +3150,24 @@ pgstat_read_current_status(void)
 
 	localtable = (LocalPgBackendStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(LocalPgBackendStatus) * MaxBackends);
+						 sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
 	localappname = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   NAMEDATALEN * MaxBackends);
+						   NAMEDATALEN * NumBackendStatSlots);
 	localactivity = (char *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   pgstat_track_activity_query_size * MaxBackends);
+					 pgstat_track_activity_query_size * NumBackendStatSlots);
 #ifdef USE_SSL
 	localsslstatus = (PgBackendSSLStatus *)
 		MemoryContextAlloc(pgStatLocalContext,
-						   sizeof(PgBackendSSLStatus) * MaxBackends);
+						   sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
 #endif
 
 	localNumBackends = 0;
 
 	beentry = BackendStatusArray;
 	localentry = localtable;
-	for (i = 1; i <= MaxBackends; i++)
+	for (i = 1; i <= NumBackendStatSlots; i++)
 	{
 		/*
 		 * Follow the protocol of retrying if st_changecount changes while we
@@ -3829,7 +3933,47 @@ pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
 	return NULL;
 }
 
+const char *
+pgstat_get_backend_desc(BackendType backendType)
+{
+	const char *backendDesc = "unknown process type";
+
+	switch (backendType)
+	{
+		case B_AUTOVAC_LAUNCHER:
+			backendDesc = "autovacuum launcher";
+			break;
+		case B_AUTOVAC_WORKER:
+			backendDesc = "autovacuum worker";
+			break;
+		case B_BACKEND:
+			backendDesc = "client backend";
+			break;
+		case B_BG_WORKER:
+			backendDesc = "background worker";
+			break;
+		case B_BG_WRITER:
+			backendDesc = "background writer";
+			break;
+		case B_CHECKPOINTER:
+			backendDesc = "checkpointer";
+			break;
+		case B_STARTUP:
+			backendDesc = "startup";
+			break;
+		case B_WAL_RECEIVER:
+			backendDesc = "walreceiver";
+			break;
+		case B_WAL_SENDER:
+			backendDesc = "walsender";
+			break;
+		case B_WAL_WRITER:
+			backendDesc = "walwriter";
+			break;
+	}
 
+	return backendDesc;
+}
 /* ------------------------------------------------------------
  * Local support functions follow
  * ------------------------------------------------------------
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index b172b5e..b623252 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -25,6 +25,7 @@
 #include "access/xlog.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/startup.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index a29d0e7..e9fef1a 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1961,8 +1961,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
 	last_reply_timestamp = GetCurrentTimestamp();
 	waiting_for_ping_response = false;
 
-	/* Report to pgstat that this process is a WAL sender */
-	pgstat_report_activity(STATE_RUNNING, "walsender");
+	/* Report to pgstat that this process is running */
+	pgstat_report_activity(STATE_RUNNING, NULL);
 
 	/*
 	 * Loop until we reach the end of this timeline or the client requests to
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 8f467be..3e716b1 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -941,6 +941,33 @@ AuxiliaryProcKill(int code, Datum arg)
 	SpinLockRelease(ProcStructLock);
 }
 
+/*
+ * AuxiliaryPidGetProc -- get PGPROC for an auxiliary process
+ * given its PID
+ *
+ * Returns NULL if not found.
+ */
+PGPROC *
+AuxiliaryPidGetProc(int pid)
+{
+	PGPROC	   *result = NULL;
+	int			index;
+
+	if (pid == 0)				/* never match dummy PGPROCs */
+		return NULL;
+
+	for (index = 0; index < NUM_AUXILIARY_PROCS; index++)
+	{
+		PGPROC	   *proc = &AuxiliaryProcs[index];
+
+		if (proc->pid == pid)
+		{
+			result = proc;
+			break;
+		}
+	}
+	return result;
+}
 
 /*
  * ProcQueue package: routines for putting processes to sleep
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..dd2b924 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -20,6 +20,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "postmaster/postmaster.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
@@ -538,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	23
+#define PG_STAT_GET_ACTIVITY_COLS	24
 	int			num_backends = pgstat_fetch_stat_numbackends();
 	int			curr_backend;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -582,8 +583,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 		LocalPgBackendStatus *local_beentry;
 		PgBackendStatus *beentry;
 		PGPROC	   *proc;
-		const char *wait_event_type;
-		const char *wait_event;
+		const char *wait_event_type = NULL;
+		const char *wait_event = NULL;
 
 		MemSet(values, 0, sizeof(values));
 		MemSet(nulls, 0, sizeof(nulls));
@@ -615,9 +616,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			continue;
 
 		/* Values available to all callers */
-		values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		if (beentry->st_databaseid != InvalidOid)
+			values[0] = ObjectIdGetDatum(beentry->st_databaseid);
+		else
+			nulls[0] = true;
+
 		values[1] = Int32GetDatum(beentry->st_procpid);
-		values[2] = ObjectIdGetDatum(beentry->st_userid);
+
+		if (beentry->st_userid != InvalidOid)
+			values[2] = ObjectIdGetDatum(beentry->st_userid);
+		else
+			nulls[2] = true;
+
 		if (beentry->st_appname)
 			values[3] = CStringGetTextDatum(beentry->st_appname);
 		else
@@ -635,17 +645,17 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
 		if (beentry->st_ssl)
 		{
-			values[17] = BoolGetDatum(true);	/* ssl */
-			values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
-			values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
-			values[20] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
-			values[21] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
-			values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
+			values[18] = BoolGetDatum(true);	/* ssl */
+			values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
+			values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
+			values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
+			values[22] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
+			values[23] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
 		}
 		else
 		{
-			values[17] = BoolGetDatum(false);	/* ssl */
-			nulls[18] = nulls[19] = nulls[20] = nulls[21] = nulls[22] = true;
+			values[18] = BoolGetDatum(false);	/* ssl */
+			nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true;
 		}
 
 		/* Values only available to role member */
@@ -690,10 +700,24 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 				wait_event = pgstat_get_wait_event(raw_wait_event);
 
 			}
-			else
+			else if (beentry->st_backendType != B_BACKEND)
 			{
-				wait_event_type = NULL;
-				wait_event = NULL;
+				/*
+				 * For an auxiliary process, retrieve process info from
+				 * AuxiliaryProcs stored in shared-memory.
+				 */
+				proc = AuxiliaryPidGetProc(beentry->st_procpid);
+
+				if (proc != NULL)
+				{
+					uint32		raw_wait_event;
+
+					raw_wait_event =
+						UINT32_ACCESS_ONCE(proc->wait_event_info);
+					wait_event_type =
+						pgstat_get_wait_event_type(raw_wait_event);
+					wait_event = pgstat_get_wait_event(raw_wait_event);
+				}
 			}
 
 			if (wait_event_type)
@@ -793,6 +817,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					nulls[14] = true;
 				}
 			}
+			/* Add backend type */
+			values[17] =
+				CStringGetTextDatum(pgstat_get_backend_desc(beentry->st_backendType));
 		}
 		else
 		{
@@ -808,6 +835,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[12] = true;
 			nulls[13] = true;
 			nulls[14] = true;
+			nulls[17] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2..b8b4a06 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -665,7 +665,12 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* The autovacuum launcher is done here */
 	if (IsAutoVacuumLauncherProcess())
+	{
+		/* report this backend in the PgBackendStatus array */
+		pgstat_bestart();
+
 		return;
+	}
 
 	/*
 	 * Start a new transaction here before first access to db, and get a
@@ -874,7 +879,10 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 		 * transaction we started before returning.
 		 */
 		if (!bootstrap)
+		{
+			pgstat_bestart();
 			CommitTransactionCommand();
+		}
 		return;
 	}
 
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 0d18ab8..41f7fae 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2800,7 +2800,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s r 1 0 2249 "23" "{23,26,23,26,25,25,25,25,25,1184,1184,1184,1184,869,25,23,28,28,25,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3318 (  pg_stat_get_progress_info			  PGNSP PGUID 12 1 100 0 0 f f f f t t s r 1 0 2249 "25" "{25,23,26,26,20,20,20,20,20,20,20,20,20,20}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{cmdtype,pid,datid,relid,param1,param2,param3,param4,param5,param6,param7,param8,param9,param10}" _null_ _null_ pg_stat_get_progress_info _null_ _null_ _null_ ));
 DESCR("statistics: information about progress of backends running maintenance command");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 2015625..e29397f 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -696,6 +696,25 @@ typedef struct PgStat_GlobalStats
 
 
 /* ----------
+ * Backend types
+ * ----------
+ */
+typedef enum BackendType
+{
+	B_AUTOVAC_LAUNCHER,
+	B_AUTOVAC_WORKER,
+	B_BACKEND,
+	B_BG_WORKER,
+	B_BG_WRITER,
+	B_CHECKPOINTER,
+	B_STARTUP,
+	B_WAL_RECEIVER,
+	B_WAL_SENDER,
+	B_WAL_WRITER
+} BackendType;
+
+
+/* ----------
  * Backend states
  * ----------
  */
@@ -927,6 +946,9 @@ typedef struct PgBackendSSLStatus
  * showing its current activity.  (The structs are allocated according to
  * BackendId, but that is not critical.)  Note that the collector process
  * has no involvement in, or even access to, these structs.
+ *
+ * Each auxiliary process also maintains a PgBackendStatus struct in shared
+ * memory.
  * ----------
  */
 typedef struct PgBackendStatus
@@ -951,6 +973,9 @@ typedef struct PgBackendStatus
 	/* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
 	int			st_procpid;
 
+	/* Type of backends */
+	BackendType st_backendType;
+
 	/* Times when current backend, transaction, and activity started */
 	TimestampTz st_proc_start_timestamp;
 	TimestampTz st_xact_start_timestamp;
@@ -1149,6 +1174,7 @@ extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
+extern const char *pgstat_get_backend_desc(BackendType backendType);
 
 extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
 							  Oid relid);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 945dd1d..e4de3ca 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -267,7 +267,6 @@ extern PGPROC *PreparedXactProcs;
  */
 #define NUM_AUXILIARY_PROCS		4
 
-
 /* configurable options */
 extern int	DeadlockTimeout;
 extern int	StatementTimeout;
@@ -304,6 +303,8 @@ extern void LockErrorCleanup(void);
 extern void ProcWaitForSignal(uint32 wait_event_info);
 extern void ProcSendSignal(int pid);
 
+extern PGPROC *AuxiliaryPidGetProc(int pid);
+
 extern void BecomeLockGroupLeader(void);
 extern bool BecomeLockGroupMember(PGPROC *leader, int pid);
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index c4c8450..771694e 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1704,8 +1704,9 @@ pg_stat_activity| SELECT s.datid,
     s.state,
     s.backend_xid,
     s.backend_xmin,
-    s.query
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+    s.query,
+    s.backend_type
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
      LEFT JOIN pg_database d ON ((s.datid = d.oid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1836,7 +1837,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_lag,
     w.sync_priority,
     w.sync_state
-   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
+   FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn)
      JOIN pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, write_lag, flush_lag, replay_lag, sync_priority, sync_state) ON ((s.pid = w.pid)))
      LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
 pg_stat_ssl| SELECT s.pid,
@@ -1846,7 +1847,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
 pg_stat_subscription| SELECT su.oid AS subid,
     su.subname,
     st.pid,
#40Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Robert Haas (#39)

On Fri, Mar 24, 2017 at 9:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Mar 23, 2017 at 7:29 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Thu, Mar 23, 2017 at 8:19 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

Hence, to be consistent with others, bgworker processes can be
initialized from BackgroundWorkerInitializeConnectionBy[Oid].

Yeah, I am fine with that. Thanks for the updated versions.

I think this is still not good. The places where pgstat_bestart() has
been added are not even correct. For example, the call added to
BackgroundWriterMain() occurs after the section that does
error-recovery, so it would get repeated every time the background
writer recovers from an error. There are similar problems elsewhere.
Furthermore, although in theory there's an idea here that we're making
it no longer the responsibility of InitPostgres() to call
pgstat_bestart(), the patch as proposed only removes one of the two
calls, so we really don't even have a consistent practice. I think
it's better to go with the idea of having InitPostgres() be
responsible for calling this for regular backends, and
AuxiliaryProcessMain() for auxiliary backends. That involves
substantially fewer calls to pgstat_bestart() and they are spread
across only two functions, which IMHO makes fewer bugs of omission a
lot less likely.

Agreed. Calling it from InitPostgres() and AuxiliaryProcessMain()
seems correct because of the following two reasons as you've mentioned
up in the thread:
1. security-filtering should be left to some higher-level facility
that can make policy decisions rather than being hard-coded in the
individual modules.
2. makes fewer bugs of omission a lot less likely.

Updated patch with that change attached. In addition to that
modification, I made some other alterations:

- I changed the elog() for the can't-happen case in pgstat_bestart()
from PANIC to FATAL. The contents of shared memory aren't corrupted,
so I think PANIC is overkill.

Agreed and duly noted for future.

- I tweaked the comment in WalSndLoop() just before the
pgstat_report_activity() call to accurately reflect what the effect of
that call now is.

- I changed the column ordering in pg_stat_get_activity() to put
backend_type with the other columns that appear in pg_stat_activity,
rather than (as the patch did) grouping it with the ones that appear
in pg_stat_ssl.

Thank you.

- I modified the code to tolerate a NULL return from
AuxiliaryPidGetProc(). I am pretty sure that without that there's a
race condition that could lead to a crash if somebody tried to call
this function just as an auxiliary process was terminating.

Wow. Haven't thought of that. If it's called after
AuxiliaryProcKill(), a crash is evident.

- I updated the documentation slightly.

Looks good to me.

- I rebased over some conflicting commits.

Sorry for the inconveniences. It seems that the conflicting changes
occurred within few hours after I've posted the patch.

If there aren't objections, I plan to commit this version.

Thank you for looking into the patch and doing the necessary changes.
All the changes look good to me and I've tested the feature and it has
passed all the regression tests.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#41Michael Paquier
michael.paquier@gmail.com
In reply to: Kuntal Ghosh (#40)

On Sat, Mar 25, 2017 at 5:26 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

On Fri, Mar 24, 2017 at 9:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

I think this is still not good. The places where pgstat_bestart() has
been added are not even correct. For example, the call added to
BackgroundWriterMain() occurs after the section that does
error-recovery, so it would get repeated every time the background
writer recovers from an error. There are similar problems elsewhere.
Furthermore, although in theory there's an idea here that we're making
it no longer the responsibility of InitPostgres() to call
pgstat_bestart(), the patch as proposed only removes one of the two
calls, so we really don't even have a consistent practice. I think
it's better to go with the idea of having InitPostgres() be
responsible for calling this for regular backends, and
AuxiliaryProcessMain() for auxiliary backends. That involves
substantially fewer calls to pgstat_bestart() and they are spread
across only two functions, which IMHO makes fewer bugs of omission a
lot less likely.

Agreed. Calling it from InitPostgres() and AuxiliaryProcessMain()
seems correct because of the following two reasons as you've mentioned
up in the thread:
1. security-filtering should be left to some higher-level facility
that can make policy decisions rather than being hard-coded in the
individual modules.
2. makes fewer bugs of omission a lot less likely.

Okay, fine for me.

- I modified the code to tolerate a NULL return from
AuxiliaryPidGetProc(). I am pretty sure that without that there's a
race condition that could lead to a crash if somebody tried to call
this function just as an auxiliary process was terminating.

Wow. Haven't thought of that. If it's called after
AuxiliaryProcKill(), a crash is evident.

This one is a good catch.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#42Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Michael Paquier (#41)

Thank you Robert for committing the patch.

commit fc70a4b0df38bda6a13941f1581f25fbb643c7f3

I've changed the status to Committed.

On Mon, Mar 27, 2017 at 6:09 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Sat, Mar 25, 2017 at 5:26 PM, Kuntal Ghosh
<kuntalghosh.2007@gmail.com> wrote:

On Fri, Mar 24, 2017 at 9:23 PM, Robert Haas <robertmhaas@gmail.com> wrote:

I think this is still not good. The places where pgstat_bestart() has
been added are not even correct. For example, the call added to
BackgroundWriterMain() occurs after the section that does
error-recovery, so it would get repeated every time the background
writer recovers from an error. There are similar problems elsewhere.
Furthermore, although in theory there's an idea here that we're making
it no longer the responsibility of InitPostgres() to call
pgstat_bestart(), the patch as proposed only removes one of the two
calls, so we really don't even have a consistent practice. I think
it's better to go with the idea of having InitPostgres() be
responsible for calling this for regular backends, and
AuxiliaryProcessMain() for auxiliary backends. That involves
substantially fewer calls to pgstat_bestart() and they are spread
across only two functions, which IMHO makes fewer bugs of omission a
lot less likely.

Agreed. Calling it from InitPostgres() and AuxiliaryProcessMain()
seems correct because of the following two reasons as you've mentioned
up in the thread:
1. security-filtering should be left to some higher-level facility
that can make policy decisions rather than being hard-coded in the
individual modules.
2. makes fewer bugs of omission a lot less likely.

Okay, fine for me.

- I modified the code to tolerate a NULL return from
AuxiliaryPidGetProc(). I am pretty sure that without that there's a
race condition that could lead to a crash if somebody tried to call
this function just as an auxiliary process was terminating.

Wow. Haven't thought of that. If it's called after
AuxiliaryProcKill(), a crash is evident.

This one is a good catch.
--
Michael

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers