diff -cpr pgsql-orig/src/backend/access/transam/slru.c pgsql/src/backend/access/transam/slru.c
*** pgsql-orig/src/backend/access/transam/slru.c	Mon Jul 31 09:22:04 2006
--- pgsql/src/backend/access/transam/slru.c	Mon Jul 31 09:37:25 2006
*************** SimpleLruInit(SlruCtl ctl, const char *n
*** 185,190 ****
--- 185,191 ----
  		char	   *ptr;
  		Size		offset;
  		int			slotno;
+ 		LWLockKind	kind;
  
  		Assert(!found);
  
*************** SimpleLruInit(SlruCtl ctl, const char *n
*** 214,226 ****
  		offset += MAXALIGN(nslots * sizeof(LWLockId));
  		ptr += BUFFERALIGN(offset);
  
  		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();
  			ptr += BLCKSZ;
  		}
  	}
--- 215,247 ----
  		offset += MAXALIGN(nslots * sizeof(LWLockId));
  		ptr += BUFFERALIGN(offset);
  
+ 		switch (ctllock)
+ 		{
+ 			case CLogControlLock:
+ 				kind = LW_KIND_CLOG;
+ 				break;
+ 			case SubtransControlLock:
+ 				kind = LW_KIND_SUBTRANS;
+ 				break;
+ 			case MultiXactOffsetControlLock:
+ 				kind = LW_KIND_MULTIXACTOFFSET;
+ 				break;
+ 			case MultiXactMemberControlLock:
+ 				kind = LW_KIND_MULTIXACTMEMBER;
+ 				break;
+ 			default:
+ 				elog(ERROR, "invalid SLRU lockid: %d", (int) ctllock);
+ 				kind = 0;
+ 				break;
+ 		}
+ 
  		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(kind);
  			ptr += BLCKSZ;
  		}
  	}
diff -cpr pgsql-orig/src/backend/catalog/system_views.sql pgsql/src/backend/catalog/system_views.sql
*** pgsql-orig/src/backend/catalog/system_views.sql	Mon Jul 31 09:22:04 2006
--- pgsql/src/backend/catalog/system_views.sql	Mon Jul 31 09:37:25 2006
*************** CREATE VIEW pg_stat_database AS 
*** 355,360 ****
--- 355,375 ----
              pg_stat_get_db_blocks_hit(D.oid) AS blks_hit 
      FROM pg_database D;
  
+ CREATE VIEW pg_stat_lwlocks AS
+     SELECT
+         kind,
+         pg_stat_get_lwlock_name(kind) AS lwlock,
+         sum(sh_call) AS sh_call,
+         sum(sh_wait) AS sh_wait,
+         sum(ex_call) AS ex_call,
+         sum(ex_wait) AS ex_wait
+     FROM pg_stat_get_lwlocks() AS L(
+          id int, kind int,
+          sh_call int8, sh_wait int8,
+          ex_call int8, ex_wait int8)
+     GROUP BY kind
+     ORDER BY kind;
+ 
  --
  -- Fix up built-in functions that make use of OUT parameters.
  -- We can't currently fill these values in during bootstrap, because
diff -cpr pgsql-orig/src/backend/storage/buffer/buf_init.c pgsql/src/backend/storage/buffer/buf_init.c
*** pgsql-orig/src/backend/storage/buffer/buf_init.c	Mon Jul 31 09:22:05 2006
--- pgsql/src/backend/storage/buffer/buf_init.c	Mon Jul 31 09:37:25 2006
*************** InitBufferPool(void)
*** 125,132 ****
  			 */
  			buf->freeNext = i + 1;
  
! 			buf->io_in_progress_lock = LWLockAssign();
! 			buf->content_lock = LWLockAssign();
  		}
  
  		/* Correct last entry of linked list */
--- 125,132 ----
  			 */
  			buf->freeNext = i + 1;
  
! 			buf->io_in_progress_lock = LWLockAssign(LW_KIND_BUFFERIO);
! 			buf->content_lock = LWLockAssign(LW_KIND_BUFFERCONTENT);
  		}
  
  		/* Correct last entry of linked list */
diff -cpr pgsql-orig/src/backend/storage/lmgr/lwlock.c pgsql/src/backend/storage/lmgr/lwlock.c
*** pgsql-orig/src/backend/storage/lmgr/lwlock.c	Mon Jul 31 09:22:05 2006
--- pgsql/src/backend/storage/lmgr/lwlock.c	Mon Jul 31 09:37:25 2006
*************** typedef struct LWLock
*** 41,46 ****
--- 41,50 ----
  	int			shared;			/* # of shared holders (0..MaxBackends) */
  	PGPROC	   *head;			/* head of list of waiting PGPROCs */
  	PGPROC	   *tail;			/* tail of list of waiting PGPROCs */
+ #ifdef LWLOCK_STAT
+ 	LWLockStat	stat;
+ #endif
+ 
  	/* tail is undefined when head is NULL */
  } LWLock;
  
*************** typedef struct LWLock
*** 53,62 ****
   * Opterons.  (Of course, we have to also ensure that the array start
   * address is suitably aligned.)
   *
!  * LWLock is between 16 and 32 bytes on all known platforms, so these two
!  * cases are sufficient.
!  */
! #define LWLOCK_PADDED_SIZE	(sizeof(LWLock) <= 16 ? 16 : 32)
  
  typedef union LWLockPadded
  {
--- 57,69 ----
   * Opterons.  (Of course, we have to also ensure that the array start
   * address is suitably aligned.)
   *
!  * LWLock is between 16 and 32 bytes on all known platforms if LWLOCK_STAT
!  * is not defined, and less than 64 bytes if defined. So these three cases
!  * are sufficient.
!  */
! #define LWLOCK_PADDED_SIZE \
! 	(sizeof(LWLock) <= 16 ? 16 : \
! 	(sizeof(LWLock) <= 32 ? 32 : 64))
  
  typedef union LWLockPadded
  {
*************** typedef union LWLockPadded
*** 71,76 ****
--- 78,84 ----
   */
  NON_EXEC_STATIC LWLockPadded *LWLockArray = NULL;
  
+ #define GetLWLockCounter()	((int *) ((char *) LWLockArray - 2 * sizeof(int)))
  
  /*
   * We use this structure to keep track of locked LWLocks for release
*************** static int *ex_acquire_counts;
*** 90,95 ****
--- 98,149 ----
  static int *block_counts;
  #endif
  
+ #ifdef LWLOCK_STAT
+ 
+ static char* LWLockIdNames[] = 
+ {
+ 	/* System fixed locks */
+ 	"BufFreelistLock",
+ 	"ShmemIndexLock",
+ 	"OidGenLock",
+ 	"XidGenLock",
+ 	"ProcArrayLock",
+ 	"SInvalLock",
+ 	"FreeSpaceLock",
+ 	"WALInsertLock",
+ 	"WALWriteLock",
+ 	"ControlFileLock",
+ 	"CheckpointLock",
+ 	"CheckpointStartLock",
+ 	"CLogControlLock",
+ 	"SubtransControlLock",
+ 	"MultiXactGenLock",
+ 	"MultiXactOffsetControlLock",
+ 	"MultiXactMemberControlLock",
+ 	"RelCacheInitLock",
+ 	"BgWriterCommLock",
+ 	"TwoPhaseStateLock",
+ 	"TablespaceCreateLock",
+ 	"BtreeVacuumLock",
+ 	"BufMappingLock",
+ 	"LockMgrLock",
+ 	/* Dynamic locks */
+ 	"BufferIO",
+ 	"BufferContent",
+ 	"CLogBuffer",
+ 	"SubTransBuffer",
+ 	"MultiXactOffsetBuffer",
+ 	"MultiXactMemberBuffer",
+ };
+ 
+ #define StaticAssert(cond)	extern char static_assertion_failure[(cond) ? 1 : -1]
+ 
+ StaticAssert( lengthof(LWLockIdNames) == NUM_LW_KINDS );
+ 
+ #define LWLockKinds	((LWLockKind *) \
+ 	((char *) LWLockArray + sizeof(LWLockPadded) * GetLWLockCounter()[1]))
+ 
+ #endif /* LWLOCK_STAT */
  
  #ifdef LOCK_DEBUG
  bool		Trace_lwlocks = false;
*************** static void
*** 121,127 ****
  print_lwlock_stats(int code, Datum arg)
  {
  	int			i;
! 	int		   *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
  	int			numLocks = LWLockCounter[1];
  
  	/* Grab an LWLock to keep different backends from mixing reports */
--- 175,181 ----
  print_lwlock_stats(int code, Datum arg)
  {
  	int			i;
! 	int		   *LWLockCounter = GetLWLockCounter();
  	int			numLocks = LWLockCounter[1];
  
  	/* Grab an LWLock to keep different backends from mixing reports */
*************** LWLockShmemSize(void)
*** 193,198 ****
--- 247,257 ----
  	/* Space for dynamic allocation counter, plus room for alignment. */
  	size = add_size(size, 2 * sizeof(int) + LWLOCK_PADDED_SIZE);
  
+ #ifdef LWLOCK_STAT
+ 	/* Space for the LWLockKind array. */
+ 	size = add_size(size, numLocks * sizeof(LWLockKind));
+ #endif
+ 
  	return size;
  }
  
*************** CreateLWLocks(void)
*** 232,246 ****
  		lock->lock.shared = 0;
  		lock->lock.head = NULL;
  		lock->lock.tail = NULL;
  	}
  
  	/*
  	 * Initialize the dynamic-allocation counter, which is stored just before
  	 * the first LWLock.
  	 */
! 	LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
  	LWLockCounter[0] = (int) NumFixedLWLocks;
  	LWLockCounter[1] = numLocks;
  }
  
  
--- 291,318 ----
  		lock->lock.shared = 0;
  		lock->lock.head = NULL;
  		lock->lock.tail = NULL;
+ #ifdef LWLOCK_STAT
+ 		memset(&lock->lock.stat, 0, sizeof(LWLockStat));
+ #endif
  	}
  
  	/*
  	 * Initialize the dynamic-allocation counter, which is stored just before
  	 * the first LWLock.
  	 */
! 	LWLockCounter = GetLWLockCounter();
  	LWLockCounter[0] = (int) NumFixedLWLocks;
  	LWLockCounter[1] = numLocks;
+ 
+ #ifdef LWLOCK_STAT
+ 	/* Initialize the named fixed locks, BufMappingLocks and LockMgrLocks. */
+ 	for (id = 0; id <= (int) LW_KIND_LASTFIXED; id++)
+ 		LWLockKinds[id] = (LWLockKind) id;
+ 	for (id = 0; id < NUM_BUFFER_PARTITIONS; id++)
+ 		LWLockKinds[FirstBufMappingLock + id] = LW_KIND_BUFFER;
+ 	for (id = 0; id < NUM_LOCK_PARTITIONS; id++)
+ 		LWLockKinds[FirstLockMgrLock + id] = LW_KIND_LOCK;
+ #endif
  }
  
  
*************** CreateLWLocks(void)
*** 253,266 ****
   * LWLocks after startup.
   */
  LWLockId
! LWLockAssign(void)
  {
  	LWLockId	result;
  
  	/* use volatile pointer to prevent code rearrangement */
  	volatile int *LWLockCounter;
  
! 	LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
  	SpinLockAcquire(ShmemLock);
  	if (LWLockCounter[0] >= LWLockCounter[1])
  	{
--- 325,338 ----
   * LWLocks after startup.
   */
  LWLockId
! LWLockAssign(LWLockKind kind)
  {
  	LWLockId	result;
  
  	/* use volatile pointer to prevent code rearrangement */
  	volatile int *LWLockCounter;
  
! 	LWLockCounter = GetLWLockCounter();
  	SpinLockAcquire(ShmemLock);
  	if (LWLockCounter[0] >= LWLockCounter[1])
  	{
*************** LWLockAssign(void)
*** 269,274 ****
--- 341,351 ----
  	}
  	result = (LWLockId) (LWLockCounter[0]++);
  	SpinLockRelease(ShmemLock);
+ 
+ #ifdef LWLOCK_STAT
+ 	LWLockKinds[result] = kind;
+ #endif
+ 
  	return result;
  }
  
*************** LWLockAcquire(LWLockId lockid, LWLockMod
*** 294,300 ****
  	/* Set up local count state first time through in a given process */
  	if (counts_for_pid != MyProcPid)
  	{
! 		int	   *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
  		int		numLocks = LWLockCounter[1];
  
  		sh_acquire_counts = calloc(numLocks, sizeof(int));
--- 371,377 ----
  	/* Set up local count state first time through in a given process */
  	if (counts_for_pid != MyProcPid)
  	{
! 		int	   *LWLockCounter = GetLWLockCounter();
  		int		numLocks = LWLockCounter[1];
  
  		sh_acquire_counts = calloc(numLocks, sizeof(int));
*************** LWLockAcquire(LWLockId lockid, LWLockMod
*** 351,356 ****
--- 428,438 ----
  		/* Acquire mutex.  Time spent holding mutex should be short! */
  		SpinLockAcquire(&lock->mutex);
  
+ #ifdef LWLOCK_STAT
+ 		if (!retry)
+ 			lock->stat.ncall[mode]++;
+ #endif /* LWLOCK_STAT */
+ 
  		/* If retrying, allow LWLockRelease to release waiters again */
  		if (retry)
  			lock->releaseOK = true;
*************** LWLockAcquire(LWLockId lockid, LWLockMod
*** 380,385 ****
--- 462,471 ----
  		if (!mustwait)
  			break;				/* got the lock */
  
+ #ifdef LWLOCK_STAT
+ 		lock->stat.nwait[mode]++;
+ #endif /* LWLOCK_STAT */
+ 
  		/*
  		 * Add myself to wait queue.
  		 *
*************** LWLockHeldByMe(LWLockId lockid)
*** 665,667 ****
--- 751,800 ----
  	}
  	return false;
  }
+ 
+ #ifdef LWLOCK_STAT
+ 
+ const char *
+ LWLockName(LWLockKind lwkind)
+ {
+ 	if (0 <= lwkind && lwkind < NUM_LW_KINDS)
+ 		return LWLockIdNames[lwkind];
+ 	return "Unknown";
+ }
+ 
+ LWLockKind
+ LWLockGetStat(LWLockId lockid, LWLockStat *dst)
+ {
+ 	int	   *LWLockCounter = GetLWLockCounter();
+ 	int		nAvailableLWLocks = LWLockCounter[0];
+ 	volatile LWLock *lock;
+ 		
+ 	if (lockid >= nAvailableLWLocks)
+ 		return LW_KIND_INVALID;
+ 
+ 	lock = &LWLockArray[lockid].lock;
+ 	SpinLockAcquire(&lock->mutex);
+ 	memcpy(dst, (const void*) &lock->stat, sizeof(LWLockStat));
+ 	SpinLockRelease(&lock->mutex);
+ 	return LWLockKinds[lockid];
+ }
+ 
+ void
+ LWLockResetStat(void)
+ {
+ 	int	   *LWLockCounter = GetLWLockCounter();
+ 	int		nAvailableLWLocks = LWLockCounter[0];
+ 	int		i;
+ 
+ 	for (i = 0; i < nAvailableLWLocks; i++)
+ 	{
+ 		volatile LWLock *lock = &LWLockArray[i].lock;
+ 		volatile LWLockStat *lwstat = &lock->stat;
+ 
+ 		SpinLockAcquire(&lock->mutex);
+ 		memset((void*) lwstat, 0, sizeof(LWLockStat));
+ 		SpinLockRelease(&lock->mutex);
+ 	}
+ }
+ 
+ #endif /* LWLOCK_STAT */
diff -cpr pgsql-orig/src/backend/utils/adt/pgstatfuncs.c pgsql/src/backend/utils/adt/pgstatfuncs.c
*** pgsql-orig/src/backend/utils/adt/pgstatfuncs.c	Mon Jul 31 09:22:05 2006
--- pgsql/src/backend/utils/adt/pgstatfuncs.c	Mon Jul 31 09:37:25 2006
***************
*** 14,19 ****
--- 14,21 ----
   */
  #include "postgres.h"
  
+ #include "access/heapam.h"
+ #include "catalog/pg_type.h"
  #include "funcapi.h"
  #include "miscadmin.h"
  #include "pgstat.h"
*************** extern Datum pg_stat_get_db_xact_rollbac
*** 53,58 ****
--- 55,63 ----
  extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
  
+ extern Datum pg_stat_get_lwlock_name(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_lwlocks(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_reset_lwlocks(PG_FUNCTION_ARGS);
  
  Datum
  pg_stat_get_numscans(PG_FUNCTION_ARGS)
*************** pg_stat_get_db_blocks_hit(PG_FUNCTION_AR
*** 600,602 ****
--- 605,736 ----
  
  	PG_RETURN_INT64(result);
  }
+ 
+ /*
+  * LWLOCK_STAT staff
+  */
+ 
+ #ifdef LWLOCK_STAT
+ 
+ static HeapTuple
+ formLWLockStatTuple(FuncCallContext *funcctx)
+ {
+ 	int32	lockid = funcctx->call_cntr;
+ 	LWLockStat	stat;
+ 	char		nulls[7];
+ 	Datum		values[7];
+ 	LWLockKind	kind;
+ 
+ 	kind = LWLockGetStat(lockid, &stat);
+ 	if (kind == LW_KIND_INVALID)
+ 		return NULL;
+ 	
+ 	MemSet(values, 0, sizeof(values));
+ 	MemSet(nulls, ' ', sizeof(nulls));
+ 
+ 	values[0] = Int32GetDatum(lockid);
+ 	values[1] = Int32GetDatum((int32) kind);
+ 	values[2] = Int64GetDatum(stat.ncall[LW_SHARED]);
+ 	values[3] = Int64GetDatum(stat.nwait[LW_SHARED]);
+ 	values[4] = Int64GetDatum(stat.ncall[LW_EXCLUSIVE]);
+ 	values[5] = Int64GetDatum(stat.nwait[LW_EXCLUSIVE]);
+ 
+ 	return heap_formtuple(funcctx->tuple_desc, values, nulls);
+ }
+ 
+ /* pg_stat_get_lwlock_name(integer) : text */
+ Datum
+ pg_stat_get_lwlock_name(PG_FUNCTION_ARGS)
+ {
+ 	LWLockKind	lwkind;
+ 	const char *name;
+ 	int			name_len;
+ 	int			ret_len;
+ 	text	   *result;
+ 
+ 	lwkind = (LWLockKind) PG_GETARG_INT32(0);
+ 
+ 	name = LWLockName(lwkind);
+ 	name_len = strlen(name);
+ 	ret_len = VARHDRSZ + name_len;
+ 	result = palloc(ret_len);
+ 	VARATT_SIZEP(result) = ret_len;
+ 	memcpy(VARDATA(result), name, name_len);
+ 
+ 	PG_RETURN_TEXT_P(result);
+ }
+ 
+ /* pg_stat_get_lwlock(void) : set of lwlock_stat */
+ Datum
+ pg_stat_get_lwlocks(PG_FUNCTION_ARGS)
+ {
+ 	FuncCallContext	   *funcctx;
+ 	HeapTuple			tuple;
+ 
+ 	if (SRF_IS_FIRSTCALL())
+ 	{
+ 		MemoryContext	oldcontext;
+ 		TupleDesc		desc;
+ 
+ 		funcctx = SRF_FIRSTCALL_INIT();
+ 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+ 		desc = CreateTemplateTupleDesc(6, false);
+ 
+ 		TupleDescInitEntry(desc, (AttrNumber)1, "id", INT4OID, -1, 0);
+ 		TupleDescInitEntry(desc, (AttrNumber)2, "kind", INT4OID, -1, 0);
+ 		TupleDescInitEntry(desc, (AttrNumber)3, "sh_call", INT8OID, -1, 0);
+ 		TupleDescInitEntry(desc, (AttrNumber)4, "sh_wait", INT8OID, -1, 0);
+ 		TupleDescInitEntry(desc, (AttrNumber)5, "ex_call", INT8OID, -1, 0);
+ 		TupleDescInitEntry(desc, (AttrNumber)6, "ex_wait", INT8OID, -1, 0);
+ 
+ 		funcctx->tuple_desc = BlessTupleDesc(desc);
+ 		funcctx->max_calls = (uint32)NumLWLocks();
+ 
+ 		MemoryContextSwitchTo(oldcontext);
+ 	}
+ 
+ 	funcctx = SRF_PERCALL_SETUP();
+ 
+ 	if (funcctx->call_cntr < funcctx->max_calls
+ 		&& (tuple = formLWLockStatTuple(funcctx)) != NULL)
+ 	{
+ 		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+ 	}
+ 	else
+ 	{
+ 		SRF_RETURN_DONE(funcctx);
+ 	}
+ }
+ 
+ /* pg_stat_reset_lwlocks(void) : boolean */
+ Datum
+ pg_stat_reset_lwlocks(PG_FUNCTION_ARGS)
+ {
+ 	LWLockResetStat();
+ 	PG_RETURN_BOOL(true);
+ }
+ 
+ #else  /* LWLOCK_STAT */
+ 
+ Datum
+ pg_stat_get_lwlock_name(PG_FUNCTION_ARGS)
+ {
+ 	elog(ERROR, "LWLOCK_STAT is disabled");
+ 	PG_RETURN_NULL();
+ }
+ 
+ Datum
+ pg_stat_get_lwlocks(PG_FUNCTION_ARGS)
+ {
+ 	elog(ERROR, "LWLOCK_STAT is disabled");
+ 	PG_RETURN_NULL();
+ }
+ 
+ Datum
+ pg_stat_reset_lwlocks(PG_FUNCTION_ARGS)
+ {
+ 	elog(ERROR, "LWLOCK_STAT is disabled");
+ 	PG_RETURN_NULL();
+ }
+ 
+ #endif /* LWLOCK_STAT */
diff -cpr pgsql-orig/src/include/catalog/pg_proc.h pgsql/src/include/catalog/pg_proc.h
*** pgsql-orig/src/include/catalog/pg_proc.h	Mon Jul 31 09:22:08 2006
--- pgsql/src/include/catalog/pg_proc.h	Mon Jul 31 09:37:25 2006
*************** DESCR("Statistics: Blocks fetched for da
*** 2917,2922 ****
--- 2917,2929 ----
  DATA(insert OID = 1945 (  pg_stat_get_db_blocks_hit		PGNSP PGUID 12 f f t f s 1 20 "26" _null_ _null_ _null_ pg_stat_get_db_blocks_hit - _null_ ));
  DESCR("Statistics: Blocks found in cache for database");
  
+ DATA(insert OID = 2830 (  pg_stat_get_lwlock_name	PGNSP PGUID 12 f f t f s 1 25 "23" _null_ _null_ _null_ pg_stat_get_lwlock_name - _null_ ));
+ DESCR("Statistics: Name of lwlock");
+ DATA(insert OID = 2831 (  pg_stat_get_lwlocks	PGNSP PGUID 12 f f t t v 0 2249 "" _null_ _null_ _null_ pg_stat_get_lwlocks - _null_ ));
+ DESCR("Statistics: Set of lwlock_stat tuple");
+ DATA(insert OID = 2832 (  pg_stat_reset_lwlocks	PGNSP PGUID 12 f f f f v 0 16  "" _null_ _null_ _null_ 	pg_stat_reset_lwlocks - _null_ ));
+ DESCR("Statistics: Reset collected statistics");
+ 
  DATA(insert OID = 1946 (  encode						PGNSP PGUID 12 f f t f i 2 25 "17 25" _null_ _null_ _null_	binary_encode - _null_ ));
  DESCR("Convert bytea value into some ascii-only text string");
  DATA(insert OID = 1947 (  decode						PGNSP PGUID 12 f f t f i 2 17 "25 25" _null_ _null_ _null_	binary_decode - _null_ ));
diff -cpr pgsql-orig/src/include/pg_config_manual.h pgsql/src/include/pg_config_manual.h
*** pgsql-orig/src/include/pg_config_manual.h	Mon Jul 31 09:22:09 2006
--- pgsql/src/include/pg_config_manual.h	Mon Jul 31 09:37:25 2006
***************
*** 245,250 ****
--- 245,255 ----
  /* #define WAL_DEBUG */
  
  /*
+  * Enable statistics collector for LWLock operations
+  */
+ /*#define LWLOCK_STAT*/
+ 
+ /*
   * Enable tracing of resource consumption during sort operations;
   * see also the trace_sort GUC var.  For 8.1 this is enabled by default.
   */
diff -cpr pgsql-orig/src/include/storage/lwlock.h pgsql/src/include/storage/lwlock.h
*** pgsql-orig/src/include/storage/lwlock.h	Mon Jul 31 09:22:09 2006
--- pgsql/src/include/storage/lwlock.h	Mon Jul 31 09:37:25 2006
*************** typedef enum LWLockMode
*** 76,87 ****
  	LW_SHARED
  } LWLockMode;
  
  
  #ifdef LOCK_DEBUG
  extern bool Trace_lwlocks;
  #endif
  
! extern LWLockId LWLockAssign(void);
  extern void LWLockAcquire(LWLockId lockid, LWLockMode mode);
  extern bool LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode);
  extern void LWLockRelease(LWLockId lockid);
--- 76,102 ----
  	LW_SHARED
  } LWLockMode;
  
+ typedef enum LWLockKind
+ {
+ 	LW_KIND_INVALID = -1,
+ 	LW_KIND_FIRSTFIXED = 0,
+ 	LW_KIND_LASTFIXED = FirstBufMappingLock - 1,
+ 	LW_KIND_BUFFER,			/* BufferMappingLock(s) */
+ 	LW_KIND_LOCK,			/* LockMgrLock(s) */
+ 	LW_KIND_BUFFERIO,		/* BufferDesc.io_in_progress_lock */
+ 	LW_KIND_BUFFERCONTENT,	/* BufferDesc.content_lock */
+ 	LW_KIND_CLOG,			/* ClogCtl */
+ 	LW_KIND_SUBTRANS,		/* SubTransCtl */
+ 	LW_KIND_MULTIXACTOFFSET,/* MultiXactOffsetCtl */
+ 	LW_KIND_MULTIXACTMEMBER,/* MultiXactMemberCtl */
+ 	NUM_LW_KINDS,			/* last kind */
+ } LWLockKind;
  
  #ifdef LOCK_DEBUG
  extern bool Trace_lwlocks;
  #endif
  
! extern LWLockId LWLockAssign(LWLockKind kind);
  extern void LWLockAcquire(LWLockId lockid, LWLockMode mode);
  extern bool LWLockConditionalAcquire(LWLockId lockid, LWLockMode mode);
  extern void LWLockRelease(LWLockId lockid);
*************** extern bool LWLockHeldByMe(LWLockId lock
*** 91,95 ****
--- 106,124 ----
  extern int	NumLWLocks(void);
  extern Size LWLockShmemSize(void);
  extern void CreateLWLocks(void);
+ 
+ #ifdef LWLOCK_STAT
+ 
+ typedef struct LWLockStat
+ {
+ 	int64	ncall[2];	/* # of calls (0:Exclusive, 1:Shared) */
+ 	int64	nwait[2];	/* # of waits (0:Exclusive, 1:Shared) */
+ } LWLockStat;
+ 
+ extern const char *LWLockName(LWLockKind lwkind);
+ extern LWLockKind LWLockGetStat(LWLockId lockid, LWLockStat *dst);
+ extern void LWLockResetStat(void);
+ 
+ #endif /* LWLOCK_STAT */
  
  #endif   /* LWLOCK_H */