From aa65de042f5828968f2f6cd65f45c543a40cc3e6 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Fri, 11 Sep 2015 13:58:28 -0400
Subject: [PATCH] When trace_lwlocks is used, identify individual lwlocks by
 name.

Naming the individual lwlocks seems like something that may be useful
for other types of debugging, monitoring, or instrumentation output,
but this commit just implements it for the specific case of
trace_lwlocks.

Patch by me, reviewed by Amit Kapila and Kyotaro Horiguchi
---
 src/backend/Makefile                          | 14 +++-
 src/backend/storage/lmgr/.gitignore           |  2 +
 src/backend/storage/lmgr/Makefile             | 11 ++-
 .../storage/lmgr/generate-lwlocknames.pl      | 67 +++++++++++++++++++
 src/backend/storage/lmgr/lwlock.c             | 60 ++++++++++++-----
 src/backend/storage/lmgr/lwlocknames.txt      | 47 +++++++++++++
 src/include/storage/.gitignore                |  1 +
 src/include/storage/lwlock.h                  | 52 +-------------
 src/tools/msvc/Solution.pm                    | 16 +++++
 9 files changed, 201 insertions(+), 69 deletions(-)
 create mode 100644 src/backend/storage/lmgr/.gitignore
 create mode 100644 src/backend/storage/lmgr/generate-lwlocknames.pl
 create mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/.gitignore

diff --git a/src/backend/Makefile b/src/backend/Makefile
index 98b978f3da4..f872deb188b 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -106,7 +106,7 @@ endif
 endif # aix
 
 # Update the commonly used headers before building the subdirectories
-$(SUBDIRS:%=%-recursive): $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/catalog/schemapg.h $(top_builddir)/src/include/utils/fmgroids.h $(top_builddir)/src/include/utils/errcodes.h $(top_builddir)/src/include/utils/probes.h
+$(SUBDIRS:%=%-recursive): $(top_builddir)/src/include/parser/gram.h $(top_builddir)/src/include/catalog/schemapg.h $(top_builddir)/src/include/storage/lwlocknames.h $(top_builddir)/src/include/utils/fmgroids.h $(top_builddir)/src/include/utils/errcodes.h $(top_builddir)/src/include/utils/probes.h
 
 # run this unconditionally to avoid needing to know its dependencies here:
 submake-schemapg:
@@ -135,6 +135,9 @@ postgres.o: $(OBJS)
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
+
 utils/fmgroids.h: utils/Gen_fmgrtab.pl catalog/Catalog.pm $(top_srcdir)/src/include/catalog/pg_proc.h
 	$(MAKE) -C utils fmgroids.h
 
@@ -165,6 +168,11 @@ $(top_builddir)/src/include/catalog/schemapg.h: catalog/schemapg.h
 	  cd '$(dir $@)' && rm -f $(notdir $@) && \
 	  $(LN_S) "$$prereqdir/$(notdir $<)" .
 
+$(top_builddir)/src/include/storage/lwlocknames.h: storage/lmgr/lwlocknames.h
+	prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
+	  cd '$(dir $@)' && rm -f $(notdir $@) && \
+	  $(LN_S) "$$prereqdir/$(notdir $<)" .
+
 $(top_builddir)/src/include/utils/errcodes.h: utils/errcodes.h
 	prereqdir=`cd '$(dir $<)' >/dev/null && pwd` && \
 	  cd '$(dir $@)' && rm -f $(notdir $@) && \
@@ -192,6 +200,7 @@ distprep:
 	$(MAKE) -C bootstrap	bootparse.c bootscanner.c
 	$(MAKE) -C catalog	schemapg.h postgres.bki postgres.description postgres.shdescription
 	$(MAKE) -C replication	repl_gram.c repl_scanner.c
+	$(MAKE) -C storage	lwlocknames.h
 	$(MAKE) -C utils	fmgrtab.c fmgroids.h errcodes.h
 	$(MAKE) -C utils/misc	guc-file.c
 	$(MAKE) -C utils/sort	qsort_tuple.c
@@ -282,6 +291,7 @@ clean:
 	rm -f $(LOCALOBJS) postgres$(X) $(POSTGRES_IMP) \
 		$(top_builddir)/src/include/parser/gram.h \
 		$(top_builddir)/src/include/catalog/schemapg.h \
+		$(top_builddir)/src/include/storage/lwlocknames.h \
 		$(top_builddir)/src/include/utils/fmgroids.h \
 		$(top_builddir)/src/include/utils/probes.h
 ifeq ($(PORTNAME), cygwin)
@@ -307,6 +317,8 @@ maintainer-clean: distclean
 	      catalog/postgres.shdescription \
 	      replication/repl_gram.c \
 	      replication/repl_scanner.c \
+	      storage/lmgr/lwlocknames.c \
+	      storage/lmgr/lwlocknames.h \
 	      utils/fmgroids.h \
 	      utils/fmgrtab.c \
 	      utils/errcodes.h \
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
new file mode 100644
index 00000000000..9355caea8c1
--- /dev/null
+++ b/src/backend/storage/lmgr/.gitignore
@@ -0,0 +1,2 @@
+/lwlocknames.c
+/lwlocknames.h
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index e12a8549f74..3ad7535d74d 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -24,8 +24,17 @@ s_lock_test: s_lock.c $(top_builddir)/src/port/libpgport.a
 	$(CC) $(CPPFLAGS) $(CFLAGS) -DS_LOCK_TEST=1 $(srcdir)/s_lock.c \
 		$(TASPATH) -L $(top_builddir)/src/port -lpgport -o s_lock_test
 
+# see explanation in ../../parser/Makefile
+lwlocknames.c: lwlocknames.h ;
+
+lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt generate-lwlocknames.pl
+	$(PERL) $(srcdir)/generate-lwlocknames.pl $<
+
 check: s_lock_test
 	./s_lock_test
 
-clean distclean maintainer-clean:
+clean distclean:
 	rm -f s_lock_test
+
+maintainer-clean: clean
+	rm -f lwlocknames.h lwlocknames.c
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
new file mode 100644
index 00000000000..3af2347c2cc
--- /dev/null
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+#
+# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Copyright (c) 2000-2015, PostgreSQL Global Development Group
+
+use warnings;
+use strict;
+
+my $lastlockidx = -1;
+my $continue = "\n";
+
+open my $lwlocknames, $ARGV[0] or die;
+
+# Include PID in suffix in case parallel make runs this multiple times.
+my $htmp = "lwlocknames.h.tmp$$";
+my $ctmp = "lwlocknames.c.tmp$$";
+open H, '>', $htmp or die "Could not open $htmp: $!";
+open C, '>', $ctmp or die "Could not open $ctmp: $!";
+
+my $autogen =
+	"/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+print H $autogen;
+print H "/* there is deliberately not an #ifndef LWLOCKNAMES_H here */\n\n";
+print C $autogen, "\n";
+
+print C "static char *MainLWLockNames[] = {";
+
+while (<$lwlocknames>)
+{
+	chomp;
+
+	# Skip comments
+	next if /^#/;
+	next if /^\s*$/;
+
+	die "unable to parse lwlocknames.txt"
+	  unless /^(\w+)\s+(\d+)$/;
+
+	(my $lockname, my $lockidx) = ($1, $2);
+
+	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
+	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+
+	while ($lastlockidx < $lockidx - 1)
+	{
+		++$lastlockidx;
+		printf C "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
+		$continue = ",\n";
+	}
+	printf C "%s	\"%s\"", $continue, $lockname;
+	$lastlockidx = $lockidx;
+	$continue = ",\n";
+
+	print H "#define $lockname (&MainLWLockArray[$lockidx].lock)\n";
+}
+
+printf C "\n};\n";
+print H "\n";
+printf H "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
+
+close H;
+close C;
+
+rename($htmp, 'lwlocknames.h') || die "rename: $htmp: $!";
+rename($ctmp, 'lwlocknames.c') || die "rename: $ctmp: $!";
+
+close $lwlocknames;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 687ed6399cb..db10a961230 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -95,6 +95,9 @@
 #include "utils/hsearch.h"
 #endif
 
+/* Constants for lwlock names */
+#include "lwlocknames.c"
+
 
 /* We use the ShmemLock spinlock to protect LWLockAssign */
 extern slock_t *ShmemLock;
@@ -183,18 +186,32 @@ PRINT_LWDEBUG(const char *where, LWLock *lock, LWLockMode mode)
 	if (Trace_lwlocks)
 	{
 		uint32		state = pg_atomic_read_u32(&lock->state);
-
-		ereport(LOG,
-				(errhidestmt(true),
-				 errhidecontext(true),
-				 errmsg("%d: %s(%s %d): excl %u shared %u haswaiters %u waiters %u rOK %d",
-						MyProcPid,
-						where, T_NAME(lock), T_ID(lock),
-						!!(state & LW_VAL_EXCLUSIVE),
-						state & LW_SHARED_MASK,
-						!!(state & LW_FLAG_HAS_WAITERS),
-						pg_atomic_read_u32(&lock->nwaiters),
-						!!(state & LW_FLAG_RELEASE_OK))));
+		int			id = T_ID(lock);
+
+		if (lock->tranche == 0 && id < NUM_INDIVIDUAL_LWLOCKS)
+			ereport(LOG,
+					(errhidestmt(true),
+					 errhidecontext(true),
+					 errmsg("%d: %s(%s): excl %u shared %u haswaiters %u waiters %u rOK %d",
+							MyProcPid,
+							where, MainLWLockNames[id],
+							!!(state & LW_VAL_EXCLUSIVE),
+							state & LW_SHARED_MASK,
+							!!(state & LW_FLAG_HAS_WAITERS),
+							pg_atomic_read_u32(&lock->nwaiters),
+							!!(state & LW_FLAG_RELEASE_OK))));
+		else
+			ereport(LOG,
+					(errhidestmt(true),
+					 errhidecontext(true),
+					 errmsg("%d: %s(%s %d): excl %u shared %u haswaiters %u waiters %u rOK %d",
+							MyProcPid,
+							where, T_NAME(lock), id,
+							!!(state & LW_VAL_EXCLUSIVE),
+							state & LW_SHARED_MASK,
+							!!(state & LW_FLAG_HAS_WAITERS),
+							pg_atomic_read_u32(&lock->nwaiters),
+							!!(state & LW_FLAG_RELEASE_OK))));
 	}
 }
 
@@ -204,11 +221,20 @@ LOG_LWDEBUG(const char *where, LWLock *lock, const char *msg)
 	/* hide statement & context here, otherwise the log is just too verbose */
 	if (Trace_lwlocks)
 	{
-		ereport(LOG,
-				(errhidestmt(true),
-				 errhidecontext(true),
-				 errmsg("%s(%s %d): %s", where,
-						T_NAME(lock), T_ID(lock), msg)));
+		int			id = T_ID(lock);
+
+		if (lock->tranche == 0 && id < NUM_INDIVIDUAL_LWLOCKS)
+			ereport(LOG,
+					(errhidestmt(true),
+					 errhidecontext(true),
+					 errmsg("%s(%s): %s", where,
+							MainLWLockNames[id], msg)));
+		else
+			ereport(LOG,
+					(errhidestmt(true),
+					 errhidecontext(true),
+					 errmsg("%s(%s %d): %s", where,
+							T_NAME(lock), id, msg)));
 	}
 }
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
new file mode 100644
index 00000000000..96bbfe8fab6
--- /dev/null
+++ b/src/backend/storage/lmgr/lwlocknames.txt
@@ -0,0 +1,47 @@
+# Some commonly-used locks have predefined positions within MainLWLockArray;
+# these are defined here.  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.
+
+# 0 is available; was formerly BufFreelistLock
+ShmemIndexLock						1
+OidGenLock							2
+XidGenLock							3
+ProcArrayLock						4
+SInvalReadLock						5
+SInvalWriteLock						6
+WALBufMappingLock					7
+WALWriteLock						8
+ControlFileLock						9
+CheckpointLock						10
+CLogControlLock						11
+SubtransControlLock					12
+MultiXactGenLock					13
+MultiXactOffsetControlLock			14
+MultiXactMemberControlLock			15
+RelCacheInitLock					16
+CheckpointerCommLock				17
+TwoPhaseStateLock					18
+TablespaceCreateLock				19
+BtreeVacuumLock						20
+AddinShmemInitLock					21
+AutovacuumLock						22
+AutovacuumScheduleLock				23
+SyncScanLock						24
+RelationMappingLock					25
+AsyncCtlLock						26
+AsyncQueueLock						27
+SerializableXactHashLock			28
+SerializableFinishedListLock		29
+SerializablePredicateLockListLock	30
+OldSerXidLock						31
+SyncRepLock							32
+BackgroundWorkerLock				33
+DynamicSharedMemoryControlLock		34
+AutoFileLock						35
+ReplicationSlotAllocationLock		36
+ReplicationSlotControlLock			37
+CommitTsControlLock					38
+CommitTsLock						39
+ReplicationOriginLock				40
diff --git a/src/include/storage/.gitignore b/src/include/storage/.gitignore
new file mode 100644
index 00000000000..209c8be7223
--- /dev/null
+++ b/src/include/storage/.gitignore
@@ -0,0 +1 @@
+/lwlocknames.h
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 84a6fc7fa01..00435b062f0 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -91,56 +91,8 @@ typedef union LWLockPadded
 } LWLockPadded;
 extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
-/*
- * Some commonly-used locks have predefined positions within 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.
- */
-/* 0 is available; was formerly BufFreelistLock */
-#define ShmemIndexLock				(&MainLWLockArray[1].lock)
-#define OidGenLock					(&MainLWLockArray[2].lock)
-#define XidGenLock					(&MainLWLockArray[3].lock)
-#define ProcArrayLock				(&MainLWLockArray[4].lock)
-#define SInvalReadLock				(&MainLWLockArray[5].lock)
-#define SInvalWriteLock				(&MainLWLockArray[6].lock)
-#define WALBufMappingLock			(&MainLWLockArray[7].lock)
-#define WALWriteLock				(&MainLWLockArray[8].lock)
-#define ControlFileLock				(&MainLWLockArray[9].lock)
-#define CheckpointLock				(&MainLWLockArray[10].lock)
-#define CLogControlLock				(&MainLWLockArray[11].lock)
-#define SubtransControlLock			(&MainLWLockArray[12].lock)
-#define MultiXactGenLock			(&MainLWLockArray[13].lock)
-#define MultiXactOffsetControlLock	(&MainLWLockArray[14].lock)
-#define MultiXactMemberControlLock	(&MainLWLockArray[15].lock)
-#define RelCacheInitLock			(&MainLWLockArray[16].lock)
-#define CheckpointerCommLock		(&MainLWLockArray[17].lock)
-#define TwoPhaseStateLock			(&MainLWLockArray[18].lock)
-#define TablespaceCreateLock		(&MainLWLockArray[19].lock)
-#define BtreeVacuumLock				(&MainLWLockArray[20].lock)
-#define AddinShmemInitLock			(&MainLWLockArray[21].lock)
-#define AutovacuumLock				(&MainLWLockArray[22].lock)
-#define AutovacuumScheduleLock		(&MainLWLockArray[23].lock)
-#define SyncScanLock				(&MainLWLockArray[24].lock)
-#define RelationMappingLock			(&MainLWLockArray[25].lock)
-#define AsyncCtlLock				(&MainLWLockArray[26].lock)
-#define AsyncQueueLock				(&MainLWLockArray[27].lock)
-#define SerializableXactHashLock	(&MainLWLockArray[28].lock)
-#define SerializableFinishedListLock		(&MainLWLockArray[29].lock)
-#define SerializablePredicateLockListLock	(&MainLWLockArray[30].lock)
-#define OldSerXidLock				(&MainLWLockArray[31].lock)
-#define SyncRepLock					(&MainLWLockArray[32].lock)
-#define BackgroundWorkerLock		(&MainLWLockArray[33].lock)
-#define DynamicSharedMemoryControlLock		(&MainLWLockArray[34].lock)
-#define AutoFileLock				(&MainLWLockArray[35].lock)
-#define ReplicationSlotAllocationLock	(&MainLWLockArray[36].lock)
-#define ReplicationSlotControlLock		(&MainLWLockArray[37].lock)
-#define CommitTsControlLock			(&MainLWLockArray[38].lock)
-#define CommitTsLock				(&MainLWLockArray[39].lock)
-#define ReplicationOriginLock		(&MainLWLockArray[40].lock)
-
-#define NUM_INDIVIDUAL_LWLOCKS		41
+/* Names for fixed lwlocks */
+#include "lwlocknames.h"
 
 /*
  * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 6b16e69b690..1564b728090 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -285,6 +285,22 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY
 			'src/include/utils/fmgroids.h');
 	}
 
+	if (IsNewer(
+			'src/include/storage/lwlocknames.h', 'src/backend/storage/lmgr/lwlocknames.txt'))
+	{
+		print "Generating lwlocknames.c and lwlocknames.h...\n";
+		chdir('src/backend/storage/lmgr');
+		system('perl generate-lwlocknames.pl lwlocknames.txt');
+		chdir('../../../..');
+	}
+	if (IsNewer(
+			'src/include/storage/lwlocknames.h',
+			'src/backend/storage/lmgr/lwlocknames.h'))
+	{
+		copyFile('src/backend/storage/lmgr/lwlocknames.h',
+			'src/include/storage/lwlocknames.h');
+	}
+
 	if (IsNewer('src/include/utils/probes.h', 'src/backend/utils/probes.d'))
 	{
 		print "Generating probes.h...\n";
-- 
GitLab