]> granicus.if.org Git - postgresql/commitdiff
Show xid and xmin in pg_stat_activity and pg_stat_replication.
authorRobert Haas <rhaas@postgresql.org>
Tue, 25 Feb 2014 17:34:04 +0000 (12:34 -0500)
committerRobert Haas <rhaas@postgresql.org>
Tue, 25 Feb 2014 17:34:04 +0000 (12:34 -0500)
Christian Kruse, reviewed by Andres Freund and myself, with further
minor adjustments by me.

doc/src/sgml/monitoring.sgml
src/backend/catalog/system_views.sql
src/backend/postmaster/pgstat.c
src/backend/storage/ipc/sinvaladt.c
src/backend/utils/adt/pgstatfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/pgstat.h
src/include/storage/sinvaladt.h
src/test/regress/expected/rules.out

index 370857a0e8c7417186b287b25bb3f3432f2a11f3..958acc4fd15d0cad4b0d8653bddbfb61a89316d3 100644 (file)
@@ -628,6 +628,16 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
        </itemizedlist>
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_xid</structfield></entry>
+     <entry><type>xid</type></entry>
+     <entry>Toplevel transaction identifier of this backend, if any.</entry>
+    </row>
+    <row>
+     <entry><structfield>backend_xmin</structfield></entry>
+     <entry><type>xid</type></entry>
+     <entry>The current backend's <literal>xmin</> horizon.</entry>
+    </row>
     <row>
      <entry><structfield>query</></entry>
      <entry><type>text</></entry>
@@ -1483,6 +1493,12 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
       client connected to this WAL sender
      </entry>
     </row>
+    <row>
+     <entry><structfield>backend_xid</structfield></entry>
+     <entry><type>xid</type></entry>
+     <entry>This standby's <literal>xmin</> horizon reported
+     by <xref linkend="guc-hot-standby-feedback">.</entry>
+    </row>
     <row>
      <entry><structfield>state</></entry>
      <entry><type>text</></entry>
index a7c6a4e094b19e4901998ba76c9e0fb4372458ea..04dfbb0ee54765dc3f23169fc932e1021f700170 100644 (file)
@@ -586,6 +586,8 @@ CREATE VIEW pg_stat_activity AS
             S.state_change,
             S.waiting,
             S.state,
+            S.backend_xid,
+            s.backend_xmin,
             S.query
     FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
     WHERE S.datid = D.oid AND
@@ -601,6 +603,7 @@ CREATE VIEW pg_stat_replication AS
             S.client_hostname,
             S.client_port,
             S.backend_start,
+            S.backend_xmin,
             W.state,
             W.sent_location,
             W.write_location,
index 305d1269124fd43eaad2c945e690e484ce8491b9..06ea588085929b370e14189b8137332f3ab66ceb 100644 (file)
 #include "postmaster/autovacuum.h"
 #include "postmaster/fork_process.h"
 #include "postmaster/postmaster.h"
+#include "storage/proc.h"
 #include "storage/backendid.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/pg_shmem.h"
 #include "storage/procsignal.h"
+#include "storage/sinvaladt.h"
 #include "utils/ascii.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
@@ -213,7 +215,7 @@ typedef struct TwoPhasePgStatRecord
  */
 static MemoryContext pgStatLocalContext = NULL;
 static HTAB *pgStatDBHash = NULL;
-static PgBackendStatus *localBackendStatusTable = NULL;
+static LocalPgBackendStatus *localBackendStatusTable = NULL;
 static int     localNumBackends = 0;
 
 /*
@@ -2303,6 +2305,28 @@ pgstat_fetch_stat_beentry(int beid)
 {
        pgstat_read_current_status();
 
+       if (beid < 1 || beid > localNumBackends)
+               return NULL;
+
+       return &localBackendStatusTable[beid - 1].backendStatus;
+}
+
+
+/* ----------
+ * pgstat_fetch_stat_local_beentry() -
+ *
+ *  Like pgstat_fetch_stat_beentry() but with locally computed addtions (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_beentry(int beid)
+{
+       pgstat_read_current_status();
+
        if (beid < 1 || beid > localNumBackends)
                return NULL;
 
@@ -2783,8 +2807,8 @@ static void
 pgstat_read_current_status(void)
 {
        volatile PgBackendStatus *beentry;
-       PgBackendStatus *localtable;
-       PgBackendStatus *localentry;
+       LocalPgBackendStatus *localtable;
+       LocalPgBackendStatus *localentry;
        char       *localappname,
                           *localactivity;
        int                     i;
@@ -2795,9 +2819,9 @@ pgstat_read_current_status(void)
 
        pgstat_setup_memcxt();
 
-       localtable = (PgBackendStatus *)
+       localtable = (LocalPgBackendStatus *)
                MemoryContextAlloc(pgStatLocalContext,
-                                                  sizeof(PgBackendStatus) * MaxBackends);
+                                                  sizeof(LocalPgBackendStatus) * MaxBackends);
        localappname = (char *)
                MemoryContextAlloc(pgStatLocalContext,
                                                   NAMEDATALEN * MaxBackends);
@@ -2821,19 +2845,19 @@ pgstat_read_current_status(void)
                {
                        int                     save_changecount = beentry->st_changecount;
 
-                       localentry->st_procpid = beentry->st_procpid;
-                       if (localentry->st_procpid > 0)
+                       localentry->backendStatus.st_procpid = beentry->st_procpid;
+                       if (localentry->backendStatus.st_procpid > 0)
                        {
-                               memcpy(localentry, (char *) beentry, sizeof(PgBackendStatus));
+                               memcpy(&localentry->backendStatus, (char *) beentry, 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);
-                               localentry->st_appname = localappname;
+                               localentry->backendStatus.st_appname = localappname;
                                strcpy(localactivity, (char *) beentry->st_activity);
-                               localentry->st_activity = localactivity;
+                               localentry->backendStatus.st_activity = localactivity;
                        }
 
                        if (save_changecount == beentry->st_changecount &&
@@ -2846,8 +2870,12 @@ pgstat_read_current_status(void)
 
                beentry++;
                /* Only valid entries get included into the local array */
-               if (localentry->st_procpid > 0)
+               if (localentry->backendStatus.st_procpid > 0)
                {
+                       BackendIdGetTransactionIds(i,
+                                                                          &localentry->backend_xid,
+                                                                          &localentry->backend_xmin);
+
                        localentry++;
                        localappname += NAMEDATALEN;
                        localactivity += pgstat_track_activity_query_size;
index e7c3fb2f548827b5116ca52e290a45e9a341b0be..e6805d96b1c69055dfe876d8856addf3e6f1f511 100644 (file)
@@ -25,6 +25,7 @@
 #include "storage/shmem.h"
 #include "storage/sinvaladt.h"
 #include "storage/spin.h"
+#include "access/transam.h"
 
 
 /*
@@ -400,6 +401,37 @@ BackendIdGetProc(int backendID)
        return result;
 }
 
+/*
+ * BackendIdGetTransactionIds
+ *             Get the xid and xmin of the backend. The result may be out of date
+ *             arbitrarily quickly, so the caller must be careful about how this
+ *             information is used.
+ */
+void
+BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin)
+{
+       ProcState  *stateP;
+       SISeg      *segP = shmInvalBuffer;
+       PGXACT     *xact;
+
+       *xid = InvalidTransactionId;
+       *xmin = InvalidTransactionId;
+
+       /* Need to lock out additions/removals of backends */
+       LWLockAcquire(SInvalWriteLock, LW_SHARED);
+
+       if (backendID > 0 && backendID <= segP->lastBackend)
+       {
+               stateP = &segP->procState[backendID - 1];
+               xact = &ProcGlobal->allPgXact[stateP->proc->pgprocno];
+
+               *xid = xact->xid;
+               *xmin = xact->xmin;
+       }
+
+       LWLockRelease(SInvalWriteLock);
+}
+
 /*
  * SIInsertDataEntries
  *             Add new invalidation message(s) to the buffer.
index a4f31cfc7fc701a5be2084788edf397ac1b419f8..140704f97ca4d538a879b8e5e37fc2a30f8cb437 100644 (file)
@@ -536,7 +536,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
                oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-               tupdesc = CreateTemplateTupleDesc(14, false);
+               tupdesc = CreateTemplateTupleDesc(16, false);
                TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid",
                                                   OIDOID, -1, 0);
                TupleDescInitEntry(tupdesc, (AttrNumber) 2, "pid",
@@ -565,6 +565,10 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                                                   TEXTOID, -1, 0);
                TupleDescInitEntry(tupdesc, (AttrNumber) 14, "client_port",
                                                   INT4OID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 15, "backend_xid",
+                                                  XIDOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 16, "backend_xmin",
+                                                  XIDOID, -1, 0);
 
                funcctx->tuple_desc = BlessTupleDesc(tupdesc);
 
@@ -616,9 +620,10 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
        if (funcctx->call_cntr < funcctx->max_calls)
        {
                /* for each row */
-               Datum           values[14];
-               bool            nulls[14];
+               Datum           values[16];
+               bool            nulls[16];
                HeapTuple       tuple;
+               LocalPgBackendStatus *local_beentry;
                PgBackendStatus *beentry;
 
                MemSet(values, 0, sizeof(values));
@@ -627,12 +632,14 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                if (*(int *) (funcctx->user_fctx) > 0)
                {
                        /* Get specific pid slot */
-                       beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
+                       local_beentry = pgstat_fetch_stat_local_beentry(*(int *) (funcctx->user_fctx));
+                       beentry = &local_beentry->backendStatus;
                }
                else
                {
                        /* Get the next one in the list */
-                       beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);            /* 1-based index */
+                       local_beentry = pgstat_fetch_stat_local_beentry(funcctx->call_cntr + 1);        /* 1-based index */
+                       beentry = &local_beentry->backendStatus;
                }
                if (!beentry)
                {
@@ -657,6 +664,16 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                else
                        nulls[3] = true;
 
+               if (TransactionIdIsValid(local_beentry->backend_xid))
+                       values[14] = TransactionIdGetDatum(local_beentry->backend_xid);
+               else
+                       nulls[14] = true;
+
+               if (TransactionIdIsValid(local_beentry->backend_xmin))
+                       values[15] = TransactionIdGetDatum(local_beentry->backend_xmin);
+               else
+                       nulls[15] = true;
+
                /* Values only available to same user or superuser */
                if (superuser() || beentry->st_userid == GetUserId())
                {
index 68f96bebaf981a917cd9e1f0f3880673980a529e..f8c8f9d5ea36d5ff34f47a4d02a25f9944c7ce74 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201402241
+#define CATALOG_VERSION_NO     201402251
 
 #endif
index a2cc19fd7b61703c1d7f2cafde824bd5d1fbf607..e33670ce8e0aae41220bd152a6c96ae76b37a7b8 100644 (file)
@@ -2632,7 +2632,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 0 0 23 "" _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 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port}" _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 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3099 (  pg_stat_get_wal_senders      PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active replication");
index 5b2e4609f65c6dfc7a1a2a1de1b8b6d35f3b9390..932c83d79e5b0c6c38619766a3d71d79dd7b9a85 100644 (file)
@@ -735,6 +735,34 @@ typedef struct PgBackendStatus
        char       *st_activity;
 } PgBackendStatus;
 
+/* ----------
+ * LocalPgBackendStatus
+ *
+ * When we build the backend status array, we use LocalPgBackendStatus to be
+ * able to add new values to the struct when needed without adding new fields
+ * to the shared memory. It contains the backend status as a first member.
+ * ----------
+ */
+typedef struct LocalPgBackendStatus
+{
+       /*
+        * Local version of the backend status entry.
+        */
+       PgBackendStatus backendStatus;
+
+       /*
+        * The xid of the current transaction if available, InvalidTransactionId
+        * if not.
+        */
+       TransactionId backend_xid;
+
+       /*
+        * The xmin of the current session if available, InvalidTransactionId
+        * if not.
+        */
+       TransactionId backend_xmin;
+} LocalPgBackendStatus;
+
 /*
  * Working state needed to accumulate per-function-call timing statistics.
  */
@@ -907,6 +935,7 @@ extern void pgstat_send_bgwriter(void);
 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 PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
 extern int     pgstat_fetch_stat_numbackends(void);
 extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
index 5f2ce4886131e2742d254d6cd4b36b1c493dc033..9b45b3efef02776a912502931eeac584ad9d4254 100644 (file)
@@ -32,6 +32,7 @@ extern Size SInvalShmemSize(void);
 extern void CreateSharedInvalidationState(void);
 extern void SharedInvalBackendInit(bool sendOnly);
 extern PGPROC *BackendIdGetProc(int backendID);
+extern void BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin);
 
 extern void SIInsertDataEntries(const SharedInvalidationMessage *data, int n);
 extern int     SIGetDataEntries(SharedInvalidationMessage *data, int datasize);
index 220e18b0bbdccdafa5ee26729987c43dd58d824a..ef50f4da217112ba310dc19033bb85ee02da7499 100644 (file)
@@ -1604,9 +1604,11 @@ pg_stat_activity| SELECT s.datid,
     s.state_change,
     s.waiting,
     s.state,
+    s.backend_xid,
+    s.backend_xmin,
     s.query
    FROM pg_database d,
-    pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port),
+    pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin),
     pg_authid u
   WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1704,6 +1706,7 @@ pg_stat_replication| SELECT s.pid,
     s.client_hostname,
     s.client_port,
     s.backend_start,
+    s.backend_xmin,
     w.state,
     w.sent_location,
     w.write_location,
@@ -1711,7 +1714,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, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port),
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin),
     pg_authid u,
     pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state)
   WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));