1
0
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:
Robert Haas
2016-03-10 12:44:09 -05:00
parent a3a8309d45
commit 53be0b1add
24 changed files with 796 additions and 104 deletions

View 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

View 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;
}

View 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);

View 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");

View 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