Provide much better wait information in pg_stat_activity.
authorRobert Haas
Thu, 10 Mar 2016 17:44:09 +0000 (12:44 -0500)
committerRobert Haas
Thu, 10 Mar 2016 17:44:09 +0000 (12:44 -0500)
When a process is waiting for a heavyweight lock, we will now indicate
the type of heavyweight lock for which it is waiting.  Also, you can
now see when a process is waiting for a lightweight lock - in which
case we will indicate the individual lock name or the tranche, as
appropriate - or for a buffer pin.

Amit Kapila, Ildus Kurbangaliev, reviewed by me.  Lots of helpful
discussion and suggestions by many others, including Alexander
Korotkov, Vladimir Borodin, and many others.

24 files changed:
doc/src/sgml/monitoring.sgml
src/backend/access/transam/xact.c
src/backend/bootstrap/bootstrap.c
src/backend/catalog/system_views.sql
src/backend/postmaster/bgwriter.c
src/backend/postmaster/checkpointer.c
src/backend/postmaster/pgstat.c
src/backend/postmaster/walwriter.c
src/backend/replication/walsender.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/lmgr/lmgr.c
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/lwlock.c
src/backend/storage/lmgr/proc.c
src/backend/utils/adt/lockfuncs.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/lmgr.h
src/include/storage/lock.h
src/include/storage/lwlock.h
src/include/storage/proc.h
src/test/regress/expected/rules.out

index 85459d04b4509a59c7135acbb0cabb45503a4728..ec5328ea8fdbe8139d0f5da3530d31a016a6a98a 100644 (file)
@@ -632,10 +632,56 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      timestamp with time zone
      Time when the state was last changed
     
+     
+      wait_event_type
+      text
+      The type of event for which the backend is waiting, if any;
+       otherwise NULL. Possible values are:
+       
+        
+         
+          LWLockNamed: The backend is waiting for a specific named
+          lightweight lock.  Each such lock protects a particular data
+          structure in shared memory.  wait_event will contain
+          the name of the lightweight lock.
+         
+        
+        
+         
+          LWLockTranche: The backend is waiting for one of a
+          group of related lightweight locks.  All locks in the group perform
+          a similar function; wait_event will identify the general
+          purpose of locks in that group.
+         
+        
+        
+         
+          Lock: The backend is waiting for a heavyweight lock.
+          Heayweight locks, also known as lock manager locks or simply locks,
+          primarily protect SQL-visible objects such as tables.  However,
+          they are also used to ensure mutual exclusion for certain internal
+          operations such as relation extension.  wait_event will
+          identify the type of lock awaited.
+         
+        
+        
+         
+          BufferPin: The server process is waiting to access to
+          a data buffer during a period when no other process can be
+          examining that buffer.  Buffer pin waits can be protracted if
+          another process holds an open cursor which last read data from the
+          buffer in question.
+         
+        
+       
+      
+     
     
-     waiting
-     boolean
-     True if this backend is currently waiting on a lock
+     wait_event
+     text
+     Wait event name if backend is currently waiting, otherwise NULL.
+     See  for details.
+     
     
     
      state
@@ -712,15 +758,351 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
 
   
    
-    The waiting and state columns are
+    The wait_event and state columns are
     independent.  If a backend is in the active state,
-    it may or may not be waiting.  If the state is
-    active and waiting is true, it means
-    that a query is being executed, but is being blocked by a lock
-    somewhere in the system.
+    it may or may not be waiting on some event.  If the state
+    is active and wait_event is non-null, it
+    means that a query is being executed, but is being blocked somewhere
+    in the system.
    
   
 
+  
+   <structname>wait_event</structname> Description
+
+    
+      
+       
+        Wait Event Type
+        Wait Event Name
+        Description
+       
+      
+
+      
+       
+        LWLockNamed
+        ShmemIndexLock
+        Waiting to find or allocate space in shared memory.
+       
+       
+        OidGenLock
+        Waiting to allocate or assign an OID.
+       
+        
+         XidGenLock
+         Waiting to allocate or assign a transaction id.
+        
+        
+         ProcArrayLock
+         Waiting to get a snapshot or clearing a transaction id at
+         transaction end.
+        
+        
+         SInvalReadLock
+         Waiting to retrieve or remove messages from shared invalidation
+         queue.
+        
+        
+         SInvalWriteLock
+         Waiting to add a message in shared invalidation queue.
+        
+        
+         WALBufMappingLock
+         Waiting to replace a page in WAL buffers.
+        
+        
+         WALWriteLock
+         Waiting for WAL buffers to be written to disk.
+        
+        
+         ControlFileLock
+         Waiting to read or update the control file or creation of a
+         new WAL file.
+        
+        
+         CheckpointLock
+         Waiting to perform checkpoint.
+        
+        
+         CLogControlLock
+         Waiting to read or update transaction status.
+        
+        
+         SubtransControlLock
+         Waiting to read or update sub-transaction information.
+        
+        
+         MultiXactGenLock
+         Waiting to read or update shared multixact state.
+        
+        
+         MultiXactOffsetControlLock
+         Waiting to read or update multixact offset mappings.
+        
+        
+         MultiXactMemberControlLock
+         Waiting to read or update multixact member mappings.
+        
+        
+         RelCacheInitLock
+         Waiting to read or write relation cache initialization
+         file.
+        
+        
+         CheckpointerCommLock
+         Waiting to manage fsync requests.
+        
+        
+         TwoPhaseStateLock
+         Waiting to read or update the state of prepared transactions.
+        
+        
+         TablespaceCreateLock
+         Waiting to create or drop the tablespace.
+        
+        
+         BtreeVacuumLock
+          Waiting to read or update vacuum-related information for a
+          Btree index.
+        
+        
+         AddinShmemInitLock
+         Waiting to manage space allocation in shared memory.
+        
+        
+         AutovacuumLock
+         Autovacuum worker or launcher waiting to update or
+         read the current state of autovacuum workers.
+        
+        
+         AutovacuumScheduleLock
+         Waiting to ensure that the table it has selected for a vacuum
+         still needs vacuuming.
+         
+        
+        
+         SyncScanLock
+         Waiting to get the start location of a scan on a table for
+         synchronized scans.
+        
+        
+         RelationMappingLock
+         Waiting to update the relation map file used to store catalog
+         to filenode mapping.
+         
+        
+        
+         AsyncCtlLock
+         Waiting to read or update shared notification state.
+        
+        
+         AsyncQueueLock
+          Waiting to read or update notification messages.
+        
+        
+         SerializableXactHashLock
+         Waiting to retrieve or store information about serializable
+         transactions.
+        
+        
+         SerializableFinishedListLock
+         Waiting to access the list of finished serializable
+         transactions.
+        
+        
+         SerializablePredicateLockListLock
+         Waiting to perform an operation on a list of locks held by
+         serializable transactions.
+        
+        
+         OldSerXidLock
+         Waiting to read or record conflicting serializable
+         transactions.
+        
+        
+         SyncRepLock
+         Waiting to read or update information about synchronous
+         replicas.
+        
+        
+         BackgroundWorkerLock
+         Waiting to read or update background worker state.
+        
+        
+         DynamicSharedMemoryControlLock
+         Waiting to read or update dynamic shared memory state.
+        
+        
+         AutoFileLock
+         Waiting to update the postgresql.auto.conf file.
+        
+        
+         ReplicationSlotAllocationLock
+         Waiting to allocate or free a replication slot.
+        
+        
+         ReplicationSlotControlLock
+         Waiting to read or update replication slot state.
+        
+        
+         CommitTsControlLock
+         Waiting to read or update transaction commit timestamps.
+        
+        
+         CommitTsLock
+         Waiting to read or update the last value set for the
+         transaction timestamp.
+        
+        
+         ReplicationOriginLock
+         Waiting to setup, drop or use replication origin.
+        
+        
+         MultiXactTruncationLock
+         Waiting to read or truncate multixact information.
+        
+        
+         LWLockTranche
+         clog
+         Waiting for I/O on a clog (transcation status) buffer.
+        
+        
+         commit_timestamp
+         Waiting for I/O on commit timestamp buffer.
+        
+        
+         subtrans
+         Waiting for I/O a subtransaction buffer.
+        
+        
+         multixact_offset
+         Waiting for I/O on a multixact offset buffer.
+        
+        
+         multixact_member
+         Waiting for I/O on a multixact_member buffer.
+        
+        
+         async
+         Waiting for I/O on an async (notify) buffer.
+        
+        
+         oldserxid
+         Waiting to I/O on an oldserxid buffer.
+        
+        
+         wal_insert
+         Waiting to insert WAL into a memory buffer.
+        
+        
+         buffer_content
+         Waiting to read or write a data page in memory.
+        
+        
+         buffer_io
+         Waiting for I/O on a data page.
+        
+        
+         replication_origin
+         Waiting to read or update the replication progress.
+        
+        
+         replication_slot_io
+         Waiting for I/O on a replication slot.
+        
+        
+         proc
+         Waiting to read or update the fast-path lock information.
+        
+        
+         buffer_mapping
+         Waiting to associate a data block with a buffer in the buffer
+         pool.
+        
+        
+         lock_manager
+         Waiting to add or examine locks for backends, or waiting to
+         join or exit a locking group (used by parallel query).
+        
+        
+         predicate_lock_manager
+         Waiting to add or examine predicate lock information.
+        
+        
+         Lock
+         relation
+         Waiting to acquire a lock on a relation.
+        
+        
+         extend
+         Waiting to extend a relation.
+        
+        
+         page
+         Waiting to acquire a lock on page of a relation.
+        
+        
+         tuple
+         Waiting to acquire a lock on a tuple.
+        
+        
+         transactionid
+         Waiting for a transaction to finish.
+        
+        
+         virtualxid
+         Waiting to acquire a virtual xid lock.
+        
+        
+         speculative token
+         Waiting to acquire a speculative insertion lock.
+        
+        
+         object
+         Waiting to acquire a lock on a non-relation database object.
+        
+        
+         userlock
+         Waiting to acquire a userlock.
+        
+        
+         advisory
+         Waiting to acquire an advisory user lock.
+        
+        
+         BufferPin
+         BufferPin
+         Waiting to acquire a pin on a buffer.
+        
+      
+     
+    
+
+   
+    
+     For tranches registered by extensions, the name is specified by extension
+     and this will be displayed as wait_event.  It is quite
+     possible that user has registered the tranche in one of the backends (by
+     having allocation in dynamic shared memory) in which case other backends
+     won't have that information, so we display extension for such
+     cases.
+    
+   
+
+   
+     Here is an example of how wait events can be viewed
+
+
+SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event is NOT NULL;
+ pid  | wait_event_type |  wait_event
+------+-----------------+---------------
+ 2540 | Lock            | relation
+ 6644 | LWLockNamed     | ProcArrayLock
+(2 rows)
+
+   
+   
   
    <structname>pg_stat_replication</structname> View
    
@@ -2030,10 +2412,20 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
       OID of the user logged into this backend
      
 
+      
+       pg_stat_get_backend_wait_event_type(integer)
+       text
+        Wait event type name if backend is currently waiting, otherwise NULL.
+        See  for details.
+        
+      
+      
      
-      pg_stat_get_backend_waiting(integer)
-      boolean
-      True if this backend is currently waiting on a lock
+      pg_stat_get_backend_wait_event(integer)
+      text
+       Wait event name if backend is currently waiting, otherwise NULL.
+       See  for details.
+       
      
 
      
index b491735d2e2b95fbf6115dc9ca7b58f0f4ddabb0..ab8758661db6977a976ab07b3a27fc568cd26367 100644 (file)
@@ -2447,13 +2447,14 @@ AbortTransaction(void)
     */
    LWLockReleaseAll();
 
+   /* Clear wait information and command progress indicator */
+   pgstat_report_wait_end();
+   pgstat_progress_end_command();
+
    /* Clean up buffer I/O and buffer context locks, too */
    AbortBufferIO();
    UnlockBuffers();
 
-   /* Clear command progress indicator */
-   pgstat_progress_end_command();
-
    /* Reset WAL record construction state */
    XLogResetInsertion();
 
@@ -4541,9 +4542,10 @@ AbortSubTransaction(void)
     */
    LWLockReleaseAll();
 
+   pgstat_report_wait_end();
+   pgstat_progress_end_command();
    AbortBufferIO();
    UnlockBuffers();
-   pgstat_progress_end_command();
 
    /* Reset WAL record construction state */
    XLogResetInsertion();
@@ -4653,6 +4655,9 @@ AbortSubTransaction(void)
     */
    XactReadOnly = s->prevXactReadOnly;
 
+   /* Report wait end here, when there is no further possibility of wait */
+   pgstat_report_wait_end();
+
    RESUME_INTERRUPTS();
 }
 
index 6c750990ac2024ce2381cb3cd4d70d4e9315f4fb..e518e178bb4b43958a929aa0b998f09d92f5a1b6 100644 (file)
@@ -26,6 +26,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "pg_getopt.h"
+#include "pgstat.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/startup.h"
 #include "postmaster/walwriter.h"
@@ -534,6 +535,7 @@ static void
 ShutdownAuxiliaryProcess(int code, Datum arg)
 {
    LWLockReleaseAll();
+   pgstat_report_wait_end();
 }
 
 /* ----------------------------------------------------------------
index abf9a7007c5a1f1c55f58de552814ad4cb340747..84aa06148efccc73fef09dfb3d00f706f33a0a56 100644 (file)
@@ -636,7 +636,8 @@ CREATE VIEW pg_stat_activity AS
             S.xact_start,
             S.query_start,
             S.state_change,
-            S.waiting,
+            S.wait_event_type,
+            S.wait_event,
             S.state,
             S.backend_xid,
             s.backend_xmin,
index 4ff4caf232126a7cb6627ea72e3c1b2629b26872..ad948168a706064939ff091caecc8a43d29a82e7 100644 (file)
@@ -224,6 +224,9 @@ BackgroundWriterMain(void)
         * It's not clear we need it elsewhere, but shouldn't hurt.
         */
        smgrcloseall();
+
+       /* Report wait end here, when there is no further possibility of wait */
+       pgstat_report_wait_end();
    }
 
    /* We can now handle ereport(ERROR) */
index aabb92849a02fcd53765a006ef8eafbbe6cbfe7c..8d4b3539b1ec8f5d901f8fa4d8d05bf92c4aff67 100644 (file)
@@ -273,6 +273,7 @@ CheckpointerMain(void)
         * files.
         */
        LWLockReleaseAll();
+       pgstat_report_wait_end();
        AbortBufferIO();
        UnlockBuffers();
        /* buffer pins are released here: */
index 4424cb8ed2b2dd1435d9e57625944e1931d66e17..14afef61fef27ce6fa940f29f32207ce83ecdf11 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/dsm.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
+#include "storage/lmgr.h"
 #include "storage/pg_shmem.h"
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
@@ -2723,7 +2723,6 @@ pgstat_bestart(void)
 #else
    beentry->st_ssl = false;
 #endif
-   beentry->st_waiting = false;
    beentry->st_state = STATE_UNDEFINED;
    beentry->st_appname[0] = '\0';
    beentry->st_activity[0] = '\0';
@@ -2810,6 +2809,8 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
    {
        if (beentry->st_state != STATE_DISABLED)
        {
+           volatile PGPROC *proc = MyProc;
+
            /*
             * track_activities is disabled, but we last reported a
             * non-disabled state.  As our final update, change the state and
@@ -2820,9 +2821,9 @@ pgstat_report_activity(BackendState state, const char *cmd_str)
            beentry->st_state_start_timestamp = 0;
            beentry->st_activity[0] = '\0';
            beentry->st_activity_start_timestamp = 0;
-           /* st_xact_start_timestamp and st_waiting are also disabled */
+           /* st_xact_start_timestamp and wait_event_info are also disabled */
            beentry->st_xact_start_timestamp = 0;
-           beentry->st_waiting = false;
+           proc->wait_event_info = 0;
            pgstat_increment_changecount_after(beentry);
        }
        return;
@@ -2978,32 +2979,6 @@ pgstat_report_xact_timestamp(TimestampTz tstamp)
    pgstat_increment_changecount_after(beentry);
 }
 
-/* ----------
- * pgstat_report_waiting() -
- *
- * Called from lock manager to report beginning or end of a lock wait.
- *
- * NB: this *must* be able to survive being called before MyBEEntry has been
- * initialized.
- * ----------
- */
-void
-pgstat_report_waiting(bool waiting)
-{
-   volatile PgBackendStatus *beentry = MyBEEntry;
-
-   if (!pgstat_track_activities || !beentry)
-       return;
-
-   /*
-    * Since this is a single-byte field in a struct that only this process
-    * may modify, there seems no need to bother with the st_changecount
-    * protocol.  The update must appear atomic in any case.
-    */
-   beentry->st_waiting = waiting;
-}
-
-
 /* ----------
  * pgstat_read_current_status() -
  *
@@ -3119,6 +3094,87 @@ pgstat_read_current_status(void)
    localBackendStatusTable = localtable;
 }
 
+/* ----------
+ * pgstat_get_wait_event_type() -
+ *
+ * Return a string representing the current wait event type, backend is
+ * waiting on.
+ */
+const char *
+pgstat_get_wait_event_type(uint32 wait_event_info)
+{
+   uint8       classId;
+   const char *event_type;
+
+   /* report process as not waiting. */
+   if (wait_event_info == 0)
+       return NULL;
+
+   wait_event_info = wait_event_info >> 24;
+   classId = wait_event_info & 0XFF;
+
+   switch (classId)
+   {
+       case WAIT_LWLOCK_NAMED:
+           event_type = "LWLockNamed";
+           break;
+       case WAIT_LWLOCK_TRANCHE:
+           event_type = "LWLockTranche";
+           break;
+       case WAIT_LOCK:
+           event_type = "Lock";
+           break;
+       case WAIT_BUFFER_PIN:
+           event_type = "BufferPin";
+           break;
+       default:
+           event_type = "???";
+           break;
+   }
+
+   return event_type;
+}
+
+/* ----------
+ * pgstat_get_wait_event() -
+ *
+ * Return a string representing the current wait event, backend is
+ * waiting on.
+ */
+const char *
+pgstat_get_wait_event(uint32 wait_event_info)
+{
+   uint8       classId;
+   uint16      eventId;
+   const char *event_name;
+
+   /* report process as not waiting. */
+   if (wait_event_info == 0)
+       return NULL;
+
+   eventId = wait_event_info & ((1 << 24) - 1);
+   wait_event_info = wait_event_info >> 24;
+   classId = wait_event_info & 0XFF;
+
+   switch (classId)
+   {
+       case WAIT_LWLOCK_NAMED:
+       case WAIT_LWLOCK_TRANCHE:
+           event_name = GetLWLockIdentifier(classId, eventId);
+           break;
+       case WAIT_LOCK:
+           event_name = GetLockNameFromTagType(eventId);
+           break;
+       case WAIT_BUFFER_PIN:
+           event_name = "BufferPin";
+           break;
+       default:
+           event_name = "unknown wait event";
+           break;
+   }
+
+   return event_name;
+}
 
 /* ----------
  * pgstat_get_backend_current_activity() -
index 9852fed82d8d305414b43c06d2b90f198cf03410..228190a836d52e59ed0f9aef0a578d4c0f906c29 100644 (file)
@@ -47,6 +47,7 @@
 #include "access/xlog.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/walwriter.h"
 #include "storage/bufmgr.h"
 #include "storage/fd.h"
@@ -168,6 +169,7 @@ WalWriterMain(void)
         * about in walwriter, but we do have LWLocks, and perhaps buffers?
         */
        LWLockReleaseAll();
+       pgstat_report_wait_end();
        AbortBufferIO();
        UnlockBuffers();
        /* buffer pins are released here: */
index c03e045c81bcfe7533ff86f02f27d6ced93cca96..f98475cbf39bdbb7abe54703112cb001f9f3db50 100644 (file)
@@ -55,6 +55,7 @@
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/replnodes.h"
+#include "pgstat.h"
 #include "replication/basebackup.h"
 #include "replication/decode.h"
 #include "replication/logical.h"
@@ -252,6 +253,7 @@ void
 WalSndErrorCleanup(void)
 {
    LWLockReleaseAll();
+   pgstat_report_wait_end();
 
    if (sendFile >= 0)
    {
index 68cf5cc9f61adb3ac56ebd3827a8e21228f359ba..e8e0825eb0c5590241e8cfdff9a4a6da5c47f1cd 100644 (file)
@@ -3351,6 +3351,9 @@ LockBufferForCleanup(Buffer buffer)
        UnlockBufHdr(bufHdr);
        LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 
+       /* Report the wait */
+       pgstat_report_wait_start(WAIT_BUFFER_PIN, 0);
+
        /* Wait to be signaled by UnpinBuffer() */
        if (InHotStandby)
        {
@@ -3364,6 +3367,8 @@ LockBufferForCleanup(Buffer buffer)
        else
            ProcWaitForSignal();
 
+       pgstat_report_wait_end();
+
        /*
         * Remove flag marking us as waiter. Normally this will not be set
         * anymore, but ProcWaitForSignal() can return for other signals as
index 9d16afb5a1bd6b0a1b0895d1b87e6ef76c972a3d..9d2663e2f9d6da9b209d050394f101852fa15eae 100644 (file)
@@ -994,3 +994,26 @@ DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
            break;
    }
 }
+
+/*
+ * GetLockNameFromTagType
+ *
+ * Given locktag type, return the corresponding lock name.
+ */
+const char *
+GetLockNameFromTagType(uint16 locktag_type)
+{
+   const char *locktypename;
+   char        tnbuf[32];
+
+   if (locktag_type <= LOCKTAG_LAST_TYPE)
+       locktypename = LockTagTypeNames[locktag_type];
+   else
+   {
+       snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
+                (int) locktag_type);
+       locktypename = tnbuf;
+   }
+
+   return locktypename;
+}
index a458c68b9e9dec78c962d6291e381d5a13b20b2d..b30b7b1009b18d797672a7be1529e0e339d11e08 100644 (file)
@@ -1676,7 +1676,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
        set_ps_display(new_status, false);
        new_status[len] = '\0'; /* truncate off " waiting" */
    }
-   pgstat_report_waiting(true);
+   pgstat_report_wait_start(WAIT_LOCK, locallock->tag.lock.locktag_type);
 
    awaitedLock = locallock;
    awaitedOwner = owner;
@@ -1724,7 +1724,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
        /* In this path, awaitedLock remains set until LockErrorCleanup */
 
        /* Report change to non-waiting status */
-       pgstat_report_waiting(false);
+       pgstat_report_wait_end();
        if (update_process_title)
        {
            set_ps_display(new_status, false);
@@ -1739,7 +1739,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
    awaitedLock = NULL;
 
    /* Report change to non-waiting status */
-   pgstat_report_waiting(false);
+   pgstat_report_wait_end();
    if (update_process_title)
    {
        set_ps_display(new_status, false);
index d245857a814d891d0943483daacfbe9599a6452e..76d75a914f38acc1116a31146f52cad3c1e064fe 100644 (file)
@@ -77,6 +77,7 @@
 #include "postgres.h"
 
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "pg_trace.h"
 #include "postmaster/postmaster.h"
 #include "replication/slot.h"
@@ -165,6 +166,9 @@ static bool lock_named_request_allowed = true;
 static void InitializeLWLocks(void);
 static void RegisterLWLockTranches(void);
 
+static inline void LWLockReportWaitStart(LWLock *lock);
+static inline void LWLockReportWaitEnd();
+
 #ifdef LWLOCK_STATS
 typedef struct lwlock_stats_key
 {
@@ -525,7 +529,7 @@ RegisterLWLockTranches(void)
    {
        LWLockTranchesAllocated = 32;
        LWLockTrancheArray = (LWLockTranche **)
-           MemoryContextAlloc(TopMemoryContext,
+           MemoryContextAllocZero(TopMemoryContext,
                          LWLockTranchesAllocated * sizeof(LWLockTranche *));
        Assert(LWLockTranchesAllocated >= LWTRANCHE_FIRST_USER_DEFINED);
    }
@@ -636,6 +640,7 @@ LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche)
    if (tranche_id >= LWLockTranchesAllocated)
    {
        int         i = LWLockTranchesAllocated;
+       int         j = LWLockTranchesAllocated;
 
        while (i <= tranche_id)
            i *= 2;
@@ -644,6 +649,8 @@ LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche)
            repalloc(LWLockTrancheArray,
                     i * sizeof(LWLockTranche *));
        LWLockTranchesAllocated = i;
+       while (j < LWLockTranchesAllocated)
+           LWLockTrancheArray[j++] = NULL;
    }
 
    LWLockTrancheArray[tranche_id] = tranche;
@@ -713,6 +720,57 @@ LWLockInitialize(LWLock *lock, int tranche_id)
    dlist_init(&lock->waiters);
 }
 
+/*
+ * Report start of wait event for light-weight locks.
+ *
+ * This function will be used by all the light-weight lock calls which
+ * needs to wait to acquire the lock.  This function distinguishes wait
+ * event based on tranche and lock id.
+ */
+static inline void
+LWLockReportWaitStart(LWLock *lock)
+{
+   int         lockId = T_ID(lock);
+
+   if (lock->tranche == 0)
+       pgstat_report_wait_start(WAIT_LWLOCK_NAMED, (uint16) lockId);
+   else
+       pgstat_report_wait_start(WAIT_LWLOCK_TRANCHE, lock->tranche);
+}
+
+/*
+ * Report end of wait event for light-weight locks.
+ */
+static inline void
+LWLockReportWaitEnd()
+{
+   pgstat_report_wait_end();
+}
+
+/*
+ * Return an identifier for an LWLock based on the wait class and event.
+ */
+const char *
+GetLWLockIdentifier(uint8 classId, uint16 eventId)
+{
+   if (classId == WAIT_LWLOCK_NAMED)
+       return MainLWLockNames[eventId];
+
+   Assert(classId == WAIT_LWLOCK_TRANCHE);
+
+   /*
+    * It is quite possible that user has registered tranche in one of the
+    * backends (e.g. by allocation lwlocks in dynamic shared memory) but not
+    * all of them, so we can't assume the tranche is registered here.
+    * extension for such cases.
+    */
+   if (eventId >= LWLockTranchesAllocated ||
+       LWLockTrancheArray[eventId]->name == NULL)
+       return "extension";
+
+   return LWLockTrancheArray[eventId]->name;
+}
+
 /*
  * Internal function that tries to atomically acquire the lwlock in the passed
  * in mode.
@@ -1162,6 +1220,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
        lwstats->block_count++;
 #endif
 
+       LWLockReportWaitStart(lock);
        TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
 
        for (;;)
@@ -1185,6 +1244,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 #endif
 
        TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
+       LWLockReportWaitEnd();
 
        LOG_LWDEBUG("LWLockAcquire", lock, "awakened");
 
@@ -1320,6 +1380,8 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
 #ifdef LWLOCK_STATS
            lwstats->block_count++;
 #endif
+
+           LWLockReportWaitStart(lock);
            TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
 
            for (;;)
@@ -1339,6 +1401,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
            }
 #endif
            TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
+           LWLockReportWaitEnd();
 
            LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened");
        }
@@ -1544,6 +1607,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
        lwstats->block_count++;
 #endif
 
+       LWLockReportWaitStart(lock);
        TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock),
                                           LW_EXCLUSIVE);
 
@@ -1566,6 +1630,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
 
        TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock),
                                          LW_EXCLUSIVE);
+       LWLockReportWaitEnd();
 
        LOG_LWDEBUG("LWLockWaitForVar", lock, "awakened");
 
index 6453b88a5b8867121c12be43f1da8d877bbd59ff..46838d852e5882a0aef58a7611a3750e4c4d8c3c 100644 (file)
@@ -404,6 +404,9 @@ InitProcess(void)
    Assert(MyProc->lockGroupLeader == NULL);
    Assert(dlist_is_empty(&MyProc->lockGroupMembers));
 
+   /* Initialize wait event information. */
+   MyProc->wait_event_info = 0;
+
    /*
     * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch
     * on it.  That allows us to repoint the process latch, which so far
index 6bcab811f5e92f6c39ab439d3b3b25f7b0d4114a..2e55368061d4423a1f0e7b72edd242e8bdc1db3c 100644 (file)
@@ -23,7 +23,7 @@
 
 
 /* This must match enum LockTagType! */
-static const char *const LockTagTypeNames[] = {
+const char *const LockTagTypeNames[] = {
    "relation",
    "extend",
    "page",
index 2fb51fa6788001f0e52bb8a5df57644e4dd1836c..0f6f891f8ac97035e6540f645c5cbbd4e7bdcd2f 100644 (file)
@@ -20,6 +20,8 @@
 #include "libpq/ip.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "storage/proc.h"
+#include "storage/procarray.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/inet.h"
@@ -58,7 +60,8 @@ extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
@@ -633,7 +636,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS  22
+#define PG_STAT_GET_ACTIVITY_COLS  23
    int         num_backends = pgstat_fetch_stat_numbackends();
    int         curr_backend;
    int         pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -676,6 +679,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
        bool        nulls[PG_STAT_GET_ACTIVITY_COLS];
        LocalPgBackendStatus *local_beentry;
        PgBackendStatus *beentry;
+       PGPROC     *proc;
+       const char *wait_event_type;
+       const char *wait_event;
 
        MemSet(values, 0, sizeof(values));
        MemSet(nulls, 0, sizeof(nulls));
@@ -720,28 +726,28 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
            nulls[3] = true;
 
        if (TransactionIdIsValid(local_beentry->backend_xid))
-           values[14] = TransactionIdGetDatum(local_beentry->backend_xid);
+           values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
        else
-           nulls[14] = true;
+           nulls[15] = true;
 
        if (TransactionIdIsValid(local_beentry->backend_xmin))
-           values[15] = TransactionIdGetDatum(local_beentry->backend_xmin);
+           values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
        else
-           nulls[15] = true;
+           nulls[16] = true;
 
        if (beentry->st_ssl)
        {
-           values[16] = BoolGetDatum(true);    /* ssl */
-           values[17] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
-           values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
-           values[19] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
-           values[20] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
-           values[21] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
+           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);
        }
        else
        {
-           values[16] = BoolGetDatum(false);   /* ssl */
-           nulls[17] = nulls[18] = nulls[19] = nulls[20] = nulls[21] = true;
+           values[17] = BoolGetDatum(false);   /* ssl */
+           nulls[18] = nulls[19] = nulls[20] = nulls[21] = nulls[22] = true;
        }
 
        /* Values only available to role member */
@@ -775,36 +781,48 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
            }
 
            values[5] = CStringGetTextDatum(beentry->st_activity);
-           values[6] = BoolGetDatum(beentry->st_waiting);
 
-           if (beentry->st_xact_start_timestamp != 0)
-               values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+           proc = BackendPidGetProc(beentry->st_procpid);
+           wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
+           if (wait_event_type)
+               values[6] = CStringGetTextDatum(wait_event_type);
+           else
+               nulls[6] = true;
+
+           wait_event = pgstat_get_wait_event(proc->wait_event_info);
+           if (wait_event)
+               values[7] = CStringGetTextDatum(wait_event);
            else
                nulls[7] = true;
 
-           if (beentry->st_activity_start_timestamp != 0)
-               values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+           if (beentry->st_xact_start_timestamp != 0)
+               values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
            else
                nulls[8] = true;
 
-           if (beentry->st_proc_start_timestamp != 0)
-               values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+           if (beentry->st_activity_start_timestamp != 0)
+               values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
            else
                nulls[9] = true;
 
-           if (beentry->st_state_start_timestamp != 0)
-               values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+           if (beentry->st_proc_start_timestamp != 0)
+               values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
            else
                nulls[10] = true;
 
+           if (beentry->st_state_start_timestamp != 0)
+               values[11] = TimestampTzGetDatum(beentry->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,
                       sizeof(zero_clientaddr)) == 0)
            {
-               nulls[11] = true;
                nulls[12] = true;
                nulls[13] = true;
+               nulls[14] = true;
            }
            else
            {
@@ -828,20 +846,20 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                    if (ret == 0)
                    {
                        clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
-                       values[11] = DirectFunctionCall1(inet_in,
+                       values[12] = DirectFunctionCall1(inet_in,
                                               CStringGetDatum(remote_host));
                        if (beentry->st_clienthostname &&
                            beentry->st_clienthostname[0])
-                           values[12] = CStringGetTextDatum(beentry->st_clienthostname);
+                           values[13] = CStringGetTextDatum(beentry->st_clienthostname);
                        else
-                           nulls[12] = true;
-                       values[13] = Int32GetDatum(atoi(remote_port));
+                           nulls[13] = true;
+                       values[14] = Int32GetDatum(atoi(remote_port));
                    }
                    else
                    {
-                       nulls[11] = true;
                        nulls[12] = true;
                        nulls[13] = true;
+                       nulls[14] = true;
                    }
                }
                else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
@@ -852,16 +870,16 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                     * connections we have no permissions to view, or with
                     * errors.
                     */
-                   nulls[11] = true;
                    nulls[12] = true;
-                   values[13] = DatumGetInt32(-1);
+                   nulls[13] = true;
+                   values[14] = DatumGetInt32(-1);
                }
                else
                {
                    /* Unknown address type, should never happen */
-                   nulls[11] = true;
                    nulls[12] = true;
                    nulls[13] = true;
+                   nulls[14] = true;
                }
            }
        }
@@ -878,6 +896,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
            nulls[11] = true;
            nulls[12] = true;
            nulls[13] = true;
+           nulls[14] = true;
        }
 
        tuplestore_putvalues(tupstore, tupdesc, values, nulls);
@@ -959,23 +978,52 @@ pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
    PG_RETURN_TEXT_P(cstring_to_text(activity));
 }
 
-
 Datum
-pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
+pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
 {
    int32       beid = PG_GETARG_INT32(0);
-   bool        result;
    PgBackendStatus *beentry;
+   PGPROC     *proc;
+   const char *wait_event_type;
 
    if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
-       PG_RETURN_NULL();
+       wait_event_type = "";
+   else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+       wait_event_type = "";
+   else
+   {
+       proc = BackendPidGetProc(beentry->st_procpid);
+       wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
+   }
 
-   if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+   if (!wait_event_type)
        PG_RETURN_NULL();
 
-   result = beentry->st_waiting;
+   PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
+}
+
+Datum
+pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
+{
+   int32       beid = PG_GETARG_INT32(0);
+   PgBackendStatus *beentry;
+   PGPROC     *proc;
+   const char *wait_event;
+
+   if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
+       wait_event = "";
+   else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+       wait_event = "";
+   else
+   {
+       proc = BackendPidGetProc(beentry->st_procpid);
+       wait_event = pgstat_get_wait_event(proc->wait_event_info);
+   }
+
+   if (!wait_event)
+       PG_RETURN_NULL();
 
-   PG_RETURN_BOOL(result);
+   PG_RETURN_TEXT_P(cstring_to_text(wait_event));
 }
 
 
index 62868915dc5a74a9a071a42dacd6d04ba32544b5..b76df550a8bea34768b8e6062f9723e06760080a 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201603091
+#define CATALOG_VERSION_NO 201603101
 
 #endif
index a0f821ac684c8adfed1f72e559d2779cb567adfb..451bad7b4e55d9abbf89bf985082f31366d5c089 100644 (file)
@@ -2708,7 +2708,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,16,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}" "{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,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}" "{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_ ));
 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 f 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");
@@ -2726,8 +2726,10 @@ DATA(insert OID = 1939 (  pg_stat_get_backend_userid PGNSP PGUID 12 1 0 0 0 f f
 DESCR("statistics: user ID of backend");
 DATA(insert OID = 1940 (  pg_stat_get_backend_activity PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 25 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_activity _null_ _null_ _null_ ));
 DESCR("statistics: current query of backend");
-DATA(insert OID = 2853 (  pg_stat_get_backend_waiting  PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 16 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_waiting _null_ _null_ _null_ ));
-DESCR("statistics: is backend currently waiting for a lock");
+DATA(insert OID = 2788 (  pg_stat_get_backend_wait_event_type  PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 25 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_wait_event_type _null_ _null_ _null_ ));
+DESCR("statistics: wait event type on which backend is currently waiting");
+DATA(insert OID = 2853 (  pg_stat_get_backend_wait_event   PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 25 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_wait_event _null_ _null_ _null_ ));
+DESCR("statistics: wait event on which backend is currently waiting");
 DATA(insert OID = 2094 (  pg_stat_get_backend_activity_start PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 1184 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_activity_start _null_ _null_ _null_ ));
 DESCR("statistics: start time for current query of backend");
 DATA(insert OID = 2857 (  pg_stat_get_backend_xact_start PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 1184 "23" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_xact_start _null_ _null_ _null_ ));
index eae6a0fee29688458eed25e52cf3d8c485d4216e..e7fbf1e39267c8b9f4c2ffaa6b18c3c14e4cabbc 100644 (file)
@@ -17,6 +17,7 @@
 #include "portability/instr_time.h"
 #include "postmaster/pgarch.h"
 #include "storage/barrier.h"
+#include "storage/proc.h"
 #include "utils/hsearch.h"
 #include "utils/relcache.h"
 
@@ -695,6 +696,21 @@ typedef enum BackendState
    STATE_DISABLED
 } BackendState;
 
+
+/* ----------
+ * Wait Classes
+ * ----------
+ */
+typedef enum WaitClass
+{
+   WAIT_UNDEFINED,
+   WAIT_LWLOCK_NAMED,
+   WAIT_LWLOCK_TRANCHE,
+   WAIT_LOCK,
+   WAIT_BUFFER_PIN
+}  WaitClass;
+
+
 /* ----------
  * Command type for progress reporting purposes
  * ----------
@@ -777,9 +793,6 @@ typedef struct PgBackendStatus
    bool        st_ssl;
    PgBackendSSLStatus *st_sslstatus;
 
-   /* Is backend currently waiting on an lmgr lock? */
-   bool        st_waiting;
-
    /* current state */
    BackendState st_state;
 
@@ -956,7 +969,8 @@ extern void pgstat_report_activity(BackendState state, const char *cmd_str);
 extern void pgstat_report_tempfile(size_t filesize);
 extern void pgstat_report_appname(const char *appname);
 extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
-extern void pgstat_report_waiting(bool waiting);
+extern const char *pgstat_get_wait_event(uint32 wait_event_info);
+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);
@@ -971,6 +985,65 @@ extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id);
 
 extern void pgstat_initstats(Relation rel);
 
+/* ----------
+ * pgstat_report_wait_start() -
+ *
+ * Called from places where server process needs to wait.  This is called
+ * to report wait event information.  The wait information is stored
+ * as 4-bytes where first byte repersents the wait event class (type of
+ * wait, for different types of wait, refer WaitClass) and the next
+ * 3-bytes repersent the actual wait event.  Currently 2-bytes are used
+ * for wait event which is sufficient for current usage, 1-byte is
+ * reserved for future usage.
+ *
+ * NB: this *must* be able to survive being called before MyProc has been
+ * initialized.
+ * ----------
+ */
+static inline void
+pgstat_report_wait_start(uint8 classId, uint16 eventId)
+{
+   volatile PGPROC *proc = MyProc;
+   uint32      wait_event_val;
+
+   if (!pgstat_track_activities || !proc)
+       return;
+
+   wait_event_val = classId;
+   wait_event_val <<= 24;
+   wait_event_val |= eventId;
+
+   /*
+    * Since this is a four-byte field which is always read and written as
+    * four-bytes, updates are atomic.
+    */
+   proc->wait_event_info = wait_event_val;
+}
+
+/* ----------
+ * pgstat_report_wait_end() -
+ *
+ * Called to report end of a wait.
+ *
+ * NB: this *must* be able to survive being called before MyProc has been
+ * initialized.
+ * ----------
+ */
+static inline void
+pgstat_report_wait_end(void)
+{
+   volatile PGPROC *proc = MyProc;
+
+   if (!pgstat_track_activities || !proc)
+       return;
+
+   /*
+    * Since this is a four-byte field which is always read and written as
+    * four-bytes, updates are atomic.
+    */
+   proc->wait_event_info = 0;
+}
+
 /* nontransactional event counts are simple enough to inline */
 
 #define pgstat_count_heap_scan(rel)                                    \
index e9d41bf27e1e0ef7a1270e9dd586b5e3ecb569dc..975b6f8155d1c7e9c0f40bafed9adc0d0fcb7080 100644 (file)
@@ -101,4 +101,6 @@ extern void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid
 /* Describe a locktag for error messages */
 extern void DescribeLockTag(StringInfo buf, const LOCKTAG *tag);
 
+extern const char *GetLockNameFromTagType(uint16 locktag_type);
+
 #endif   /* LMGR_H */
index 788d50a35f3c6ad965b3edcd3e9cdb44203060a9..b26427dea311ae47adc0e6c105885eb99d6f22eb 100644 (file)
@@ -166,6 +166,8 @@ typedef enum LockTagType
 
 #define LOCKTAG_LAST_TYPE  LOCKTAG_ADVISORY
 
+extern const char *const LockTagTypeNames[];
+
 /*
  * The LOCKTAG struct is defined with malice aforethought to fit into 16
  * bytes with no padding.  Note that this would need adjustment if we were
index de92d166e4c7fb7c57a70b3526d912cbdbfa5a7e..5e6299af1d0d41cbbda3a546d33647d282b265bc 100644 (file)
@@ -187,6 +187,8 @@ extern Size LWLockShmemSize(void);
 extern void CreateLWLocks(void);
 extern void InitLWLockAccess(void);
 
+extern const char *GetLWLockIdentifier(uint8 classId, uint16 eventId);
+
 /*
  * Extensions (or core code) can obtain an LWLocks by calling
  * RequestNamedLWLockTranche() during postmaster startup.  Subsequently,
index dbcdd3f340ea187509cef8a583c01f8cf73c1c15..612fa052be01370a2fa41da62003d406731ebcab 100644 (file)
@@ -152,6 +152,8 @@ struct PGPROC
     */
    TransactionId   procArrayGroupMemberXid;
 
+   uint32          wait_event_info;        /* proc's wait information */
+
    /* Per-backend LWLock.  Protects fields below (but not group fields). */
    LWLock      backendLock;
 
index 81bc5c9504b23fc285bb995cc8891b3c8c0e2439..22ea06c150553d375ed49ae55055f3a7748593f9 100644 (file)
@@ -1650,13 +1650,14 @@ pg_stat_activity| SELECT s.datid,
     s.xact_start,
     s.query_start,
     s.state_change,
-    s.waiting,
+    s.wait_event_type,
+    s.wait_event,
     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, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
+    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),
     pg_authid u
   WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1762,7 +1763,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, 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),
     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));
@@ -1773,7 +1774,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, waiting, 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);
 pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid,
     pg_stat_all_indexes.indexrelid,
     pg_stat_all_indexes.schemaname,