mirror of
https://github.com/postgres/postgres.git
synced 2025-11-29 23:43:17 +03:00
Provide much better wait information in pg_stat_activity.
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user