*** /dev/null
--- b/contrib/pg_stat_lwlock/Makefile
***************
*** 0 ****
--- 1,18 ----
+ # contrib/pg_stat_lwlock/Makefile
+ 
+ MODULE_big = pg_stat_lwlock
+ OBJS = pg_stat_lwlock_list.o
+ 
+ EXTENSION = pg_stat_lwlock
+ DATA = pg_stat_lwlock--1.0.sql
+ 
+ ifdef USE_PGXS
+ PG_CONFIG = pg_config
+ PGXS := $(shell $(PG_CONFIG) --pgxs)
+ include $(PGXS)
+ else
+ subdir = contrib/pg_stat_lwlock
+ top_builddir = ../..
+ include $(top_builddir)/src/Makefile.global
+ include $(top_srcdir)/contrib/contrib-global.mk
+ endif
*** /dev/null
--- b/contrib/pg_stat_lwlock/pg_stat_lwlock--1.0.sql
***************
*** 0 ****
--- 1,19 ----
+ /* contrib/pg_stats_lwlock/pg_stats_lwlock--1.0.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pg_stat_lwlock" to load this file. \quit
+ 
+ -- Register the function.
+ CREATE FUNCTION pg_stat_lwlock_list()
+ RETURNS SETOF RECORD
+ AS 'MODULE_PATHNAME', 'pg_stat_lwlock_list'
+ LANGUAGE C;
+ 
+ -- Create a view for convenient access.
+ CREATE VIEW pg_stat_lwlock AS
+ 	SELECT L.* FROM pg_stat_lwlock_list() AS L
+ 	(lwlockid integer, pid integer);
+ 
+ -- Don't want these to be available to public.
+ REVOKE ALL ON FUNCTION pg_stat_lwlock_list() FROM PUBLIC;
+ REVOKE ALL ON pg_stat_lwlock FROM PUBLIC;
*** /dev/null
--- b/contrib/pg_stat_lwlock/pg_stat_lwlock.control
***************
*** 0 ****
--- 1,5 ----
+ # pg_stat_lwlock extension
+ comment = 'shows the list of lwlock id currently holding by backend'
+ default_version = '1.0'
+ module_pathname = '$libdir/pg_stat_lwlock'
+ relocatable = true
*** /dev/null
--- b/contrib/pg_stat_lwlock/pg_stat_lwlock_list.c
***************
*** 0 ****
--- 1,147 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_stat_lwlock_list.c
+  *	  display some histogramm of lightweight locks 
+  *
+  *	  contrib/pg_stat_lwlock/pg_stat_lwlock_list.c
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/htup_details.h"
+ #include "catalog/pg_type.h"
+ #include "funcapi.h"
+ #include "storage/buf_internals.h"
+ #include "storage/bufmgr.h"
+ #include "storage/proc.h"
+ 
+ 
+ #define NUM_STAT_LWLOCK_ELEM	2
+ 
+ PG_MODULE_MAGIC;
+ 
+ 
+ /*
+ * structure represents one record, contains lwlock id and process id
+ */
+ 
+ typedef struct 
+ {
+ 	uint32 lwLockId;
+ 	uint32 pid; 
+ } LwLockIdListRec; 
+ 
+ /*
+ * structure to hold function context between calls 
+ */
+ 
+ typedef struct
+ {
+ 	TupleDesc tupdesc;
+ 	LwLockIdListRec *record;
+ } LwLockListContext;
+ 
+ /* 
+  * Function returning information about long lwlocks holding by pid:
+  * currently lwlock id and pid (if any).
+  */
+ 
+ PG_FUNCTION_INFO_V1(pg_stat_lwlock_list);
+ 
+ Datum
+ pg_stat_lwlock_list(PG_FUNCTION_ARGS)
+ {
+ 	FuncCallContext *funcctx;
+ 	Datum result;
+ 	MemoryContext oldcontext;
+ 	LwLockListContext *fctx;
+ 	TupleDesc	tupledesc;
+ 	HeapTuple tuple;
+ 
+ 
+ 	int		call_cntr;
+ 	int		max_calls;
+ 
+ 	if (SRF_IS_FIRSTCALL())
+ 	{
+ 		int ii;
+ 		List *lwLockList;
+ 		ListCell *lc;
+ 
+ 		funcctx = SRF_FIRSTCALL_INIT();
+ 
+ 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+ 		fctx = (LwLockListContext *) palloc(sizeof(LwLockListContext));
+ 
+ 		tupledesc = CreateTemplateTupleDesc(NUM_STAT_LWLOCK_ELEM, false);
+ 
+ 		TupleDescInitEntry(tupledesc, (AttrNumber) 1, "lwLockId",
+ 						   INT4OID, -1, 0);
+ 	
+ 		TupleDescInitEntry(tupledesc, (AttrNumber) 2, "pid",
+ 						   INT4OID, -1, 0);
+ 	
+ 
+ 		fctx->tupdesc = BlessTupleDesc(tupledesc);
+ 		fctx->record = (LwLockIdListRec *) palloc(sizeof(LwLockIdListRec) * NBuffers);
+ 		
+ 		/*
+ 		 * getting list of pairs, lwlockid and pid, from procarray
+ 		 */
+ 		lwLockList = GetLwLockList(); 
+ 
+ 		funcctx->max_calls = list_length(lwLockList);
+ 		funcctx->user_fctx = fctx;
+ 
+ 		MemoryContextSwitchTo(oldcontext);
+ 
+ 		
+ 		for( ii = list_length(lwLockList) - 1; ii >= 0; ii--)
+ 		{
+ 			lwLockCell *lc = list_nth(lwLockList, ii);
+ 			 
+ 			if( lc->lwLockId > 0 )
+ 			{
+ 				fctx->record[ii].lwLockId	= lc->lwLockId;
+ 				fctx->record[ii].pid		= lc->pid;
+ 			}
+ 			else
+ 			{
+ 				fctx->record[ii].lwLockId	= 0;
+ 				fctx->record[ii].pid 		= 0;	
+ 			}
+ 		}
+ 	}
+ 
+ 	funcctx = SRF_PERCALL_SETUP();
+ 
+ 	fctx = funcctx->user_fctx;
+ 
+ 	if( funcctx->call_cntr < funcctx->max_calls )
+ 	{
+ 		uint32	i = funcctx->call_cntr;
+ 		Datum values[NUM_STAT_LWLOCK_ELEM];
+ 		bool nulls[NUM_STAT_LWLOCK_ELEM];
+ 
+ 		if( fctx->record[i].lwLockId > 0) 
+ 		{
+ 			values[0] = Int32GetDatum(fctx->record[i].lwLockId);
+ 			nulls[0] = false;
+ 
+ 			values[1] = Int32GetDatum(fctx->record[i].pid);
+ 			nulls[1] = false;
+ 		}
+ 		else
+ 		{
+ 			nulls[0] = true;
+ 			nulls[1] = true;
+ 		}
+ 
+ 		tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
+ 		result = HeapTupleGetDatum(tuple);
+ 
+ 		SRF_RETURN_NEXT(funcctx, result);
+ 	}
+ 	else
+ 		SRF_RETURN_DONE(funcctx);
+ }
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
***************
*** 392,397 **** MarkAsPreparing(TransactionId xid, const char *gid,
--- 392,398 ----
  	proc->lwWaitLink = NULL;
  	proc->waitLock = NULL;
  	proc->waitProcLock = NULL;
+ 	proc->lwLockId = 0;
  	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
  		SHMQueueInit(&(proc->myProcLocks[i]));
  	/* subxid data must be filled later by GXactLoadSubxactData */
*** a/src/backend/storage/ipc/procarray.c
--- b/src/backend/storage/ipc/procarray.c
***************
*** 2795,2800 **** XidCacheRemoveRunningXids(TransactionId xid,
--- 2795,2852 ----
  	LWLockRelease(ProcArrayLock);
  }
  
+ /*
+  * GetLwLockList --- puts all LWLockId's from procarrays to List
+  */
+ 
+ List 
+ *GetLwLockList()
+ {
+ 	ProcArrayStruct *arrayP = procArray;
+ 	int			count = 0;
+ 	int			index;
+ 
+ 	List *lwLockList = NIL;
+ 
+ 	/*
+ 	 * Acquiring procarray lock to read. Not sure if it is a good idea,
+ 	 * since we actually do not need any consisitency for our purposes. 
+ 	 */
+ 	LWLockAcquire(ProcArrayLock, LW_SHARED);
+ 
+ 	for (index = 0; index < arrayP->numProcs; index++)
+ 	{
+ 		int			pgprocno = arrayP->pgprocnos[index];
+ 		volatile 	PGPROC *proc = &allProcs[pgprocno];
+ 
+ 		int		lwLockId;
+ 		int		pid;
+ 
+ 		lwLockCell *lwLockListCell;
+ 
+ 		lwLockId	= proc->lwLockId;
+ 		pid			= proc->pid;		
+ 		/* elog(WARNING, " iteration is %u, lwLockId in cycle %u in getlwlocklist", index, lwLockId);*/
+ 
+ 		/* skipping if there is no active lwlocks*/
+ 		if (lwLockId == 0)
+ 			continue;			
+ 		if (lwLockId == -1)
+ 			continue;
+ 
+ 		lwLockListCell = (lwLockCell *) palloc(sizeof(lwLockCell));
+ 		lwLockListCell->lwLockId	= lwLockId;
+ 		lwLockListCell->pid			= pid;
+ 		
+ 		/* elog(WARNING, "lwLockId-> in cycle %u in getlwlocklist", lwLockListCell->id);*/
+ 		lwLockList = lappend(lwLockList, lwLockListCell);
+ 	}
+ 
+ 	LWLockRelease(ProcArrayLock);
+ 
+ 	return lwLockList;
+ }
+ 
  #ifdef XIDCACHE_DEBUG
  
  /*
*** a/src/backend/storage/lmgr/lwlock.c
--- b/src/backend/storage/lmgr/lwlock.c
***************
*** 644,649 **** LWLockAcquireCommon(LWLock *lock, LWLockMode mode, uint64 *valptr, uint64 val)
--- 644,652 ----
  #endif
  
  		TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
+  		
+ 		/* we put lwloch id from tranche to procarray */
+  		proc->lwLockId = T_ID(l);
  
  		for (;;)
  		{
***************
*** 654,659 **** LWLockAcquireCommon(LWLock *lock, LWLockMode mode, uint64 *valptr, uint64 val)
--- 657,668 ----
  			extraWaits++;
  		}
  
+  		/* 
+  		 * we set lwlock id to -1 to set it apart from currently active lwlock
+  		 * with id and from just initialized lwLockId which is 0
+  		 */
+  		proc->lwLockId = -1;
+ 
  		TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
  
  		LOG_LWDEBUG("LWLockAcquire", T_NAME(lock), T_ID(lock), "awakened");
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
***************
*** 375,380 **** InitProcess(void)
--- 375,382 ----
  	MyProc->lwWaitLink = NULL;
  	MyProc->waitLock = NULL;
  	MyProc->waitProcLock = NULL;
+ 	MyProc->lwLockId = 0;
+ 
  #ifdef USE_ASSERT_CHECKING
  	{
  		int			i;
***************
*** 538,543 **** InitAuxiliaryProcess(void)
--- 540,546 ----
  	MyProc->lwWaitLink = NULL;
  	MyProc->waitLock = NULL;
  	MyProc->waitProcLock = NULL;
+ 	MyProc->lwLockId = 0;
  #ifdef USE_ASSERT_CHECKING
  	{
  		int			i;
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 572,574 **** pg_column_is_updatable(PG_FUNCTION_ARGS)
--- 572,579 ----
  
  	PG_RETURN_BOOL((events & REQ_EVENTS) == REQ_EVENTS);
  }
+ 
+ 
+ 
+ 
+ 
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
***************
*** 105,110 **** struct PGPROC
--- 105,111 ----
  	bool		lwWaiting;		/* true if waiting for an LW lock */
  	uint8		lwWaitMode;		/* lwlock mode being waited for */
  	struct PGPROC *lwWaitLink;	/* next waiter for same LW lock */
+ 	int lwLockId;
  
  	/* Info about lock the process is currently waiting for, if any. */
  	/* waitLock and waitProcLock are NULL if not currently waiting. */
***************
*** 211,216 **** extern PROC_HDR *ProcGlobal;
--- 212,228 ----
  
  extern PGPROC *PreparedXactProcs;
  
+ 
+ /*
+  * We set this structure for pg_stat_lwlock extension. 
+  * We use it as a List cell to deliver info about lwlock 
+  * and process which is holding this lwlock
+  */
+ typedef struct{
+ 	int lwLockId;
+ 	int pid;
+ } lwLockCell;
+ 
  /*
   * We set aside some extra PGPROC structures for auxiliary processes,
   * ie things that aren't full-fledged backends but need shmem access.
*** a/src/include/storage/procarray.h
--- b/src/include/storage/procarray.h
***************
*** 78,84 **** extern bool CountOtherDBBackends(Oid databaseId,
  extern void XidCacheRemoveRunningXids(TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid);
! 
  extern void ProcArraySetReplicationSlotXmin(TransactionId xmin,
  							TransactionId catalog_xmin, bool already_locked);
  
--- 78,84 ----
  extern void XidCacheRemoveRunningXids(TransactionId xid,
  						  int nxids, const TransactionId *xids,
  						  TransactionId latestXid);
! extern List *GetLwLockList();
  extern void ProcArraySetReplicationSlotXmin(TransactionId xmin,
  							TransactionId catalog_xmin, bool already_locked);
  
