diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 85459d04b4..ec5328ea8f 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -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. + diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index b491735d2e..ab8758661d 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -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(); } diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 6c750990ac..e518e178bb 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -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(); } /* ---------------------------------------------------------------- diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index abf9a7007c..84aa06148e 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -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, diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 4ff4caf232..ad948168a7 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -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) */ diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index aabb92849a..8d4b3539b1 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -273,6 +273,7 @@ CheckpointerMain(void) * files. */ LWLockReleaseAll(); + pgstat_report_wait_end(); AbortBufferIO(); UnlockBuffers(); /* buffer pins are released here: */ diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 4424cb8ed2..14afef61fe 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -48,12 +48,12 @@ #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() - diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 9852fed82d..228190a836 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -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: */ diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index c03e045c81..f98475cbf3 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -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) { diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 68cf5cc9f6..e8e0825eb0 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -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 diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 9d16afb5a1..9d2663e2f9 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -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; +} diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index a458c68b9e..b30b7b1009 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -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); diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index d245857a81..76d75a914f 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -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"); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 6453b88a5b..46838d852e 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -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 diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 6bcab811f5..2e55368061 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -23,7 +23,7 @@ /* This must match enum LockTagType! */ -static const char *const LockTagTypeNames[] = { +const char *const LockTagTypeNames[] = { "relation", "extend", "page", diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 2fb51fa678..0f6f891f8a 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -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); - else - nulls[14] = true; - - if (TransactionIdIsValid(local_beentry->backend_xmin)) - values[15] = TransactionIdGetDatum(local_beentry->backend_xmin); + values[15] = TransactionIdGetDatum(local_beentry->backend_xid); else nulls[15] = true; + if (TransactionIdIsValid(local_beentry->backend_xmin)) + values[16] = TransactionIdGetDatum(local_beentry->backend_xmin); + else + 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) + 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 (!wait_event_type) PG_RETURN_NULL(); - if (!has_privs_of_role(GetUserId(), beentry->st_userid)) + 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(); - result = beentry->st_waiting; - - PG_RETURN_BOOL(result); + PG_RETURN_TEXT_P(cstring_to_text(wait_event)); } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 62868915dc..b76df550a8 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201603091 +#define CATALOG_VERSION_NO 201603101 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index a0f821ac68..451bad7b4e 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -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_ )); diff --git a/src/include/pgstat.h b/src/include/pgstat.h index eae6a0fee2..e7fbf1e392 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -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) \ diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index e9d41bf27e..975b6f8155 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -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 */ diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 788d50a35f..b26427dea3 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -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 diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index de92d166e4..5e6299af1d 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -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, diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index dbcdd3f340..612fa052be 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -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; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 81bc5c9504..22ea06c150 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -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,