public inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH v26 1/6] version nm24
22+ messages / 8 participants
[nested] [flat]

* [PATCH v26 1/6] version nm24
@ 2019-11-21 06:28  Kyotaro Horiguchi <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Kyotaro Horiguchi @ 2019-11-21 06:28 UTC (permalink / raw)

Noah Misch's version 24.
---
 doc/src/sgml/config.sgml                 |  43 +++--
 doc/src/sgml/perform.sgml                |  47 ++----
 src/backend/access/gist/gistutil.c       |   7 +-
 src/backend/access/heap/heapam.c         |  45 +-----
 src/backend/access/heap/heapam_handler.c |  22 +--
 src/backend/access/heap/rewriteheap.c    |  21 +--
 src/backend/access/nbtree/nbtsort.c      |  41 ++---
 src/backend/access/transam/README        |  47 +++++-
 src/backend/access/transam/xact.c        |  14 ++
 src/backend/access/transam/xloginsert.c  |  10 +-
 src/backend/access/transam/xlogutils.c   |  17 +-
 src/backend/catalog/heap.c               |   4 +
 src/backend/catalog/storage.c            | 198 +++++++++++++++++++++--
 src/backend/commands/cluster.c           |  11 ++
 src/backend/commands/copy.c              |  58 +------
 src/backend/commands/createas.c          |  11 +-
 src/backend/commands/matview.c           |  12 +-
 src/backend/commands/tablecmds.c         |  11 +-
 src/backend/storage/buffer/bufmgr.c      |  37 +++--
 src/backend/storage/smgr/md.c            |   9 +-
 src/backend/utils/cache/relcache.c       | 122 ++++++++++----
 src/backend/utils/misc/guc.c             |  13 ++
 src/include/access/heapam.h              |   3 -
 src/include/access/rewriteheap.h         |   2 +-
 src/include/access/tableam.h             |  18 +--
 src/include/catalog/storage.h            |   5 +
 src/include/storage/bufmgr.h             |   5 +
 src/include/utils/rel.h                  |  57 +++++--
 src/include/utils/relcache.h             |   8 +-
 src/test/regress/pg_regress.c            |   2 +
 30 files changed, 551 insertions(+), 349 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index d4d1fe45cc..d0f7dbd7d7 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2483,21 +2483,14 @@ include_dir 'conf.d'
         levels.  This parameter can only be set at server start.
        </para>
        <para>
-        In <literal>minimal</literal> level, WAL-logging of some bulk
-        operations can be safely skipped, which can make those
-        operations much faster (see <xref linkend="populate-pitr"/>).
-        Operations in which this optimization can be applied include:
-        <simplelist>
-         <member><command>CREATE TABLE AS</command></member>
-         <member><command>CREATE INDEX</command></member>
-         <member><command>CLUSTER</command></member>
-         <member><command>COPY</command> into tables that were created or truncated in the same
-         transaction</member>
-        </simplelist>
-        But minimal WAL does not contain enough information to reconstruct the
-        data from a base backup and the WAL logs, so <literal>replica</literal> or
-        higher must be used to enable WAL archiving
-        (<xref linkend="guc-archive-mode"/>) and streaming replication.
+        In <literal>minimal</literal> level, no information is logged for
+        tables or indexes for the remainder of a transaction that creates or
+        truncates them.  This can make bulk operations much faster (see
+        <xref linkend="populate-pitr"/>).  But minimal WAL does not contain
+        enough information to reconstruct the data from a base backup and the
+        WAL logs, so <literal>replica</literal> or higher must be used to
+        enable WAL archiving (<xref linkend="guc-archive-mode"/>) and
+        streaming replication.
        </para>
        <para>
         In <literal>logical</literal> level, the same information is logged as
@@ -2889,6 +2882,26 @@ include_dir 'conf.d'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-wal-skip-threshold" xreflabel="wal_skip_threshold">
+      <term><varname>wal_skip_threshold</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>wal_skip_threshold</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        When <varname>wal_level</varname> is <literal>minimal</literal> and a
+        transaction commits after creating or rewriting a permanent table,
+        materialized view, or index, this setting determines how to persist
+        the new data.  If the data is smaller than this setting, write it to
+        the WAL log; otherwise, use an fsync of the data file.  Depending on
+        the properties of your storage, raising or lowering this value might
+        help if such commits are slowing concurrent transactions.  The default
+        is 64 kilobytes (<literal>64kB</literal>).
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-commit-delay" xreflabel="commit_delay">
       <term><varname>commit_delay</varname> (<type>integer</type>)
       <indexterm>
diff --git a/doc/src/sgml/perform.sgml b/doc/src/sgml/perform.sgml
index 715aff63c8..fcc60173fb 100644
--- a/doc/src/sgml/perform.sgml
+++ b/doc/src/sgml/perform.sgml
@@ -1605,8 +1605,8 @@ SELECT * FROM x, y, a, b, c WHERE something AND somethingelse;
     needs to be written, because in case of an error, the files
     containing the newly loaded data will be removed anyway.
     However, this consideration only applies when
-    <xref linkend="guc-wal-level"/> is <literal>minimal</literal> for
-    non-partitioned tables as all commands must write WAL otherwise.
+    <xref linkend="guc-wal-level"/> is <literal>minimal</literal>
+    as all commands must write WAL otherwise.
    </para>
 
   </sect2>
@@ -1706,42 +1706,13 @@ SELECT * FROM x, y, a, b, c WHERE something AND somethingelse;
    </para>
 
    <para>
-    Aside from avoiding the time for the archiver or WAL sender to
-    process the WAL data,
-    doing this will actually make certain commands faster, because they
-    are designed not to write WAL at all if <varname>wal_level</varname>
-    is <literal>minimal</literal>.  (They can guarantee crash safety more cheaply
-    by doing an <function>fsync</function> at the end than by writing WAL.)
-    This applies to the following commands:
-    <itemizedlist>
-     <listitem>
-      <para>
-       <command>CREATE TABLE AS SELECT</command>
-      </para>
-     </listitem>
-     <listitem>
-      <para>
-       <command>CREATE INDEX</command> (and variants such as
-       <command>ALTER TABLE ADD PRIMARY KEY</command>)
-      </para>
-     </listitem>
-     <listitem>
-      <para>
-       <command>ALTER TABLE SET TABLESPACE</command>
-      </para>
-     </listitem>
-     <listitem>
-      <para>
-       <command>CLUSTER</command>
-      </para>
-     </listitem>
-     <listitem>
-      <para>
-       <command>COPY FROM</command>, when the target table has been
-       created or truncated earlier in the same transaction
-      </para>
-     </listitem>
-    </itemizedlist>
+    Aside from avoiding the time for the archiver or WAL sender to process the
+    WAL data, doing this will actually make certain commands faster, because
+    they do not to write WAL at all if <varname>wal_level</varname>
+    is <literal>minimal</literal> and the current subtransaction (or top-level
+    transaction) created or truncated the table or index they change.  (They
+    can guarantee crash safety more cheaply by doing
+    an <function>fsync</function> at the end than by writing WAL.)
    </para>
   </sect2>
 
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 553a6d67b1..66c52d6dd6 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1013,7 +1013,12 @@ gistGetFakeLSN(Relation rel)
 {
 	static XLogRecPtr counter = FirstNormalUnloggedLSN;
 
-	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+	/*
+	 * XXX before commit fix this.  This is not correct for
+	 * RELPERSISTENCE_PERMANENT, but it suffices to make tests pass.
+	 */
+	if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP
+		|| rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
 	{
 		/*
 		 * Temporary relations are only accessible in our session, so a simple
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 0128bb34ef..be19c34cbd 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -21,7 +21,6 @@
  *		heap_multi_insert - insert multiple tuples into a relation
  *		heap_delete		- delete a tuple from a relation
  *		heap_update		- replace a tuple in a relation with another tuple
- *		heap_sync		- sync heap, for when no WAL has been written
  *
  * NOTES
  *	  This file contains the heap_ routines which implement
@@ -1936,7 +1935,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
 	MarkBufferDirty(buffer);
 
 	/* XLOG stuff */
-	if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
+	if (RelationNeedsWAL(relation))
 	{
 		xl_heap_insert xlrec;
 		xl_heap_header xlhdr;
@@ -2119,7 +2118,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
 	/* currently not needed (thus unsupported) for heap_multi_insert() */
 	AssertArg(!(options & HEAP_INSERT_NO_LOGICAL));
 
-	needwal = !(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation);
+	needwal = RelationNeedsWAL(relation);
 	saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
 												   HEAP_DEFAULT_FILLFACTOR);
 
@@ -8920,46 +8919,6 @@ heap2_redo(XLogReaderState *record)
 	}
 }
 
-/*
- *	heap_sync		- sync a heap, for use when no WAL has been written
- *
- * This forces the heap contents (including TOAST heap if any) down to disk.
- * If we skipped using WAL, and WAL is otherwise needed, we must force the
- * relation down to disk before it's safe to commit the transaction.  This
- * requires writing out any dirty buffers and then doing a forced fsync.
- *
- * Indexes are not touched.  (Currently, index operations associated with
- * the commands that use this are WAL-logged and so do not need fsync.
- * That behavior might change someday, but in any case it's likely that
- * any fsync decisions required would be per-index and hence not appropriate
- * to be done here.)
- */
-void
-heap_sync(Relation rel)
-{
-	/* non-WAL-logged tables never need fsync */
-	if (!RelationNeedsWAL(rel))
-		return;
-
-	/* main heap */
-	FlushRelationBuffers(rel);
-	/* FlushRelationBuffers will have opened rd_smgr */
-	smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
-
-	/* FSM is not critical, don't bother syncing it */
-
-	/* toast heap, if any */
-	if (OidIsValid(rel->rd_rel->reltoastrelid))
-	{
-		Relation	toastrel;
-
-		toastrel = table_open(rel->rd_rel->reltoastrelid, AccessShareLock);
-		FlushRelationBuffers(toastrel);
-		smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
-		table_close(toastrel, AccessShareLock);
-	}
-}
-
 /*
  * Mask a heap page before performing consistency checks on it.
  */
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 92073fec54..07fe717faa 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -555,17 +555,6 @@ tuple_lock_retry:
 	return result;
 }
 
-static void
-heapam_finish_bulk_insert(Relation relation, int options)
-{
-	/*
-	 * If we skipped writing WAL, then we need to sync the heap (but not
-	 * indexes since those use WAL anyway / don't go through tableam)
-	 */
-	if (options & HEAP_INSERT_SKIP_WAL)
-		heap_sync(relation);
-}
-
 
 /* ------------------------------------------------------------------------
  * DDL related callbacks for heap AM.
@@ -698,7 +687,6 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
 	IndexScanDesc indexScan;
 	TableScanDesc tableScan;
 	HeapScanDesc heapScan;
-	bool		use_wal;
 	bool		is_system_catalog;
 	Tuplesortstate *tuplesort;
 	TupleDesc	oldTupDesc = RelationGetDescr(OldHeap);
@@ -713,12 +701,9 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
 	is_system_catalog = IsSystemRelation(OldHeap);
 
 	/*
-	 * We need to log the copied data in WAL iff WAL archiving/streaming is
-	 * enabled AND it's a WAL-logged rel.
+	 * Valid smgr_targblock implies something already wrote to the relation.
+	 * This may be harmless, but this function hasn't planned for it.
 	 */
-	use_wal = XLogIsNeeded() && RelationNeedsWAL(NewHeap);
-
-	/* use_wal off requires smgr_targblock be initially invalid */
 	Assert(RelationGetTargetBlock(NewHeap) == InvalidBlockNumber);
 
 	/* Preallocate values/isnull arrays */
@@ -728,7 +713,7 @@ heapam_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap,
 
 	/* Initialize the rewrite operation */
 	rwstate = begin_heap_rewrite(OldHeap, NewHeap, OldestXmin, *xid_cutoff,
-								 *multi_cutoff, use_wal);
+								 *multi_cutoff);
 
 
 	/* Set up sorting if wanted */
@@ -2515,7 +2500,6 @@ static const TableAmRoutine heapam_methods = {
 	.tuple_delete = heapam_tuple_delete,
 	.tuple_update = heapam_tuple_update,
 	.tuple_lock = heapam_tuple_lock,
-	.finish_bulk_insert = heapam_finish_bulk_insert,
 
 	.tuple_fetch_row_version = heapam_fetch_row_version,
 	.tuple_get_latest_tid = heap_get_latest_tid,
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index d285b1f390..3e564838fa 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -136,7 +136,6 @@ typedef struct RewriteStateData
 	Page		rs_buffer;		/* page currently being built */
 	BlockNumber rs_blockno;		/* block where page will go */
 	bool		rs_buffer_valid;	/* T if any tuples in buffer */
-	bool		rs_use_wal;		/* must we WAL-log inserts? */
 	bool		rs_logical_rewrite; /* do we need to do logical rewriting */
 	TransactionId rs_oldest_xmin;	/* oldest xmin used by caller to determine
 									 * tuple visibility */
@@ -230,15 +229,13 @@ static void logical_end_heap_rewrite(RewriteState state);
  * oldest_xmin	xid used by the caller to determine which tuples are dead
  * freeze_xid	xid before which tuples will be frozen
  * cutoff_multi	multixact before which multis will be removed
- * use_wal		should the inserts to the new heap be WAL-logged?
  *
  * Returns an opaque RewriteState, allocated in current memory context,
  * to be used in subsequent calls to the other functions.
  */
 RewriteState
 begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xmin,
-				   TransactionId freeze_xid, MultiXactId cutoff_multi,
-				   bool use_wal)
+				   TransactionId freeze_xid, MultiXactId cutoff_multi)
 {
 	RewriteState state;
 	MemoryContext rw_cxt;
@@ -263,7 +260,6 @@ begin_heap_rewrite(Relation old_heap, Relation new_heap, TransactionId oldest_xm
 	/* new_heap needn't be empty, just locked */
 	state->rs_blockno = RelationGetNumberOfBlocks(new_heap);
 	state->rs_buffer_valid = false;
-	state->rs_use_wal = use_wal;
 	state->rs_oldest_xmin = oldest_xmin;
 	state->rs_freeze_xid = freeze_xid;
 	state->rs_cutoff_multi = cutoff_multi;
@@ -322,7 +318,7 @@ end_heap_rewrite(RewriteState state)
 	/* Write the last page, if any */
 	if (state->rs_buffer_valid)
 	{
-		if (state->rs_use_wal)
+		if (RelationNeedsWAL(state->rs_new_rel))
 			log_newpage(&state->rs_new_rel->rd_node,
 						MAIN_FORKNUM,
 						state->rs_blockno,
@@ -337,18 +333,14 @@ end_heap_rewrite(RewriteState state)
 	}
 
 	/*
-	 * If the rel is WAL-logged, must fsync before commit.  We use heap_sync
-	 * to ensure that the toast table gets fsync'd too.
-	 *
-	 * It's obvious that we must do this when not WAL-logging. It's less
-	 * obvious that we have to do it even if we did WAL-log the pages. The
+	 * When we WAL-logged rel pages, we must nonetheless fsync them.  The
 	 * reason is the same as in storage.c's RelationCopyStorage(): we're
 	 * writing data that's not in shared buffers, and so a CHECKPOINT
 	 * occurring during the rewriteheap operation won't have fsync'd data we
 	 * wrote before the checkpoint.
 	 */
 	if (RelationNeedsWAL(state->rs_new_rel))
-		heap_sync(state->rs_new_rel);
+		smgrimmedsync(state->rs_new_rel->rd_smgr, MAIN_FORKNUM);
 
 	logical_end_heap_rewrite(state);
 
@@ -646,9 +638,6 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
 	{
 		int			options = HEAP_INSERT_SKIP_FSM;
 
-		if (!state->rs_use_wal)
-			options |= HEAP_INSERT_SKIP_WAL;
-
 		/*
 		 * While rewriting the heap for VACUUM FULL / CLUSTER, make sure data
 		 * for the TOAST table are not logically decoded.  The main heap is
@@ -687,7 +676,7 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
 			/* Doesn't fit, so write out the existing page */
 
 			/* XLOG stuff */
-			if (state->rs_use_wal)
+			if (RelationNeedsWAL(state->rs_new_rel))
 				log_newpage(&state->rs_new_rel->rd_node,
 							MAIN_FORKNUM,
 							state->rs_blockno,
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 1dd39a9535..b61692aefc 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -31,18 +31,6 @@
  * them.  They will need to be re-read into shared buffers on first use after
  * the build finishes.
  *
- * Since the index will never be used unless it is completely built,
- * from a crash-recovery point of view there is no need to WAL-log the
- * steps of the build.  After completing the index build, we can just sync
- * the whole file to disk using smgrimmedsync() before exiting this module.
- * This can be seen to be sufficient for crash recovery by considering that
- * it's effectively equivalent to what would happen if a CHECKPOINT occurred
- * just after the index build.  However, it is clearly not sufficient if the
- * DBA is using the WAL log for PITR or replication purposes, since another
- * machine would not be able to reconstruct the index from WAL.  Therefore,
- * we log the completed index pages to WAL if and only if WAL archiving is
- * active.
- *
  * This code isn't concerned about the FSM at all. The caller is responsible
  * for initializing that.
  *
@@ -563,12 +551,7 @@ _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
 	wstate.heap = btspool->heap;
 	wstate.index = btspool->index;
 	wstate.inskey = _bt_mkscankey(wstate.index, NULL);
-
-	/*
-	 * We need to log index creation in WAL iff WAL archiving/streaming is
-	 * enabled UNLESS the index isn't WAL-logged anyway.
-	 */
-	wstate.btws_use_wal = XLogIsNeeded() && RelationNeedsWAL(wstate.index);
+	wstate.btws_use_wal = RelationNeedsWAL(wstate.index);
 
 	/* reserve the metapage */
 	wstate.btws_pages_alloced = BTREE_METAPAGE + 1;
@@ -1265,21 +1248,15 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
 	_bt_uppershutdown(wstate, state);
 
 	/*
-	 * If the index is WAL-logged, we must fsync it down to disk before it's
-	 * safe to commit the transaction.  (For a non-WAL-logged index we don't
-	 * care since the index will be uninteresting after a crash anyway.)
-	 *
-	 * It's obvious that we must do this when not WAL-logging the build. It's
-	 * less obvious that we have to do it even if we did WAL-log the index
-	 * pages.  The reason is that since we're building outside shared buffers,
-	 * a CHECKPOINT occurring during the build has no way to flush the
-	 * previously written data to disk (indeed it won't know the index even
-	 * exists).  A crash later on would replay WAL from the checkpoint,
-	 * therefore it wouldn't replay our earlier WAL entries. If we do not
-	 * fsync those pages here, they might still not be on disk when the crash
-	 * occurs.
+	 * When we WAL-logged index pages, we must nonetheless fsync index files.
+	 * Since we're building outside shared buffers, a CHECKPOINT occurring
+	 * during the build has no way to flush the previously written data to
+	 * disk (indeed it won't know the index even exists).  A crash later on
+	 * would replay WAL from the checkpoint, therefore it wouldn't replay our
+	 * earlier WAL entries. If we do not fsync those pages here, they might
+	 * still not be on disk when the crash occurs.
 	 */
-	if (RelationNeedsWAL(wstate->index))
+	if (wstate->btws_use_wal)
 	{
 		RelationOpenSmgr(wstate->index);
 		smgrimmedsync(wstate->index->rd_smgr, MAIN_FORKNUM);
diff --git a/src/backend/access/transam/README b/src/backend/access/transam/README
index b5a2cb2de8..641809cfda 100644
--- a/src/backend/access/transam/README
+++ b/src/backend/access/transam/README
@@ -717,6 +717,40 @@ then restart recovery.  This is part of the reason for not writing a WAL
 entry until we've successfully done the original action.
 
 
+Skipping WAL for New RelFileNode
+--------------------------------
+
+Under wal_level=minimal, if a change modifies a relfilenode that
+RollbackAndReleaseCurrentSubTransaction() would unlink, in-tree access methods
+write no WAL for that change.  For any access method, CommitTransaction()
+writes and fsyncs affected blocks before recording the commit.  This skipping
+is mandatory; if a WAL-writing change preceded a WAL-skipping change for the
+same block, REDO could overwrite the WAL-skipping change.  Code that writes
+WAL without calling RelationNeedsWAL() must check for this case.
+
+If skipping were not mandatory, a related problem would arise.  Suppose, under
+full_page_writes=off, a WAL-writing change follows a WAL-skipping change.
+When a WAL record contains no full-page image, REDO expects the page to match
+its contents from just before record insertion.  A WAL-skipping change may not
+reach disk at all, violating REDO's expectation.
+
+Prefer to do the same in future access methods.  However, two other approaches
+can work.  First, an access method can irreversibly transition a given fork
+from WAL-skipping to WAL-writing by calling FlushRelationBuffers() and
+smgrimmedsync().  Second, an access method can opt to write WAL
+unconditionally for permanent relations.  When using the second method, do not
+call RelationCopyStorage(), which skips WAL.
+
+This applies only to WAL records whose replay would modify bytes stored in the
+new relfilenode.  It does not apply to other records about the relfilenode,
+such as XLOG_SMGR_CREATE.  Because it operates at the level of individual
+relfilenodes, RelationNeedsWAL() can differ for tightly-coupled relations.
+Consider "CREATE TABLE t (); BEGIN; ALTER TABLE t ADD c text; ..." in which
+ALTER TABLE adds a TOAST relation.  The TOAST relation will skip WAL, while
+the table owning it will not.  ALTER TABLE SET TABLESPACE will cause a table
+to skip WAL, but that won't affect its indexes.
+
+
 Asynchronous Commit
 -------------------
 
@@ -820,13 +854,12 @@ Changes to a temp table are not WAL-logged, hence could reach disk in
 advance of T1's commit, but we don't care since temp table contents don't
 survive crashes anyway.
 
-Database writes made via any of the paths we have introduced to avoid WAL
-overhead for bulk updates are also safe.  In these cases it's entirely
-possible for the data to reach disk before T1's commit, because T1 will
-fsync it down to disk without any sort of interlock, as soon as it finishes
-the bulk update.  However, all these paths are designed to write data that
-no other transaction can see until after T1 commits.  The situation is thus
-not different from ordinary WAL-logged updates.
+Database writes that skip WAL for new relfilenodes are also safe.  In these
+cases it's entirely possible for the data to reach disk before T1's commit,
+because T1 will fsync it down to disk without any sort of interlock.  However,
+all these paths are designed to write data that no other transaction can see
+until after T1 commits.  The situation is thus not different from ordinary
+WAL-logged updates.
 
 Transaction Emulation during Recovery
 -------------------------------------
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 5c0d0f2af0..750f95c482 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -2109,6 +2109,13 @@ CommitTransaction(void)
 	 */
 	PreCommit_on_commit_actions();
 
+	/*
+	 * Synchronize files that are created and not WAL-logged during this
+	 * transaction. This must happen before AtEOXact_RelationMap(), so that we
+	 * don't see committed-but-broken files after a crash.
+	 */
+	smgrDoPendingSyncs();
+
 	/* close large objects before lower-level cleanup */
 	AtEOXact_LargeObject(true);
 
@@ -2342,6 +2349,13 @@ PrepareTransaction(void)
 	 */
 	PreCommit_on_commit_actions();
 
+	/*
+	 * Synchronize files that are created and not WAL-logged during this
+	 * transaction. This must happen before EndPrepare(), so that we don't see
+	 * committed-but-broken files after a crash and COMMIT PREPARED.
+	 */
+	smgrDoPendingSyncs();
+
 	/* close large objects before lower-level cleanup */
 	AtEOXact_LargeObject(true);
 
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index aa9dca0036..dda1dea08b 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -1043,8 +1043,13 @@ log_newpage_range(Relation rel, ForkNumber forkNum,
 				  BlockNumber startblk, BlockNumber endblk,
 				  bool page_std)
 {
+	int			flags;
 	BlockNumber blkno;
 
+	flags = REGBUF_FORCE_IMAGE;
+	if (page_std)
+		flags |= REGBUF_STANDARD;
+
 	/*
 	 * Iterate over all the pages in the range. They are collected into
 	 * batches of XLR_MAX_BLOCK_ID pages, and a single WAL-record is written
@@ -1066,7 +1071,8 @@ log_newpage_range(Relation rel, ForkNumber forkNum,
 		nbufs = 0;
 		while (nbufs < XLR_MAX_BLOCK_ID && blkno < endblk)
 		{
-			Buffer		buf = ReadBuffer(rel, blkno);
+			Buffer		buf = ReadBufferExtended(rel, forkNum, blkno,
+												 RBM_NORMAL, NULL);
 
 			LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
 
@@ -1088,7 +1094,7 @@ log_newpage_range(Relation rel, ForkNumber forkNum,
 		START_CRIT_SECTION();
 		for (i = 0; i < nbufs; i++)
 		{
-			XLogRegisterBuffer(i, bufpack[i], REGBUF_FORCE_IMAGE | REGBUF_STANDARD);
+			XLogRegisterBuffer(i, bufpack[i], flags);
 			MarkBufferDirty(bufpack[i]);
 		}
 
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 446760ed6e..9561e30b08 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -544,6 +544,8 @@ typedef FakeRelCacheEntryData *FakeRelCacheEntry;
  * fields related to physical storage, like rd_rel, are initialized, so the
  * fake entry is only usable in low-level operations like ReadBuffer().
  *
+ * This is also used for syncing WAL-skipped files.
+ *
  * Caller must free the returned entry with FreeFakeRelcacheEntry().
  */
 Relation
@@ -552,18 +554,19 @@ CreateFakeRelcacheEntry(RelFileNode rnode)
 	FakeRelCacheEntry fakeentry;
 	Relation	rel;
 
-	Assert(InRecovery);
-
 	/* Allocate the Relation struct and all related space in one block. */
 	fakeentry = palloc0(sizeof(FakeRelCacheEntryData));
 	rel = (Relation) fakeentry;
 
 	rel->rd_rel = &fakeentry->pgc;
 	rel->rd_node = rnode;
-	/* We will never be working with temp rels during recovery */
+	/*
+	 * We will never be working with temp rels during recovery or while
+	 * syncing WAL-skipped files.
+	 */
 	rel->rd_backend = InvalidBackendId;
 
-	/* It must be a permanent table if we're in recovery. */
+	/* It must be a permanent table here */
 	rel->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
 
 	/* We don't know the name of the relation; use relfilenode instead */
@@ -572,9 +575,9 @@ CreateFakeRelcacheEntry(RelFileNode rnode)
 	/*
 	 * We set up the lockRelId in case anything tries to lock the dummy
 	 * relation.  Note that this is fairly bogus since relNode may be
-	 * different from the relation's OID.  It shouldn't really matter though,
-	 * since we are presumably running by ourselves and can't have any lock
-	 * conflicts ...
+	 * different from the relation's OID.  It shouldn't really matter though.
+	 * In recovery, we are running by ourselves and can't have any lock
+	 * conflicts.  While syncing, we already hold AccessExclusiveLock.
 	 */
 	rel->rd_lockInfo.lockRelId.dbId = rnode.dbNode;
 	rel->rd_lockInfo.lockRelId.relId = rnode.relNode;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index b7bcdd9d0f..293ea9a9dd 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -440,6 +440,10 @@ heap_create(const char *relname,
 				break;
 		}
 	}
+	else
+	{
+		rel->rd_createSubid = InvalidSubTransactionId;
+	}
 
 	return rel;
 }
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 056ea3d5d3..51c233dac6 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -29,9 +29,13 @@
 #include "miscadmin.h"
 #include "storage/freespace.h"
 #include "storage/smgr.h"
+#include "utils/hsearch.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
+/* GUC variables */
+int	wal_skip_threshold = 64;  /* in kilobytes */
+
 /*
  * We keep a list of all relations (represented as RelFileNode values)
  * that have been created or deleted in the current transaction.  When
@@ -58,6 +62,7 @@ typedef struct PendingRelDelete
 	BackendId	backend;		/* InvalidBackendId if not a temp rel */
 	bool		atCommit;		/* T=delete at commit; F=delete at abort */
 	int			nestLevel;		/* xact nesting level of request */
+	bool		sync;			/* whether to fsync at commit */
 	struct PendingRelDelete *next;	/* linked-list link */
 } PendingRelDelete;
 
@@ -114,6 +119,8 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
 	pending->backend = backend;
 	pending->atCommit = false;	/* delete if abort */
 	pending->nestLevel = GetCurrentTransactionNestLevel();
+	pending->sync =
+		relpersistence == RELPERSISTENCE_PERMANENT && !XLogIsNeeded();
 	pending->next = pendingDeletes;
 	pendingDeletes = pending;
 
@@ -155,6 +162,7 @@ RelationDropStorage(Relation rel)
 	pending->backend = rel->rd_backend;
 	pending->atCommit = true;	/* delete if commit */
 	pending->nestLevel = GetCurrentTransactionNestLevel();
+	pending->sync = false;
 	pending->next = pendingDeletes;
 	pendingDeletes = pending;
 
@@ -355,7 +363,9 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
 
 	/*
 	 * We need to log the copied data in WAL iff WAL archiving/streaming is
-	 * enabled AND it's a permanent relation.
+	 * enabled AND it's a permanent relation.  This gives the same answer as
+	 * "RelationNeedsWAL(rel) || copying_initfork", because we know the
+	 * current operation created a new relfilenode.
 	 */
 	use_wal = XLogIsNeeded() &&
 		(relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
@@ -397,24 +407,43 @@ RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
 	}
 
 	/*
-	 * If the rel is WAL-logged, must fsync before commit.  We use heap_sync
-	 * to ensure that the toast table gets fsync'd too.  (For a temp or
-	 * unlogged rel we don't care since the data will be gone after a crash
-	 * anyway.)
-	 *
-	 * It's obvious that we must do this when not WAL-logging the copy. It's
-	 * less obvious that we have to do it even if we did WAL-log the copied
-	 * pages. The reason is that since we're copying outside shared buffers, a
-	 * CHECKPOINT occurring during the copy has no way to flush the previously
-	 * written data to disk (indeed it won't know the new rel even exists).  A
-	 * crash later on would replay WAL from the checkpoint, therefore it
-	 * wouldn't replay our earlier WAL entries. If we do not fsync those pages
-	 * here, they might still not be on disk when the crash occurs.
+	 * When we WAL-logged rel pages, we must nonetheless fsync them.  The
+	 * reason is that since we're copying outside shared buffers, a CHECKPOINT
+	 * occurring during the copy has no way to flush the previously written
+	 * data to disk (indeed it won't know the new rel even exists).  A crash
+	 * later on would replay WAL from the checkpoint, therefore it wouldn't
+	 * replay our earlier WAL entries. If we do not fsync those pages here,
+	 * they might still not be on disk when the crash occurs.
 	 */
-	if (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork)
+	if (use_wal || copying_initfork)
 		smgrimmedsync(dst, forkNum);
 }
 
+/*
+ * RelFileNodeSkippingWAL - check if a BM_PERMANENT relfilenode is using WAL
+ *
+ *   Changes of certain relfilenodes must not write WAL; see "Skipping WAL for
+ *   New RelFileNode" in src/backend/access/transam/README.  Though it is
+ *   known from Relation efficiently, this function is intended for the code
+ *   paths not having access to Relation.
+ */
+bool
+RelFileNodeSkippingWAL(RelFileNode rnode)
+{
+	PendingRelDelete *pending;
+
+	if (XLogIsNeeded())
+		return false;  /* no permanent relfilenode skips WAL */
+
+	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+	{
+		if (RelFileNodeEquals(pending->relnode, rnode) && pending->sync)
+			return true;
+	}
+
+	return false;
+}
+
 /*
  *	smgrDoPendingDeletes() -- Take care of relation deletes at end of xact.
  *
@@ -492,6 +521,145 @@ smgrDoPendingDeletes(bool isCommit)
 	}
 }
 
+/*
+ *	smgrDoPendingSyncs() -- Take care of relation syncs at commit.
+ *
+ * This should be called before smgrDoPendingDeletes() at every commit or
+ * prepare. Also this should be called before emitting WAL record so that sync
+ * failure prevents commit.
+ */
+void
+smgrDoPendingSyncs(void)
+{
+	PendingRelDelete *pending;
+	HTAB	*delhash = NULL;
+
+	if (XLogIsNeeded())
+		return;  /* no relation can use this */
+
+	Assert(GetCurrentTransactionNestLevel() == 1);
+	AssertPendingSyncs_RelationCache();
+
+	/*
+	 * Pending syncs on the relation that are to be deleted in this
+	 * transaction-end should be ignored. Collect pending deletes that will
+	 * happen in the following call to smgrDoPendingDeletes().
+	 */
+	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+	{
+		bool found PG_USED_FOR_ASSERTS_ONLY;
+
+		if (!pending->atCommit)
+			continue;
+
+		/* create the hash if not yet */
+		if (delhash == NULL)
+		{
+			HASHCTL hash_ctl;
+
+			memset(&hash_ctl, 0, sizeof(hash_ctl));
+			hash_ctl.keysize = sizeof(RelFileNode);
+			hash_ctl.entrysize = sizeof(RelFileNode);
+			hash_ctl.hcxt = CurrentMemoryContext;
+			delhash =
+				hash_create("pending del temporary hash", 8, &hash_ctl,
+							HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
+		}
+
+		(void) hash_search(delhash, (void *) &pending->relnode,
+						   HASH_ENTER, &found);
+		Assert(!found);
+	}
+
+	for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+	{
+		bool to_be_removed = false; /* don't sync if aborted */
+		ForkNumber fork;
+		BlockNumber nblocks[MAX_FORKNUM + 1];
+		BlockNumber total_blocks = 0;
+		SMgrRelation srel;
+
+		if (!pending->sync)
+			continue;
+		Assert(!pending->atCommit);
+
+		/* don't sync relnodes that is being deleted */
+		if (delhash)
+			hash_search(delhash, (void *) &pending->relnode,
+						HASH_FIND, &to_be_removed);
+		if (to_be_removed)
+			continue;
+
+		/* Now the time to sync the rnode */
+		srel = smgropen(pending->relnode, pending->backend);
+
+		/*
+		 * We emit newpage WAL records for smaller relations.
+		 *
+		 * Small WAL records have a chance to be emitted along with other
+		 * backends' WAL records. We emit WAL records instead of syncing for
+		 * files that are smaller than a certain threshold, expecting faster
+		 * commit. The threshold is defined by the GUC wal_skip_threshold.
+		 */
+		for (fork = 0 ; fork <= MAX_FORKNUM ; fork++)
+		{
+			if (smgrexists(srel, fork))
+			{
+				BlockNumber n = smgrnblocks(srel, fork);
+
+				/* we shouldn't come here for unlogged relations */
+				Assert(fork != INIT_FORKNUM);
+
+				nblocks[fork] = n;
+				total_blocks += n;
+			}
+			else
+				nblocks[fork] = InvalidBlockNumber;
+		}
+
+		/*
+		 * Sync file or emit WAL record for the file according to the total
+		 * size.
+		 */
+		if (total_blocks * BLCKSZ >= wal_skip_threshold * 1024)
+		{
+			/* Flush all buffers then sync the file */
+			FlushRelationBuffersWithoutRelcache(srel, false);
+
+			for (fork = 0; fork <= MAX_FORKNUM; fork++)
+			{
+				if (smgrexists(srel, fork))
+					smgrimmedsync(srel, fork);
+			}
+		}
+		else
+		{
+			/* Emit WAL records for all blocks. The file is small enough. */
+			for (fork = 0 ; fork <= MAX_FORKNUM ; fork++)
+			{
+				int    n        = nblocks[fork];
+				Relation rel;
+
+				if (!BlockNumberIsValid(n))
+					continue;
+
+				/*
+				 * Emit WAL for the whole file.  Unfortunately we don't know
+				 * what kind of a page this is, so we have to log the full
+				 * page including any unused space.  ReadBufferExtended()
+				 * counts some pgstat events; unfortunately, we discard them.
+				 */
+				rel = CreateFakeRelcacheEntry(srel->smgr_rnode.node);
+				log_newpage_range(rel, fork, 0, n, false);
+				FreeFakeRelcacheEntry(rel);
+			}
+		}
+	}
+
+	if (delhash)
+		hash_destroy(delhash);
+}
+
 /*
  * smgrGetPendingDeletes() -- Get a list of non-temp relations to be deleted.
  *
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index b8c349f245..093fff8c5c 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1014,6 +1014,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 				relfilenode2;
 	Oid			swaptemp;
 	char		swptmpchr;
+	Relation	rel1;
 
 	/* We need writable copies of both pg_class tuples. */
 	relRelation = table_open(RelationRelationId, RowExclusiveLock);
@@ -1039,6 +1040,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 		 */
 		Assert(!target_is_pg_class);
 
+		/* swap relfilenodes, reltablespaces, relpersistence */
 		swaptemp = relform1->relfilenode;
 		relform1->relfilenode = relform2->relfilenode;
 		relform2->relfilenode = swaptemp;
@@ -1173,6 +1175,15 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 		CacheInvalidateRelcacheByTuple(reltup2);
 	}
 
+	/*
+	 * Recognize that rel1's relfilenode (swapped from rel2) is new in this
+	 * subtransaction. Since the next step for rel2 is deletion, don't bother
+	 * recording the newness of its relfilenode.
+	 */
+	rel1 = relation_open(r1, AccessExclusiveLock);
+	RelationAssumeNewRelfilenode(rel1);
+	relation_close(rel1, NoLock);
+
 	/*
 	 * Post alter hook for modified relations. The change to r2 is always
 	 * internal, but r1 depends on the invocation context.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 42a147b67d..607e2558a3 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2711,63 +2711,15 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*----------
-	 * Check to see if we can avoid writing WAL
-	 *
-	 * If archive logging/streaming is not enabled *and* either
-	 *	- table was created in same transaction as this COPY
-	 *	- data is being written to relfilenode created in this transaction
-	 * then we can skip writing WAL.  It's safe because if the transaction
-	 * doesn't commit, we'll discard the table (or the new relfilenode file).
-	 * If it does commit, we'll have done the table_finish_bulk_insert() at
-	 * the bottom of this routine first.
-	 *
-	 * As mentioned in comments in utils/rel.h, the in-same-transaction test
-	 * is not always set correctly, since in rare cases rd_newRelfilenodeSubid
-	 * can be cleared before the end of the transaction. The exact case is
-	 * when a relation sets a new relfilenode twice in same transaction, yet
-	 * the second one fails in an aborted subtransaction, e.g.
-	 *
-	 * BEGIN;
-	 * TRUNCATE t;
-	 * SAVEPOINT save;
-	 * TRUNCATE t;
-	 * ROLLBACK TO save;
-	 * COPY ...
-	 *
-	 * Also, if the target file is new-in-transaction, we assume that checking
-	 * FSM for free space is a waste of time, even if we must use WAL because
-	 * of archiving.  This could possibly be wrong, but it's unlikely.
-	 *
-	 * The comments for table_tuple_insert and RelationGetBufferForTuple
-	 * specify that skipping WAL logging is only safe if we ensure that our
-	 * tuples do not go into pages containing tuples from any other
-	 * transactions --- but this must be the case if we have a new table or
-	 * new relfilenode, so we need no additional work to enforce that.
-	 *
-	 * We currently don't support this optimization if the COPY target is a
-	 * partitioned table as we currently only lazily initialize partition
-	 * information when routing the first tuple to the partition.  We cannot
-	 * know at this stage if we can perform this optimization.  It should be
-	 * possible to improve on this, but it does mean maintaining heap insert
-	 * option flags per partition and setting them when we first open the
-	 * partition.
-	 *
-	 * This optimization is not supported for relation types which do not
-	 * have any physical storage, with foreign tables and views using
-	 * INSTEAD OF triggers entering in this category.  Partitioned tables
-	 * are not supported as per the description above.
-	 *----------
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
 	 */
-	/* createSubid is creation check, newRelfilenodeSubid is truncation check */
 	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
 		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId))
-	{
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
 		ti_options |= TABLE_INSERT_SKIP_FSM;
-		if (!XLogIsNeeded())
-			ti_options |= TABLE_INSERT_SKIP_WAL;
-	}
 
 	/*
 	 * Optimize if new relfilenode was created in this subxact or one of its
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 2bf7083719..20225dc62f 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -552,16 +552,13 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
 	myState->rel = intoRelationDesc;
 	myState->reladdr = intoRelationAddr;
 	myState->output_cid = GetCurrentCommandId(true);
+	myState->ti_options = TABLE_INSERT_SKIP_FSM;
+	myState->bistate = GetBulkInsertState();
 
 	/*
-	 * We can skip WAL-logging the insertions, unless PITR or streaming
-	 * replication is in use. We can skip the FSM in any case.
+	 * Valid smgr_targblock implies something already wrote to the relation.
+	 * This may be harmless, but this function hasn't planned for it.
 	 */
-	myState->ti_options = TABLE_INSERT_SKIP_FSM |
-		(XLogIsNeeded() ? 0 : TABLE_INSERT_SKIP_WAL);
-	myState->bistate = GetBulkInsertState();
-
-	/* Not using WAL requires smgr_targblock be initially invalid */
 	Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber);
 }
 
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 537d0e8cef..ae809c9801 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -457,17 +457,13 @@ transientrel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
 	 */
 	myState->transientrel = transientrel;
 	myState->output_cid = GetCurrentCommandId(true);
-
-	/*
-	 * We can skip WAL-logging the insertions, unless PITR or streaming
-	 * replication is in use. We can skip the FSM in any case.
-	 */
 	myState->ti_options = TABLE_INSERT_SKIP_FSM | TABLE_INSERT_FROZEN;
-	if (!XLogIsNeeded())
-		myState->ti_options |= TABLE_INSERT_SKIP_WAL;
 	myState->bistate = GetBulkInsertState();
 
-	/* Not using WAL requires smgr_targblock be initially invalid */
+	/*
+	 * Valid smgr_targblock implies something already wrote to the relation.
+	 * This may be harmless, but this function hasn't planned for it.
+	 */
 	Assert(RelationGetTargetBlock(transientrel) == InvalidBlockNumber);
 }
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 5440eb9015..0e2f5f4259 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4770,19 +4770,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
 		newrel = NULL;
 
 	/*
-	 * Prepare a BulkInsertState and options for table_tuple_insert. Because
-	 * we're building a new heap, we can skip WAL-logging and fsync it to disk
-	 * at the end instead (unless WAL-logging is required for archiving or
-	 * streaming replication). The FSM is empty too, so don't bother using it.
+	 * Prepare a BulkInsertState and options for table_tuple_insert.  The FSM
+	 * is empty, so don't bother using it.
 	 */
 	if (newrel)
 	{
 		mycid = GetCurrentCommandId(true);
 		bistate = GetBulkInsertState();
-
 		ti_options = TABLE_INSERT_SKIP_FSM;
-		if (!XLogIsNeeded())
-			ti_options |= TABLE_INSERT_SKIP_WAL;
 	}
 	else
 	{
@@ -12462,6 +12457,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 
 	table_close(pg_class, RowExclusiveLock);
 
+	RelationAssumeNewRelfilenode(rel);
+
 	relation_close(rel, NoLock);
 
 	/* Make sure the reltablespace change is visible */
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 7ad10736d5..746ce477fc 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3203,20 +3203,27 @@ PrintPinnedBufs(void)
 void
 FlushRelationBuffers(Relation rel)
 {
-	int			i;
-	BufferDesc *bufHdr;
-
-	/* Open rel at the smgr level if not already done */
 	RelationOpenSmgr(rel);
 
-	if (RelationUsesLocalBuffers(rel))
+	FlushRelationBuffersWithoutRelcache(rel->rd_smgr,
+										RelationUsesLocalBuffers(rel));
+}
+
+void
+FlushRelationBuffersWithoutRelcache(SMgrRelation smgr, bool islocal)
+{
+	RelFileNode rnode = smgr->smgr_rnode.node;
+	int i;
+	BufferDesc *bufHdr;
+
+	if (islocal)
 	{
 		for (i = 0; i < NLocBuffer; i++)
 		{
 			uint32		buf_state;
 
 			bufHdr = GetLocalBufferDescriptor(i);
-			if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
+			if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
 				((buf_state = pg_atomic_read_u32(&bufHdr->state)) &
 				 (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY))
 			{
@@ -3233,7 +3240,7 @@ FlushRelationBuffers(Relation rel)
 
 				PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
 
-				smgrwrite(rel->rd_smgr,
+				smgrwrite(smgr,
 						  bufHdr->tag.forkNum,
 						  bufHdr->tag.blockNum,
 						  localpage,
@@ -3263,18 +3270,18 @@ FlushRelationBuffers(Relation rel)
 		 * As in DropRelFileNodeBuffers, an unlocked precheck should be safe
 		 * and saves some cycles.
 		 */
-		if (!RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node))
+		if (!RelFileNodeEquals(bufHdr->tag.rnode, rnode))
 			continue;
 
 		ReservePrivateRefCountEntry();
 
 		buf_state = LockBufHdr(bufHdr);
-		if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
+		if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&
 			(buf_state & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY))
 		{
 			PinBuffer_Locked(bufHdr);
 			LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED);
-			FlushBuffer(bufHdr, rel->rd_smgr);
+			FlushBuffer(bufHdr, smgr);
 			LWLockRelease(BufferDescriptorGetContentLock(bufHdr));
 			UnpinBuffer(bufHdr, true);
 		}
@@ -3484,13 +3491,15 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
 			(pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT))
 		{
 			/*
-			 * If we're in recovery we cannot dirty a page because of a hint.
-			 * We can set the hint, just not dirty the page as a result so the
-			 * hint is lost when we evict the page or shutdown.
+			 * If we must not write WAL, due to a relfilenode-specific
+			 * condition or being in recovery, don't dirty the page.  We can
+			 * set the hint, just not dirty the page as a result so the hint
+			 * is lost when we evict the page or shutdown.
 			 *
 			 * See src/backend/storage/page/README for longer discussion.
 			 */
-			if (RecoveryInProgress())
+			if (RecoveryInProgress() ||
+				RelFileNodeSkippingWAL(bufHdr->tag.rnode))
 				return;
 
 			/*
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 8a9eaf6430..1d408c339c 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -248,11 +248,10 @@ mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
  * During replay, we would delete the file and then recreate it, which is fine
  * if the contents of the file were repopulated by subsequent WAL entries.
  * But if we didn't WAL-log insertions, but instead relied on fsyncing the
- * file after populating it (as for instance CLUSTER and CREATE INDEX do),
- * the contents of the file would be lost forever.  By leaving the empty file
- * until after the next checkpoint, we prevent reassignment of the relfilenode
- * number until it's safe, because relfilenode assignment skips over any
- * existing file.
+ * file after populating it (as we do at wal_level=minimal), the contents of
+ * the file would be lost forever.  By leaving the empty file until after the
+ * next checkpoint, we prevent reassignment of the relfilenode number until
+ * it's safe, because relfilenode assignment skips over any existing file.
  *
  * We do not need to go through this dance for temp relations, though, because
  * we never make WAL entries for temp rels, and so a temp rel poses no threat
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index ad1ff01b32..f3831f0077 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -262,6 +262,9 @@ static void RelationReloadIndexInfo(Relation relation);
 static void RelationReloadNailed(Relation relation);
 static void RelationFlushRelation(Relation relation);
 static void RememberToFreeTupleDescAtEOX(TupleDesc td);
+#ifdef USE_ASSERT_CHECKING
+static void AssertPendingSyncConsistency(Relation relation);
+#endif
 static void AtEOXact_cleanup(Relation relation, bool isCommit);
 static void AtEOSubXact_cleanup(Relation relation, bool isCommit,
 								SubTransactionId mySubid, SubTransactionId parentSubid);
@@ -1095,6 +1098,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	relation->rd_isnailed = false;
 	relation->rd_createSubid = InvalidSubTransactionId;
 	relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
+	relation->rd_firstRelfilenodeSubid = InvalidSubTransactionId;
 	switch (relation->rd_rel->relpersistence)
 	{
 		case RELPERSISTENCE_UNLOGGED:
@@ -1828,6 +1832,7 @@ formrdesc(const char *relationName, Oid relationReltype,
 	relation->rd_isnailed = true;
 	relation->rd_createSubid = InvalidSubTransactionId;
 	relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
+	relation->rd_firstRelfilenodeSubid = InvalidSubTransactionId;
 	relation->rd_backend = InvalidBackendId;
 	relation->rd_islocaltemp = false;
 
@@ -2035,6 +2040,12 @@ RelationIdGetRelation(Oid relationId)
 	rd = RelationBuildDesc(relationId, true);
 	if (RelationIsValid(rd))
 		RelationIncrementReferenceCount(rd);
+
+#ifdef USE_ASSERT_CHECKING
+	if (!XLogIsNeeded() && RelationIsValid(rd))
+		AssertPendingSyncConsistency(rd);
+#endif
+
 	return rd;
 }
 
@@ -2093,7 +2104,7 @@ RelationClose(Relation relation)
 #ifdef RELCACHE_FORCE_RELEASE
 	if (RelationHasReferenceCountZero(relation) &&
 		relation->rd_createSubid == InvalidSubTransactionId &&
-		relation->rd_newRelfilenodeSubid == InvalidSubTransactionId)
+		relation->rd_firstRelfilenodeSubid == InvalidSubTransactionId)
 		RelationClearRelation(relation, false);
 #endif
 }
@@ -2509,13 +2520,13 @@ RelationClearRelation(Relation relation, bool rebuild)
 		 * problem.
 		 *
 		 * When rebuilding an open relcache entry, we must preserve ref count,
-		 * rd_createSubid/rd_newRelfilenodeSubid, and rd_toastoid state.  Also
-		 * attempt to preserve the pg_class entry (rd_rel), tupledesc,
-		 * rewrite-rule, partition key, and partition descriptor substructures
-		 * in place, because various places assume that these structures won't
-		 * move while they are working with an open relcache entry.  (Note:
-		 * the refcount mechanism for tupledescs might someday allow us to
-		 * remove this hack for the tupledesc.)
+		 * rd_*Subid, and rd_toastoid state.  Also attempt to preserve the
+		 * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
+		 * and partition descriptor substructures in place, because various
+		 * places assume that these structures won't move while they are
+		 * working with an open relcache entry.  (Note:  the refcount
+		 * mechanism for tupledescs might someday allow us to remove this hack
+		 * for the tupledesc.)
 		 *
 		 * Note that this process does not touch CurrentResourceOwner; which
 		 * is good because whatever ref counts the entry may have do not
@@ -2599,6 +2610,7 @@ RelationClearRelation(Relation relation, bool rebuild)
 		/* creation sub-XIDs must be preserved */
 		SWAPFIELD(SubTransactionId, rd_createSubid);
 		SWAPFIELD(SubTransactionId, rd_newRelfilenodeSubid);
+		SWAPFIELD(SubTransactionId, rd_firstRelfilenodeSubid);
 		/* un-swap rd_rel pointers, swap contents instead */
 		SWAPFIELD(Form_pg_class, rd_rel);
 		/* ... but actually, we don't have to update newrel->rd_rel */
@@ -2666,7 +2678,7 @@ static void
 RelationFlushRelation(Relation relation)
 {
 	if (relation->rd_createSubid != InvalidSubTransactionId ||
-		relation->rd_newRelfilenodeSubid != InvalidSubTransactionId)
+		relation->rd_firstRelfilenodeSubid != InvalidSubTransactionId)
 	{
 		/*
 		 * New relcache entries are always rebuilt, not flushed; else we'd
@@ -2751,11 +2763,10 @@ RelationCacheInvalidateEntry(Oid relationId)
  *	 relation cache and re-read relation mapping data.
  *
  *	 This is currently used only to recover from SI message buffer overflow,
- *	 so we do not touch new-in-transaction relations; they cannot be targets
- *	 of cross-backend SI updates (and our own updates now go through a
- *	 separate linked list that isn't limited by the SI message buffer size).
- *	 Likewise, we need not discard new-relfilenode-in-transaction hints,
- *	 since any invalidation of those would be a local event.
+ *	 so we do not touch relations having new-in-transaction relfilenodes; they
+ *	 cannot be targets of cross-backend SI updates (and our own updates now go
+ *	 through a separate linked list that isn't limited by the SI message
+ *	 buffer size).
  *
  *	 We do this in two phases: the first pass deletes deletable items, and
  *	 the second one rebuilds the rebuildable items.  This is essential for
@@ -2806,7 +2817,7 @@ RelationCacheInvalidate(void)
 		 * pending invalidations.
 		 */
 		if (relation->rd_createSubid != InvalidSubTransactionId ||
-			relation->rd_newRelfilenodeSubid != InvalidSubTransactionId)
+			relation->rd_firstRelfilenodeSubid != InvalidSubTransactionId)
 			continue;
 
 		relcacheInvalsReceived++;
@@ -2918,6 +2929,40 @@ RememberToFreeTupleDescAtEOX(TupleDesc td)
 	EOXactTupleDescArray[NextEOXactTupleDescNum++] = td;
 }
 
+#ifdef USE_ASSERT_CHECKING
+static void
+AssertPendingSyncConsistency(Relation relation)
+{
+	bool relcache_verdict =
+		relation->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT &&
+		((relation->rd_createSubid != InvalidSubTransactionId &&
+		  RELKIND_HAS_STORAGE(relation->rd_rel->relkind)) ||
+		 relation->rd_firstRelfilenodeSubid != InvalidSubTransactionId);
+	Assert(relcache_verdict == RelFileNodeSkippingWAL(relation->rd_node));
+}
+
+/*
+ * AssertPendingSyncs_RelationCache
+ *
+ *	Assert that relcache.c and storage.c agree on whether to skip WAL.
+ *
+ * This consistently detects relcache.c skipping WAL while storage.c is not
+ * skipping WAL.  It often fails to detect the reverse error, because
+ * invalidation will have destroyed the relcache entry.  It will detect the
+ * reverse error if something opens the relation after the DDL.
+ */
+void
+AssertPendingSyncs_RelationCache(void)
+{
+	HASH_SEQ_STATUS status;
+	RelIdCacheEnt *idhentry;
+
+	hash_seq_init(&status, RelationIdCache);
+	while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
+		AssertPendingSyncConsistency(idhentry->reldesc);
+}
+#endif
+
 /*
  * AtEOXact_RelationCache
  *
@@ -3029,10 +3074,7 @@ AtEOXact_cleanup(Relation relation, bool isCommit)
 	 *
 	 * During commit, reset the flag to zero, since we are now out of the
 	 * creating transaction.  During abort, simply delete the relcache entry
-	 * --- it isn't interesting any longer.  (NOTE: if we have forgotten the
-	 * new-ness of a new relation due to a forced cache flush, the entry will
-	 * get deleted anyway by shared-cache-inval processing of the aborted
-	 * pg_class insertion.)
+	 * --- it isn't interesting any longer.
 	 */
 	if (relation->rd_createSubid != InvalidSubTransactionId)
 	{
@@ -3060,9 +3102,10 @@ AtEOXact_cleanup(Relation relation, bool isCommit)
 	}
 
 	/*
-	 * Likewise, reset the hint about the relfilenode being new.
+	 * Likewise, reset any record of the relfilenode being new.
 	 */
 	relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
+	relation->rd_firstRelfilenodeSubid = InvalidSubTransactionId;
 }
 
 /*
@@ -3154,7 +3197,7 @@ AtEOSubXact_cleanup(Relation relation, bool isCommit,
 	}
 
 	/*
-	 * Likewise, update or drop any new-relfilenode-in-subtransaction hint.
+	 * Likewise, update or drop any new-relfilenode-in-subtransaction.
 	 */
 	if (relation->rd_newRelfilenodeSubid == mySubid)
 	{
@@ -3163,6 +3206,14 @@ AtEOSubXact_cleanup(Relation relation, bool isCommit,
 		else
 			relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
 	}
+
+	if (relation->rd_firstRelfilenodeSubid == mySubid)
+	{
+		if (isCommit)
+			relation->rd_firstRelfilenodeSubid = parentSubid;
+		else
+			relation->rd_firstRelfilenodeSubid = InvalidSubTransactionId;
+	}
 }
 
 
@@ -3252,6 +3303,7 @@ RelationBuildLocalRelation(const char *relname,
 	/* it's being created in this transaction */
 	rel->rd_createSubid = GetCurrentSubTransactionId();
 	rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
+	rel->rd_firstRelfilenodeSubid = InvalidSubTransactionId;
 
 	/*
 	 * create a new tuple descriptor from the one passed in.  We do this
@@ -3549,14 +3601,29 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 	 */
 	CommandCounterIncrement();
 
-	/*
-	 * Mark the rel as having been given a new relfilenode in the current
-	 * (sub) transaction.  This is a hint that can be used to optimize later
-	 * operations on the rel in the same transaction.
-	 */
+	RelationAssumeNewRelfilenode(relation);
+}
+
+/*
+ * RelationAssumeNewRelfilenode
+ *
+ * Code that modifies pg_class.reltablespace or pg_class.relfilenode must call
+ * this.  The call shall precede any code that might insert WAL records whose
+ * replay would modify bytes in the new RelFileNode, and the call shall follow
+ * any WAL modifying bytes in the prior RelFileNode.  See struct RelationData.
+ * Ideally, call this as near as possible to the CommandCounterIncrement()
+ * that makes the pg_class change visible (before it or after it); that
+ * minimizes the chance of future development adding a forbidden WAL insertion
+ * between RelationAssumeNewRelfilenode() and CommandCounterIncrement().
+ */
+void
+RelationAssumeNewRelfilenode(Relation relation)
+{
 	relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
+	if (relation->rd_firstRelfilenodeSubid == InvalidSubTransactionId)
+		relation->rd_firstRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
 
-	/* Flag relation as needing eoxact cleanup (to remove the hint) */
+	/* Flag relation as needing eoxact cleanup (to clear these fields) */
 	EOXactListAdd(relation);
 }
 
@@ -5591,6 +5658,7 @@ load_relcache_init_file(bool shared)
 		rel->rd_fkeylist = NIL;
 		rel->rd_createSubid = InvalidSubTransactionId;
 		rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
+		rel->rd_firstRelfilenodeSubid = InvalidSubTransactionId;
 		rel->rd_amcache = NULL;
 		MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ba4edde71a..eecaf398c5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -36,6 +36,7 @@
 #include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_authid.h"
+#include "catalog/storage.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
 #include "commands/trigger.h"
@@ -2651,6 +2652,18 @@ static struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"wal_skip_threshold", PGC_USERSET, RESOURCES_DISK,
+			gettext_noop("Size of new file to fsync instead of writing WAL."),
+			NULL,
+			GUC_UNIT_KB
+		},
+		&wal_skip_threshold,
+		64,
+		0, MAX_KILOBYTES,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"max_wal_senders", PGC_POSTMASTER, REPLICATION_SENDING,
 			gettext_noop("Sets the maximum number of simultaneously running WAL sender processes."),
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 858bcb6bc9..22916e8e0e 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -29,7 +29,6 @@
 
 
 /* "options" flag bits for heap_insert */
-#define HEAP_INSERT_SKIP_WAL	TABLE_INSERT_SKIP_WAL
 #define HEAP_INSERT_SKIP_FSM	TABLE_INSERT_SKIP_FSM
 #define HEAP_INSERT_FROZEN		TABLE_INSERT_FROZEN
 #define HEAP_INSERT_NO_LOGICAL	TABLE_INSERT_NO_LOGICAL
@@ -166,8 +165,6 @@ extern void simple_heap_delete(Relation relation, ItemPointer tid);
 extern void simple_heap_update(Relation relation, ItemPointer otid,
 							   HeapTuple tup);
 
-extern void heap_sync(Relation relation);
-
 extern TransactionId heap_compute_xid_horizon_for_tuples(Relation rel,
 														 ItemPointerData *items,
 														 int nitems);
diff --git a/src/include/access/rewriteheap.h b/src/include/access/rewriteheap.h
index 8056253916..7f9736e294 100644
--- a/src/include/access/rewriteheap.h
+++ b/src/include/access/rewriteheap.h
@@ -23,7 +23,7 @@ typedef struct RewriteStateData *RewriteState;
 
 extern RewriteState begin_heap_rewrite(Relation OldHeap, Relation NewHeap,
 									   TransactionId OldestXmin, TransactionId FreezeXid,
-									   MultiXactId MultiXactCutoff, bool use_wal);
+									   MultiXactId MultiXactCutoff);
 extern void end_heap_rewrite(RewriteState state);
 extern void rewrite_heap_tuple(RewriteState state, HeapTuple oldTuple,
 							   HeapTuple newTuple);
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 64022917e2..aca88d0620 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -127,7 +127,7 @@ typedef struct TM_FailureData
 } TM_FailureData;
 
 /* "options" flag bits for table_tuple_insert */
-#define TABLE_INSERT_SKIP_WAL		0x0001
+/* TABLE_INSERT_SKIP_WAL was 0x0001; RelationNeedsWAL() now governs */
 #define TABLE_INSERT_SKIP_FSM		0x0002
 #define TABLE_INSERT_FROZEN			0x0004
 #define TABLE_INSERT_NO_LOGICAL		0x0008
@@ -409,9 +409,8 @@ typedef struct TableAmRoutine
 
 	/*
 	 * Perform operations necessary to complete insertions made via
-	 * tuple_insert and multi_insert with a BulkInsertState specified. This
-	 * may for example be used to flush the relation, when the
-	 * TABLE_INSERT_SKIP_WAL option was used.
+	 * tuple_insert and multi_insert with a BulkInsertState specified. In-tree
+	 * access methods ceased to use this.
 	 *
 	 * Typically callers of tuple_insert and multi_insert will just pass all
 	 * the flags that apply to them, and each AM has to decide which of them
@@ -1087,10 +1086,6 @@ table_compute_xid_horizon_for_tuples(Relation rel,
  * The options bitmask allows the caller to specify options that may change the
  * behaviour of the AM. The AM will ignore options that it does not support.
  *
- * If the TABLE_INSERT_SKIP_WAL option is specified, the new tuple doesn't
- * need to be logged to WAL, even for a non-temp relation. It is the AMs
- * choice whether this optimization is supported.
- *
  * If the TABLE_INSERT_SKIP_FSM option is specified, AMs are free to not reuse
  * free space in the relation. This can save some cycles when we know the
  * relation is new and doesn't contain useful amounts of free space.
@@ -1309,10 +1304,9 @@ table_tuple_lock(Relation rel, ItemPointer tid, Snapshot snapshot,
 }
 
 /*
- * Perform operations necessary to complete insertions made via
- * tuple_insert and multi_insert with a BulkInsertState specified. This
- * e.g. may e.g. used to flush the relation when inserting with
- * TABLE_INSERT_SKIP_WAL specified.
+ * Perform operations necessary to complete insertions made via tuple_insert
+ * and multi_insert with a BulkInsertState specified. In-tree access methods
+ * ceased to use this.
  */
 static inline void
 table_finish_bulk_insert(Relation rel, int options)
diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h
index 3579d3f3eb..108115a023 100644
--- a/src/include/catalog/storage.h
+++ b/src/include/catalog/storage.h
@@ -19,18 +19,23 @@
 #include "storage/smgr.h"
 #include "utils/relcache.h"
 
+/* GUC variables */
+extern int	wal_skip_threshold;
+
 extern SMgrRelation RelationCreateStorage(RelFileNode rnode, char relpersistence);
 extern void RelationDropStorage(Relation rel);
 extern void RelationPreserveStorage(RelFileNode rnode, bool atCommit);
 extern void RelationTruncate(Relation rel, BlockNumber nblocks);
 extern void RelationCopyStorage(SMgrRelation src, SMgrRelation dst,
 								ForkNumber forkNum, char relpersistence);
+extern bool RelFileNodeSkippingWAL(RelFileNode rnode);
 
 /*
  * These functions used to be in storage/smgr/smgr.c, which explains the
  * naming
  */
 extern void smgrDoPendingDeletes(bool isCommit);
+extern void smgrDoPendingSyncs(void);
 extern int	smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr);
 extern void AtSubCommit_smgr(void);
 extern void AtSubAbort_smgr(void);
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 17b97f7e38..8097d5ab22 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -49,6 +49,9 @@ typedef enum
 /* forward declared, to avoid having to expose buf_internals.h here */
 struct WritebackContext;
 
+/* forward declared, to avoid including smgr.h here */
+struct SMgrRelationData;
+
 /* in globals.c ... this duplicates miscadmin.h */
 extern PGDLLIMPORT int NBuffers;
 
@@ -189,6 +192,8 @@ extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation,
 												   ForkNumber forkNum);
 extern void FlushOneBuffer(Buffer buffer);
 extern void FlushRelationBuffers(Relation rel);
+extern void FlushRelationBuffersWithoutRelcache(struct SMgrRelationData *smgr,
+												bool islocal);
 extern void FlushDatabaseBuffers(Oid dbid);
 extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, ForkNumber *forkNum,
 								   int nforks, BlockNumber *firstDelBlock);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 31d8a1a10e..9db3d23897 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -63,22 +63,40 @@ typedef struct RelationData
 								 * rd_replidindex) */
 	bool		rd_statvalid;	/* is rd_statlist valid? */
 
-	/*
+	/*----------
 	 * rd_createSubid is the ID of the highest subtransaction the rel has
-	 * survived into; or zero if the rel was not created in the current top
-	 * transaction.  This can be now be relied on, whereas previously it could
-	 * be "forgotten" in earlier releases. Likewise, rd_newRelfilenodeSubid is
-	 * the ID of the highest subtransaction the relfilenode change has
-	 * survived into, or zero if not changed in the current transaction (or we
-	 * have forgotten changing it). rd_newRelfilenodeSubid can be forgotten
-	 * when a relation has multiple new relfilenodes within a single
-	 * transaction, with one of them occurring in a subsequently aborted
-	 * subtransaction, e.g. BEGIN; TRUNCATE t; SAVEPOINT save; TRUNCATE t;
-	 * ROLLBACK TO save; -- rd_newRelfilenodeSubid is now forgotten
+	 * survived into or zero if the rel was not created in the current top
+	 * transaction.  rd_firstRelfilenodeSubid is the ID of the highest
+	 * subtransaction an rd_node change has survived into or zero if rd_node
+	 * matches the value it had at the start of the current top transaction.
+	 * (Rolling back the subtransaction that rd_firstRelfilenodeSubid denotes
+	 * would restore rd_node to the value it had at the start of the current
+	 * top transaction.  Rolling back any lower subtransaction would not.)
+	 * Their accuracy is critical to RelationNeedsWAL().
+	 *
+	 * rd_newRelfilenodeSubid is the ID of the highest subtransaction the
+	 * most-recent relfilenode change has survived into or zero if not changed
+	 * in the current transaction (or we have forgotten changing it).  This
+	 * field is accurate when non-zero, but it can be zero when a relation has
+	 * multiple new relfilenodes within a single transaction, with one of them
+	 * occurring in a subsequently aborted subtransaction, e.g.
+	 *		BEGIN;
+	 *		TRUNCATE t;
+	 *		SAVEPOINT save;
+	 *		TRUNCATE t;
+	 *		ROLLBACK TO save;
+	 *		-- rd_newRelfilenodeSubid is now forgotten
+	 *
+	 * These fields are read-only outside relcache.c.  Other files trigger
+	 * rd_node changes by updating pg_class.reltablespace and/or
+	 * pg_class.relfilenode.  They must call RelationAssumeNewRelfilenode() to
+	 * update these fields.
 	 */
 	SubTransactionId rd_createSubid;	/* rel was created in current xact */
-	SubTransactionId rd_newRelfilenodeSubid;	/* new relfilenode assigned in
-												 * current xact */
+	SubTransactionId rd_newRelfilenodeSubid;	/* highest subxact changing
+												 * rd_node to current value */
+	SubTransactionId rd_firstRelfilenodeSubid;	/* highest subxact changing
+												 * rd_node to any value */
 
 	Form_pg_class rd_rel;		/* RELATION tuple */
 	TupleDesc	rd_att;			/* tuple descriptor */
@@ -520,9 +538,16 @@ typedef struct ViewOptions
 /*
  * RelationNeedsWAL
  *		True if relation needs WAL.
- */
-#define RelationNeedsWAL(relation) \
-	((relation)->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
+ *
+ * Returns false if wal_level = minimal and this relation is created or
+ * truncated in the current transaction.  See "Skipping WAL for New
+ * RelFileNode" in src/backend/access/transam/README.
+ */
+#define RelationNeedsWAL(relation)										\
+	((relation)->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT &&	\
+	 (XLogIsNeeded() ||													\
+	  (relation->rd_createSubid == InvalidSubTransactionId &&			\
+	   relation->rd_firstRelfilenodeSubid == InvalidSubTransactionId)))
 
 /*
  * RelationUsesLocalBuffers
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 2f2ace35b0..d3e8348c1b 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -105,9 +105,10 @@ extern Relation RelationBuildLocalRelation(const char *relname,
 										   char relkind);
 
 /*
- * Routine to manage assignment of new relfilenode to a relation
+ * Routines to manage assignment of new relfilenode to a relation
  */
 extern void RelationSetNewRelfilenode(Relation relation, char persistence);
+extern void RelationAssumeNewRelfilenode(Relation relation);
 
 /*
  * Routines for flushing/rebuilding relcache entries in various scenarios
@@ -120,6 +121,11 @@ extern void RelationCacheInvalidate(void);
 
 extern void RelationCloseSmgrByOid(Oid relationId);
 
+#ifdef USE_ASSERT_CHECKING
+extern void AssertPendingSyncs_RelationCache(void);
+#else
+#define AssertPendingSyncs_RelationCache() do {} while (0)
+#endif
 extern void AtEOXact_RelationCache(bool isCommit);
 extern void AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
 									  SubTransactionId parentSubid);
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 297b8fbd6f..1ddde3ecce 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -2354,6 +2354,8 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		fputs("log_lock_waits = on\n", pg_conf);
 		fputs("log_temp_files = 128kB\n", pg_conf);
 		fputs("max_prepared_transactions = 2\n", pg_conf);
+		fputs("wal_level = minimal\n", pg_conf); /* XXX before commit remove */
+		fputs("max_wal_senders = 0\n", pg_conf);
 
 		for (sl = temp_configs; sl != NULL; sl = sl->next)
 		{
-- 
2.23.0


----Next_Part(Thu_Nov_28_20_56_20_2019_909)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="v26-0002-change-swap_relation_files.patch"



^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-12 06:09  Julien Rouhaud <[email protected]>
  0 siblings, 2 replies; 22+ messages in thread

From: Julien Rouhaud @ 2022-01-12 06:09 UTC (permalink / raw)
  To: Bharath Rupireddy <[email protected]>; +Cc: Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

Hi,

On Tue, Dec 28, 2021 at 10:56 AM Bharath Rupireddy
<[email protected]> wrote:
>
> attaching v1-0001-XXX from the initial mail again just for the sake of
> completion:

Unfortunately this breaks the cfbot as it tries to apply this patch
too: http://cfbot.cputube.org/patch_36_3474.log.

For this kind of situation I think that the usual solution is to use a
.txt extension to make sure that the cfbot won't try to apply it.






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message)
@ 2022-01-12 06:19  Tom Lane <[email protected]>
  parent: Julien Rouhaud <[email protected]>
  1 sibling, 1 reply; 22+ messages in thread

From: Tom Lane @ 2022-01-12 06:19 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: Julien Rouhaud <[email protected]>; Bharath Rupireddy <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

Julien Rouhaud <[email protected]> writes:
> For this kind of situation I think that the usual solution is to use a
> .txt extension to make sure that the cfbot won't try to apply it.

Yeah ... this has come up before.  Is there a documented way to
attach files that the cfbot will ignore?

Two specific scenarios seem to be interesting:

1. You are attaching patch(es) plus some non-patch files

2. You are attaching some random files, and would like to not
displace the cfbot's idea of the latest patchset.

I don't know exactly how to do either of those.

			regards, tom lane






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message)
@ 2022-01-12 06:31  Julien Rouhaud <[email protected]>
  parent: Tom Lane <[email protected]>
  0 siblings, 1 reply; 22+ messages in thread

From: Julien Rouhaud @ 2022-01-12 06:31 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Thomas Munro <[email protected]>; Bharath Rupireddy <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Wed, Jan 12, 2022 at 01:19:22AM -0500, Tom Lane wrote:
> Julien Rouhaud <[email protected]> writes:
> > For this kind of situation I think that the usual solution is to use a
> > .txt extension to make sure that the cfbot won't try to apply it.
> 
> Yeah ... this has come up before.  Is there a documented way to
> attach files that the cfbot will ignore?

Not that I know of unfortunately.  I think the apply part is done by
https://github.com/macdice/cfbot/blob/master/cfbot_patchburner_chroot_ctl.sh#L93-L120,
which seems reasonable.  So basically any extension outside of those could be
used, excluding of course anything clearly suspicious that would be rejected by
many email providers.

> Two specific scenarios seem to be interesting:
> 
> 1. You are attaching patch(es) plus some non-patch files
> 
> 2. You are attaching some random files, and would like to not
> displace the cfbot's idea of the latest patchset.

I'm assuming that someone wanting to send an additional patch to be applied on
top of the OP patchset is part of 2?






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message)
@ 2022-01-12 06:37  Tom Lane <[email protected]>
  parent: Julien Rouhaud <[email protected]>
  0 siblings, 2 replies; 22+ messages in thread

From: Tom Lane @ 2022-01-12 06:37 UTC (permalink / raw)
  To: Julien Rouhaud <[email protected]>; +Cc: Thomas Munro <[email protected]>; Bharath Rupireddy <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

Julien Rouhaud <[email protected]> writes:
> On Wed, Jan 12, 2022 at 01:19:22AM -0500, Tom Lane wrote:
>> 2. You are attaching some random files, and would like to not
>> displace the cfbot's idea of the latest patchset.

> I'm assuming that someone wanting to send an additional patch to be applied on
> top of the OP patchset is part of 2?

AFAIK, if you're submitting a patch then you have to attach a complete
patchset, or the cfbot will be totally lost.  Getting the bot to
understand incremental patches would be useful for sure ... but it's
outside the scope of what I'm asking for now, which is just clear
documentation of what the bot can do already.

			regards, tom lane






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message)
@ 2022-01-12 06:50  Julien Rouhaud <[email protected]>
  parent: Tom Lane <[email protected]>
  1 sibling, 0 replies; 22+ messages in thread

From: Julien Rouhaud @ 2022-01-12 06:50 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Thomas Munro <[email protected]>; Bharath Rupireddy <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Wed, Jan 12, 2022 at 2:37 PM Tom Lane <[email protected]> wrote:
>
> AFAIK, if you're submitting a patch then you have to attach a complete
> patchset, or the cfbot will be totally lost.  Getting the bot to
> understand incremental patches would be useful for sure ... but it's
> outside the scope of what I'm asking for now, which is just clear
> documentation of what the bot can do already.

Right, but the use case I'm mentioning is a bit different: provide
another patch while *not* triggering the cfbot.  I've seen cases in
the past where people want to share some code to the OP and it seems
reasonable to allow that without risking the trigger the cfbot, at
least not without the OP validating or adapting the changes.






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message)
@ 2022-01-12 06:52  Thomas Munro <[email protected]>
  parent: Tom Lane <[email protected]>
  1 sibling, 1 reply; 22+ messages in thread

From: Thomas Munro @ 2022-01-12 06:52 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Julien Rouhaud <[email protected]>; Bharath Rupireddy <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Wed, Jan 12, 2022 at 7:37 PM Tom Lane <[email protected]> wrote:
> Julien Rouhaud <[email protected]> writes:
> > On Wed, Jan 12, 2022 at 01:19:22AM -0500, Tom Lane wrote:
> >> 2. You are attaching some random files, and would like to not
> >> displace the cfbot's idea of the latest patchset.
>
> > I'm assuming that someone wanting to send an additional patch to be applied on
> > top of the OP patchset is part of 2?
>
> AFAIK, if you're submitting a patch then you have to attach a complete
> patchset, or the cfbot will be totally lost.  Getting the bot to
> understand incremental patches would be useful for sure ... but it's
> outside the scope of what I'm asking for now, which is just clear
> documentation of what the bot can do already.

By way of documentation, I've just now tried to answer these question
in the new FAQ at:

https://wiki.postgresql.org/wiki/Cfbot






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message)
@ 2022-01-12 06:58  Tom Lane <[email protected]>
  parent: Thomas Munro <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Tom Lane @ 2022-01-12 06:58 UTC (permalink / raw)
  To: Thomas Munro <[email protected]>; +Cc: Julien Rouhaud <[email protected]>; Bharath Rupireddy <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

Thomas Munro <[email protected]> writes:
> By way of documentation, I've just now tried to answer these question
> in the new FAQ at:
> https://wiki.postgresql.org/wiki/Cfbot

Thanks!

			regards, tom lane






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-13 06:20  Bharath Rupireddy <[email protected]>
  parent: Julien Rouhaud <[email protected]>
  1 sibling, 1 reply; 22+ messages in thread

From: Bharath Rupireddy @ 2022-01-13 06:20 UTC (permalink / raw)
  To: Julien Rouhaud <[email protected]>; +Cc: Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Wed, Jan 12, 2022 at 11:39 AM Julien Rouhaud <[email protected]> wrote:
>
> Hi,
>
> On Tue, Dec 28, 2021 at 10:56 AM Bharath Rupireddy
> <[email protected]> wrote:
> >
> > attaching v1-0001-XXX from the initial mail again just for the sake of
> > completion:
>
> Unfortunately this breaks the cfbot as it tries to apply this patch
> too: http://cfbot.cputube.org/patch_36_3474.log.
>
> For this kind of situation I think that the usual solution is to use a
> .txt extension to make sure that the cfbot won't try to apply it.

Thanks.  IMO, the following format of logging is better, so attaching
the v2-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch as
.patch

2021-12-28 02:52:24.464 UTC [2394396] LOG:  checkpoint completed at
location=0/212FFC8 with REDO start location=0/212FF90: wrote 451
buffers (2.8%); 0 WAL file(s) added, 0 removed, 1 recycled;
write=0.012 s, sync=0.032 s, total=0.071 s; sync files=6,
longest=0.022 s, average=0.006 s; distance=6272 kB, estimate=6272 kB

Others are attached as .txt files.

Regards,
Bharath Rupireddy.

From c23010c67a66dd21e318ae4d475ee0d85c5c1d08 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Tue, 28 Dec 2021 02:52:49 +0000
Subject: [PATCH v2] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN and REDO LSN. It gives more context while
analyzing checkpoint-related issues. The pg_controldata gives the
last checkpoint LSN and REDO LSN, but having this info alongside
the log message helps analyze issues that happened previously,
connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1e1fbe957f..cd3fce6a2c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8920,11 +8920,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint completed at location=%X/%X with REDO start location=%X/%X: "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8940,11 +8943,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint completed at location=%X/%X with REDO start location=%X/%X: "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1


From 999cfd53ce4e16ccfff94c0022cd80fe8ff84be5 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Tue, 28 Dec 2021 02:45:51 +0000
Subject: [PATCH v2] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN and REDO LSN. It gives more context while
analyzing checkpoint-related issues. The pg_controldata gives the
last checkpoint LSN and REDO LSN, but having this info alongside
the log message helps analyze issues that happened previously,
connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1e1fbe957f..26eb2a22f3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8920,11 +8920,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint complete: location=%X/%X, REDO start location=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8940,11 +8943,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint complete: location=%X/%X, REDO start location=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1



Attachments:

  [text/plain] v2-0002-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.txt (2.5K, ../../CALj2ACUGutu6As-9p76Ta2bV59J97fbiCc9NSzaWXqxPJdMvag@mail.gmail.com/2-v2-0002-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.txt)
  download | inline diff:
From c23010c67a66dd21e318ae4d475ee0d85c5c1d08 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Tue, 28 Dec 2021 02:52:49 +0000
Subject: [PATCH v2] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN and REDO LSN. It gives more context while
analyzing checkpoint-related issues. The pg_controldata gives the
last checkpoint LSN and REDO LSN, but having this info alongside
the log message helps analyze issues that happened previously,
connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1e1fbe957f..cd3fce6a2c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8920,11 +8920,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint completed at location=%X/%X with REDO start location=%X/%X: "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8940,11 +8943,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint completed at location=%X/%X with REDO start location=%X/%X: "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1



  [application/octet-stream] v2-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch (2.5K, ../../CALj2ACUGutu6As-9p76Ta2bV59J97fbiCc9NSzaWXqxPJdMvag@mail.gmail.com/3-v2-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch)
  download | inline diff:
From c23010c67a66dd21e318ae4d475ee0d85c5c1d08 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Tue, 28 Dec 2021 02:52:49 +0000
Subject: [PATCH v2] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN and REDO LSN. It gives more context while
analyzing checkpoint-related issues. The pg_controldata gives the
last checkpoint LSN and REDO LSN, but having this info alongside
the log message helps analyze issues that happened previously,
connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1e1fbe957f..cd3fce6a2c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8920,11 +8920,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint completed at location=%X/%X with REDO start location=%X/%X: "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8940,11 +8943,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint completed at location=%X/%X with REDO start location=%X/%X: "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1



  [text/plain] v2-0003-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.txt (2.5K, ../../CALj2ACUGutu6As-9p76Ta2bV59J97fbiCc9NSzaWXqxPJdMvag@mail.gmail.com/4-v2-0003-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.txt)
  download | inline diff:
From 999cfd53ce4e16ccfff94c0022cd80fe8ff84be5 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Tue, 28 Dec 2021 02:45:51 +0000
Subject: [PATCH v2] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN and REDO LSN. It gives more context while
analyzing checkpoint-related issues. The pg_controldata gives the
last checkpoint LSN and REDO LSN, but having this info alongside
the log message helps analyze issues that happened previously,
connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1e1fbe957f..26eb2a22f3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8920,11 +8920,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint complete: location=%X/%X, REDO start location=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8940,11 +8943,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint complete: location=%X/%X, REDO start location=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1



^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-14 13:22  Bharath Rupireddy <[email protected]>
  parent: Bharath Rupireddy <[email protected]>
  0 siblings, 1 reply; 22+ messages in thread

From: Bharath Rupireddy @ 2022-01-14 13:22 UTC (permalink / raw)
  To: Julien Rouhaud <[email protected]>; +Cc: Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, Jan 13, 2022 at 11:50 AM Bharath Rupireddy
<[email protected]> wrote:
> Thanks.  IMO, the following format of logging is better, so attaching
> the v2-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch as
> .patch
>
> 2021-12-28 02:52:24.464 UTC [2394396] LOG:  checkpoint completed at
> location=0/212FFC8 with REDO start location=0/212FF90: wrote 451
> buffers (2.8%); 0 WAL file(s) added, 0 removed, 1 recycled;
> write=0.012 s, sync=0.032 s, total=0.071 s; sync files=6,
> longest=0.022 s, average=0.006 s; distance=6272 kB, estimate=6272 kB

One of the test cases was failing with the above style of the log
message, changing "checkpoint complete" to "checkpoint completed at
location" doesn't seem to be a better idea. It looks like the users or
the log monitoring tools might be using the same text "checkpoint
complete", therefore I don't want to break that. Here's the v3 patch
that I think will work better. Please review.

Regards,
Bharath Rupireddy.


Attachments:

  [application/x-patch] v3-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch (2.5K, ../../CALj2ACVM4wjS+wiNZf4ssdNMhSR-XUhR99fYbV=pC9_-=5wCtw@mail.gmail.com/2-v3-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch)
  download | inline diff:
From b6f2a53bcaea2d37e317bc3d9922893c10712d3a Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Fri, 14 Jan 2022 12:55:30 +0000
Subject: [PATCH v3] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN and REDO LSN. It gives more context while
analyzing checkpoint-related issues. The pg_controldata gives the
last checkpoint LSN and REDO LSN, but having this info alongside
the log message helps analyze issues that happened previously,
connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c9d4cbf3ff..b2eabc72f9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8920,11 +8920,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint complete: location=%X/%X, REDO start location=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8940,11 +8943,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint complete: location=%X/%X, REDO start location=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1



^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-20 00:36  Bossart, Nathan <[email protected]>
  parent: Bharath Rupireddy <[email protected]>
  0 siblings, 2 replies; 22+ messages in thread

From: Bossart, Nathan @ 2022-01-20 00:36 UTC (permalink / raw)
  To: Bharath Rupireddy <[email protected]>; Julien Rouhaud <[email protected]>; +Cc: Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On 1/3/22, 5:52 PM, "Kyotaro Horiguchi" <[email protected]> wrote:
> It seems to me "LSN" or just "location" is more confusing or
> mysterious than "REDO LSN" for the average user. If we want to avoid
> being technically too detailed, we would use just "start LSN=%X/%X,
> end LSN=%X/%X".  And it is equivalent to "WAL range=[%X/%X, %X/%X]"..

My first instinct was that this should stay aligned with
pg_controldata, but that would mean using "location=%X/%X, REDO
location=%X/%X," which doesn't seem terribly descriptive.  IIUC the
"checkpoint location" is the LSN of the WAL record for the checkpoint,
and the "checkpoint's REDO location" is the LSN where checkpoint
creation began (i.e., what you must retain for crash recovery).  My
vote is for "start=%X/%X, end=%X/%X."

Nathan



^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-20 03:00  Kyotaro Horiguchi <[email protected]>
  parent: Bossart, Nathan <[email protected]>
  1 sibling, 1 reply; 22+ messages in thread

From: Kyotaro Horiguchi @ 2022-01-20 03:00 UTC (permalink / raw)
  To: [email protected]; +Cc: [email protected]; [email protected]; [email protected]; [email protected]

At Thu, 20 Jan 2022 00:36:32 +0000, "Bossart, Nathan" <[email protected]> wrote in 
> On 1/3/22, 5:52 PM, "Kyotaro Horiguchi" <[email protected]> wrote:
> > It seems to me "LSN" or just "location" is more confusing or
> > mysterious than "REDO LSN" for the average user. If we want to avoid
> > being technically too detailed, we would use just "start LSN=%X/%X,
> > end LSN=%X/%X".  And it is equivalent to "WAL range=[%X/%X, %X/%X]"..
> 
> My first instinct was that this should stay aligned with
> pg_controldata, but that would mean using "location=%X/%X, REDO
> location=%X/%X," which doesn't seem terribly descriptive.  IIUC the
> "checkpoint location" is the LSN of the WAL record for the checkpoint,
> and the "checkpoint's REDO location" is the LSN where checkpoint
> creation began (i.e., what you must retain for crash recovery).  My
> vote is for "start=%X/%X, end=%X/%X."

+1. Works for me.  %X/%X itself expresses it is an LSN.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-27 15:07  Bharath Rupireddy <[email protected]>
  parent: Bossart, Nathan <[email protected]>
  1 sibling, 1 reply; 22+ messages in thread

From: Bharath Rupireddy @ 2022-01-27 15:07 UTC (permalink / raw)
  To: Bossart, Nathan <[email protected]>; +Cc: Julien Rouhaud <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, Jan 20, 2022 at 6:06 AM Bossart, Nathan <[email protected]> wrote:
>
> On 1/3/22, 5:52 PM, "Kyotaro Horiguchi" <[email protected]> wrote:
> > It seems to me "LSN" or just "location" is more confusing or
> > mysterious than "REDO LSN" for the average user. If we want to avoid
> > being technically too detailed, we would use just "start LSN=%X/%X,
> > end LSN=%X/%X".  And it is equivalent to "WAL range=[%X/%X, %X/%X]"..
>
> My first instinct was that this should stay aligned with
> pg_controldata, but that would mean using "location=%X/%X, REDO
> location=%X/%X," which doesn't seem terribly descriptive.  IIUC the
> "checkpoint location" is the LSN of the WAL record for the checkpoint,
> and the "checkpoint's REDO location" is the LSN where checkpoint
> creation began (i.e., what you must retain for crash recovery).  My
> vote is for "start=%X/%X, end=%X/%X."

I'm still not clear how the REDO location can be treated as a start
LSN? Can someone throw some light one what this checkpoint's REDO
location is?

Regards,
Bharath Rupireddy.






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-27 23:57  Nathan Bossart <[email protected]>
  parent: Bharath Rupireddy <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Nathan Bossart @ 2022-01-27 23:57 UTC (permalink / raw)
  To: Bharath Rupireddy <[email protected]>; +Cc: Bossart, Nathan <[email protected]>; Julien Rouhaud <[email protected]>; Michael Paquier <[email protected]>; Kyotaro Horiguchi <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, Jan 27, 2022 at 08:37:37PM +0530, Bharath Rupireddy wrote:
> I'm still not clear how the REDO location can be treated as a start
> LSN? Can someone throw some light one what this checkpoint's REDO
> location is?

It's the WAL insert location at the time the checkpoint began (i.e., where
you need to begin replaying WAL from after a crash).

-- 
Nathan Bossart
Amazon Web Services: https://aws.amazon.com/






^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* Re: Add checkpoint and redo LSN to LogCheckpointEnd log message
@ 2022-01-28 03:13  Bharath Rupireddy <[email protected]>
  parent: Kyotaro Horiguchi <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Bharath Rupireddy @ 2022-01-28 03:13 UTC (permalink / raw)
  To: Kyotaro Horiguchi <[email protected]>; +Cc: Bossart, Nathan <[email protected]>; Julien Rouhaud <[email protected]>; Michael Paquier <[email protected]>; PostgreSQL Hackers <[email protected]>

On Thu, Jan 20, 2022 at 8:30 AM Kyotaro Horiguchi
<[email protected]> wrote:
>
> At Thu, 20 Jan 2022 00:36:32 +0000, "Bossart, Nathan" <[email protected]> wrote in
> > On 1/3/22, 5:52 PM, "Kyotaro Horiguchi" <[email protected]> wrote:
> > > It seems to me "LSN" or just "location" is more confusing or
> > > mysterious than "REDO LSN" for the average user. If we want to avoid
> > > being technically too detailed, we would use just "start LSN=%X/%X,
> > > end LSN=%X/%X".  And it is equivalent to "WAL range=[%X/%X, %X/%X]"..
> >
> > My first instinct was that this should stay aligned with
> > pg_controldata, but that would mean using "location=%X/%X, REDO
> > location=%X/%X," which doesn't seem terribly descriptive.  IIUC the
> > "checkpoint location" is the LSN of the WAL record for the checkpoint,
> > and the "checkpoint's REDO location" is the LSN where checkpoint
> > creation began (i.e., what you must retain for crash recovery).  My
> > vote is for "start=%X/%X, end=%X/%X."
>
> +1. Works for me.  %X/%X itself expresses it is an LSN.

Thanks for the review. Here's the v4 patch, please have a look.

Let's not attempt to change how pg_controldata (tool and core
functions) emit the start and end LSN as checkpoint_lsn/redo_lsn and
checkpoint location/checkpoint's REDO location.

[1]
2022-01-28 03:06:10.213 UTC [2409486] LOG:  checkpoint starting:
immediate force wait
2022-01-28 03:06:10.257 UTC [2409486] LOG:  checkpoint complete:
start=0/14D9510, end=0/14D9548; wrote 4 buffers (0.0%); 0 WAL file(s)
added, 0 removed, 0 recycled; write=0.007 s, sync=0.008 s, total=0.044
s; sync files=3, longest=0.005 s, average=0.003 s; distance=0 kB,
estimate=0 kB

2022-01-28 03:06:42.254 UTC [2409486] LOG:  checkpoint starting:
immediate force wait
2022-01-28 03:06:42.279 UTC [2409486] LOG:  checkpoint complete:
start=0/14DBDB8, end=0/14DBDF0; wrote 2 buffers (0.0%); 0 WAL file(s)
added, 0 removed, 0 recycled; write=0.004 s, sync=0.004 s, total=0.025
s; sync files=2, longest=0.003 s, average=0.002 s; distance=10 kB,
estimate=10 kB

Regards,
Bharath Rupireddy.


Attachments:

  [application/octet-stream] v4-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch (2.4K, ../../CALj2ACUaGJQVbQ5Hms_C2tu+6iJX-EWkEdOiXwX1WfrxQX8pHA@mail.gmail.com/2-v4-0001-Add-checkpoint-and-redo-LSN-to-LogCheckpointEnd-l.patch)
  download | inline diff:
From f2319df1eba9600c8628910c509757ce5208874f Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <[email protected]>
Date: Fri, 28 Jan 2022 03:07:07 +0000
Subject: [PATCH v4] Add checkpoint and redo LSN to LogCheckpointEnd log
 message

It is useful (for debugging purposes) if the checkpoint end message
has the checkpoint LSN(end) and REDO LSN(start). It gives more
context while analyzing checkpoint-related issues. The pg_controldata
gives the last checkpoint LSN and REDO LSN, but having this info
alongside the log message helps analyze issues that happened
previously, connect the dots and identify the root cause.
---
 src/backend/access/transam/xlog.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index dfe2a0bcce..adecc979c2 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8919,11 +8919,14 @@ LogCheckpointEnd(bool restartpoint)
 
 	if (restartpoint)
 		ereport(LOG,
-				(errmsg("restartpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("restartpoint complete: start=%X/%X, end=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
@@ -8939,11 +8942,14 @@ LogCheckpointEnd(bool restartpoint)
 						(int) (CheckPointDistanceEstimate / 1024.0))));
 	else
 		ereport(LOG,
-				(errmsg("checkpoint complete: wrote %d buffers (%.1f%%); "
+				(errmsg("checkpoint complete: start=%X/%X, end=%X/%X; "
+						"wrote %d buffers (%.1f%%); "
 						"%d WAL file(s) added, %d removed, %d recycled; "
 						"write=%ld.%03d s, sync=%ld.%03d s, total=%ld.%03d s; "
 						"sync files=%d, longest=%ld.%03d s, average=%ld.%03d s; "
 						"distance=%d kB, estimate=%d kB",
+						LSN_FORMAT_ARGS(ControlFile->checkPointCopy.redo),
+						LSN_FORMAT_ARGS(ControlFile->checkPoint),
 						CheckpointStats.ckpt_bufs_written,
 						(double) CheckpointStats.ckpt_bufs_written * 100 / NBuffers,
 						CheckpointStats.ckpt_segs_added,
-- 
2.25.1



^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 52 ++++++------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 --------------
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlocklist.h              | 82 +++++++++++++++++++
 8 files changed, 124 insertions(+), 107 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..34bb6393c4 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl $(top_srcdir)/src/include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..9d7dbe5abd 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: $(top_srcdir)/src/include/storage/lwlocklist.h $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..f46634a180 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/backend/storage/lmgr/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -64,17 +60,30 @@ while (<$wait_event_names>)
 	push(@wait_event_lwlocks, $waiteventname . "Lock");
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip uniline C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
+
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\w+),\s+(\d+)\)$/;
 
 	(my $lockname, my $lockidx) = ($1, $2);
 
@@ -82,25 +91,23 @@ while (<$lwlocknames>)
 	$trimmedlockname =~ s/Lock$//;
 	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
@@ -109,18 +116,15 @@ while (<$lwlocknames>)
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index d405c61b21..1112389af5 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -115,8 +115,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -129,9 +129,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(lockname, id) [id] = CppAsString(lockname),
+#include "storage/lwlocknames.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -745,11 +746,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index ec2f31f82a..105ca977a5 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -279,9 +279,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -332,9 +332,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..3396eed58e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlock-names.pl processes this file.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(ShmemIndexLock, 1)
+PG_LWLOCK(OidGenLock, 2)
+PG_LWLOCK(XidGenLock, 3)
+PG_LWLOCK(ProcArrayLock, 4)
+PG_LWLOCK(SInvalReadLock, 5)
+PG_LWLOCK(SInvalWriteLock, 6)
+PG_LWLOCK(WALBufMappingLock, 7)
+PG_LWLOCK(WALWriteLock, 8)
+PG_LWLOCK(ControlFileLock, 9)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(MultiXactGenLock, 13)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(RelCacheInitLock, 16)
+PG_LWLOCK(CheckpointerCommLock, 17)
+PG_LWLOCK(TwoPhaseStateLock, 18)
+PG_LWLOCK(TablespaceCreateLock, 19)
+PG_LWLOCK(BtreeVacuumLock, 20)
+PG_LWLOCK(AddinShmemInitLock, 21)
+PG_LWLOCK(AutovacuumLock, 22)
+PG_LWLOCK(AutovacuumScheduleLock, 23)
+PG_LWLOCK(SyncScanLock, 24)
+PG_LWLOCK(RelationMappingLock, 25)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(NotifyQueueLock, 27)
+PG_LWLOCK(SerializableXactHashLock, 28)
+PG_LWLOCK(SerializableFinishedListLock, 29)
+PG_LWLOCK(SerializablePredicateListLock, 30)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(SyncRepLock, 32)
+PG_LWLOCK(BackgroundWorkerLock, 33)
+PG_LWLOCK(DynamicSharedMemoryControlLock, 34)
+PG_LWLOCK(AutoFileLock, 35)
+PG_LWLOCK(ReplicationSlotAllocationLock, 36)
+PG_LWLOCK(ReplicationSlotControlLock, 37)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(CommitTsLock, 39)
+PG_LWLOCK(ReplicationOriginLock, 40)
+PG_LWLOCK(MultiXactTruncationLock, 41)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(LogicalRepWorkerLock, 43)
+PG_LWLOCK(XactTruncationLock, 44)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(WrapLimitsVacuumLock, 46)
+PG_LWLOCK(NotifyQueueTailLock, 47)
+PG_LWLOCK(WaitEventExtensionLock, 48)
+PG_LWLOCK(WALSummarizerLock, 49)
+PG_LWLOCK(DSMRegistryLock, 50)
+PG_LWLOCK(InjectionPointLock, 51)
+PG_LWLOCK(SerialControlLock, 52)
-- 
2.39.2


--hafsgxjamluc3fye--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH v2] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.

We still have to build lwlocknames.h using Perl code, which initially I
wanted to avoid, but it gives us the chance to cross-check
wait_event_names.txt.

Discussion: https://postgr.es/m/[email protected]
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 60 ++++++-------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 -------------
 src/backend/storage/lmgr/meson.build          |  2 -
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlock.h                  |  4 +-
 src/include/storage/lwlocklist.h              | 85 +++++++++++++++++++
 src/include/storage/meson.build               | 12 ++-
 src/tools/pginclude/headerscheck              |  1 +
 12 files changed, 136 insertions(+), 125 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..79a12dfd1e 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl ../include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..3f89548bde 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: ../../../include/storage/lwlocklist.h ../../utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..eaddd9d3b9 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/include/storage/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -61,66 +57,70 @@ while (<$wait_event_names>)
 
 	# Record the LWLock.
 	(my $waiteventname, my $waitevendocsentence) = split(/\t/, $_);
-	push(@wait_event_lwlocks, $waiteventname . "Lock");
+	push(@wait_event_lwlocks, $waiteventname);
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip single-line C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
 
-	(my $lockname, my $lockidx) = ($1, $2);
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\d+),\s+(\w+)\)$/;
 
-	my $trimmedlockname = $lockname;
-	$trimmedlockname =~ s/Lock$//;
-	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
+	(my $lockidx, my $lockname) = ($1, $2);
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
-	print $h "#define $lockname (&MainLWLockArray[$lockidx].lock)\n";
+	print $h "#define ${lockname}Lock (&MainLWLockArray[$lockidx].lock)\n";
 }
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 30f3a09a4c..83992725de 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -112,8 +112,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -126,9 +126,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(id, lockname) [id] = CppAsString(lockname) "Lock",
+#include "storage/lwlocklist.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -742,11 +743,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/storage/lmgr/meson.build b/src/backend/storage/lmgr/meson.build
index da32198f78..05ac41e809 100644
--- a/src/backend/storage/lmgr/meson.build
+++ b/src/backend/storage/lmgr/meson.build
@@ -11,5 +11,3 @@ backend_sources += files(
   's_lock.c',
   'spin.c',
 )
-
-generated_backend_sources += lwlocknames[1]
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index c08e00d1d6..b0ab833602 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -280,9 +280,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -333,9 +333,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 10bea8c595..3479b4cf52 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -19,6 +19,7 @@
 #endif
 
 #include "port/atomics.h"
+#include "storage/lwlocknames.h"
 #include "storage/proclist_types.h"
 
 struct PGPROC;
@@ -82,9 +83,6 @@ typedef struct NamedLWLockTranche
 extern PGDLLIMPORT NamedLWLockTranche *NamedLWLockTrancheArray;
 extern PGDLLIMPORT int NamedLWLockTrancheRequests;
 
-/* Names for fixed lwlocks */
-#include "storage/lwlocknames.h"
-
 /*
  * 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
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..85f6568b9e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,85 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlocknames.pl processes this file to create lwlocknames.h.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ *
+ * Note that the names here don't include the Lock suffix, to appease the
+ * C preprocessor; it's added elsewhere.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(1, ShmemIndex)
+PG_LWLOCK(2, OidGen)
+PG_LWLOCK(3, XidGen)
+PG_LWLOCK(4, ProcArray)
+PG_LWLOCK(5, SInvalRead)
+PG_LWLOCK(6, SInvalWrite)
+PG_LWLOCK(7, WALBufMapping)
+PG_LWLOCK(8, WALWrite)
+PG_LWLOCK(9, ControlFile)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(13, MultiXactGen)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(16, RelCacheInit)
+PG_LWLOCK(17, CheckpointerComm)
+PG_LWLOCK(18, TwoPhaseState)
+PG_LWLOCK(19, TablespaceCreate)
+PG_LWLOCK(20, BtreeVacuum)
+PG_LWLOCK(21, AddinShmemInit)
+PG_LWLOCK(22, Autovacuum)
+PG_LWLOCK(23, AutovacuumSchedule)
+PG_LWLOCK(24, SyncScan)
+PG_LWLOCK(25, RelationMapping)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(27, NotifyQueue)
+PG_LWLOCK(28, SerializableXactHash)
+PG_LWLOCK(29, SerializableFinishedList)
+PG_LWLOCK(30, SerializablePredicateList)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(32, SyncRep)
+PG_LWLOCK(33, BackgroundWorker)
+PG_LWLOCK(34, DynamicSharedMemoryControl)
+PG_LWLOCK(35, AutoFile)
+PG_LWLOCK(36, ReplicationSlotAllocation)
+PG_LWLOCK(37, ReplicationSlotControl)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(39, CommitTs)
+PG_LWLOCK(40, ReplicationOrigin)
+PG_LWLOCK(41, MultiXactTruncation)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(43, LogicalRepWorker)
+PG_LWLOCK(44, XactTruncation)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(46, WrapLimitsVacuum)
+PG_LWLOCK(47, NotifyQueueTail)
+PG_LWLOCK(48, WaitEventExtension)
+PG_LWLOCK(49, WALSummarizer)
+PG_LWLOCK(50, DSMRegistry)
+PG_LWLOCK(51, InjectionPoint)
+PG_LWLOCK(52, SerialControl)
diff --git a/src/include/storage/meson.build b/src/include/storage/meson.build
index 666fb22408..f889093117 100644
--- a/src/include/storage/meson.build
+++ b/src/include/storage/meson.build
@@ -1,10 +1,10 @@
 # Copyright (c) 2022-2024, PostgreSQL Global Development Group
 
-lwlocknames = custom_target('lwlocknames',
+lwlocknames_h = custom_target('lwlocknames_h',
   input: files(
-    '../../backend/storage/lmgr/lwlocknames.txt',
+    '../../include/storage/lwlocklist.h',
     '../../backend/utils/activity/wait_event_names.txt'),
-  output: ['lwlocknames.h', 'lwlocknames.c'],
+  output: ['lwlocknames.h'],
   command: [
     perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'),
     '-o', '@OUTDIR@',
@@ -12,12 +12,10 @@ lwlocknames = custom_target('lwlocknames',
   ],
   build_by_default: true,
   install: true,
-  install_dir: [dir_include_server / 'storage', false],
+  install_dir: dir_include_server / 'storage',
 )
 
-lwlocknames_h = lwlocknames[0]
-
 generated_backend_headers += lwlocknames_h
 
 # autoconf generates the file there, ensure we get a conflict
-generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.c', 'lwlocknames.h']}
+generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.h']}
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index 5c12ab99b8..13b9735f84 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -133,6 +133,7 @@ do
 	test "$f" = src/interfaces/ecpg/preproc/c_kwlist.h && continue
 	test "$f" = src/interfaces/ecpg/preproc/ecpg_kwlist.h && continue
 	test "$f" = src/include/regex/regerrs.h && continue
+	test "$f" = src/include/storage/lwlocklist.h && continue
 	test "$f" = src/include/tcop/cmdtaglist.h && continue
 	test "$f" = src/pl/plpgsql/src/plerrcodes.h && continue
 	test "$f" = src/pl/plpython/spiexceptions.h && continue
-- 
2.39.2


--t4gqyw67m6fqhs6t--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 52 ++++++------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 --------------
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlocklist.h              | 82 +++++++++++++++++++
 8 files changed, 124 insertions(+), 107 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..34bb6393c4 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl $(top_srcdir)/src/include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..9d7dbe5abd 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: $(top_srcdir)/src/include/storage/lwlocklist.h $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..f46634a180 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/backend/storage/lmgr/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -64,17 +60,30 @@ while (<$wait_event_names>)
 	push(@wait_event_lwlocks, $waiteventname . "Lock");
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip uniline C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
+
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\w+),\s+(\d+)\)$/;
 
 	(my $lockname, my $lockidx) = ($1, $2);
 
@@ -82,25 +91,23 @@ while (<$lwlocknames>)
 	$trimmedlockname =~ s/Lock$//;
 	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
@@ -109,18 +116,15 @@ while (<$lwlocknames>)
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index d405c61b21..1112389af5 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -115,8 +115,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -129,9 +129,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(lockname, id) [id] = CppAsString(lockname),
+#include "storage/lwlocknames.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -745,11 +746,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index ec2f31f82a..105ca977a5 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -279,9 +279,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -332,9 +332,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..3396eed58e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlock-names.pl processes this file.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(ShmemIndexLock, 1)
+PG_LWLOCK(OidGenLock, 2)
+PG_LWLOCK(XidGenLock, 3)
+PG_LWLOCK(ProcArrayLock, 4)
+PG_LWLOCK(SInvalReadLock, 5)
+PG_LWLOCK(SInvalWriteLock, 6)
+PG_LWLOCK(WALBufMappingLock, 7)
+PG_LWLOCK(WALWriteLock, 8)
+PG_LWLOCK(ControlFileLock, 9)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(MultiXactGenLock, 13)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(RelCacheInitLock, 16)
+PG_LWLOCK(CheckpointerCommLock, 17)
+PG_LWLOCK(TwoPhaseStateLock, 18)
+PG_LWLOCK(TablespaceCreateLock, 19)
+PG_LWLOCK(BtreeVacuumLock, 20)
+PG_LWLOCK(AddinShmemInitLock, 21)
+PG_LWLOCK(AutovacuumLock, 22)
+PG_LWLOCK(AutovacuumScheduleLock, 23)
+PG_LWLOCK(SyncScanLock, 24)
+PG_LWLOCK(RelationMappingLock, 25)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(NotifyQueueLock, 27)
+PG_LWLOCK(SerializableXactHashLock, 28)
+PG_LWLOCK(SerializableFinishedListLock, 29)
+PG_LWLOCK(SerializablePredicateListLock, 30)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(SyncRepLock, 32)
+PG_LWLOCK(BackgroundWorkerLock, 33)
+PG_LWLOCK(DynamicSharedMemoryControlLock, 34)
+PG_LWLOCK(AutoFileLock, 35)
+PG_LWLOCK(ReplicationSlotAllocationLock, 36)
+PG_LWLOCK(ReplicationSlotControlLock, 37)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(CommitTsLock, 39)
+PG_LWLOCK(ReplicationOriginLock, 40)
+PG_LWLOCK(MultiXactTruncationLock, 41)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(LogicalRepWorkerLock, 43)
+PG_LWLOCK(XactTruncationLock, 44)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(WrapLimitsVacuumLock, 46)
+PG_LWLOCK(NotifyQueueTailLock, 47)
+PG_LWLOCK(WaitEventExtensionLock, 48)
+PG_LWLOCK(WALSummarizerLock, 49)
+PG_LWLOCK(DSMRegistryLock, 50)
+PG_LWLOCK(InjectionPointLock, 51)
+PG_LWLOCK(SerialControlLock, 52)
-- 
2.39.2


--hafsgxjamluc3fye--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH v2] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.

We still have to build lwlocknames.h using Perl code, which initially I
wanted to avoid, but it gives us the chance to cross-check
wait_event_names.txt.

Discussion: https://postgr.es/m/[email protected]
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 60 ++++++-------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 -------------
 src/backend/storage/lmgr/meson.build          |  2 -
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlock.h                  |  4 +-
 src/include/storage/lwlocklist.h              | 85 +++++++++++++++++++
 src/include/storage/meson.build               | 12 ++-
 src/tools/pginclude/headerscheck              |  1 +
 12 files changed, 136 insertions(+), 125 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..79a12dfd1e 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl ../include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..3f89548bde 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: ../../../include/storage/lwlocklist.h ../../utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..eaddd9d3b9 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/include/storage/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -61,66 +57,70 @@ while (<$wait_event_names>)
 
 	# Record the LWLock.
 	(my $waiteventname, my $waitevendocsentence) = split(/\t/, $_);
-	push(@wait_event_lwlocks, $waiteventname . "Lock");
+	push(@wait_event_lwlocks, $waiteventname);
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip single-line C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
 
-	(my $lockname, my $lockidx) = ($1, $2);
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\d+),\s+(\w+)\)$/;
 
-	my $trimmedlockname = $lockname;
-	$trimmedlockname =~ s/Lock$//;
-	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
+	(my $lockidx, my $lockname) = ($1, $2);
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
-	print $h "#define $lockname (&MainLWLockArray[$lockidx].lock)\n";
+	print $h "#define ${lockname}Lock (&MainLWLockArray[$lockidx].lock)\n";
 }
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 30f3a09a4c..83992725de 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -112,8 +112,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -126,9 +126,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(id, lockname) [id] = CppAsString(lockname) "Lock",
+#include "storage/lwlocklist.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -742,11 +743,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/storage/lmgr/meson.build b/src/backend/storage/lmgr/meson.build
index da32198f78..05ac41e809 100644
--- a/src/backend/storage/lmgr/meson.build
+++ b/src/backend/storage/lmgr/meson.build
@@ -11,5 +11,3 @@ backend_sources += files(
   's_lock.c',
   'spin.c',
 )
-
-generated_backend_sources += lwlocknames[1]
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index c08e00d1d6..b0ab833602 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -280,9 +280,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -333,9 +333,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 10bea8c595..3479b4cf52 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -19,6 +19,7 @@
 #endif
 
 #include "port/atomics.h"
+#include "storage/lwlocknames.h"
 #include "storage/proclist_types.h"
 
 struct PGPROC;
@@ -82,9 +83,6 @@ typedef struct NamedLWLockTranche
 extern PGDLLIMPORT NamedLWLockTranche *NamedLWLockTrancheArray;
 extern PGDLLIMPORT int NamedLWLockTrancheRequests;
 
-/* Names for fixed lwlocks */
-#include "storage/lwlocknames.h"
-
 /*
  * 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
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..85f6568b9e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,85 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlocknames.pl processes this file to create lwlocknames.h.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ *
+ * Note that the names here don't include the Lock suffix, to appease the
+ * C preprocessor; it's added elsewhere.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(1, ShmemIndex)
+PG_LWLOCK(2, OidGen)
+PG_LWLOCK(3, XidGen)
+PG_LWLOCK(4, ProcArray)
+PG_LWLOCK(5, SInvalRead)
+PG_LWLOCK(6, SInvalWrite)
+PG_LWLOCK(7, WALBufMapping)
+PG_LWLOCK(8, WALWrite)
+PG_LWLOCK(9, ControlFile)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(13, MultiXactGen)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(16, RelCacheInit)
+PG_LWLOCK(17, CheckpointerComm)
+PG_LWLOCK(18, TwoPhaseState)
+PG_LWLOCK(19, TablespaceCreate)
+PG_LWLOCK(20, BtreeVacuum)
+PG_LWLOCK(21, AddinShmemInit)
+PG_LWLOCK(22, Autovacuum)
+PG_LWLOCK(23, AutovacuumSchedule)
+PG_LWLOCK(24, SyncScan)
+PG_LWLOCK(25, RelationMapping)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(27, NotifyQueue)
+PG_LWLOCK(28, SerializableXactHash)
+PG_LWLOCK(29, SerializableFinishedList)
+PG_LWLOCK(30, SerializablePredicateList)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(32, SyncRep)
+PG_LWLOCK(33, BackgroundWorker)
+PG_LWLOCK(34, DynamicSharedMemoryControl)
+PG_LWLOCK(35, AutoFile)
+PG_LWLOCK(36, ReplicationSlotAllocation)
+PG_LWLOCK(37, ReplicationSlotControl)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(39, CommitTs)
+PG_LWLOCK(40, ReplicationOrigin)
+PG_LWLOCK(41, MultiXactTruncation)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(43, LogicalRepWorker)
+PG_LWLOCK(44, XactTruncation)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(46, WrapLimitsVacuum)
+PG_LWLOCK(47, NotifyQueueTail)
+PG_LWLOCK(48, WaitEventExtension)
+PG_LWLOCK(49, WALSummarizer)
+PG_LWLOCK(50, DSMRegistry)
+PG_LWLOCK(51, InjectionPoint)
+PG_LWLOCK(52, SerialControl)
diff --git a/src/include/storage/meson.build b/src/include/storage/meson.build
index 666fb22408..f889093117 100644
--- a/src/include/storage/meson.build
+++ b/src/include/storage/meson.build
@@ -1,10 +1,10 @@
 # Copyright (c) 2022-2024, PostgreSQL Global Development Group
 
-lwlocknames = custom_target('lwlocknames',
+lwlocknames_h = custom_target('lwlocknames_h',
   input: files(
-    '../../backend/storage/lmgr/lwlocknames.txt',
+    '../../include/storage/lwlocklist.h',
     '../../backend/utils/activity/wait_event_names.txt'),
-  output: ['lwlocknames.h', 'lwlocknames.c'],
+  output: ['lwlocknames.h'],
   command: [
     perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'),
     '-o', '@OUTDIR@',
@@ -12,12 +12,10 @@ lwlocknames = custom_target('lwlocknames',
   ],
   build_by_default: true,
   install: true,
-  install_dir: [dir_include_server / 'storage', false],
+  install_dir: dir_include_server / 'storage',
 )
 
-lwlocknames_h = lwlocknames[0]
-
 generated_backend_headers += lwlocknames_h
 
 # autoconf generates the file there, ensure we get a conflict
-generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.c', 'lwlocknames.h']}
+generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.h']}
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index 5c12ab99b8..13b9735f84 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -133,6 +133,7 @@ do
 	test "$f" = src/interfaces/ecpg/preproc/c_kwlist.h && continue
 	test "$f" = src/interfaces/ecpg/preproc/ecpg_kwlist.h && continue
 	test "$f" = src/include/regex/regerrs.h && continue
+	test "$f" = src/include/storage/lwlocklist.h && continue
 	test "$f" = src/include/tcop/cmdtaglist.h && continue
 	test "$f" = src/pl/plpgsql/src/plerrcodes.h && continue
 	test "$f" = src/pl/plpython/spiexceptions.h && continue
-- 
2.39.2


--t4gqyw67m6fqhs6t--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 52 ++++++------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 --------------
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlocklist.h              | 82 +++++++++++++++++++
 8 files changed, 124 insertions(+), 107 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..34bb6393c4 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl $(top_srcdir)/src/include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..9d7dbe5abd 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: $(top_srcdir)/src/include/storage/lwlocklist.h $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..f46634a180 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/backend/storage/lmgr/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -64,17 +60,30 @@ while (<$wait_event_names>)
 	push(@wait_event_lwlocks, $waiteventname . "Lock");
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip uniline C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
+
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\w+),\s+(\d+)\)$/;
 
 	(my $lockname, my $lockidx) = ($1, $2);
 
@@ -82,25 +91,23 @@ while (<$lwlocknames>)
 	$trimmedlockname =~ s/Lock$//;
 	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
@@ -109,18 +116,15 @@ while (<$lwlocknames>)
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index d405c61b21..1112389af5 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -115,8 +115,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -129,9 +129,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(lockname, id) [id] = CppAsString(lockname),
+#include "storage/lwlocknames.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -745,11 +746,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index ec2f31f82a..105ca977a5 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -279,9 +279,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -332,9 +332,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..3396eed58e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlock-names.pl processes this file.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(ShmemIndexLock, 1)
+PG_LWLOCK(OidGenLock, 2)
+PG_LWLOCK(XidGenLock, 3)
+PG_LWLOCK(ProcArrayLock, 4)
+PG_LWLOCK(SInvalReadLock, 5)
+PG_LWLOCK(SInvalWriteLock, 6)
+PG_LWLOCK(WALBufMappingLock, 7)
+PG_LWLOCK(WALWriteLock, 8)
+PG_LWLOCK(ControlFileLock, 9)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(MultiXactGenLock, 13)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(RelCacheInitLock, 16)
+PG_LWLOCK(CheckpointerCommLock, 17)
+PG_LWLOCK(TwoPhaseStateLock, 18)
+PG_LWLOCK(TablespaceCreateLock, 19)
+PG_LWLOCK(BtreeVacuumLock, 20)
+PG_LWLOCK(AddinShmemInitLock, 21)
+PG_LWLOCK(AutovacuumLock, 22)
+PG_LWLOCK(AutovacuumScheduleLock, 23)
+PG_LWLOCK(SyncScanLock, 24)
+PG_LWLOCK(RelationMappingLock, 25)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(NotifyQueueLock, 27)
+PG_LWLOCK(SerializableXactHashLock, 28)
+PG_LWLOCK(SerializableFinishedListLock, 29)
+PG_LWLOCK(SerializablePredicateListLock, 30)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(SyncRepLock, 32)
+PG_LWLOCK(BackgroundWorkerLock, 33)
+PG_LWLOCK(DynamicSharedMemoryControlLock, 34)
+PG_LWLOCK(AutoFileLock, 35)
+PG_LWLOCK(ReplicationSlotAllocationLock, 36)
+PG_LWLOCK(ReplicationSlotControlLock, 37)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(CommitTsLock, 39)
+PG_LWLOCK(ReplicationOriginLock, 40)
+PG_LWLOCK(MultiXactTruncationLock, 41)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(LogicalRepWorkerLock, 43)
+PG_LWLOCK(XactTruncationLock, 44)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(WrapLimitsVacuumLock, 46)
+PG_LWLOCK(NotifyQueueTailLock, 47)
+PG_LWLOCK(WaitEventExtensionLock, 48)
+PG_LWLOCK(WALSummarizerLock, 49)
+PG_LWLOCK(DSMRegistryLock, 50)
+PG_LWLOCK(InjectionPointLock, 51)
+PG_LWLOCK(SerialControlLock, 52)
-- 
2.39.2


--hafsgxjamluc3fye--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH v2] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.

We still have to build lwlocknames.h using Perl code, which initially I
wanted to avoid, but it gives us the chance to cross-check
wait_event_names.txt.

Discussion: https://postgr.es/m/[email protected]
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 60 ++++++-------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 -------------
 src/backend/storage/lmgr/meson.build          |  2 -
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlock.h                  |  4 +-
 src/include/storage/lwlocklist.h              | 85 +++++++++++++++++++
 src/include/storage/meson.build               | 12 ++-
 src/tools/pginclude/headerscheck              |  1 +
 12 files changed, 136 insertions(+), 125 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..79a12dfd1e 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl ../include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..3f89548bde 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: ../../../include/storage/lwlocklist.h ../../utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..eaddd9d3b9 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/include/storage/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -61,66 +57,70 @@ while (<$wait_event_names>)
 
 	# Record the LWLock.
 	(my $waiteventname, my $waitevendocsentence) = split(/\t/, $_);
-	push(@wait_event_lwlocks, $waiteventname . "Lock");
+	push(@wait_event_lwlocks, $waiteventname);
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip single-line C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
 
-	(my $lockname, my $lockidx) = ($1, $2);
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\d+),\s+(\w+)\)$/;
 
-	my $trimmedlockname = $lockname;
-	$trimmedlockname =~ s/Lock$//;
-	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
+	(my $lockidx, my $lockname) = ($1, $2);
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
-	print $h "#define $lockname (&MainLWLockArray[$lockidx].lock)\n";
+	print $h "#define ${lockname}Lock (&MainLWLockArray[$lockidx].lock)\n";
 }
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 30f3a09a4c..83992725de 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -112,8 +112,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -126,9 +126,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(id, lockname) [id] = CppAsString(lockname) "Lock",
+#include "storage/lwlocklist.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -742,11 +743,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/storage/lmgr/meson.build b/src/backend/storage/lmgr/meson.build
index da32198f78..05ac41e809 100644
--- a/src/backend/storage/lmgr/meson.build
+++ b/src/backend/storage/lmgr/meson.build
@@ -11,5 +11,3 @@ backend_sources += files(
   's_lock.c',
   'spin.c',
 )
-
-generated_backend_sources += lwlocknames[1]
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index c08e00d1d6..b0ab833602 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -280,9 +280,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -333,9 +333,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 10bea8c595..3479b4cf52 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -19,6 +19,7 @@
 #endif
 
 #include "port/atomics.h"
+#include "storage/lwlocknames.h"
 #include "storage/proclist_types.h"
 
 struct PGPROC;
@@ -82,9 +83,6 @@ typedef struct NamedLWLockTranche
 extern PGDLLIMPORT NamedLWLockTranche *NamedLWLockTrancheArray;
 extern PGDLLIMPORT int NamedLWLockTrancheRequests;
 
-/* Names for fixed lwlocks */
-#include "storage/lwlocknames.h"
-
 /*
  * 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
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..85f6568b9e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,85 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlocknames.pl processes this file to create lwlocknames.h.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ *
+ * Note that the names here don't include the Lock suffix, to appease the
+ * C preprocessor; it's added elsewhere.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(1, ShmemIndex)
+PG_LWLOCK(2, OidGen)
+PG_LWLOCK(3, XidGen)
+PG_LWLOCK(4, ProcArray)
+PG_LWLOCK(5, SInvalRead)
+PG_LWLOCK(6, SInvalWrite)
+PG_LWLOCK(7, WALBufMapping)
+PG_LWLOCK(8, WALWrite)
+PG_LWLOCK(9, ControlFile)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(13, MultiXactGen)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(16, RelCacheInit)
+PG_LWLOCK(17, CheckpointerComm)
+PG_LWLOCK(18, TwoPhaseState)
+PG_LWLOCK(19, TablespaceCreate)
+PG_LWLOCK(20, BtreeVacuum)
+PG_LWLOCK(21, AddinShmemInit)
+PG_LWLOCK(22, Autovacuum)
+PG_LWLOCK(23, AutovacuumSchedule)
+PG_LWLOCK(24, SyncScan)
+PG_LWLOCK(25, RelationMapping)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(27, NotifyQueue)
+PG_LWLOCK(28, SerializableXactHash)
+PG_LWLOCK(29, SerializableFinishedList)
+PG_LWLOCK(30, SerializablePredicateList)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(32, SyncRep)
+PG_LWLOCK(33, BackgroundWorker)
+PG_LWLOCK(34, DynamicSharedMemoryControl)
+PG_LWLOCK(35, AutoFile)
+PG_LWLOCK(36, ReplicationSlotAllocation)
+PG_LWLOCK(37, ReplicationSlotControl)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(39, CommitTs)
+PG_LWLOCK(40, ReplicationOrigin)
+PG_LWLOCK(41, MultiXactTruncation)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(43, LogicalRepWorker)
+PG_LWLOCK(44, XactTruncation)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(46, WrapLimitsVacuum)
+PG_LWLOCK(47, NotifyQueueTail)
+PG_LWLOCK(48, WaitEventExtension)
+PG_LWLOCK(49, WALSummarizer)
+PG_LWLOCK(50, DSMRegistry)
+PG_LWLOCK(51, InjectionPoint)
+PG_LWLOCK(52, SerialControl)
diff --git a/src/include/storage/meson.build b/src/include/storage/meson.build
index 666fb22408..f889093117 100644
--- a/src/include/storage/meson.build
+++ b/src/include/storage/meson.build
@@ -1,10 +1,10 @@
 # Copyright (c) 2022-2024, PostgreSQL Global Development Group
 
-lwlocknames = custom_target('lwlocknames',
+lwlocknames_h = custom_target('lwlocknames_h',
   input: files(
-    '../../backend/storage/lmgr/lwlocknames.txt',
+    '../../include/storage/lwlocklist.h',
     '../../backend/utils/activity/wait_event_names.txt'),
-  output: ['lwlocknames.h', 'lwlocknames.c'],
+  output: ['lwlocknames.h'],
   command: [
     perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'),
     '-o', '@OUTDIR@',
@@ -12,12 +12,10 @@ lwlocknames = custom_target('lwlocknames',
   ],
   build_by_default: true,
   install: true,
-  install_dir: [dir_include_server / 'storage', false],
+  install_dir: dir_include_server / 'storage',
 )
 
-lwlocknames_h = lwlocknames[0]
-
 generated_backend_headers += lwlocknames_h
 
 # autoconf generates the file there, ensure we get a conflict
-generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.c', 'lwlocknames.h']}
+generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.h']}
diff --git a/src/tools/pginclude/headerscheck b/src/tools/pginclude/headerscheck
index 5c12ab99b8..13b9735f84 100755
--- a/src/tools/pginclude/headerscheck
+++ b/src/tools/pginclude/headerscheck
@@ -133,6 +133,7 @@ do
 	test "$f" = src/interfaces/ecpg/preproc/c_kwlist.h && continue
 	test "$f" = src/interfaces/ecpg/preproc/ecpg_kwlist.h && continue
 	test "$f" = src/include/regex/regerrs.h && continue
+	test "$f" = src/include/storage/lwlocklist.h && continue
 	test "$f" = src/include/tcop/cmdtaglist.h && continue
 	test "$f" = src/pl/plpgsql/src/plerrcodes.h && continue
 	test "$f" = src/pl/plpython/spiexceptions.h && continue
-- 
2.39.2


--t4gqyw67m6fqhs6t--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread

* [PATCH] Rework lwlocknames.txt to become lwlocklist.h
@ 2024-03-01 12:03  Alvaro Herrera <[email protected]>
  0 siblings, 0 replies; 22+ messages in thread

From: Alvaro Herrera @ 2024-03-01 12:03 UTC (permalink / raw)

This saves some code and some space in BuiltinTrancheNames, as foreseen
in commit 74a730631065.
---
 src/backend/Makefile                          |  4 +-
 src/backend/storage/lmgr/.gitignore           |  1 -
 src/backend/storage/lmgr/Makefile             |  9 +-
 .../storage/lmgr/generate-lwlocknames.pl      | 52 ++++++------
 src/backend/storage/lmgr/lwlock.c             | 15 ++--
 src/backend/storage/lmgr/lwlocknames.txt      | 60 --------------
 .../utils/activity/wait_event_names.txt       |  8 +-
 src/include/storage/lwlocklist.h              | 82 +++++++++++++++++++
 8 files changed, 124 insertions(+), 107 deletions(-)
 delete mode 100644 src/backend/storage/lmgr/lwlocknames.txt
 create mode 100644 src/include/storage/lwlocklist.h

diff --git a/src/backend/Makefile b/src/backend/Makefile
index d66e2a4b9f..34bb6393c4 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -110,8 +110,8 @@ $(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 parser/gram.h: parser/gram.y
 	$(MAKE) -C parser gram.h
 
-storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt utils/activity/wait_event_names.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
+storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl $(top_srcdir)/src/include/storage/lwlocklist.h utils/activity/wait_event_names.txt
+	$(MAKE) -C storage/lmgr lwlocknames.h
 
 utils/activity/wait_event_types.h: utils/activity/generate-wait_event_types.pl utils/activity/wait_event_names.txt
 	$(MAKE) -C utils/activity wait_event_types.h pgstat_wait_event.c wait_event_funcs_data.c
diff --git a/src/backend/storage/lmgr/.gitignore b/src/backend/storage/lmgr/.gitignore
index dab4c3f580..8e5b734f15 100644
--- a/src/backend/storage/lmgr/.gitignore
+++ b/src/backend/storage/lmgr/.gitignore
@@ -1,3 +1,2 @@
-/lwlocknames.c
 /lwlocknames.h
 /s_lock_test
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index 1aef423384..9d7dbe5abd 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -18,7 +18,6 @@ OBJS = \
 	lmgr.o \
 	lock.o \
 	lwlock.o \
-	lwlocknames.o \
 	predicate.o \
 	proc.o \
 	s_lock.o \
@@ -35,11 +34,7 @@ s_lock_test: s_lock.c $(top_builddir)/src/common/libpgcommon.a $(top_builddir)/s
 		$(TASPATH) -L $(top_builddir)/src/common -lpgcommon \
 		-L $(top_builddir)/src/port -lpgport -lm -o s_lock_test
 
-# see notes in src/backend/parser/Makefile
-lwlocknames.c: lwlocknames.h
-	touch $@
-
-lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
+lwlocknames.h: $(top_srcdir)/src/include/storage/lwlocklist.h $(top_srcdir)/src/backend/utils/activity/wait_event_names.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $^
 
 check: s_lock_test
@@ -47,4 +42,4 @@ check: s_lock_test
 
 clean:
 	rm -f s_lock_test
-	rm -f lwlocknames.h lwlocknames.c
+	rm -f lwlocknames.h
diff --git a/src/backend/storage/lmgr/generate-lwlocknames.pl b/src/backend/storage/lmgr/generate-lwlocknames.pl
index 7b93ecf6c1..f46634a180 100644
--- a/src/backend/storage/lmgr/generate-lwlocknames.pl
+++ b/src/backend/storage/lmgr/generate-lwlocknames.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# Generate lwlocknames.h and lwlocknames.c from lwlocknames.txt
+# Generate lwlocknames.h from lwlocklist.h
 # Copyright (c) 2000-2024, PostgreSQL Global Development Group
 
 use strict;
@@ -14,26 +14,22 @@ my $continue = "\n";
 
 GetOptions('outdir:s' => \$output_path);
 
-open my $lwlocknames, '<', $ARGV[0] or die;
+open my $lwlocklist, '<', $ARGV[0] or die;
 open my $wait_event_names, '<', $ARGV[1] or die;
 
 # Include PID in suffix in case parallel make runs this multiple times.
 my $htmp = "$output_path/lwlocknames.h.tmp$$";
-my $ctmp = "$output_path/lwlocknames.c.tmp$$";
 open my $h, '>', $htmp or die "Could not open $htmp: $!";
-open my $c, '>', $ctmp or die "Could not open $ctmp: $!";
 
 my $autogen =
-  "/* autogenerated from src/backend/storage/lmgr/lwlocknames.txt, do not edit */\n";
+  "/* autogenerated from src/backend/storage/lmgr/lwlocklist.h, 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 "const char *const IndividualLWLockNames[] = {";
 
 #
 # First, record the predefined LWLocks listed in wait_event_names.txt.  We'll
-# cross-check those with the ones in lwlocknames.txt.
+# cross-check those with the ones in lwlocklist.h.
 #
 my @wait_event_lwlocks;
 my $record_lwlocks = 0;
@@ -64,17 +60,30 @@ while (<$wait_event_names>)
 	push(@wait_event_lwlocks, $waiteventname . "Lock");
 }
 
+my $in_comment = 0;
 my $i = 0;
-while (<$lwlocknames>)
+while (<$lwlocklist>)
 {
 	chomp;
 
-	# Skip comments
-	next if /^#/;
+	# Skip uniline C comments and empty lines
+	next if m{^\s*/\*.*\*/$};
 	next if /^\s*$/;
 
-	die "unable to parse lwlocknames.txt"
-	  unless /^(\w+)\s+(\d+)$/;
+	# skip multiline C comments
+	if ($in_comment == 1)
+	{
+		$in_comment = 0 if m{\*/};
+		next;
+	}
+	elsif (m{^\s*/\*})
+	{
+		$in_comment = 1;
+		next;
+	}
+
+	die "unable to parse lwlocklist.h line \"$_\""
+	  unless /^PG_LWLOCK\((\w+),\s+(\d+)\)$/;
 
 	(my $lockname, my $lockidx) = ($1, $2);
 
@@ -82,25 +91,23 @@ while (<$lwlocknames>)
 	$trimmedlockname =~ s/Lock$//;
 	die "lock names must end with 'Lock'" if $trimmedlockname eq $lockname;
 
-	die "lwlocknames.txt not in order" if $lockidx < $lastlockidx;
-	die "lwlocknames.txt has duplicates" if $lockidx == $lastlockidx;
+	die "lwlocklist.h not in order" if $lockidx < $lastlockidx;
+	die "lwlocklist.h has duplicates" if $lockidx == $lastlockidx;
 
-	die "$lockname defined in lwlocknames.txt but missing from "
+	die "$lockname defined in lwlocklist.h but missing from "
 	  . "wait_event_names.txt"
 	  if $i >= scalar @wait_event_lwlocks;
 	die "lists of predefined LWLocks do not match (first mismatch at "
 	  . "$wait_event_lwlocks[$i] in wait_event_names.txt and $lockname in "
-	  . "lwlocknames.txt)"
+	  . "lwlocklist.h)"
 	  if $wait_event_lwlocks[$i] ne $lockname;
 	$i++;
 
 	while ($lastlockidx < $lockidx - 1)
 	{
 		++$lastlockidx;
-		printf $c "%s	\"<unassigned:%d>\"", $continue, $lastlockidx;
 		$continue = ",\n";
 	}
-	printf $c "%s	\"%s\"", $continue, $trimmedlockname;
 	$lastlockidx = $lockidx;
 	$continue = ",\n";
 
@@ -109,18 +116,15 @@ while (<$lwlocknames>)
 
 die
   "$wait_event_lwlocks[$i] defined in wait_event_names.txt but missing from "
-  . "lwlocknames.txt"
+  . "lwlocklist.h"
   if $i < scalar @wait_event_lwlocks;
 
-printf $c "\n};\n";
 print $h "\n";
 printf $h "#define NUM_INDIVIDUAL_LWLOCKS		%s\n", $lastlockidx + 1;
 
 close $h;
-close $c;
 
 rename($htmp, "$output_path/lwlocknames.h")
   || die "rename: $htmp to $output_path/lwlocknames.h: $!";
-rename($ctmp, "$output_path/lwlocknames.c") || die "rename: $ctmp: $!";
 
-close $lwlocknames;
+close $lwlocklist;
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index d405c61b21..1112389af5 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -115,8 +115,8 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * There are three sorts of LWLock "tranches":
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
- * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * own tranche.  We absorb the names of these tranches from there into
+ * BuiltinTrancheNames here.
  *
  * 2. There are some predefined tranches for built-in groups of locks.
  * These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
@@ -129,9 +129,10 @@ StaticAssertDecl(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
  * All these names are user-visible as wait event names, so choose with care
  * ... and do not forget to update the documentation's list of wait events.
  */
-extern const char *const IndividualLWLockNames[];	/* in lwlocknames.c */
-
 static const char *const BuiltinTrancheNames[] = {
+#define PG_LWLOCK(lockname, id) [id] = CppAsString(lockname),
+#include "storage/lwlocknames.h"
+#undef PG_LWLOCK
 	[LWTRANCHE_XACT_BUFFER] = "XactBuffer",
 	[LWTRANCHE_COMMITTS_BUFFER] = "CommitTsBuffer",
 	[LWTRANCHE_SUBTRANS_BUFFER] = "SubtransBuffer",
@@ -745,11 +746,7 @@ LWLockReportWaitEnd(void)
 static const char *
 GetLWTrancheName(uint16 trancheId)
 {
-	/* Individual LWLock? */
-	if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
-		return IndividualLWLockNames[trancheId];
-
-	/* Built-in tranche? */
+	/* Built-in tranche or individual LWLock? */
 	if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
 		return BuiltinTrancheNames[trancheId];
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
deleted file mode 100644
index 284d168f77..0000000000
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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.  Also, do not forget to update the section
-# WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
-
-# 0 is available; was formerly BufFreelistLock
-ShmemIndexLock						1
-OidGenLock							2
-XidGenLock							3
-ProcArrayLock						4
-SInvalReadLock						5
-SInvalWriteLock						6
-WALBufMappingLock					7
-WALWriteLock						8
-ControlFileLock						9
-# 10 was CheckpointLock
-# 11 was XactSLRULock
-# 12 was SubtransSLRULock
-MultiXactGenLock					13
-# 14 was MultiXactOffsetSLRULock
-# 15 was MultiXactMemberSLRULock
-RelCacheInitLock					16
-CheckpointerCommLock				17
-TwoPhaseStateLock					18
-TablespaceCreateLock				19
-BtreeVacuumLock						20
-AddinShmemInitLock					21
-AutovacuumLock						22
-AutovacuumScheduleLock				23
-SyncScanLock						24
-RelationMappingLock					25
-#26 was NotifySLRULock
-NotifyQueueLock						27
-SerializableXactHashLock			28
-SerializableFinishedListLock		29
-SerializablePredicateListLock		30
-# 31 was SerialSLRULock
-SyncRepLock							32
-BackgroundWorkerLock				33
-DynamicSharedMemoryControlLock		34
-AutoFileLock						35
-ReplicationSlotAllocationLock		36
-ReplicationSlotControlLock			37
-#38 was CommitTsSLRULock
-CommitTsLock						39
-ReplicationOriginLock				40
-MultiXactTruncationLock				41
-# 42 was OldSnapshotTimeMapLock
-LogicalRepWorkerLock				43
-XactTruncationLock					44
-# 45 was XactTruncationLock until removal of BackendRandomLock
-WrapLimitsVacuumLock				46
-NotifyQueueTailLock					47
-WaitEventExtensionLock				48
-WALSummarizerLock					49
-DSMRegistryLock						50
-InjectionPointLock				51
-SerialControlLock					52
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index ec2f31f82a..105ca977a5 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -279,9 +279,9 @@ Extension	"Waiting in an extension."
 # This class of wait events has its own set of C structure, so these are
 # only used for the documentation.
 #
-# NB: Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be
+# NB: Predefined LWLocks (i.e., those declared in lwlocknames.h) must be
 # listed in the top section of locks and must be listed in the same order as in
-# lwlocknames.txt.
+# lwlocknames.h.
 #
 
 Section: ClassName - WaitEventLWLock
@@ -332,9 +332,9 @@ SerialControl	"Waiting to read or update shared <filename>pg_serial</filename> s
 #
 # END OF PREDEFINED LWLOCKS (DO NOT CHANGE THIS LINE)
 #
-# Predefined LWLocks (i.e., those declared in lwlocknames.txt) must be listed
+# Predefined LWLocks (i.e., those declared in lwlocknames.h) must be listed
 # in the section above and must be listed in the same order as in
-# lwlocknames.txt.  Other LWLocks must be listed in the section below.
+# lwlocknames.h.  Other LWLocks must be listed in the section below.
 #
 
 XactBuffer	"Waiting for I/O on a transaction status SLRU buffer."
diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h
new file mode 100644
index 0000000000..3396eed58e
--- /dev/null
+++ b/src/include/storage/lwlocklist.h
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------
+ *
+ * lwlocklist.h
+ *
+ * The predefined LWLock list is kept in its own source file for use by
+ * automatic tools.  The exact representation of a keyword is determined by
+ * the PG_LWLOCK macro, which is not defined in this file; it can be
+ * defined by the caller for special purposes.
+ *
+ * Also, generate-lwlock-names.pl processes this file.
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *    src/include/storage/lwlocklist.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * 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.  Also, do not forget to update the section
+ * WaitEventLWLock of src/backend/utils/activity/wait_event_names.txt.
+ */
+
+/* 0 is available; was formerly BufFreelistLock */
+PG_LWLOCK(ShmemIndexLock, 1)
+PG_LWLOCK(OidGenLock, 2)
+PG_LWLOCK(XidGenLock, 3)
+PG_LWLOCK(ProcArrayLock, 4)
+PG_LWLOCK(SInvalReadLock, 5)
+PG_LWLOCK(SInvalWriteLock, 6)
+PG_LWLOCK(WALBufMappingLock, 7)
+PG_LWLOCK(WALWriteLock, 8)
+PG_LWLOCK(ControlFileLock, 9)
+/* 10 was CheckpointLock */
+/* 11 was XactSLRULock */
+/* 12 was SubtransSLRULock */
+PG_LWLOCK(MultiXactGenLock, 13)
+/* 14 was MultiXactOffsetSLRULock */
+/* 15 was MultiXactMemberSLRULock */
+PG_LWLOCK(RelCacheInitLock, 16)
+PG_LWLOCK(CheckpointerCommLock, 17)
+PG_LWLOCK(TwoPhaseStateLock, 18)
+PG_LWLOCK(TablespaceCreateLock, 19)
+PG_LWLOCK(BtreeVacuumLock, 20)
+PG_LWLOCK(AddinShmemInitLock, 21)
+PG_LWLOCK(AutovacuumLock, 22)
+PG_LWLOCK(AutovacuumScheduleLock, 23)
+PG_LWLOCK(SyncScanLock, 24)
+PG_LWLOCK(RelationMappingLock, 25)
+/* 26 was NotifySLRULock */
+PG_LWLOCK(NotifyQueueLock, 27)
+PG_LWLOCK(SerializableXactHashLock, 28)
+PG_LWLOCK(SerializableFinishedListLock, 29)
+PG_LWLOCK(SerializablePredicateListLock, 30)
+/* 31 was SerialSLRULock */
+PG_LWLOCK(SyncRepLock, 32)
+PG_LWLOCK(BackgroundWorkerLock, 33)
+PG_LWLOCK(DynamicSharedMemoryControlLock, 34)
+PG_LWLOCK(AutoFileLock, 35)
+PG_LWLOCK(ReplicationSlotAllocationLock, 36)
+PG_LWLOCK(ReplicationSlotControlLock, 37)
+/* 38 was CommitTsSLRULock */
+PG_LWLOCK(CommitTsLock, 39)
+PG_LWLOCK(ReplicationOriginLock, 40)
+PG_LWLOCK(MultiXactTruncationLock, 41)
+/* 42 was OldSnapshotTimeMapLock */
+PG_LWLOCK(LogicalRepWorkerLock, 43)
+PG_LWLOCK(XactTruncationLock, 44)
+/* 45 was XactTruncationLock until removal of BackendRandomLock */
+PG_LWLOCK(WrapLimitsVacuumLock, 46)
+PG_LWLOCK(NotifyQueueTailLock, 47)
+PG_LWLOCK(WaitEventExtensionLock, 48)
+PG_LWLOCK(WALSummarizerLock, 49)
+PG_LWLOCK(DSMRegistryLock, 50)
+PG_LWLOCK(InjectionPointLock, 51)
+PG_LWLOCK(SerialControlLock, 52)
-- 
2.39.2


--hafsgxjamluc3fye--





^ permalink  raw  reply  [nested|flat] 22+ messages in thread


end of thread, other threads:[~2024-03-01 12:03 UTC | newest]

Thread overview: 22+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-11-21 06:28 [PATCH v26 1/6] version nm24 Kyotaro Horiguchi <[email protected]>
2022-01-12 06:09 Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Julien Rouhaud <[email protected]>
2022-01-12 06:19 ` cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message) Tom Lane <[email protected]>
2022-01-12 06:31   ` Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message) Julien Rouhaud <[email protected]>
2022-01-12 06:37     ` Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message) Tom Lane <[email protected]>
2022-01-12 06:50       ` Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message) Julien Rouhaud <[email protected]>
2022-01-12 06:52       ` Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message) Thomas Munro <[email protected]>
2022-01-12 06:58         ` Re: cfbot wrangling (was Re: Add checkpoint and redo LSN to LogCheckpointEnd log message) Tom Lane <[email protected]>
2022-01-13 06:20 ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Bharath Rupireddy <[email protected]>
2022-01-14 13:22   ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Bharath Rupireddy <[email protected]>
2022-01-20 00:36     ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Bossart, Nathan <[email protected]>
2022-01-20 03:00       ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Kyotaro Horiguchi <[email protected]>
2022-01-28 03:13         ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Bharath Rupireddy <[email protected]>
2022-01-27 15:07       ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Bharath Rupireddy <[email protected]>
2022-01-27 23:57         ` Re: Add checkpoint and redo LSN to LogCheckpointEnd log message Nathan Bossart <[email protected]>
2024-03-01 12:03 [PATCH] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>
2024-03-01 12:03 [PATCH v2] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>
2024-03-01 12:03 [PATCH v2] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>
2024-03-01 12:03 [PATCH] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>
2024-03-01 12:03 [PATCH v2] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>
2024-03-01 12:03 [PATCH] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>
2024-03-01 12:03 [PATCH] Rework lwlocknames.txt to become lwlocklist.h Alvaro Herrera <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox