aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2016-03-10 12:44:09 -0500
committerRobert Haas <rhaas@postgresql.org>2016-03-10 12:44:09 -0500
commit53be0b1add7064ca5db3cd884302dfc3268d884e (patch)
tree913271b90f5a41778fe5bdbe2ac200c785dd6778 /src/backend/storage
parenta3a8309d450f7c4d1b743e84ba54ef5f7877d7be (diff)
downloadpostgresql-53be0b1add7064ca5db3cd884302dfc3268d884e.tar.gz
postgresql-53be0b1add7064ca5db3cd884302dfc3268d884e.zip
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.
Diffstat (limited to 'src/backend/storage')
-rw-r--r--src/backend/storage/buffer/bufmgr.c5
-rw-r--r--src/backend/storage/lmgr/lmgr.c23
-rw-r--r--src/backend/storage/lmgr/lock.c6
-rw-r--r--src/backend/storage/lmgr/lwlock.c67
-rw-r--r--src/backend/storage/lmgr/proc.c3
5 files changed, 100 insertions, 4 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 68cf5cc9f61..e8e0825eb0c 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 9d16afb5a1b..9d2663e2f9d 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 a458c68b9e9..b30b7b1009b 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 d245857a814..76d75a914f3 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;
@@ -714,6 +721,57 @@ LWLockInitialize(LWLock *lock, int tranche_id)
}
/*
+ * 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 6453b88a5b8..46838d852e5 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