On 07/28/2015 10:28 PM, Heikki Linnakangas wrote:
On 07/27/2015 01:20 PM, Ildus Kurbangaliev wrote:
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).

This needs some work in order to be maintainable:

* The patch requires that the LWLOCK_INDIVIDUAL_NAMES array is kept in sync with the list of individual locks in lwlock.h. Sooner or later someone will add an LWLock and forget to update the names-array. That needs to be made less error-prone, so that the names are maintained in the same place as the #defines. Perhaps something like rmgrlist.h.

* The "base" tranches are a bit funny. They all have the same array_base, pointing to MainLWLockArray. If there are e.g. 5 clog buffer locks, I would expect the T_NAME() to return "ClogBufferLocks" for all of them, and T_ID() to return numbers between 0-4. But in reality, T_ID() will return something like 55-59.

Instead of passing a tranche-id to LWLockAssign(), I think it would be more clear to have a new function to allocate a contiguous block of lwlocks as a new tranche. It could then set the base correctly.

* Instead of having LWLOCK_INDIVIDUAL_NAMES to name "individual" locks, how about just giving each one of them a separate tranche?

* User manual needs to be updated to explain the new column in pg_stat_activity.

- Heikki


Hello. Thanks for review. I attached new version of patch.

It adds new field in pg_stat_activity that shows current wait in backend.

I've did a some refactoring LWLocks tranche mechanism. In lwlock.c only
invididual and user defined LWLocks is creating, other LWLocks created by
modules who need them. I think that is more logical (user know about module,
not module about of all users). It also simplifies LWLocks acquirement.

Now each individual LWLock and other groups of LWLocks have their tranche, and can be easily identified. If somebody will add new individual LWLock and forget to add its name, postgres will show a message. Individual LWLocks still allocated in
one array but tranches for them point to particular index in main array.

Sample:

b1=# select pid, wait_event from pg_stat_activity; \watch 1

 pid  |       wait_event
------+-------------------------
 7722 | Storage: READ
 7653 |
 7723 | Network: WRITE
 7725 | Network: READ
 7727 | Locks: Transaction
 7731 | Storage: READ
 7734 | Network: READ
 7735 | Storage: READ
 7739 | LWLocks: WALInsertLocks
 7738 | Locks: Transaction
 7740 | LWLocks: BufferMgrLocks
 7741 | Network: READ
 7742 | Network: READ
 7743 | Locks: Transaction


--
Ildus Kurbangaliev
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e64b7ef..2e4e67e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -630,6 +630,11 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      <entry>True if this backend is currently waiting on a lock</entry>
     </row>
     <row>
+     <entry><structfield>wait_event</></entry>
+     <entry><type>text</></entry>
+     <entry>Name of a current wait event in backend</entry>
+    </row>
+    <row>
      <entry><structfield>state</></entry>
      <entry><type>text</></entry>
      <entry>Current overall state of this backend.
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3a58f1e..10c25cf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -457,7 +457,8 @@ CLOGShmemInit(void)
 {
 	ClogCtl->PagePrecedes = CLOGPagePrecedes;
 	SimpleLruInit(ClogCtl, "CLOG Ctl", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
-				  CLogControlLock, "pg_clog");
+				  CLogControlLock, "pg_clog",
+				  "CLogBufferLocks");
 }
 
 /*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 5ad35c0..dd7578f 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",
+				  "CommitTSBufferLocks");
 
 	commitTsShared = ShmemInitStruct("CommitTs shared",
 									 sizeof(CommitTimestampShared),
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1933a87..b905c59 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",
+				  "MultiXactOffsetBufferLocks");
 	SimpleLruInit(MultiXactMemberCtl,
 				  "MultiXactMember Ctl", NUM_MXACTMEMBER_BUFFERS, 0,
-				  MultiXactMemberControlLock, "pg_multixact/members");
+				  MultiXactMemberControlLock, "pg_multixact/members",
+				  "MultiXactMemberBufferLocks");
 
 	/* 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..4bf3fee 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -156,15 +156,20 @@ SimpleLruShmemSize(int nslots, int nlsns)
 	if (nlsns > 0)
 		sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));	/* group_lsn[] */
 
+	/* size of lwlocks */
+	sz = add_size(sz, LWLockTrancheShmemSize(nslots));
+
 	return BUFFERALIGN(sz) + BLCKSZ * nslots;
 }
 
 void
 SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
-			  LWLock *ctllock, const char *subdir)
+			  LWLock *ctllock, const char *subdir,
+			  const char *lwlocks_tranche)
 {
-	SlruShared	shared;
-	bool		found;
+	SlruShared    shared;
+	bool          found;
+	LWLockPadded *lwlock_array;
 
 	shared = (SlruShared) ShmemInitStruct(name,
 										  SimpleLruShmemSize(nslots, nlsns),
@@ -212,13 +217,18 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
 		}
 
 		ptr += BUFFERALIGN(offset);
+
+		/* Create tranche and lwlocks required for slots */
+		LWLockCreateTranche(lwlocks_tranche, nslots, &lwlock_array);
+
+		/* Initialize slots */
 		for (slotno = 0; slotno < nslots; slotno++)
 		{
 			shared->page_buffer[slotno] = ptr;
 			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] = &lwlock_array[slotno].lock;
 			ptr += BLCKSZ;
 		}
 	}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6b70982..eed2fd9 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",
+				  "SubtransBufferLocks");
 	/* Override default assumption that writes should be fsync'd */
 	SubTransCtl->do_fsync = false;
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f06b51d..bf79504 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4679,11 +4679,12 @@ XLOGShmemInit(void)
 
 	XLogCtl->Insert.WALInsertLockTrancheId = LWLockNewTrancheId();
 
-	XLogCtl->Insert.WALInsertLockTranche.name = "WALInsertLocks";
+	strcpy(XLogCtl->Insert.WALInsertLockTranche.name, "WALInsertLocks");
 	XLogCtl->Insert.WALInsertLockTranche.array_base = WALInsertLocks;
 	XLogCtl->Insert.WALInsertLockTranche.array_stride = sizeof(WALInsertLockPadded);
 
-	LWLockRegisterTranche(XLogCtl->Insert.WALInsertLockTrancheId, &XLogCtl->Insert.WALInsertLockTranche);
+	LWLockRegisterTranche(XLogCtl->Insert.WALInsertLockTrancheId,
+		&XLogCtl->Insert.WALInsertLockTranche);
 	for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
 	{
 		LWLockInitialize(&WALInsertLocks[i].l.lock,
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c0bd6fa..c4d01be 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -623,6 +623,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..7b5f00e 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", "AsyncBufferLocks");
 	/* 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 26d8faa..d99f833 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;
@@ -122,6 +123,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;
@@ -168,6 +171,7 @@ retry:
 	 * interrupts from being processed.
 	 */
 	ProcessClientReadInterrupt(false);
+	pgstat_report_wait_end();
 
 	return n;
 }
@@ -202,6 +206,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
@@ -247,6 +253,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 ab018c4..8d5ff6bc 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
@@ -2929,6 +2939,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 LWLOCK_TRANCHE_NAME(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/logical/origin.c b/src/backend/replication/logical/origin.c
index f4ba86e..c254a62 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -470,7 +470,7 @@ ReplicationOriginShmemInit(void)
 		int			i;
 
 		replication_states_ctl->tranche_id = LWLockNewTrancheId();
-		replication_states_ctl->tranche.name = "ReplicationOrigins";
+		strcpy(replication_states_ctl->tranche.name, "ReplicationOrigins");
 		replication_states_ctl->tranche.array_base =
 			&replication_states[0].lock;
 		replication_states_ctl->tranche.array_stride =
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index f8544de..04b0805 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -118,6 +118,9 @@ ReplicationSlotsShmemSize(void)
 	size = add_size(size,
 					mul_size(max_replication_slots, sizeof(ReplicationSlot)));
 
+	/* size of lwlocks */
+	size = add_size(size, LWLockTrancheShmemSize(max_replication_slots));
+
 	return size;
 }
 
@@ -127,7 +130,8 @@ ReplicationSlotsShmemSize(void)
 void
 ReplicationSlotsShmemInit(void)
 {
-	bool		found;
+	bool         found;
+	LWLockPadded *lwlocks_array;
 
 	if (max_replication_slots == 0)
 		return;
@@ -143,13 +147,17 @@ ReplicationSlotsShmemInit(void)
 		/* First time through, so initialize */
 		MemSet(ReplicationSlotCtl, 0, ReplicationSlotsShmemSize());
 
+		/* Create lwlocks */
+		LWLockCreateTranche("ReplicationSlotLocks", max_replication_slots,
+			&lwlocks_array);
+
 		for (i = 0; i < max_replication_slots; i++)
 		{
 			ReplicationSlot *slot = &ReplicationSlotCtl->replication_slots[i];
 
 			/* everything else is zeroed by the memset above */
 			SpinLockInit(&slot->mutex);
-			slot->io_in_progress_lock = LWLockAssign();
+			slot->io_in_progress_lock = &lwlocks_array[i].lock;
 		}
 	}
 }
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 3ae2848..40cf33f 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -18,8 +18,9 @@
 #include "storage/buf_internals.h"
 
 
-BufferDescPadded *BufferDescriptors;
-char	   *BufferBlocks;
+BufferDescPadded  *BufferDescriptors;
+char              *BufferBlocks;
+LWLockPadded      *BufferLWLockArray;
 
 
 /*
@@ -64,8 +65,9 @@ char	   *BufferBlocks;
 void
 InitBufferPool(void)
 {
-	bool		foundBufs,
-				foundDescs;
+	bool          foundBufs;
+	bool          foundDescs;
+	LWLockPadded *lwlocks_array;
 
 	/* Align descriptors to a cacheline boundary. */
 	BufferDescriptors = (BufferDescPadded *) CACHELINEALIGN(
@@ -77,6 +79,10 @@ InitBufferPool(void)
 		ShmemInitStruct("Buffer Blocks",
 						NBuffers * (Size) BLCKSZ, &foundBufs);
 
+	/* Init LWLocks for buffer headers */
+	LWLockCreateTranche("BufferMgrLocks", 2 * NBuffers,
+		&lwlocks_array);
+
 	if (foundDescs || foundBufs)
 	{
 		/* both should be present or neither */
@@ -110,14 +116,18 @@ InitBufferPool(void)
 			 */
 			buf->freeNext = i + 1;
 
-			buf->io_in_progress_lock = LWLockAssign();
-			buf->content_lock = LWLockAssign();
+			buf->io_in_progress_lock = &lwlocks_array[i * 2].lock;
+			buf->content_lock = &lwlocks_array[i * 2 + 1].lock;
 		}
 
 		/* Correct last entry of linked list */
 		GetBufferDescriptor(NBuffers - 1)->freeNext = FREENEXT_END_OF_LIST;
 	}
 
+	/* Init bufmgr LWLocks */
+	LWLockCreateTranche("BufferLWLocks", NUM_BUFFER_PARTITIONS,
+		&BufferLWLockArray);
+
 	/* Init other shared buffer-management stuff */
 	StrategyInitialize(!foundDescs);
 }
@@ -144,5 +154,9 @@ BufferShmemSize(void)
 	/* size of stuff controlled by freelist.c */
 	size = add_size(size, StrategyShmemSize());
 
+	/* size of LWLock structures required for buffers */
+	size = add_size(size, LWLockTrancheShmemSize(NUM_BUFFER_PARTITIONS));
+	size = add_size(size, LWLockTrancheShmemSize(2 * NBuffers));
+
 	return size;
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 1eb2d4b..85e758e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -48,12 +48,29 @@
 #include "utils/resowner_private.h"
 
 
+/* LWLocks tranche and array */
+LWLockPadded		    *LockMgrLWLockArray;
+
 /* This configuration variable is used to set the lock table size */
 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.
@@ -446,6 +463,10 @@ InitLocks(void)
 									  16,
 									  &info,
 									  HASH_ELEM | HASH_BLOBS);
+
+	/* Init LWLocks tranche and array */
+	LWLockCreateTranche("LockMgrLWLocks", NUM_LOCK_PARTITIONS,
+		&LockMgrLWLockArray);
 }
 
 
@@ -1591,6 +1612,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 +1661,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 +1677,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);
@@ -3282,6 +3306,9 @@ LockShmemSize(void)
 	 */
 	size = add_size(size, size / 10);
 
+	/* Lock Manager LWLock structures */
+	size = add_size(size, LWLockTrancheShmemSize(NUM_LOCK_PARTITIONS));
+
 	return size;
 }
 
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 687ed63..ff925f5 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -82,6 +82,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"
@@ -110,11 +111,9 @@ extern slock_t *ShmemLock;
 #define LW_SHARED_MASK				((uint32)(1 << 23))
 
 /*
- * This is indexed by tranche ID and stores metadata for all tranches known
- * to the current backend.
+ * This is indexed by tranche ID and stores metadata for all tranches
  */
-static LWLockTranche **LWLockTrancheArray = NULL;
-static int	LWLockTranchesAllocated = 0;
+LWLockTranche **LWLockTrancheArray = NULL;
 
 #define T_NAME(lock) \
 	(LWLockTrancheArray[(lock)->tranche]->name)
@@ -129,7 +128,9 @@ static int	LWLockTranchesAllocated = 0;
  * where we have special measures to pass it down).
  */
 LWLockPadded *MainLWLockArray = NULL;
-static LWLockTranche MainLWLockTranche;
+
+/* Points to the array of user defined LWLocks in shared memory */
+static LWLockPadded *userdef_lwlocks_array;
 
 /*
  * We use this structure to keep track of locked LWLocks for release
@@ -173,6 +174,64 @@ static HTAB *lwlock_stats_htab;
 static lwlock_stats lwlock_stats_dummy;
 #endif
 
+/* Wraps pgstat_report_wait_start for LWLocks */
+static inline void lwlock_report_stat(LWLock *lock);
+
+/*
+ * We keep individual LWLock names here. This array
+ * used to create tranches for individual LWLocks
+ */
+static const char *INDIVIDUAL_LWLOCK_NAMES[] =
+{
+	"", /* 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",
+
+	/*
+	 * Indicates end of array, used for control that every individual
+	 * LWLock has its name
+	 */
+	"",
+};
+
 #ifdef LOCK_DEBUG
 bool		Trace_lwlocks = false;
 
@@ -316,64 +375,6 @@ get_lwlock_stats_entry(LWLock *lock)
 }
 #endif   /* LWLOCK_STATS */
 
-
-/*
- * Compute number of LWLocks to allocate in the main array.
- */
-static int
-NumLWLocks(void)
-{
-	int			numLocks;
-
-	/*
-	 * Possibly this logic should be spread out among the affected modules,
-	 * the same way that shmem space estimation is done.  But for now, there
-	 * are few enough users of LWLocks that we can get away with just keeping
-	 * the knowledge here.
-	 */
-
-	/* Predefined LWLocks */
-	numLocks = NUM_FIXED_LWLOCKS;
-
-	/* bufmgr.c needs two for each shared buffer */
-	numLocks += 2 * NBuffers;
-
-	/* proc.c needs one for each backend or auxiliary process */
-	numLocks += MaxBackends + NUM_AUXILIARY_PROCS;
-
-	/* clog.c needs one per CLOG buffer */
-	numLocks += CLOGShmemBuffers();
-
-	/* commit_ts.c needs one per CommitTs buffer */
-	numLocks += CommitTsShmemBuffers();
-
-	/* subtrans.c needs one per SubTrans buffer */
-	numLocks += NUM_SUBTRANS_BUFFERS;
-
-	/* multixact.c needs two SLRU areas */
-	numLocks += NUM_MXACTOFFSET_BUFFERS + NUM_MXACTMEMBER_BUFFERS;
-
-	/* async.c needs one per Async buffer */
-	numLocks += NUM_ASYNC_BUFFERS;
-
-	/* predicate.c needs one per old serializable xid buffer */
-	numLocks += NUM_OLDSERXID_BUFFERS;
-
-	/* slot.c needs one for each slot */
-	numLocks += max_replication_slots;
-
-	/*
-	 * Add any requested by loadable modules; for backwards-compatibility
-	 * reasons, allocate at least NUM_USER_DEFINED_LWLOCKS of them even if
-	 * there are no explicit requests.
-	 */
-	lock_addin_request_allowed = false;
-	numLocks += Max(lock_addin_request, NUM_USER_DEFINED_LWLOCKS);
-
-	return numLocks;
-}
-
-
 /*
  * RequestAddinLWLocks
  *		Request that extra LWLocks be allocated for use by
@@ -393,21 +394,59 @@ RequestAddinLWLocks(int n)
 	lock_addin_request += n;
 }
 
+/*
+ * Return number of user defined LWLocks
+ */
+static int
+NumUserDefinedLWLocks()
+{
+	/*
+	 * Add any requested by loadable modules; for backwards-compatibility
+	 * reasons, allocate at least NUM_USER_DEFINED_LWLOCKS of them even if
+	 * there are no explicit requests.
+	 */
+
+	lock_addin_request_allowed = false;
+	return Max(lock_addin_request, NUM_USER_DEFINED_LWLOCKS);
+}
+
+/*
+ * Compute shmem space for LWLock counters, individual LWLocks array
+ * and tranches
+ */
+static Size
+LWLocksIndividualShmemSize(void)
+{
+	Size		size;
+
+	/* Space for dynamic allocation counter, plus room for alignment. */
+	size = 3 * sizeof(int) + LWLOCK_PADDED_SIZE;
+
+	/* Space for individual LWLock tranches */
+	size = add_size(size,
+		mul_size(sizeof(LWLockTranche), NUM_INDIVIDUAL_LWLOCKS));
+
+	/* Space for individual LWLocks */
+	size = add_size(size,
+		mul_size(sizeof(LWLockPadded), NUM_INDIVIDUAL_LWLOCKS));
+
+	return size;
+}
 
 /*
- * Compute shmem space needed for LWLocks.
+ * Compute shmem space needed by LWLocks initialization
  */
 Size
 LWLockShmemSize(void)
 {
-	Size		size;
-	int			numLocks = NumLWLocks();
+	Size size = LWLocksIndividualShmemSize();
 
-	/* Space for the LWLock array. */
-	size = mul_size(numLocks, sizeof(LWLockPadded));
+	/* Space for tranches array */
+	size = add_size(size,
+		mul_size(sizeof(LWLockTranche **), NUM_LWLOCK_TRANCHES));
 
-	/* Space for dynamic allocation counter, plus room for alignment. */
-	size = add_size(size, 3 * sizeof(int) + LWLOCK_PADDED_SIZE);
+	/* Space for user defined lwlocks */
+	size = add_size(size, LWLockTrancheShmemSize(NumUserDefinedLWLocks()));
 
 	return size;
 }
@@ -415,7 +454,7 @@ LWLockShmemSize(void)
 
 /*
  * Allocate shmem space for the main LWLock array and initialize it.  We also
- * register the main tranch here.
+ * register the tranches for individual LWLocks here.
  */
 void
 CreateLWLocks(void)
@@ -425,12 +464,16 @@ CreateLWLocks(void)
 
 	if (!IsUnderPostmaster)
 	{
-		int			numLocks = NumLWLocks();
-		Size		spaceLocks = LWLockShmemSize();
-		LWLockPadded *lock;
-		int		   *LWLockCounter;
-		char	   *ptr;
-		int			id;
+		int           *LWLockCounter;
+		int            i;
+		char          *ptr;
+		Size           spaceLocks = LWLocksIndividualShmemSize();
+		int            numUserLocks = NumUserDefinedLWLocks();
+		LWLockTranche *tranche;
+
+		/* Init LWLock tranches array */
+		LWLockTrancheArray = (LWLockTranche **)ShmemAlloc(
+			mul_size(sizeof(LWLockTranche**), NUM_LWLOCK_TRANCHES));
 
 		/* Allocate space */
 		ptr = (char *) ShmemAlloc(spaceLocks);
@@ -443,35 +486,53 @@ CreateLWLocks(void)
 
 		MainLWLockArray = (LWLockPadded *) ptr;
 
-		/* Initialize all LWLocks in main array */
-		for (id = 0, lock = MainLWLockArray; id < numLocks; id++, lock++)
-			LWLockInitialize(&lock->lock, 0);
+		/* Now points to individual LWlock tranches */
+		ptr += mul_size(sizeof(LWLockPadded), NUM_INDIVIDUAL_LWLOCKS);
 
 		/*
 		 * Initialize the dynamic-allocation counters, which are stored just
 		 * before the first LWLock.  LWLockCounter[0] is the allocation
 		 * counter for lwlocks, LWLockCounter[1] is the maximum number that
-		 * can be allocated from the main array, and LWLockCounter[2] is the
-		 * allocation counter for tranches.
+		 * can be allocated from the user defined lwlocks array,
+		 * and LWLockCounter[2] is the allocation counter for tranches.
 		 */
 		LWLockCounter = (int *) ((char *) MainLWLockArray - 3 * sizeof(int));
-		LWLockCounter[0] = NUM_FIXED_LWLOCKS;
-		LWLockCounter[1] = numLocks;
-		LWLockCounter[2] = 1;	/* 0 is the main array */
-	}
+		LWLockCounter[0] = 0;
+		LWLockCounter[1] = numUserLocks;
+		LWLockCounter[2] = 0;
 
-	if (LWLockTrancheArray == NULL)
-	{
-		LWLockTranchesAllocated = 16;
-		LWLockTrancheArray = (LWLockTranche **)
-			MemoryContextAlloc(TopMemoryContext,
-						  LWLockTranchesAllocated * sizeof(LWLockTranche *));
-	}
+		tranche = (LWLockTranche *) ptr;
 
-	MainLWLockTranche.name = "main";
-	MainLWLockTranche.array_base = MainLWLockArray;
-	MainLWLockTranche.array_stride = sizeof(LWLockPadded);
-	LWLockRegisterTranche(0, &MainLWLockTranche);
+		/* Create tranches for individual LWLocks */
+		for (i = 0; i < NUM_INDIVIDUAL_LWLOCKS; i++, tranche++)
+		{
+			int id = LWLockNewTrancheId();
+
+			/*
+			 * We need to be sure that generated id is equal to index
+			 * for individual LWLocks
+			 */
+			Assert(id == i);
+
+			if (i > 0 && strcmp(INDIVIDUAL_LWLOCK_NAMES[i], "") == 0)
+				elog(ERROR, "Individual LWLock hasn't a name. "\
+					"You must add name to INDIVIDUAL_LWLOCK_NAMES array");
+
+			tranche->array_base = MainLWLockArray + i;
+			tranche->array_stride = sizeof(LWLockPadded);
+			strcpy(tranche->name, INDIVIDUAL_LWLOCK_NAMES[i]);
+
+			/* Initialize individual LWLock */
+			LWLockInitialize(&MainLWLockArray[i].lock, id);
+
+			/* Register new tranche in tranches array */
+			LWLockRegisterTranche(id, tranche);
+		}
+
+		/* Create tranche for user defined LWLocks */
+		LWLockCreateTranche("UserDefinedLocks", numUserLocks,
+			&userdef_lwlocks_array);
+	}
 }
 
 /*
@@ -506,7 +567,8 @@ LWLockAssign(void)
 		SpinLockRelease(ShmemLock);
 		elog(ERROR, "no more LWLocks available");
 	}
-	result = &MainLWLockArray[LWLockCounter[0]++].lock;
+	result = &userdef_lwlocks_array[LWLockCounter[0]++].lock;
+
 	SpinLockRelease(ShmemLock);
 	return result;
 }
@@ -529,30 +591,76 @@ LWLockNewTrancheId(void)
 }
 
 /*
- * Register a tranche ID in the lookup table for the current process.  This
- * routine will save a pointer to the tranche object passed as an argument,
- * so that object should be allocated in a backend-lifetime context
- * (TopMemoryContext, static variable, or similar).
+ * Register a tranche ID in the lookup table in shared memory.
+ * Tranche object must be allocated in shared memory previously
  */
 void
 LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche)
 {
-	Assert(LWLockTrancheArray != NULL);
+	Assert(ShmemAddrIsValid((void *)tranche));
+	LWLockTrancheArray[tranche_id] = tranche;
+}
 
-	if (tranche_id >= LWLockTranchesAllocated)
-	{
-		int			i = LWLockTranchesAllocated;
+/*
+ * LWLockCreateTranche - create new tranche for LWLockPadded based LWLocks
+ *
+ * Space for LWLocks and LWLockTranche must be already acquired in
+ * shared memory.
+ * If LWLocks are not based on LWLockPadded then backend must register
+ * tranche itself with LWLockNewTrancheId and LWLockRegisterTranche functions
+ */
+void
+LWLockCreateTranche(const char *tranche_name, int locks_count,
+	LWLockPadded **array)
+{
+	LWLockTranche *tranche;
+	int tranche_id;
 
-		while (i <= tranche_id)
-			i *= 2;
+	Assert(strlen(tranche_name) < LWLOCK_MAX_TRANCHE_NAME);
 
-		LWLockTrancheArray = (LWLockTranche **)
-			repalloc(LWLockTrancheArray,
-					 i * sizeof(LWLockTranche *));
-		LWLockTranchesAllocated = i;
-	}
+	/* Generate id for new tranche */
+	tranche_id = LWLockNewTrancheId();
 
-	LWLockTrancheArray[tranche_id] = tranche;
+	/* Allocate space in shared memory for tranche */
+	tranche = (LWLockTranche *) ShmemAlloc(sizeof(LWLockTranche));
+
+	if (tranche == NULL)
+		ereport(PANIC, (errcode(ERRCODE_OUT_OF_MEMORY),
+						errmsg("out of memory")));
+
+	/* Allocate space in shared memory for lwlocks */
+	*array = (LWLockPadded *) ShmemAlloc(
+		mul_size(sizeof(LWLockPadded), locks_count));
+
+	if (*array == NULL)
+		ereport(PANIC, (errcode(ERRCODE_OUT_OF_MEMORY),
+						errmsg("out of memory")));
+
+	/* Init tranche fields */
+	strcpy(tranche->name, tranche_name);
+	tranche->array_base = (void *)*array;
+	tranche->array_stride = sizeof(LWLockPadded);
+
+	LWLockRegisterTranche(tranche_id, tranche);
+
+	/* Initialize new LWLocks within created tranche */
+	for (int i=0; i < locks_count; i++)
+		LWLockInitialize(&(*array)[i].lock, tranche_id);
+}
+
+/*
+ * LWLockTrancheShmemSize - calculate size required in shared memory for
+ * for tranche with locks_count of LWLocks.
+ *
+ * This function used in pair with LWLockCreateTranche
+ */
+Size
+LWLockTrancheShmemSize(int locks_count)
+{
+	Size size;
+	size = MAXALIGN(sizeof(LWLockTranche));
+	size = add_size(size, mul_size(sizeof(LWLockPadded), locks_count));
+	return size;
 }
 
 /*
@@ -571,6 +679,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, lock->tranche);
+}
+
+/*
  * Internal function that tries to atomically acquire the lwlock in the passed
  * in mode.
  *
@@ -1021,6 +1141,9 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 
 		TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
 
+		/* Report the wait */
+		lwlock_report_stat(lock);
+
 		for (;;)
 		{
 			PGSemaphoreLock(&proc->sem);
@@ -1041,6 +1164,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 		}
 #endif
 
+		pgstat_report_wait_end();
 		TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
 
 		LOG_LWDEBUG("LWLockAcquire", lock, "awakened");
@@ -1179,6 +1303,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);
@@ -1195,6 +1322,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");
@@ -1404,6 +1533,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);
@@ -1421,6 +1553,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..af4bb25 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -239,13 +239,20 @@
  * apply one of these macros.
  * NB: NUM_PREDICATELOCK_PARTITIONS must be a power of 2!
  */
+
+/* Number of partitions the shared predicate lock tables are divided into */
+#define LOG2_NUM_PREDICATELOCK_PARTITIONS  4
+#define NUM_PREDICATELOCK_PARTITIONS  (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS)
+
+/* LWLocks tranche and array */
+static LWLockPadded		*PredLWLockArray;
+
 #define PredicateLockHashPartition(hashcode) \
 	((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
 #define PredicateLockHashPartitionLock(hashcode) \
-	(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + \
-		PredicateLockHashPartition(hashcode)].lock)
+	(&PredLWLockArray[PredicateLockHashPartition(hashcode)].lock)
 #define PredicateLockHashPartitionLockByIndex(i) \
-	(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
+	(&PredLWLockArray[i].lock)
 
 #define NPREDICATELOCKTARGETENTS() \
 	mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
@@ -395,6 +402,8 @@ static LWLock *ScratchPartitionLock;
  */
 static HTAB *LocalPredicateLockHash = NULL;
 
+
+
 /*
  * Keep a pointer to the currently-running serializable transaction (if any)
  * for quick reference. Also, remember if we have written anything that could
@@ -795,7 +804,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",
+				  "OldSerXidBufferLocks");
 	/* Override default assumption that writes should be fsync'd */
 	OldSerXidSlruCtl->do_fsync = false;
 
@@ -1289,6 +1299,9 @@ InitPredicateLocks(void)
 	/* Pre-calculate the hash and partition lock of the scratch entry */
 	ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
 	ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
+
+	LWLockCreateTranche("PredicateLWLocks", NUM_PREDICATELOCK_PARTITIONS,
+		&PredLWLockArray);
 }
 
 /*
@@ -1340,6 +1353,9 @@ PredicateLockShmemSize(void)
 	size = add_size(size, sizeof(OldSerXidControlData));
 	size = add_size(size, SimpleLruShmemSize(NUM_OLDSERXID_BUFFERS, 0));
 
+	/* LWLocks */
+	size = add_size(size, LWLockTrancheShmemSize(NUM_PREDICATELOCK_PARTITIONS));
+
 	return size;
 }
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 884e91b..a0b4170 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -114,6 +114,10 @@ ProcGlobalShmemSize(void)
 	size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT)));
 	size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT)));
 
+	/* LWLocks */
+	size = add_size(size,
+		LWLockTrancheShmemSize(MaxBackends + NUM_AUXILIARY_PROCS));
+
 	return size;
 }
 
@@ -157,12 +161,13 @@ ProcGlobalSemas(void)
 void
 InitProcGlobal(void)
 {
-	PGPROC	   *procs;
-	PGXACT	   *pgxacts;
-	int			i,
-				j;
-	bool		found;
-	uint32		TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+	PGPROC       *procs;
+	PGXACT       *pgxacts;
+	LWLockPadded *lwlocks_array;
+	int           i, j;
+	bool          found;
+	uint32        TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS
+		+ max_prepared_xacts;
 
 	/* Create the ProcGlobal shared structure */
 	ProcGlobal = (PROC_HDR *)
@@ -212,6 +217,10 @@ InitProcGlobal(void)
 	MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
 	ProcGlobal->allPgXact = pgxacts;
 
+	/* Create LWLocks */
+	LWLockCreateTranche("ProcessLocks", MaxBackends + NUM_AUXILIARY_PROCS,
+		&lwlocks_array);
+
 	for (i = 0; i < TotalProcs; i++)
 	{
 		/* Common initialization for all PGPROCs, regardless of type. */
@@ -225,7 +234,7 @@ InitProcGlobal(void)
 		{
 			PGSemaphoreCreate(&(procs[i].sem));
 			InitSharedLatch(&(procs[i].procLatch));
-			procs[i].backendLock = LWLockAssign();
+			procs[i].backendLock = &lwlocks_array[i].lock;
 		}
 		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..d9e9582 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -136,7 +136,8 @@ 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,
+			  const char *lwlocks_tranche);
 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 c9fe0f8..c08e69a 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/buf_internals.h b/src/include/storage/buf_internals.h
index 521ee1c..1c50d68 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -53,6 +53,10 @@ typedef bits16 BufFlags;
  */
 #define BM_MAX_USAGE_COUNT	5
 
+/* Number of partitions of the shared buffer mapping hashtable */
+#define NUM_BUFFER_PARTITIONS  128
+
+
 /*
  * Buffer tag identifies which disk block the buffer contains.
  *
@@ -104,10 +108,8 @@ typedef struct buftag
 #define BufTableHashPartition(hashcode) \
 	((hashcode) % NUM_BUFFER_PARTITIONS)
 #define BufMappingPartitionLock(hashcode) \
-	(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + \
-		BufTableHashPartition(hashcode)].lock)
-#define BufMappingPartitionLockByIndex(i) \
-	(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock)
+	(&BufferLWLockArray[BufTableHashPartition(hashcode)].lock)
+#define BufMappingPartitionLockByIndex(i) (&BufferLWLockArray[i].lock)
 
 /*
  *	BufferDesc -- shared descriptor/state data for a single shared buffer.
@@ -206,6 +208,7 @@ typedef union BufferDescPadded
 
 /* in buf_init.c */
 extern PGDLLIMPORT BufferDescPadded *BufferDescriptors;
+extern PGDLLIMPORT LWLockPadded *BufferLWLockArray;
 
 /* in localbuf.c */
 extern BufferDesc *LocalBufferDescriptors;
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 96fe3a6..b357c2d 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
@@ -490,13 +493,19 @@ typedef enum
  * hash code with LockTagHashCode(), then apply one of these macros.
  * NB: NUM_LOCK_PARTITIONS must be a power of 2!
  */
+
+/* Number of partitions the shared lock tables are divided into */
+#define LOG2_NUM_LOCK_PARTITIONS  4
+#define NUM_LOCK_PARTITIONS  (1 << LOG2_NUM_LOCK_PARTITIONS)
+
+extern PGDLLIMPORT LWLockPadded *LockMgrLWLockArray;
+
 #define LockHashPartition(hashcode) \
 	((hashcode) % NUM_LOCK_PARTITIONS)
 #define LockHashPartitionLock(hashcode) \
-	(&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + \
-		LockHashPartition(hashcode)].lock)
+	(&LockMgrLWLockArray[LockHashPartition(hashcode)].lock)
 #define LockHashPartitionLockByIndex(i) \
-	(&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
+	(&LockMgrLWLockArray[i].lock)
 
 /*
  * function prototypes
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index cbd6318..e2211ed 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -33,13 +33,22 @@ struct PGPROC;
  * be an array of lwlocks, but rather some larger data structure that includes
  * one or more lwlocks per element.
  */
+
+#define NUM_LWLOCK_TRANCHES 64
+#define LWLOCK_MAX_TRANCHE_NAME 64
+
 typedef struct LWLockTranche
 {
-	const char *name;
+	char name[LWLOCK_MAX_TRANCHE_NAME];
 	void	   *array_base;
 	Size		array_stride;
 } LWLockTranche;
 
+extern PGDLLIMPORT LWLockTranche **LWLockTrancheArray;
+
+#define LWLOCK_TRANCHE_NAME(tranche_id) \
+	(LWLockTrancheArray[tranche_id]->name)
+
 /*
  * Code outside of lwlock.c should not manipulate the contents of this
  * structure directly, but we have to declare it here to allow LWLocks to be
@@ -85,6 +94,7 @@ typedef union LWLockPadded
 	LWLock		lock;
 	char		pad[LWLOCK_PADDED_SIZE];
 } LWLockPadded;
+
 extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
 /*
@@ -92,7 +102,8 @@ extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
  * defining macros here makes it much easier to keep track of these.  If you
  * add a lock, add it to the end to avoid renumbering the existing locks;
  * if you remove a lock, consider leaving a gap in the numbering sequence for
- * the benefit of DTrace and other external debugging scripts.
+ * the benefit of DTrace and other external debugging scripts; names for
+ * individual locks keeped in corresponding array, don't forget add it
  */
 /* 0 is available; was formerly BufFreelistLock */
 #define ShmemIndexLock				(&MainLWLockArray[1].lock)
@@ -138,32 +149,6 @@ extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
 #define NUM_INDIVIDUAL_LWLOCKS		41
 
-/*
- * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS
- * here, but we need them to figure out offsets within MainLWLockArray, and
- * having this file include lock.h or bufmgr.h would be backwards.
- */
-
-/* Number of partitions of the shared buffer mapping hashtable */
-#define NUM_BUFFER_PARTITIONS  128
-
-/* Number of partitions the shared lock tables are divided into */
-#define LOG2_NUM_LOCK_PARTITIONS  4
-#define NUM_LOCK_PARTITIONS  (1 << LOG2_NUM_LOCK_PARTITIONS)
-
-/* Number of partitions the shared predicate lock tables are divided into */
-#define LOG2_NUM_PREDICATELOCK_PARTITIONS  4
-#define NUM_PREDICATELOCK_PARTITIONS  (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS)
-
-/* Offsets for various chunks of preallocated lwlocks. */
-#define BUFFER_MAPPING_LWLOCK_OFFSET	NUM_INDIVIDUAL_LWLOCKS
-#define LOCK_MANAGER_LWLOCK_OFFSET		\
-	(BUFFER_MAPPING_LWLOCK_OFFSET + NUM_BUFFER_PARTITIONS)
-#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET \
-	(LOCK_MANAGER_LWLOCK_OFFSET + NUM_LOCK_PARTITIONS)
-#define NUM_FIXED_LWLOCKS \
-	(PREDICATELOCK_MANAGER_LWLOCK_OFFSET + NUM_PREDICATELOCK_PARTITIONS)
-
 typedef enum LWLockMode
 {
 	LW_EXCLUSIVE,
@@ -173,7 +158,6 @@ typedef enum LWLockMode
 								 * to be used as LWLockAcquire argument */
 } LWLockMode;
 
-
 #ifdef LOCK_DEBUG
 extern bool Trace_lwlocks;
 #endif
@@ -218,6 +202,9 @@ extern LWLock *LWLockAssign(void);
 extern int	LWLockNewTrancheId(void);
 extern void LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche);
 extern void LWLockInitialize(LWLock *lock, int tranche_id);
+extern void LWLockCreateTranche(const char *tranche_name, int locks_count,
+	LWLockPadded **array);
+extern Size LWLockTrancheShmemSize(int locks_count);
 
 /*
  * Prior to PostgreSQL 9.4, we used an enum type called LWLockId to refer
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 6206c81..7fda57d 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

Reply via email to