Hello.
In the attached patch I've made a refactoring for tranches.
The prefix for them was extended, and I've did a split of LWLockAssign
to two
functions (one with tranche and second for user defined LWLocks).
--
Ildus Kurbangaliev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 0eb991c..e75ca4d 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -480,7 +480,7 @@ pgss_shmem_startup(void)
if (!found)
{
/* First time through ... */
- pgss->lock = LWLockAssign();
+ pgss->lock = LWLockUserAssign();
pgss->cur_median_usage = ASSUMED_MEDIAN_INIT;
pgss->mean_query_len = ASSUMED_LENGTH_INIT;
SpinLockInit(&pgss->mutex);
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 9c15950..b365565 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3356,7 +3356,7 @@ if (!ptr)
{
initialize contents of shmem area;
acquire any requested LWLocks using:
- ptr->mylockid = LWLockAssign();
+ ptr->mylockid = LWLockUserAssign();
}
LWLockRelease(AddinShmemInitLock);
}
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3a58f1e..3a55511 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -457,7 +457,7 @@ CLOGShmemInit(void)
{
ClogCtl->PagePrecedes = CLOGPagePrecedes;
SimpleLruInit(ClogCtl, "CLOG Ctl", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
- CLogControlLock, "pg_clog");
+ CLogControlLock, "pg_clog", LW_TRANCHE_CLOG_BUFFERS);
}
/*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 5ad35c0..2571203 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -466,7 +466,8 @@ CommitTsShmemInit(void)
CommitTsCtl->PagePrecedes = CommitTsPagePrecedes;
SimpleLruInit(CommitTsCtl, "CommitTs Ctl", CommitTsShmemBuffers(), 0,
- CommitTsControlLock, "pg_commit_ts");
+ CommitTsControlLock, "pg_commit_ts",
+ LW_TRANCHE_COMMITTS_BUFFERS);
commitTsShared = ShmemInitStruct("CommitTs shared",
sizeof(CommitTimestampShared),
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1933a87..e8d2474 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1842,10 +1842,12 @@ MultiXactShmemInit(void)
SimpleLruInit(MultiXactOffsetCtl,
"MultiXactOffset Ctl", NUM_MXACTOFFSET_BUFFERS, 0,
- MultiXactOffsetControlLock, "pg_multixact/offsets");
+ MultiXactOffsetControlLock, "pg_multixact/offsets",
+ LW_TRANCHE_MULTIXACT_BUFFERS);
SimpleLruInit(MultiXactMemberCtl,
"MultiXactMember Ctl", NUM_MXACTMEMBER_BUFFERS, 0,
- MultiXactMemberControlLock, "pg_multixact/members");
+ MultiXactMemberControlLock, "pg_multixact/members",
+ LW_TRANCHE_MULTIXACT_BUFFERS);
/* Initialize our shared state struct */
MultiXactState = ShmemInitStruct("Shared MultiXact State",
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5fcea11..7709f6d 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -161,7 +161,7 @@ SimpleLruShmemSize(int nslots, int nlsns)
void
SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
- LWLock *ctllock, const char *subdir)
+ LWLock *ctllock, const char *subdir, int lwlocktranche)
{
SlruShared shared;
bool found;
@@ -218,7 +218,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->page_status[slotno] = SLRU_PAGE_EMPTY;
shared->page_dirty[slotno] = false;
shared->page_lru_count[slotno] = 0;
- shared->buffer_locks[slotno] = LWLockAssign();
+ shared->buffer_locks[slotno] = LWLockAssign(lwlocktranche);
ptr += BLCKSZ;
}
}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6b70982..80690bc 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -179,7 +179,8 @@ SUBTRANSShmemInit(void)
{
SubTransCtl->PagePrecedes = SubTransPagePrecedes;
SimpleLruInit(SubTransCtl, "SUBTRANS Ctl", NUM_SUBTRANS_BUFFERS, 0,
- SubtransControlLock, "pg_subtrans");
+ SubtransControlLock, "pg_subtrans",
+ LW_TRANCHE_SUBTRANS_BUFFERS);
/* Override default assumption that writes should be fsync'd */
SubTransCtl->do_fsync = false;
}
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index e82a53a..fd04258 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -621,6 +621,7 @@ CREATE VIEW pg_stat_activity AS
S.query_start,
S.state_change,
S.waiting,
+ S.wait_event,
S.state,
S.backend_xid,
s.backend_xmin,
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 3b71174..4325f12 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -469,7 +469,7 @@ AsyncShmemInit(void)
*/
AsyncCtl->PagePrecedes = asyncQueuePagePrecedes;
SimpleLruInit(AsyncCtl, "Async Ctl", NUM_ASYNC_BUFFERS, 0,
- AsyncCtlLock, "pg_notify");
+ AsyncCtlLock, "pg_notify", LW_TRANCHE_ASYNC_BUFFERS);
/* Override default assumption that writes should be fsync'd */
AsyncCtl->do_fsync = false;
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 4a650cc..e5c023f 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -36,6 +36,7 @@
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
#include "storage/proc.h"
+#include "pgstat.h"
char *ssl_cert_file;
@@ -129,6 +130,8 @@ secure_read(Port *port, void *ptr, size_t len)
ssize_t n;
int waitfor;
+ pgstat_report_wait_start(WAIT_NETWORK, WAIT_NETWORK_READ);
+
retry:
#ifdef USE_SSL
waitfor = 0;
@@ -175,6 +178,7 @@ retry:
* interrupts from being processed.
*/
ProcessClientReadInterrupt(false);
+ pgstat_report_wait_end();
return n;
}
@@ -209,6 +213,8 @@ secure_write(Port *port, void *ptr, size_t len)
ssize_t n;
int waitfor;
+ pgstat_report_wait_start(WAIT_NETWORK, WAIT_NETWORK_WRITE);
+
retry:
waitfor = 0;
#ifdef USE_SSL
@@ -254,6 +260,7 @@ retry:
* interrupts from being processed.
*/
ProcessClientWriteInterrupt(false);
+ pgstat_report_wait_end();
return n;
}
diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c
index 90ec4f8..dcebfe4 100644
--- a/src/backend/port/unix_latch.c
+++ b/src/backend/port/unix_latch.c
@@ -55,6 +55,7 @@
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/shmem.h"
+#include "pgstat.h"
/* Are we currently in WaitLatch? The signal handler would like to know. */
static volatile sig_atomic_t waiting = false;
@@ -262,6 +263,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
#endif
}
+ pgstat_report_wait_start(WAIT_LATCH, 0);
+
waiting = true;
do
{
@@ -500,6 +503,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
}
} while (result == 0);
waiting = false;
+ pgstat_report_wait_end();
return result;
}
diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c
index 0e3aaee..92bb5a0 100644
--- a/src/backend/port/win32_latch.c
+++ b/src/backend/port/win32_latch.c
@@ -177,6 +177,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
/* Ensure that signals are serviced even if latch is already set */
pgwin32_dispatch_queued_signals();
+ pgstat_report_wait_start(WAIT_LATCH, 0);
+
do
{
/*
@@ -278,6 +280,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
}
} while (result == 0);
+ pgstat_report_wait_end();
+
/* Clean up the event object we created for the socket */
if (sockevent != WSA_INVALID_EVENT)
{
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index e9fbc38..7cc48031 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -54,6 +54,7 @@
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/latch.h"
+#include "storage/lwlock.h"
#include "storage/pg_shmem.h"
#include "storage/procsignal.h"
#include "storage/sinvaladt.h"
@@ -99,7 +100,6 @@
#define PGSTAT_TAB_HASH_SIZE 512
#define PGSTAT_FUNCTION_HASH_SIZE 512
-
/* ----------
* GUC parameters
* ----------
@@ -242,6 +242,16 @@ static volatile bool got_SIGHUP = false;
*/
static instr_time total_func_time;
+/* Names of WAIT_CLASSES */
+static const char *WAIT_CLASS_NAMES[] =
+{
+ "",
+ "LWLocks",
+ "Locks",
+ "Storage",
+ "Latch",
+ "Network"
+};
/* ----------
* Local function forward declarations
@@ -2918,6 +2928,89 @@ pgstat_report_waiting(bool waiting)
beentry->st_waiting = waiting;
}
+/*
+ * pgstat_get_wait_class_name() -
+ *
+ * Return wait class name for given class
+ */
+
+const char *
+pgstat_get_wait_class_name(uint8 classId)
+{
+ return WAIT_CLASS_NAMES[classId];
+}
+
+/*
+ * pgstat_get_wait_event_name() -
+ *
+ * Return wait event name for the given class and event
+ */
+const char *
+pgstat_get_wait_event_name(uint8 classId, uint8 eventId)
+{
+ static const char *eventsIO[] = {"READ", "WRITE"};
+ static const char *empty = "";
+
+ switch (classId)
+ {
+ case WAIT_LOCK: return LOCK_NAMES[eventId];
+ case WAIT_LWLOCK: return LWLockGroupName(eventId);
+ case WAIT_IO: /* fallthrough */;
+ case WAIT_NETWORK: return eventsIO[eventId];
+ case WAIT_LATCH: return WAIT_CLASS_NAMES[WAIT_LATCH];
+ };
+ return empty;
+}
+
+/* ----------
+ * pgstat_report_wait_start() -
+ *
+ * Called from backends to report wait event type information.
+ *
+ * NB: this *must* be able to survive being called before MyBEEntry has been
+ * initialized.
+ * ----------
+ */
+void
+pgstat_report_wait_start(uint8 classId, uint8 eventId)
+{
+ volatile PgBackendStatus *beentry = MyBEEntry;
+
+ if (!pgstat_track_activities || !beentry)
+ return;
+
+ /* prevent nested waits */
+ if (beentry->st_wait_nested++ > 0)
+ return;
+
+ /*
+ * Since this is a uint32 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_wait_data = ((uint32)classId << 8) + eventId;
+}
+
+/* ----------
+ * pgstat_report_wait_end() -
+ *
+ * Called from backends, indicates that wait was ended
+ * ---------
+ */
+void
+pgstat_report_wait_end()
+{
+ volatile PgBackendStatus *beentry = MyBEEntry;
+
+ if (!pgstat_track_activities || !beentry)
+ return;
+
+ /* prevent nested waits */
+ if ((--beentry->st_wait_nested) > 0)
+ return;
+
+ beentry->st_wait_data = 0;
+}
/* ----------
* pgstat_read_current_status() -
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index f8544de..168df90 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -149,7 +149,7 @@ ReplicationSlotsShmemInit(void)
/* everything else is zeroed by the memset above */
SpinLockInit(&slot->mutex);
- slot->io_in_progress_lock = LWLockAssign();
+ slot->io_in_progress_lock = LWLockAssign(LW_TRANCHE_REPLICATIONSLOT);
}
}
}
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 3ae2848..1170cc8 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -110,8 +110,8 @@ InitBufferPool(void)
*/
buf->freeNext = i + 1;
- buf->io_in_progress_lock = LWLockAssign();
- buf->content_lock = LWLockAssign();
+ buf->io_in_progress_lock = LWLockAssign(LW_TRANCHE_BUFFER_MANAGER);
+ buf->content_lock = LWLockAssign(LW_TRANCHE_BUFFER_MANAGER);
}
/* Correct last entry of linked list */
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 1eb2d4b..c3a6621 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -54,6 +54,20 @@ int max_locks_per_xact; /* set by guc.c */
#define NLOCKENTS() \
mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
+/* Lock names. For monitoring purposes */
+const char *LOCK_NAMES[] =
+{
+ "Relation",
+ "RelationExtend",
+ "Page",
+ "Tuple",
+ "Transaction",
+ "VirtualTransaction",
+ "SpeculativeToken",
+ "Object",
+ "Userlock",
+ "Advisory"
+};
/*
* Data structures defining the semantics of the standard lock methods.
@@ -1591,6 +1605,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
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;
@@ -1639,6 +1654,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
/* Report change to non-waiting status */
pgstat_report_waiting(false);
+ pgstat_report_wait_end();
if (update_process_title)
{
set_ps_display(new_status, false);
@@ -1654,6 +1670,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
/* 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 46cab49..14c80d1 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -80,6 +80,7 @@
#include "access/subtrans.h"
#include "commands/async.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "pg_trace.h"
#include "postmaster/postmaster.h"
#include "replication/slot.h"
@@ -127,7 +128,6 @@ static int LWLockTranchesAllocated = 0;
* where we have special measures to pass it down).
*/
LWLockPadded *MainLWLockArray = NULL;
-static LWLockTranche MainLWLockTranche;
/*
* We use this structure to keep track of locked LWLocks for release
@@ -152,6 +152,81 @@ static bool lock_addin_request_allowed = true;
static inline bool LWLockAcquireCommon(LWLock *l, LWLockMode mode,
uint64 *valptr, uint64 val);
+static inline void lwlock_report_stat(LWLock *lock);
+
+/*
+ * We keep individual LWLock names here. Other names
+ * obtained from tranches
+ */
+const char *LWLOCK_INDIVIDUAL_NAMES[] =
+{
+ /* Individual LWLocks */
+ "", /* formely was BufFreelistLock */
+ "ShmemIndexLock",
+ "OidGenLock",
+ "XidGenLock",
+ "ProcArrayLock",
+ "SInvalReadLock",
+ "SInvalWriteLock",
+ "WALBufMappingLock",
+ "WALWriteLock",
+ "ControlFileLock",
+ "CheckpointLock",
+ "CLogControlLock",
+ "SubtransControlLock",
+ "MultiXactGenLock",
+ "MultiXactOffsetControlLock",
+ "MultiXactMemberControlLock",
+ "RelCacheInitLock",
+ "CheckpointerCommLock",
+ "TwoPhaseStateLock",
+ "TablespaceCreateLock",
+ "BtreeVacuumLock",
+ "AddinShmemInitLock",
+ "AutovacuumLock",
+ "AutovacuumScheduleLock",
+ "SyncScanLock",
+ "RelationMappingLock",
+ "AsyncCtlLock",
+ "AsyncQueueLock",
+ "SerializableXactHashLock",
+ "SerializableFinishedListLock",
+ "SerializablePredicateLockListLock",
+ "OldSerXidLock",
+ "SyncRepLock",
+ "BackgroundWorkerLock",
+ "DynamicSharedMemoryControlLock",
+ "AutoFileLock",
+ "ReplicationSlotAllocationLock",
+ "ReplicationSlotControlLock",
+ "CommitTsControlLock",
+ "CommitTsLock",
+ "ReplicationOriginLock"
+};
+
+/* Map of base tranches */
+static const struct tranche_map
+{
+ LWLockBaseTranche tranche_id;
+ const char *tranche_name;
+}
+
+baseTranchesMap[] = {
+ {LW_TRANCHE_INDIVIDUAL, "main"},
+ {LW_TRANCHE_BUFFER_MAPPING, "BufferMappingLocks"},
+ {LW_TRANCHE_LOCK_MANAGER, "LockManagerLocks"},
+ {LW_TRANCHE_PREDICATELOCK_MANAGER, "PredicateLockManagerLocks"},
+ {LW_TRANCHE_BUFFER_MANAGER, "BufferManagerLocks"},
+ {LW_TRANCHE_AUXILIARY_PROC, "AuxiliaryProcLocks"},
+ {LW_TRANCHE_CLOG_BUFFERS, "CLogBufferLocks"},
+ {LW_TRANCHE_COMMITTS_BUFFERS, "CommitTSBufferLocks"},
+ {LW_TRANCHE_SUBTRANS_BUFFERS, "SubtransBufferLocks"},
+ {LW_TRANCHE_MULTIXACT_BUFFERS, "MultixactBufferLocks"},
+ {LW_TRANCHE_ASYNC_BUFFERS, "AsyncBufferLocks"},
+ {LW_TRANCHE_OLDSERXID_BUFFERS, "OldSerXidBufferLocks"},
+ {LW_TRANCHE_REPLICATIONSLOT, "ReplicationSlotLocks"},
+ {LW_TRANCHE_USERDEFINED, "UserDefinedLocks"}
+};
#ifdef LWLOCK_STATS
typedef struct lwlock_stats_key
@@ -317,6 +392,33 @@ get_lwlock_stats_entry(LWLock *lock)
}
#endif /* LWLOCK_STATS */
+/*
+ * Initiate base LWLock tranches. All these tranches point to one
+ * array, and used for identification LWLocks from main array
+ */
+static void
+init_base_tranches(void)
+{
+ int i;
+ int id = 0;
+
+ for (i = 0; i < lengthof(baseTranchesMap); i++)
+ {
+ LWLockTranche *tranche = (LWLockTranche *)MemoryContextAllocZero(
+ TopMemoryContext, sizeof(LWLockTranche));
+
+ /* We need to be sure that generated id is equal to map key */
+ Assert(id == baseTranchesMap[i].tranche_id);
+
+ tranche->array_base = MainLWLockArray;
+ tranche->array_stride = sizeof(LWLockPadded);
+ tranche->name = baseTranchesMap[i].tranche_name;
+
+ LWLockRegisterTranche(id, tranche);
+ id = LWLockNewTrancheId();
+ }
+}
+
/*
* Compute number of LWLocks to allocate in the main array.
@@ -374,7 +476,6 @@ NumLWLocks(void)
return numLocks;
}
-
/*
* RequestAddinLWLocks
* Request that extra LWLocks be allocated for use by
@@ -448,6 +549,30 @@ CreateLWLocks(void)
for (id = 0, lock = MainLWLockArray; id < numLocks; id++, lock++)
LWLockInitialize(&lock->lock, 0);
+ /* Initialized tranche id for buffer mapping lwlocks */
+ for (id = 0; id < NUM_BUFFER_PARTITIONS; id++)
+ {
+ LWLock *lock;
+ lock = &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + id].lock;
+ lock->tranche = LW_TRANCHE_BUFFER_MAPPING;
+ }
+
+ /* Initialized tranche id for lock manager lwlocks */
+ for (id = 0; id < NUM_LOCK_PARTITIONS; id++)
+ {
+ LWLock *lock;
+ lock = &MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + id].lock;
+ lock->tranche = LW_TRANCHE_LOCK_MANAGER;
+ }
+
+ /* Initialized tranche id for predicate lock manager lwlocks */
+ for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++)
+ {
+ LWLock *lock;
+ lock = &MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + id].lock;
+ lock->tranche = LW_TRANCHE_PREDICATELOCK_MANAGER;
+ }
+
/*
* Initialize the dynamic-allocation counters, which are stored just
* before the first LWLock. LWLockCounter[0] is the allocation
@@ -469,10 +594,18 @@ CreateLWLocks(void)
LWLockTranchesAllocated * sizeof(LWLockTranche *));
}
- MainLWLockTranche.name = "main";
- MainLWLockTranche.array_base = MainLWLockArray;
- MainLWLockTranche.array_stride = sizeof(LWLockPadded);
- LWLockRegisterTranche(0, &MainLWLockTranche);
+ init_base_tranches();
+}
+
+/* LWLockGroupName - return name of LWLock by its groupId */
+const char *
+LWLockGroupName(int groupId)
+{
+ Assert(groupId != NUM_INDIVIDUAL_LWLOCKS);
+ if (groupId > NUM_INDIVIDUAL_LWLOCKS)
+ return LWLockTrancheArray[groupId - NUM_INDIVIDUAL_LWLOCKS]->name;
+ else
+ return LWLOCK_INDIVIDUAL_NAMES[groupId];
}
/*
@@ -495,7 +628,7 @@ InitLWLockAccess(void)
* LWLocks after startup.
*/
LWLock *
-LWLockAssign(void)
+LWLockAssign(int tranche_id)
{
LWLock *result;
int *LWLockCounter;
@@ -508,11 +641,23 @@ LWLockAssign(void)
elog(ERROR, "no more LWLocks available");
}
result = &MainLWLockArray[LWLockCounter[0]++].lock;
+ result->tranche = tranche_id;
+
SpinLockRelease(ShmemLock);
return result;
}
/*
+ * LWLockUserAssign - assign a dynamically-allocated user defined
+ * LWLock number
+ */
+LWLock *
+LWLockUserAssign(void)
+{
+ return LWLockAssign(LW_TRANCHE_USERDEFINED);
+}
+
+/*
* Allocate a new tranche ID.
*/
int
@@ -572,6 +717,18 @@ LWLockInitialize(LWLock *lock, int tranche_id)
}
/*
+ * Report 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.
+ */
+static inline void
+lwlock_report_stat(LWLock *lock)
+{
+ pgstat_report_wait_start(WAIT_LWLOCK, LWLOCK_GET_GROUP(lock));
+}
+
+/*
* Internal function that tries to atomically acquire the lwlock in the passed
* in mode.
*
@@ -1037,6 +1194,9 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode, uint64 *valptr, uint64 val)
TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
+ /* Report the wait */
+ lwlock_report_stat(lock);
+
for (;;)
{
PGSemaphoreLock(&proc->sem);
@@ -1057,6 +1217,7 @@ LWLockAcquireCommon(LWLock *lock, LWLockMode mode, uint64 *valptr, uint64 val)
}
#endif
+ pgstat_report_wait_end();
TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
LOG_LWDEBUG("LWLockAcquire", lock, "awakened");
@@ -1199,6 +1360,9 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
#endif
TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
+ /* Report the wait */
+ lwlock_report_stat(lock);
+
for (;;)
{
PGSemaphoreLock(&proc->sem);
@@ -1215,6 +1379,8 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
Assert(nwaiters < MAX_BACKENDS);
}
#endif
+
+ pgstat_report_wait_end();
TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened");
@@ -1401,6 +1567,9 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock),
LW_EXCLUSIVE);
+ /* Report the wait */
+ lwlock_report_stat(lock);
+
for (;;)
{
PGSemaphoreLock(&proc->sem);
@@ -1418,6 +1587,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
}
#endif
+ pgstat_report_wait_end();
TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock),
LW_EXCLUSIVE);
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index bad5618..60eb4d4 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -795,7 +795,8 @@ OldSerXidInit(void)
*/
OldSerXidSlruCtl->PagePrecedes = OldSerXidPagePrecedesLogically;
SimpleLruInit(OldSerXidSlruCtl, "OldSerXid SLRU Ctl",
- NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial");
+ NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial",
+ LW_TRANCHE_OLDSERXID_BUFFERS);
/* Override default assumption that writes should be fsync'd */
OldSerXidSlruCtl->do_fsync = false;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 455ad26..b7d6c97 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -225,7 +225,7 @@ InitProcGlobal(void)
{
PGSemaphoreCreate(&(procs[i].sem));
InitSharedLatch(&(procs[i].procLatch));
- procs[i].backendLock = LWLockAssign();
+ procs[i].backendLock = LWLockAssign(LW_TRANCHE_AUXILIARY_PROC);
}
procs[i].pgprocno = i;
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 42a43bb..71661d3 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -37,6 +37,7 @@
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "pg_trace.h"
+#include "pgstat.h"
/* intervals for calling AbsorbFsyncRequests in mdsync and mdpostckpt */
@@ -674,6 +675,8 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
int nbytes;
MdfdVec *v;
+ pgstat_report_wait_start(WAIT_IO, WAIT_IO_READ);
+
TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
reln->smgr_rnode.node.spcNode,
reln->smgr_rnode.node.dbNode,
@@ -702,6 +705,8 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
nbytes,
BLCKSZ);
+ pgstat_report_wait_end();
+
if (nbytes != BLCKSZ)
{
if (nbytes < 0)
@@ -749,6 +754,8 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
Assert(blocknum < mdnblocks(reln, forknum));
#endif
+ pgstat_report_wait_start(WAIT_IO, WAIT_IO_WRITE);
+
TRACE_POSTGRESQL_SMGR_MD_WRITE_START(forknum, blocknum,
reln->smgr_rnode.node.spcNode,
reln->smgr_rnode.node.dbNode,
@@ -777,6 +784,8 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
nbytes,
BLCKSZ);
+ pgstat_report_wait_end();
+
if (nbytes != BLCKSZ)
{
if (nbytes < 0)
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index f7c9bf6..bb67850 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -530,7 +530,7 @@ pg_stat_get_backend_idset(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);
@@ -617,28 +617,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 */
@@ -674,34 +674,58 @@ 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);
+ if (beentry->st_wait_data > 0)
+ {
+ /*
+ * Reassigning of value is important, because st_wait_data
+ * can change if we read class and event separately
+ */
+
+ uint16 wait_data = beentry->st_wait_data;
+ uint8 classId = (uint8)(wait_data >> 8);
+ uint8 eventId = (uint8)wait_data;
+ const char *class_name = pgstat_get_wait_class_name(classId);
+ const char *event_name = pgstat_get_wait_event_name(classId,
+ eventId);
+
+ int size = strlen(class_name) + strlen(event_name) + 3;
+ char *wait_name = (char *)palloc(size);
+ snprintf(wait_name, size, "%s: %s", class_name, event_name);
+
+ values[7] = CStringGetTextDatum(wait_name);
+ pfree(wait_name);
+ }
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
{
@@ -725,20 +749,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)
@@ -749,16 +773,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;
}
}
}
@@ -775,6 +799,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);
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 9c7f019..c574e1e 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -136,7 +136,7 @@ typedef SlruCtlData *SlruCtl;
extern Size SimpleLruShmemSize(int nslots, int nlsns);
extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
- LWLock *ctllock, const char *subdir);
+ LWLock *ctllock, const char *subdir, int lwlocktranche);
extern int SimpleLruZeroPage(SlruCtl ctl, int pageno);
extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
TransactionId xid);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 1d68ad7..05bc0af 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2777,7 +2777,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 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 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 1 0 2249 "23" "{23,26,23,26,25,25,25,16,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,waiting,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 = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9ecc163..a73e047 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -67,6 +67,33 @@ typedef enum StatMsgType
} StatMsgType;
/* ----------
+ * Wait definitions
+ * ----------
+ */
+
+typedef enum WAIT_CLASSES
+{
+ WAIT_UNDEFINED,
+ WAIT_LWLOCK,
+ WAIT_LOCK,
+ WAIT_IO,
+ WAIT_LATCH,
+ WAIT_NETWORK
+} WAIT_CLASSES;
+
+typedef enum WAIT_EVENTS_IO
+{
+ WAIT_IO_READ,
+ WAIT_IO_WRITE
+} WAIT_EVENTS_IO;
+
+typedef enum WAIT_EVENTS_NETWORK
+{
+ WAIT_NETWORK_READ,
+ WAIT_NETWORK_WRITE
+} WAIT_EVENT_NETWORK;
+
+/* ----------
* The data type used for counters.
* ----------
*/
@@ -768,6 +795,14 @@ typedef struct PgBackendStatus
/* Is backend currently waiting on an lmgr lock? */
bool st_waiting;
+ /* Contains class end event of wait. It's in one
+ * variable because we need read it atomically
+ */
+ volatile uint16 st_wait_data;
+
+ /* keep track of nested waits, and skip them */
+ int st_wait_nested;
+
/* current state */
BackendState st_state;
@@ -932,6 +967,12 @@ 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 void pgstat_report_wait_start(uint8 classId, uint8 eventId);
+extern void pgstat_report_wait_end(void);
+extern const char *pgstat_get_wait_class_name(uint8 classId);
+extern const char *pgstat_get_wait_event_name(uint8 classId, uint8 eventId);
+
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);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 96fe3a6..e05bea4 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -39,6 +39,9 @@ extern int Trace_lock_table;
extern bool Debug_deadlocks;
#endif /* LOCK_DEBUG */
+/* Contains names of all heavyweight locks */
+extern PGDLLIMPORT const char *LOCK_NAMES[];
+
/*
* Top-level transactions are identified by VirtualTransactionIDs comprising
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index cff3b99..ffd5525 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -87,6 +87,9 @@ typedef union LWLockPadded
} LWLockPadded;
extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
+/* Individual LWLocks names */
+extern const char *LWLOCK_INDIVIDUAL_NAMES[];
+
/*
* Some commonly-used locks have predefined positions within MainLWLockArray;
* defining macros here makes it much easier to keep track of these. If you
@@ -173,6 +176,31 @@ typedef enum LWLockMode
* to be used as LWLockAcquire argument */
} LWLockMode;
+typedef enum LWLockBaseTranche
+{
+ LW_TRANCHE_INDIVIDUAL,
+ LW_TRANCHE_BUFFER_MAPPING,
+ LW_TRANCHE_LOCK_MANAGER,
+ LW_TRANCHE_PREDICATELOCK_MANAGER,
+ LW_TRANCHE_BUFFER_MANAGER,
+ LW_TRANCHE_AUXILIARY_PROC,
+ LW_TRANCHE_CLOG_BUFFERS,
+ LW_TRANCHE_COMMITTS_BUFFERS,
+ LW_TRANCHE_SUBTRANS_BUFFERS,
+ LW_TRANCHE_MULTIXACT_BUFFERS,
+ LW_TRANCHE_ASYNC_BUFFERS,
+ LW_TRANCHE_OLDSERXID_BUFFERS,
+ LW_TRANCHE_REPLICATIONSLOT,
+ LW_TRANCHE_USERDEFINED,
+} LWLockBaseTranche;
+
+/*
+ * Group for individual lwlocks equal to their index in main array,
+ * other LWLocks identified by their tranche number
+ */
+
+#define LWLOCK_GET_GROUP(lock) \
+ ((lock)->tranche>0? NUM_INDIVIDUAL_LWLOCKS + (lock)->tranche : T_ID(lock))
#ifdef LOCK_DEBUG
extern bool Trace_lwlocks;
@@ -192,6 +220,7 @@ extern void LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 value);
extern Size LWLockShmemSize(void);
extern void CreateLWLocks(void);
extern void InitLWLockAccess(void);
+extern const char *LWLockGroupName(int groupId);
/*
* The traditional method for obtaining an lwlock for use by an extension is
@@ -200,7 +229,10 @@ extern void InitLWLockAccess(void);
* a lock can be allocated using LWLockAssign.
*/
extern void RequestAddinLWLocks(int n);
-extern LWLock *LWLockAssign(void);
+extern LWLock *LWLockAssign(int tranche_id);
+
+/* Allocates LWLock in UserDefinedLocks tranche */
+extern LWLock *LWLockUserAssign(void);
/*
* There is another, more flexible method of obtaining lwlocks. First, call
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index cd53375..1bafb75 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1647,12 +1647,13 @@ pg_stat_activity| SELECT s.datid,
s.query_start,
s.state_change,
s.waiting,
+ 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, waiting, 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,
@@ -1758,7 +1759,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, waiting, 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));
@@ -1769,7 +1770,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, waiting, 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,
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers