Hi,

On Thu, Aug 15, 2024 at 08:40:42PM -0400, Alvaro Herrera wrote:
> On 2024-Aug-14, Bertrand Drouvot wrote:
> 
> > Out of curiosity, checking the sizes of affected files (O2, no debug):
> > 
> > with patch:
> > 
> >    text    data     bss     dec     hex filename
> >   30304       0       8   30312    7668 
> > src/backend/replication/logical/reorderbuffer.o
> 
> > without patch:
> >   30286       0       8   30294    7656 
> > src/backend/replication/logical/reorderbuffer.o
> 
> Hmm, I suppose this delta can be explained because because the literal
> string is used inside larger snprintf() format strings or similar, so
> things like
> 
>             snprintf(path, sizeof(path),
> -                    "pg_replslot/%s/%s", slotname,
> +                    "%s/%s/%s", PG_REPLSLOT_DIR, slotname,
>                      spill_de->d_name);
> 
> and
> 
>                 ereport(ERROR,
>                         (errcode_for_file_access(),
> -                        errmsg("could not remove file \"%s\" during removal 
> of pg_replslot/%s/xid*: %m",
> -                               path, slotname)));
> +                        errmsg("could not remove file \"%s\" during removal 
> of %s/%s/xid*: %m",
> +                               PG_REPLSLOT_DIR, path, slotname)));
> 

I did not look in details, but yeah that could probably be explained that way.

> I don't disagree with making this change, but changing some of the other
> directory names you suggest, such as
> 
> > pg_notify
> > pg_serial
> > pg_subtrans
> > pg_multixact
> > pg_wal
> 
> would probably make no difference, since there are no literal strings
> that contain that as a substring(*).  It might some sense to handle
> pg_tblspc similarly.  As for pg_logical, I think you'll want separate
> defines for pg_logical/mappings, pg_logical/snapshots and so on.
> 
> 
> (*) I hope you're not going to suggest this kind of change (word-diff):
> 
>     if (GetOldestSnapshot())
>         ereport(ERROR,
>                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
>                  errmsg("[-pg_wal-]{+%s+}_replay_wait() must be only called 
> without an active or registered snapshot"{+, PG_WAL_DIR+}),
>                  errdetail("Make sure [-pg_wal-]{+%s+}_replay_wait() isn't 
> called within a transaction with an isolation level higher than READ 
> COMMITTED, another procedure, or a function."{+, PG_WAL_DIR+})));
> 

Yeah, would not cross my mind ;-). I might have been tempted to do the change
in pg_combinebackup.c though.

Having said that, I agree to focus only on:

pg_replslot
pg_tblspc
pg_logical/*

I made the changes for pg_tblspc in pg_combinebackup.c as the number of 
occurences
are greater that the "pg_wal" ones and we were to define PG_TBLSPC_DIR in any
case.

Please find attached the related patches.

Regards,

-- 
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
>From 5057933a8a4f49b57dfa50fe792d9f8162abf11a Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot...@gmail.com>
Date: Wed, 14 Aug 2024 09:16:21 +0000
Subject: [PATCH v2 1/5] Define PG_REPLSLOT_DIR

Replace most of the places where "pg_replslot" is used in .c files with a new
PG_REPLSLOT_DIR define. The places where it is not done is for consistency with
the existing PG_STAT_TMP_DIR define.
---
 src/backend/backup/basebackup.c               |  3 +-
 .../replication/logical/reorderbuffer.c       | 15 ++++----
 src/backend/replication/slot.c                | 38 +++++++++----------
 src/backend/utils/adt/genfile.c               |  5 ++-
 src/bin/initdb/initdb.c                       |  2 +-
 src/bin/pg_rewind/filemap.c                   |  2 +-
 src/include/replication/slot.h                |  2 +
 7 files changed, 36 insertions(+), 31 deletions(-)
  24.0% src/backend/replication/logical/
  59.8% src/backend/replication/
   8.7% src/backend/utils/adt/
   4.1% src/bin/
   3.2% src/

diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index 01b35e26bd..de16afac74 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -36,6 +36,7 @@
 #include "port.h"
 #include "postmaster/syslogger.h"
 #include "postmaster/walsummarizer.h"
+#include "replication/slot.h"
 #include "replication/walsender.h"
 #include "replication/walsender_private.h"
 #include "storage/bufpage.h"
@@ -161,7 +162,7 @@ static const char *const excludeDirContents[] =
 	 * even if the intention is to restore to another primary. See backup.sgml
 	 * for a more detailed description.
 	 */
-	"pg_replslot",
+	PG_REPLSLOT_DIR,
 
 	/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
 	PG_DYNSHMEM_DIR,
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 00a8327e77..6f98115d1e 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -4573,7 +4573,7 @@ ReorderBufferCleanupSerializedTXNs(const char *slotname)
 	struct stat statbuf;
 	char		path[MAXPGPATH * 2 + 12];
 
-	sprintf(path, "pg_replslot/%s", slotname);
+	sprintf(path, "%s/%s", PG_REPLSLOT_DIR, slotname);
 
 	/* we're only handling directories here, skip if it's not ours */
 	if (lstat(path, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode))
@@ -4586,14 +4586,14 @@ ReorderBufferCleanupSerializedTXNs(const char *slotname)
 		if (strncmp(spill_de->d_name, "xid", 3) == 0)
 		{
 			snprintf(path, sizeof(path),
-					 "pg_replslot/%s/%s", slotname,
+					 "%s/%s/%s", PG_REPLSLOT_DIR, slotname,
 					 spill_de->d_name);
 
 			if (unlink(path) != 0)
 				ereport(ERROR,
 						(errcode_for_file_access(),
-						 errmsg("could not remove file \"%s\" during removal of pg_replslot/%s/xid*: %m",
-								path, slotname)));
+						 errmsg("could not remove file \"%s\" during removal of %s/%s/xid*: %m",
+								PG_REPLSLOT_DIR, path, slotname)));
 		}
 	}
 	FreeDir(spill_dir);
@@ -4612,7 +4612,8 @@ ReorderBufferSerializedPath(char *path, ReplicationSlot *slot, TransactionId xid
 
 	XLogSegNoOffsetToRecPtr(segno, 0, wal_segment_size, recptr);
 
-	snprintf(path, MAXPGPATH, "pg_replslot/%s/xid-%u-lsn-%X-%X.spill",
+	snprintf(path, MAXPGPATH, "%s/%s/xid-%u-lsn-%X-%X.spill",
+			 PG_REPLSLOT_DIR,
 			 NameStr(MyReplicationSlot->data.name),
 			 xid, LSN_FORMAT_ARGS(recptr));
 }
@@ -4627,8 +4628,8 @@ StartupReorderBuffer(void)
 	DIR		   *logical_dir;
 	struct dirent *logical_de;
 
-	logical_dir = AllocateDir("pg_replslot");
-	while ((logical_de = ReadDir(logical_dir, "pg_replslot")) != NULL)
+	logical_dir = AllocateDir(PG_REPLSLOT_DIR);
+	while ((logical_de = ReadDir(logical_dir, PG_REPLSLOT_DIR)) != NULL)
 	{
 		if (strcmp(logical_de->d_name, ".") == 0 ||
 			strcmp(logical_de->d_name, "..") == 0)
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index c290339af5..55e161f8c9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -20,7 +20,7 @@
  * on standbys (to support cascading setups).  The requirement that slots be
  * usable on standbys precludes storing them in the system catalogs.
  *
- * Each replication slot gets its own directory inside the $PGDATA/pg_replslot
+ * Each replication slot gets its own directory inside the $PGDATA/PG_REPLSLOT_DIR
  * directory. Inside that directory the state file will contain the slot's
  * own data. Additional data can be stored alongside that file if required.
  * While the server is running, the state data is also cached in memory for
@@ -916,8 +916,8 @@ ReplicationSlotDropPtr(ReplicationSlot *slot)
 	LWLockAcquire(ReplicationSlotAllocationLock, LW_EXCLUSIVE);
 
 	/* Generate pathnames. */
-	sprintf(path, "pg_replslot/%s", NameStr(slot->data.name));
-	sprintf(tmppath, "pg_replslot/%s.tmp", NameStr(slot->data.name));
+	sprintf(path, "%s/%s", PG_REPLSLOT_DIR, NameStr(slot->data.name));
+	sprintf(tmppath, "%s/%s.tmp", PG_REPLSLOT_DIR, NameStr(slot->data.name));
 
 	/*
 	 * Rename the slot directory on disk, so that we'll no longer recognize
@@ -938,7 +938,7 @@ ReplicationSlotDropPtr(ReplicationSlot *slot)
 		 */
 		START_CRIT_SECTION();
 		fsync_fname(tmppath, true);
-		fsync_fname("pg_replslot", true);
+		fsync_fname(PG_REPLSLOT_DIR, true);
 		END_CRIT_SECTION();
 	}
 	else
@@ -1016,7 +1016,7 @@ ReplicationSlotSave(void)
 
 	Assert(MyReplicationSlot != NULL);
 
-	sprintf(path, "pg_replslot/%s", NameStr(MyReplicationSlot->data.name));
+	sprintf(path, "%s/%s", PG_REPLSLOT_DIR, NameStr(MyReplicationSlot->data.name));
 	SaveSlotToPath(MyReplicationSlot, path, ERROR);
 }
 
@@ -1881,7 +1881,7 @@ CheckPointReplicationSlots(bool is_shutdown)
 			continue;
 
 		/* save the slot to disk, locking is handled in SaveSlotToPath() */
-		sprintf(path, "pg_replslot/%s", NameStr(s->data.name));
+		sprintf(path, "%s/%s", PG_REPLSLOT_DIR, NameStr(s->data.name));
 
 		/*
 		 * Slot's data is not flushed each time the confirmed_flush LSN is
@@ -1922,17 +1922,17 @@ StartupReplicationSlots(void)
 	elog(DEBUG1, "starting up replication slots");
 
 	/* restore all slots by iterating over all on-disk entries */
-	replication_dir = AllocateDir("pg_replslot");
-	while ((replication_de = ReadDir(replication_dir, "pg_replslot")) != NULL)
+	replication_dir = AllocateDir(PG_REPLSLOT_DIR);
+	while ((replication_de = ReadDir(replication_dir, PG_REPLSLOT_DIR)) != NULL)
 	{
-		char		path[MAXPGPATH + 12];
+		char		path[MAXPGPATH + sizeof(PG_REPLSLOT_DIR)];
 		PGFileType	de_type;
 
 		if (strcmp(replication_de->d_name, ".") == 0 ||
 			strcmp(replication_de->d_name, "..") == 0)
 			continue;
 
-		snprintf(path, sizeof(path), "pg_replslot/%s", replication_de->d_name);
+		snprintf(path, sizeof(path), "%s/%s", PG_REPLSLOT_DIR, replication_de->d_name);
 		de_type = get_dirent_type(path, replication_de, false, DEBUG1);
 
 		/* we're only creating directories here, skip if it's not our's */
@@ -1949,7 +1949,7 @@ StartupReplicationSlots(void)
 								path)));
 				continue;
 			}
-			fsync_fname("pg_replslot", true);
+			fsync_fname(PG_REPLSLOT_DIR, true);
 			continue;
 		}
 
@@ -1987,8 +1987,8 @@ CreateSlotOnDisk(ReplicationSlot *slot)
 	 * takes out the lock, if we'd take the lock here, we'd deadlock.
 	 */
 
-	sprintf(path, "pg_replslot/%s", NameStr(slot->data.name));
-	sprintf(tmppath, "pg_replslot/%s.tmp", NameStr(slot->data.name));
+	sprintf(path, "%s/%s", PG_REPLSLOT_DIR, NameStr(slot->data.name));
+	sprintf(tmppath, "%s/%s.tmp", PG_REPLSLOT_DIR, NameStr(slot->data.name));
 
 	/*
 	 * It's just barely possible that some previous effort to create or drop a
@@ -2027,7 +2027,7 @@ CreateSlotOnDisk(ReplicationSlot *slot)
 	START_CRIT_SECTION();
 
 	fsync_fname(path, true);
-	fsync_fname("pg_replslot", true);
+	fsync_fname(PG_REPLSLOT_DIR, true);
 
 	END_CRIT_SECTION();
 }
@@ -2170,7 +2170,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
 
 	fsync_fname(path, false);
 	fsync_fname(dir, true);
-	fsync_fname("pg_replslot", true);
+	fsync_fname(PG_REPLSLOT_DIR, true);
 
 	END_CRIT_SECTION();
 
@@ -2195,8 +2195,8 @@ RestoreSlotFromDisk(const char *name)
 {
 	ReplicationSlotOnDisk cp;
 	int			i;
-	char		slotdir[MAXPGPATH + 12];
-	char		path[MAXPGPATH + 22];
+	char		slotdir[MAXPGPATH + sizeof(PG_REPLSLOT_DIR)];
+	char		path[MAXPGPATH + sizeof(PG_REPLSLOT_DIR) + 10];
 	int			fd;
 	bool		restored = false;
 	int			readBytes;
@@ -2205,7 +2205,7 @@ RestoreSlotFromDisk(const char *name)
 	/* no need to lock here, no concurrent access allowed yet */
 
 	/* delete temp file if it exists */
-	sprintf(slotdir, "pg_replslot/%s", name);
+	sprintf(slotdir, "%s/%s", PG_REPLSLOT_DIR, name);
 	sprintf(path, "%s/state.tmp", slotdir);
 	if (unlink(path) < 0 && errno != ENOENT)
 		ereport(PANIC,
@@ -2332,7 +2332,7 @@ RestoreSlotFromDisk(const char *name)
 					(errmsg("could not remove directory \"%s\"",
 							slotdir)));
 		}
-		fsync_fname("pg_replslot", true);
+		fsync_fname(PG_REPLSLOT_DIR, true);
 		return;
 	}
 
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index 0d82557417..e645e6b85a 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -708,7 +708,7 @@ pg_ls_logicalmapdir(PG_FUNCTION_ARGS)
 }
 
 /*
- * Function to return the list of files in the pg_replslot/<replication_slot>
+ * Function to return the list of files in the PG_REPLSLOT_DIR/<replication_slot>
  * directory.
  */
 Datum
@@ -728,6 +728,7 @@ pg_ls_replslotdir(PG_FUNCTION_ARGS)
 				 errmsg("replication slot \"%s\" does not exist",
 						slotname)));
 
-	snprintf(path, sizeof(path), "pg_replslot/%s", slotname);
+	snprintf(path, sizeof(path), "%s/%s", PG_REPLSLOT_DIR, slotname);
+
 	return pg_ls_dir_files(fcinfo, path, false);
 }
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index f00718a015..2ee55eced0 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -242,7 +242,7 @@ static const char *const subdirs[] = {
 	"pg_multixact/offsets",
 	"base",
 	"base/1",
-	"pg_replslot",
+	"pg_replslot",				/* defined as PG_REPLSLOT_DIR */
 	"pg_tblspc",
 	"pg_stat",
 	"pg_stat_tmp",
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 4458324c9d..00e644d988 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -97,7 +97,7 @@ static const char *const excludeDirContents[] =
 	 * even if the intention is to restore to another primary. See backup.sgml
 	 * for a more detailed description.
 	 */
-	"pg_replslot",
+	"pg_replslot",				/* defined as PG_REPLSLOT_DIR */
 
 	/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
 	"pg_dynshmem",				/* defined as PG_DYNSHMEM_DIR */
diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h
index c2ee149fd6..9665faac1c 100644
--- a/src/include/replication/slot.h
+++ b/src/include/replication/slot.h
@@ -17,6 +17,8 @@
 #include "storage/spin.h"
 #include "replication/walreceiver.h"
 
+#define PG_REPLSLOT_DIR     "pg_replslot"
+
 /*
  * Behaviour of replication slots, upon release or crash.
  *
-- 
2.34.1

>From 2cc59f7da6acb507587ca7c56732797a79e7112e Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot...@gmail.com>
Date: Mon, 19 Aug 2024 09:30:16 +0000
Subject: [PATCH v2 2/5] Define PG_LOGICAL_MAPPINGS_DIR

Replace most of the places where "pg_logical/mappings" is used in .c files with
a new PG_LOGICAL_MAPPINGS_DIR define. The places where it is not done is for
consistency with the existing PG_STAT_TMP_DIR define.
---
 src/backend/access/heap/rewriteheap.c          | 18 +++++++++---------
 .../replication/logical/reorderbuffer.c        |  6 +++---
 src/backend/utils/adt/genfile.c                |  4 ++--
 src/include/replication/reorderbuffer.h        |  2 ++
 4 files changed, 16 insertions(+), 14 deletions(-)
  57.1% src/backend/access/heap/
  22.0% src/backend/replication/logical/
  17.4% src/backend/utils/adt/
   3.3% src/include/replication/

diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 473f3aa9be..09ef220449 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -961,8 +961,8 @@ logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
 			dboid = MyDatabaseId;
 
 		snprintf(path, MAXPGPATH,
-				 "pg_logical/mappings/" LOGICAL_REWRITE_FORMAT,
-				 dboid, relid,
+				 "%s/" LOGICAL_REWRITE_FORMAT,
+				 PG_LOGICAL_MAPPINGS_DIR, dboid, relid,
 				 LSN_FORMAT_ARGS(state->rs_begin_lsn),
 				 xid, GetCurrentTransactionId());
 
@@ -1081,8 +1081,8 @@ heap_xlog_logical_rewrite(XLogReaderState *r)
 	xlrec = (xl_heap_rewrite_mapping *) XLogRecGetData(r);
 
 	snprintf(path, MAXPGPATH,
-			 "pg_logical/mappings/" LOGICAL_REWRITE_FORMAT,
-			 xlrec->mapped_db, xlrec->mapped_rel,
+			 "%s/" LOGICAL_REWRITE_FORMAT,
+			 PG_LOGICAL_MAPPINGS_DIR, xlrec->mapped_db, xlrec->mapped_rel,
 			 LSN_FORMAT_ARGS(xlrec->start_lsn),
 			 xlrec->mapped_xid, XLogRecGetXid(r));
 
@@ -1158,7 +1158,7 @@ CheckPointLogicalRewriteHeap(void)
 	XLogRecPtr	redo;
 	DIR		   *mappings_dir;
 	struct dirent *mapping_de;
-	char		path[MAXPGPATH + 20];
+	char		path[MAXPGPATH + sizeof(PG_LOGICAL_MAPPINGS_DIR)];
 
 	/*
 	 * We start of with a minimum of the last redo pointer. No new decoding
@@ -1173,8 +1173,8 @@ CheckPointLogicalRewriteHeap(void)
 	if (cutoff != InvalidXLogRecPtr && redo < cutoff)
 		cutoff = redo;
 
-	mappings_dir = AllocateDir("pg_logical/mappings");
-	while ((mapping_de = ReadDir(mappings_dir, "pg_logical/mappings")) != NULL)
+	mappings_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
+	while ((mapping_de = ReadDir(mappings_dir, PG_LOGICAL_MAPPINGS_DIR)) != NULL)
 	{
 		Oid			dboid;
 		Oid			relid;
@@ -1189,7 +1189,7 @@ CheckPointLogicalRewriteHeap(void)
 			strcmp(mapping_de->d_name, "..") == 0)
 			continue;
 
-		snprintf(path, sizeof(path), "pg_logical/mappings/%s", mapping_de->d_name);
+		snprintf(path, sizeof(path), "%s/%s", PG_LOGICAL_MAPPINGS_DIR, mapping_de->d_name);
 		de_type = get_dirent_type(path, mapping_de, false, DEBUG1);
 
 		if (de_type != PGFILETYPE_ERROR && de_type != PGFILETYPE_REG)
@@ -1249,5 +1249,5 @@ CheckPointLogicalRewriteHeap(void)
 	FreeDir(mappings_dir);
 
 	/* persist directory entries to disk */
-	fsync_fname("pg_logical/mappings", true);
+	fsync_fname(PG_LOGICAL_MAPPINGS_DIR, true);
 }
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 6f98115d1e..8e59ea9801 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -5057,7 +5057,7 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, const char *fname)
 	int			readBytes;
 	LogicalRewriteMappingData map;
 
-	sprintf(path, "pg_logical/mappings/%s", fname);
+	sprintf(path, "%s/%s", PG_LOGICAL_MAPPINGS_DIR, fname);
 	fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
 	if (fd < 0)
 		ereport(ERROR,
@@ -5173,8 +5173,8 @@ UpdateLogicalMappings(HTAB *tuplecid_data, Oid relid, Snapshot snapshot)
 	ListCell   *file;
 	Oid			dboid = IsSharedRelation(relid) ? InvalidOid : MyDatabaseId;
 
-	mapping_dir = AllocateDir("pg_logical/mappings");
-	while ((mapping_de = ReadDir(mapping_dir, "pg_logical/mappings")) != NULL)
+	mapping_dir = AllocateDir(PG_LOGICAL_MAPPINGS_DIR);
+	while ((mapping_de = ReadDir(mapping_dir, PG_LOGICAL_MAPPINGS_DIR)) != NULL)
 	{
 		Oid			f_dboid;
 		Oid			f_relid;
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index e645e6b85a..b57254286b 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -699,12 +699,12 @@ pg_ls_logicalsnapdir(PG_FUNCTION_ARGS)
 }
 
 /*
- * Function to return the list of files in the pg_logical/mappings directory.
+ * Function to return the list of files in the PG_LOGICAL_MAPPINGS_DIR directory.
  */
 Datum
 pg_ls_logicalmapdir(PG_FUNCTION_ARGS)
 {
-	return pg_ls_dir_files(fcinfo, "pg_logical/mappings", false);
+	return pg_ls_dir_files(fcinfo, PG_LOGICAL_MAPPINGS_DIR, false);
 }
 
 /*
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index 851a001c8b..bf3b8010f6 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -18,6 +18,8 @@
 #include "utils/snapshot.h"
 #include "utils/timestamp.h"
 
+#define PG_LOGICAL_MAPPINGS_DIR "pg_logical/mappings"
+
 /* GUC variables */
 extern PGDLLIMPORT int logical_decoding_work_mem;
 extern PGDLLIMPORT int debug_logical_replication_streaming;
-- 
2.34.1

>From a76100f2fbb1906195a18ffbffbf897e83627916 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot...@gmail.com>
Date: Mon, 19 Aug 2024 09:42:40 +0000
Subject: [PATCH v2 3/5] Define PG_LOGICAL_SNAPSHOTS_DIR

Replace most of the places where "pg_logical/snapshots" is used in .c files with
a new PG_LOGICAL_SNAPSHOTS_DIR define. The places where it is not done is for
consistency with the existing PG_STAT_TMP_DIR define.
---
 src/backend/replication/logical/snapbuild.c | 28 ++++++++++++---------
 src/backend/utils/adt/genfile.c             |  4 +--
 src/include/replication/reorderbuffer.h     |  1 +
 3 files changed, 19 insertions(+), 14 deletions(-)
  79.1% src/backend/replication/logical/
  17.5% src/backend/utils/adt/
   3.3% src/include/replication/

diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index ae676145e6..0450f94ba8 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -1654,7 +1654,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	 * unless the user used pg_resetwal or similar. If a user did so, there's
 	 * no hope continuing to decode anyway.
 	 */
-	sprintf(path, "pg_logical/snapshots/%X-%X.snap",
+	sprintf(path, "%s/%X-%X.snap",
+			PG_LOGICAL_SNAPSHOTS_DIR,
 			LSN_FORMAT_ARGS(lsn));
 
 	/*
@@ -1681,7 +1682,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 		 * be safely on disk.
 		 */
 		fsync_fname(path, false);
-		fsync_fname("pg_logical/snapshots", true);
+		fsync_fname(PG_LOGICAL_SNAPSHOTS_DIR, true);
 
 		builder->last_serialized_snapshot = lsn;
 		goto out;
@@ -1697,7 +1698,8 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	elog(DEBUG1, "serializing snapshot to %s", path);
 
 	/* to make sure only we will write to this tempfile, include pid */
-	sprintf(tmppath, "pg_logical/snapshots/%X-%X.snap.%d.tmp",
+	sprintf(tmppath, "%s/%X-%X.snap.%d.tmp",
+			PG_LOGICAL_SNAPSHOTS_DIR,
 			LSN_FORMAT_ARGS(lsn), MyProcPid);
 
 	/*
@@ -1818,7 +1820,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 				(errcode_for_file_access(),
 				 errmsg("could not close file \"%s\": %m", tmppath)));
 
-	fsync_fname("pg_logical/snapshots", true);
+	fsync_fname(PG_LOGICAL_SNAPSHOTS_DIR, true);
 
 	/*
 	 * We may overwrite the work from some other backend, but that's ok, our
@@ -1834,7 +1836,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 
 	/* make sure we persist */
 	fsync_fname(path, false);
-	fsync_fname("pg_logical/snapshots", true);
+	fsync_fname(PG_LOGICAL_SNAPSHOTS_DIR, true);
 
 	/*
 	 * Now there's no way we can lose the dumped state anymore, remember this
@@ -1871,7 +1873,8 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 	if (builder->state == SNAPBUILD_CONSISTENT)
 		return false;
 
-	sprintf(path, "pg_logical/snapshots/%X-%X.snap",
+	sprintf(path, "%s/%X-%X.snap",
+			PG_LOGICAL_SNAPSHOTS_DIR,
 			LSN_FORMAT_ARGS(lsn));
 
 	fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
@@ -1892,7 +1895,7 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 	 * ----
 	 */
 	fsync_fname(path, false);
-	fsync_fname("pg_logical/snapshots", true);
+	fsync_fname(PG_LOGICAL_SNAPSHOTS_DIR, true);
 
 
 	/* read statically sized portion of snapshot */
@@ -2074,7 +2077,7 @@ CheckPointSnapBuild(void)
 	XLogRecPtr	redo;
 	DIR		   *snap_dir;
 	struct dirent *snap_de;
-	char		path[MAXPGPATH + 21];
+	char		path[MAXPGPATH + sizeof(PG_LOGICAL_SNAPSHOTS_DIR)];
 
 	/*
 	 * We start off with a minimum of the last redo pointer. No new
@@ -2090,8 +2093,8 @@ CheckPointSnapBuild(void)
 	if (redo < cutoff)
 		cutoff = redo;
 
-	snap_dir = AllocateDir("pg_logical/snapshots");
-	while ((snap_de = ReadDir(snap_dir, "pg_logical/snapshots")) != NULL)
+	snap_dir = AllocateDir(PG_LOGICAL_SNAPSHOTS_DIR);
+	while ((snap_de = ReadDir(snap_dir, PG_LOGICAL_SNAPSHOTS_DIR)) != NULL)
 	{
 		uint32		hi;
 		uint32		lo;
@@ -2102,7 +2105,7 @@ CheckPointSnapBuild(void)
 			strcmp(snap_de->d_name, "..") == 0)
 			continue;
 
-		snprintf(path, sizeof(path), "pg_logical/snapshots/%s", snap_de->d_name);
+		snprintf(path, sizeof(path), "%s/%s", PG_LOGICAL_SNAPSHOTS_DIR, snap_de->d_name);
 		de_type = get_dirent_type(path, snap_de, false, DEBUG1);
 
 		if (de_type != PGFILETYPE_ERROR && de_type != PGFILETYPE_REG)
@@ -2162,7 +2165,8 @@ SnapBuildSnapshotExists(XLogRecPtr lsn)
 	int			ret;
 	struct stat stat_buf;
 
-	sprintf(path, "pg_logical/snapshots/%X-%X.snap",
+	sprintf(path, "%s/%X-%X.snap",
+			PG_LOGICAL_SNAPSHOTS_DIR,
 			LSN_FORMAT_ARGS(lsn));
 
 	ret = stat(path, &stat_buf);
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
index b57254286b..9f8c044eeb 100644
--- a/src/backend/utils/adt/genfile.c
+++ b/src/backend/utils/adt/genfile.c
@@ -690,12 +690,12 @@ pg_ls_archive_statusdir(PG_FUNCTION_ARGS)
 }
 
 /*
- * Function to return the list of files in the pg_logical/snapshots directory.
+ * Function to return the list of files in the PG_LOGICAL_SNAPSHOTS_DIR directory.
  */
 Datum
 pg_ls_logicalsnapdir(PG_FUNCTION_ARGS)
 {
-	return pg_ls_dir_files(fcinfo, "pg_logical/snapshots", false);
+	return pg_ls_dir_files(fcinfo, PG_LOGICAL_SNAPSHOTS_DIR, false);
 }
 
 /*
diff --git a/src/include/replication/reorderbuffer.h b/src/include/replication/reorderbuffer.h
index bf3b8010f6..60a30763c9 100644
--- a/src/include/replication/reorderbuffer.h
+++ b/src/include/replication/reorderbuffer.h
@@ -19,6 +19,7 @@
 #include "utils/timestamp.h"
 
 #define PG_LOGICAL_MAPPINGS_DIR "pg_logical/mappings"
+#define PG_LOGICAL_SNAPSHOTS_DIR "pg_logical/snapshots"
 
 /* GUC variables */
 extern PGDLLIMPORT int logical_decoding_work_mem;
-- 
2.34.1

>From 214a015557573f25b5db7ae1bcec90ea92366fb0 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot...@gmail.com>
Date: Mon, 19 Aug 2024 09:53:03 +0000
Subject: [PATCH v2 4/5] Define PG_LOGICAL_REPLORIGIN_CHECKPOINT_DIR

Replace the places where "pg_logical/replorigin_checkpoint" is used in .c files
with a new PG_LOGICAL_REPLORIGIN_CHECKPOINT_DIR define.
---
 src/backend/replication/logical/origin.c | 6 +++---
 src/include/replication/origin.h         | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)
  67.1% src/backend/replication/logical/
  32.8% src/include/replication/

diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 419e4814f0..a4aaefa97c 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -572,8 +572,8 @@ ReplicationOriginShmemInit(void)
 void
 CheckPointReplicationOrigin(void)
 {
-	const char *tmppath = "pg_logical/replorigin_checkpoint.tmp";
-	const char *path = "pg_logical/replorigin_checkpoint";
+	const char *tmppath = PG_LOGICAL_REPLORIGIN_CHECKPOINT_TMP_DIR;
+	const char *path = PG_LOGICAL_REPLORIGIN_CHECKPOINT_DIR;
 	int			tmpfd;
 	int			i;
 	uint32		magic = REPLICATION_STATE_MAGIC;
@@ -698,7 +698,7 @@ CheckPointReplicationOrigin(void)
 void
 StartupReplicationOrigin(void)
 {
-	const char *path = "pg_logical/replorigin_checkpoint";
+	const char *path = PG_LOGICAL_REPLORIGIN_CHECKPOINT_DIR;
 	int			fd;
 	int			readBytes;
 	uint32		magic = REPLICATION_STATE_MAGIC;
diff --git a/src/include/replication/origin.h b/src/include/replication/origin.h
index 7189ba9e76..1cb44be58d 100644
--- a/src/include/replication/origin.h
+++ b/src/include/replication/origin.h
@@ -15,6 +15,9 @@
 #include "access/xlogreader.h"
 #include "catalog/pg_replication_origin.h"
 
+#define PG_LOGICAL_REPLORIGIN_CHECKPOINT_DIR "pg_logical/replorigin_checkpoint"
+#define PG_LOGICAL_REPLORIGIN_CHECKPOINT_TMP_DIR PG_LOGICAL_REPLORIGIN_CHECKPOINT_DIR ".tmp"
+
 typedef struct xl_replorigin_set
 {
 	XLogRecPtr	remote_lsn;
-- 
2.34.1

>From 46bd885f0e5ae146f7b08d08bb54747c7cee0c1c Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot...@gmail.com>
Date: Mon, 19 Aug 2024 07:40:10 +0000
Subject: [PATCH v2 5/5] Define PG_TBLSPC_DIR

Replace most of the places where "pg_tblspc" is used in .c files with a new
PG_TBLSPC_DIR define. The places where it is not done is for consistency with
the existing PG_STAT_TMP_DIR define.
---
 src/backend/access/transam/xlog.c           | 20 +++++------
 src/backend/access/transam/xlogrecovery.c   | 26 +++++++-------
 src/backend/backup/backup_manifest.c        |  3 +-
 src/backend/backup/basebackup.c             | 10 +++---
 src/backend/commands/dbcommands.c           |  6 ++--
 src/backend/commands/tablespace.c           | 14 ++++----
 src/backend/storage/file/fd.c               | 39 +++++++++++----------
 src/backend/storage/file/reinit.c           | 16 ++++-----
 src/backend/utils/adt/dbsize.c              |  8 ++---
 src/backend/utils/adt/misc.c                |  6 ++--
 src/backend/utils/cache/relcache.c          |  4 +--
 src/bin/pg_checksums/pg_checksums.c         |  8 ++---
 src/bin/pg_combinebackup/pg_combinebackup.c | 35 +++++++++---------
 src/bin/pg_rewind/file_ops.c                |  4 +--
 src/bin/pg_upgrade/exec.c                   |  2 +-
 src/common/file_utils.c                     |  9 ++---
 src/common/relpath.c                        | 20 +++++------
 src/fe_utils/astreamer_file.c               | 13 ++++---
 src/include/common/relpath.h                |  4 +++
 19 files changed, 129 insertions(+), 118 deletions(-)
  17.5% src/backend/access/transam/
   5.5% src/backend/backup/
   8.5% src/backend/commands/
  23.3% src/backend/storage/file/
   5.5% src/backend/utils/adt/
   3.5% src/bin/pg_checksums/
  14.8% src/bin/pg_combinebackup/
  10.6% src/common/
   5.3% src/fe_utils/
   4.9% src/

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index ee0fb0e28f..48718cbdf3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5558,8 +5558,8 @@ StartupXLOG(void)
 	 * in place if the database had been cleanly shut down, but it seems
 	 * safest to just remove them always and let them be rebuilt during the
 	 * first backend startup.  These files needs to be removed from all
-	 * directories including pg_tblspc, however the symlinks are created only
-	 * after reading tablespace_map file in case of archive recovery from
+	 * directories including PG_TBLSPC_DIR, however the symlinks are created
+	 * only after reading tablespace_map file in case of archive recovery from
 	 * backup, so needs to clear old relcache files here after creating
 	 * symlinks.
 	 */
@@ -8944,10 +8944,10 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
 		datadirpathlen = strlen(DataDir);
 
 		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+		tblspcdir = AllocateDir(PG_TBLSPC_DIR);
+		while ((de = ReadDir(tblspcdir, PG_TBLSPC_DIR)) != NULL)
 		{
-			char		fullpath[MAXPGPATH + 10];
+			char		fullpath[MAXPGPATH + sizeof(PG_TBLSPC_DIR)];
 			char		linkpath[MAXPGPATH];
 			char	   *relpath = NULL;
 			char	   *s;
@@ -8970,7 +8970,7 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
 			if (*badp != '\0' || errno == EINVAL || errno == ERANGE)
 				continue;
 
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+			snprintf(fullpath, sizeof(fullpath), "%s/%s", PG_TBLSPC_DIR, de->d_name);
 
 			de_type = get_dirent_type(fullpath, de, false, ERROR);
 
@@ -9025,14 +9025,14 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
 			{
 				/*
 				 * It's possible to use allow_in_place_tablespaces to create
-				 * directories directly under pg_tblspc, for testing purposes
-				 * only.
+				 * directories directly under PG_TBLSPC_DIR, for testing
+				 * purposes only.
 				 *
 				 * In this case, we store a relative path rather than an
 				 * absolute path into the tablespaceinfo.
 				 */
-				snprintf(linkpath, sizeof(linkpath), "pg_tblspc/%s",
-						 de->d_name);
+				snprintf(linkpath, sizeof(linkpath), "%s/%s",
+						 PG_TBLSPC_DIR, de->d_name);
 				relpath = pstrdup(linkpath);
 			}
 			else
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index ad817fbca6..9ae72933d7 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -677,7 +677,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 				tablespaceinfo *ti = lfirst(lc);
 				char	   *linkloc;
 
-				linkloc = psprintf("pg_tblspc/%u", ti->oid);
+				linkloc = psprintf("%s/%u", PG_TBLSPC_DIR, ti->oid);
 
 				/*
 				 * Remove the existing symlink if any and Create the symlink
@@ -2138,11 +2138,11 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
 }
 
 /*
- * Verify that, in non-test mode, ./pg_tblspc doesn't contain any real
+ * Verify that, in non-test mode, ./PG_TBLSPC_DIR doesn't contain any real
  * directories.
  *
  * Replay of database creation XLOG records for databases that were later
- * dropped can create fake directories in pg_tblspc.  By the time consistency
+ * dropped can create fake directories in PG_TBLSPC_DIR.  By the time consistency
  * is reached these directories should have been removed; here we verify
  * that this did indeed happen.  This is to be called at the point where
  * consistent state is reached.
@@ -2157,23 +2157,23 @@ CheckTablespaceDirectory(void)
 	DIR		   *dir;
 	struct dirent *de;
 
-	dir = AllocateDir("pg_tblspc");
-	while ((de = ReadDir(dir, "pg_tblspc")) != NULL)
+	dir = AllocateDir(PG_TBLSPC_DIR);
+	while ((de = ReadDir(dir, PG_TBLSPC_DIR)) != NULL)
 	{
-		char		path[MAXPGPATH + 10];
+		char		path[MAXPGPATH + sizeof(PG_TBLSPC_DIR)];
 
 		/* Skip entries of non-oid names */
 		if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
 			continue;
 
-		snprintf(path, sizeof(path), "pg_tblspc/%s", de->d_name);
+		snprintf(path, sizeof(path), "%s/%s", PG_TBLSPC_DIR, de->d_name);
 
 		if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
 			ereport(allow_in_place_tablespaces ? WARNING : PANIC,
 					(errcode(ERRCODE_DATA_CORRUPTED),
 					 errmsg("unexpected directory entry \"%s\" found in %s",
-							de->d_name, "pg_tblspc/"),
-					 errdetail("All directory entries in pg_tblspc/ should be symbolic links."),
+							de->d_name, PG_TBLSPC_DIR),
+					 errdetail("All directory entries in %s/ should be symbolic links.", PG_TBLSPC_DIR),
 					 errhint("Remove those directories, or set \"allow_in_place_tablespaces\" to ON transiently to let recovery complete.")));
 	}
 }
@@ -2247,10 +2247,10 @@ CheckRecoveryConsistency(void)
 		XLogCheckInvalidPages();
 
 		/*
-		 * Check that pg_tblspc doesn't contain any real directories. Replay
-		 * of Database/CREATE_* records may have created fictitious tablespace
-		 * directories that should have been removed by the time consistency
-		 * was reached.
+		 * Check that PG_TBLSPC_DIR doesn't contain any real directories.
+		 * Replay of Database/CREATE_* records may have created fictitious
+		 * tablespace directories that should have been removed by the time
+		 * consistency was reached.
 		 */
 		CheckTablespaceDirectory();
 
diff --git a/src/backend/backup/backup_manifest.c b/src/backend/backup/backup_manifest.c
index 4357cfa31d..a2e2f86332 100644
--- a/src/backend/backup/backup_manifest.c
+++ b/src/backend/backup/backup_manifest.c
@@ -16,6 +16,7 @@
 #include "access/xlog.h"
 #include "backup/backup_manifest.h"
 #include "backup/basebackup_sink.h"
+#include "common/relpath.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/json.h"
@@ -117,7 +118,7 @@ AddFileToBackupManifest(backup_manifest_info *manifest, Oid spcoid,
 	 */
 	if (OidIsValid(spcoid))
 	{
-		snprintf(pathbuf, sizeof(pathbuf), "pg_tblspc/%u/%s", spcoid,
+		snprintf(pathbuf, sizeof(pathbuf), "%s/%u/%s", PG_TBLSPC_DIR, spcoid,
 				 pathname);
 		pathname = pathbuf;
 	}
diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index de16afac74..9612fe33ce 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -1405,8 +1405,8 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
 			continue;			/* don't recurse into pg_wal */
 		}
 
-		/* Allow symbolic links in pg_tblspc only */
-		if (strcmp(path, "./pg_tblspc") == 0 && S_ISLNK(statbuf.st_mode))
+		/* Allow symbolic links in PG_TBLSPC_DIR only */
+		if (strcmp(path, RELATIVE_PG_TBLSPC_DIR) == 0 && S_ISLNK(statbuf.st_mode))
 		{
 			char		linkpath[MAXPGPATH];
 			int			rllen;
@@ -1462,9 +1462,9 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
 			}
 
 			/*
-			 * skip sending directories inside pg_tblspc, if not required.
+			 * skip sending directories inside PG_TBLSPC_DIR, if not required.
 			 */
-			if (strcmp(pathbuf, "./pg_tblspc") == 0 && !sendtblspclinks)
+			if (strcmp(pathbuf, RELATIVE_PG_TBLSPC_DIR) == 0 && !sendtblspclinks)
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
@@ -1488,7 +1488,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
 				if (OidIsValid(spcoid))
 				{
 					relspcoid = spcoid;
-					lookup_path = psprintf("pg_tblspc/%u/%s", spcoid,
+					lookup_path = psprintf("%s/%u/%s", PG_TBLSPC_DIR, spcoid,
 										   tarfilename);
 				}
 				else
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index d00ae40e19..01585232a3 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -3243,9 +3243,9 @@ database_is_invalid_oid(Oid dboid)
  * removed before the server stopped.  Since we expect that the directory will
  * be gone before reaching recovery consistency, and we have no knowledge about
  * the tablespace other than its OID here, we create a real directory under
- * pg_tblspc here instead of restoring the symlink.
+ * PG_TBLSPC_DIR here instead of restoring the symlink.
  *
- * If only_tblspc is true, then the requested directory must be in pg_tblspc/
+ * If only_tblspc is true, then the requested directory must be in PG_TBLSPC_DIR/
  */
 static void
 recovery_create_dbdir(char *path, bool only_tblspc)
@@ -3257,7 +3257,7 @@ recovery_create_dbdir(char *path, bool only_tblspc)
 	if (stat(path, &st) == 0)
 		return;
 
-	if (only_tblspc && strstr(path, "pg_tblspc/") == NULL)
+	if (only_tblspc && strstr(path, PG_TBLSPC_DIR_SLASH) == NULL)
 		elog(PANIC, "requested to created invalid directory: %s", path);
 
 	if (reachedConsistency && !allow_in_place_tablespaces)
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 113b480731..9b8f02a995 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -13,13 +13,13 @@
  * files within a tablespace into database-specific subdirectories.
  *
  * To support file access via the information given in RelFileLocator, we
- * maintain a symbolic-link map in $PGDATA/pg_tblspc. The symlinks are
+ * maintain a symbolic-link map in $PGDATA/PG_TBLSPC_DIR. The symlinks are
  * named by tablespace OIDs and point to the actual tablespace directories.
  * There is also a per-cluster version directory in each tablespace.
  * Thus the full path to an arbitrary file is
- *			$PGDATA/pg_tblspc/spcoid/PG_MAJORVER_CATVER/dboid/relfilenumber
+ *			$PGDATA/PG_TBLSPC_DIR/spcoid/PG_MAJORVER_CATVER/dboid/relfilenumber
  * e.g.
- *			$PGDATA/pg_tblspc/20981/PG_9.0_201002161/719849/83292814
+ *			$PGDATA/PG_TBLSPC_DIR/20981/PG_9.0_201002161/719849/83292814
  *
  * There are two tablespaces created at initdb time: pg_global (for shared
  * tables) and pg_default (for everything else).  For backwards compatibility
@@ -565,7 +565,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 /*
  * create_tablespace_directories
  *
- *	Attempt to create filesystem infrastructure linking $PGDATA/pg_tblspc/
+ *	Attempt to create filesystem infrastructure linking $PGDATA/PG_TBLSPC_DIR/
  *	to the specified directory
  */
 static void
@@ -576,7 +576,7 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
 	struct stat st;
 	bool		in_place;
 
-	linkloc = psprintf("pg_tblspc/%u", tablespaceoid);
+	linkloc = psprintf("%s/%u", PG_TBLSPC_DIR, tablespaceoid);
 
 	/*
 	 * If we're asked to make an 'in place' tablespace, create the directory
@@ -692,7 +692,7 @@ destroy_tablespace_directories(Oid tablespaceoid, bool redo)
 	char	   *subfile;
 	struct stat st;
 
-	linkloc_with_version_dir = psprintf("pg_tblspc/%u/%s", tablespaceoid,
+	linkloc_with_version_dir = psprintf("%s/%u/%s", PG_TBLSPC_DIR, tablespaceoid,
 										TABLESPACE_VERSION_DIRECTORY);
 
 	/*
@@ -873,7 +873,7 @@ directory_is_empty(const char *path)
 /*
  *	remove_tablespace_symlink
  *
- * This function removes symlinks in pg_tblspc.  On Windows, junction points
+ * This function removes symlinks in PG_TBLSPC_DIR.  On Windows, junction points
  * act like directories so we must be able to apply rmdir.  This function
  * works like the symlink removal code in destroy_tablespace_directories,
  * except that failure to remove is always an ERROR.  But if the file doesn't
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 3944321ff3..bf309ba611 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1790,8 +1790,8 @@ TempTablespacePath(char *path, Oid tablespace)
 	else
 	{
 		/* All other tablespaces are accessed via symlinks */
-		snprintf(path, MAXPGPATH, "pg_tblspc/%u/%s/%s",
-				 tablespace, TABLESPACE_VERSION_DIRECTORY,
+		snprintf(path, MAXPGPATH, "%s/%u/%s/%s",
+				 PG_TBLSPC_DIR, tablespace, TABLESPACE_VERSION_DIRECTORY,
 				 PG_TEMP_FILES_DIR);
 	}
 }
@@ -3273,7 +3273,7 @@ CleanupTempFiles(bool isCommit, bool isProcExit)
 void
 RemovePgTempFiles(void)
 {
-	char		temp_path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY) + sizeof(PG_TEMP_FILES_DIR)];
+	char		temp_path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY) + sizeof(PG_TEMP_FILES_DIR)];
 	DIR		   *spc_dir;
 	struct dirent *spc_de;
 
@@ -3287,20 +3287,21 @@ RemovePgTempFiles(void)
 	/*
 	 * Cycle through temp directories for all non-default tablespaces.
 	 */
-	spc_dir = AllocateDir("pg_tblspc");
+	spc_dir = AllocateDir(PG_TBLSPC_DIR);
 
-	while ((spc_de = ReadDirExtended(spc_dir, "pg_tblspc", LOG)) != NULL)
+	while ((spc_de = ReadDirExtended(spc_dir, PG_TBLSPC_DIR, LOG)) != NULL)
 	{
 		if (strcmp(spc_de->d_name, ".") == 0 ||
 			strcmp(spc_de->d_name, "..") == 0)
 			continue;
 
-		snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s/%s",
-				 spc_de->d_name, TABLESPACE_VERSION_DIRECTORY, PG_TEMP_FILES_DIR);
+		snprintf(temp_path, sizeof(temp_path), "%s/%s/%s/%s",
+				 PG_TBLSPC_DIR, spc_de->d_name, TABLESPACE_VERSION_DIRECTORY,
+				 PG_TEMP_FILES_DIR);
 		RemovePgTempFilesInDir(temp_path, true, false);
 
-		snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s",
-				 spc_de->d_name, TABLESPACE_VERSION_DIRECTORY);
+		snprintf(temp_path, sizeof(temp_path), "%s/%s/%s",
+				 PG_TBLSPC_DIR, spc_de->d_name, TABLESPACE_VERSION_DIRECTORY);
 		RemovePgTempRelationFiles(temp_path);
 	}
 
@@ -3523,7 +3524,7 @@ do_syncfs(const char *path)
  * all potential filesystem, depending on recovery_init_sync_method setting.
  *
  * We fsync regular files and directories wherever they are, but we
- * follow symlinks only for pg_wal and immediately under pg_tblspc.
+ * follow symlinks only for pg_wal and immediately under PG_TBLSPC_DIR.
  * Other symlinks are presumed to point at files we're not responsible
  * for fsyncing, and might not have privileges to write at all.
  *
@@ -3587,15 +3588,15 @@ SyncDataDirectory(void)
 		/* Sync the top level pgdata directory. */
 		do_syncfs(".");
 		/* If any tablespaces are configured, sync each of those. */
-		dir = AllocateDir("pg_tblspc");
-		while ((de = ReadDirExtended(dir, "pg_tblspc", LOG)))
+		dir = AllocateDir(PG_TBLSPC_DIR);
+		while ((de = ReadDirExtended(dir, PG_TBLSPC_DIR, LOG)))
 		{
 			char		path[MAXPGPATH];
 
 			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
 				continue;
 
-			snprintf(path, MAXPGPATH, "pg_tblspc/%s", de->d_name);
+			snprintf(path, MAXPGPATH, "%s/%s", PG_TBLSPC_DIR, de->d_name);
 			do_syncfs(path);
 		}
 		FreeDir(dir);
@@ -3618,7 +3619,7 @@ SyncDataDirectory(void)
 	walkdir(".", pre_sync_fname, false, DEBUG1);
 	if (xlog_is_symlink)
 		walkdir("pg_wal", pre_sync_fname, false, DEBUG1);
-	walkdir("pg_tblspc", pre_sync_fname, true, DEBUG1);
+	walkdir(PG_TBLSPC_DIR, pre_sync_fname, true, DEBUG1);
 #endif
 
 	/* Prepare to report progress syncing the data directory via fsync. */
@@ -3628,15 +3629,15 @@ SyncDataDirectory(void)
 	 * Now we do the fsync()s in the same order.
 	 *
 	 * The main call ignores symlinks, so in addition to specially processing
-	 * pg_wal if it's a symlink, pg_tblspc has to be visited separately with
-	 * process_symlinks = true.  Note that if there are any plain directories
-	 * in pg_tblspc, they'll get fsync'd twice.  That's not an expected case
-	 * so we don't worry about optimizing it.
+	 * pg_wal if it's a symlink, PG_TBLSPC_DIR has to be visited separately
+	 * with process_symlinks = true.  Note that if there are any plain
+	 * directories in PG_TBLSPC_DIR, they'll get fsync'd twice.  That's not an
+	 * expected case so we don't worry about optimizing it.
 	 */
 	walkdir(".", datadir_fsync_fname, false, LOG);
 	if (xlog_is_symlink)
 		walkdir("pg_wal", datadir_fsync_fname, false, LOG);
-	walkdir("pg_tblspc", datadir_fsync_fname, true, LOG);
+	walkdir(PG_TBLSPC_DIR, datadir_fsync_fname, true, LOG);
 }
 
 /*
diff --git a/src/backend/storage/file/reinit.c b/src/backend/storage/file/reinit.c
index f1cd1a38d9..ee63c4e4e5 100644
--- a/src/backend/storage/file/reinit.c
+++ b/src/backend/storage/file/reinit.c
@@ -46,7 +46,7 @@ typedef struct
 void
 ResetUnloggedRelations(int op)
 {
-	char		temp_path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
+	char		temp_path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
 	DIR		   *spc_dir;
 	struct dirent *spc_de;
 	MemoryContext tmpctx,
@@ -77,16 +77,16 @@ ResetUnloggedRelations(int op)
 	/*
 	 * Cycle through directories for all non-default tablespaces.
 	 */
-	spc_dir = AllocateDir("pg_tblspc");
+	spc_dir = AllocateDir(PG_TBLSPC_DIR);
 
-	while ((spc_de = ReadDir(spc_dir, "pg_tblspc")) != NULL)
+	while ((spc_de = ReadDir(spc_dir, PG_TBLSPC_DIR)) != NULL)
 	{
 		if (strcmp(spc_de->d_name, ".") == 0 ||
 			strcmp(spc_de->d_name, "..") == 0)
 			continue;
 
-		snprintf(temp_path, sizeof(temp_path), "pg_tblspc/%s/%s",
-				 spc_de->d_name, TABLESPACE_VERSION_DIRECTORY);
+		snprintf(temp_path, sizeof(temp_path), "%s/%s/%s",
+				 PG_TBLSPC_DIR, spc_de->d_name, TABLESPACE_VERSION_DIRECTORY);
 		ResetUnloggedRelationsInTablespaceDir(temp_path, op);
 	}
 
@@ -114,9 +114,9 @@ ResetUnloggedRelationsInTablespaceDir(const char *tsdirname, int op)
 	/*
 	 * If we get ENOENT on a tablespace directory, log it and return.  This
 	 * can happen if a previous DROP TABLESPACE crashed between removing the
-	 * tablespace directory and removing the symlink in pg_tblspc.  We don't
-	 * really want to prevent database startup in that scenario, so let it
-	 * pass instead.  Any other type of error will be reported by ReadDir
+	 * tablespace directory and removing the symlink in PG_TBLSPC_DIR.  We
+	 * don't really want to prevent database startup in that scenario, so let
+	 * it pass instead.  Any other type of error will be reported by ReadDir
 	 * (causing a startup failure).
 	 */
 	if (ts_dir == NULL && errno == ENOENT)
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index b2d9cc2792..e63e99c141 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -143,7 +143,7 @@ calculate_database_size(Oid dbOid)
 	totalsize = db_dir_size(pathname);
 
 	/* Scan the non-default tablespaces */
-	snprintf(dirpath, MAXPGPATH, "pg_tblspc");
+	snprintf(dirpath, MAXPGPATH, PG_TBLSPC_DIR);
 	dirdesc = AllocateDir(dirpath);
 
 	while ((direntry = ReadDir(dirdesc, dirpath)) != NULL)
@@ -154,8 +154,8 @@ calculate_database_size(Oid dbOid)
 			strcmp(direntry->d_name, "..") == 0)
 			continue;
 
-		snprintf(pathname, sizeof(pathname), "pg_tblspc/%s/%s/%u",
-				 direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid);
+		snprintf(pathname, sizeof(pathname), "%s/%s/%s/%u",
+				 PG_TBLSPC_DIR, direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid);
 		totalsize += db_dir_size(pathname);
 	}
 
@@ -227,7 +227,7 @@ calculate_tablespace_size(Oid tblspcOid)
 	else if (tblspcOid == GLOBALTABLESPACE_OID)
 		snprintf(tblspcPath, MAXPGPATH, "global");
 	else
-		snprintf(tblspcPath, MAXPGPATH, "pg_tblspc/%u/%s", tblspcOid,
+		snprintf(tblspcPath, MAXPGPATH, "%s/%u/%s", PG_TBLSPC_DIR, tblspcOid,
 				 TABLESPACE_VERSION_DIRECTORY);
 
 	dirdesc = AllocateDir(tblspcPath);
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 0e6c45807a..af6123d2f6 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -242,7 +242,7 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
 	if (tablespaceOid == DEFAULTTABLESPACE_OID)
 		location = "base";
 	else
-		location = psprintf("pg_tblspc/%u/%s", tablespaceOid,
+		location = psprintf("%s/%u/%s", PG_TBLSPC_DIR, tablespaceOid,
 							TABLESPACE_VERSION_DIRECTORY);
 
 	dirdesc = AllocateDir(location);
@@ -323,9 +323,9 @@ pg_tablespace_location(PG_FUNCTION_ARGS)
 
 	/*
 	 * Find the location of the tablespace by reading the symbolic link that
-	 * is in pg_tblspc/<oid>.
+	 * is in PG_TBLSPC_DIR/<oid>.
 	 */
-	snprintf(sourcepath, sizeof(sourcepath), "pg_tblspc/%u", tablespaceOid);
+	snprintf(sourcepath, sizeof(sourcepath), "%s/%u", PG_TBLSPC_DIR, tablespaceOid);
 
 	/*
 	 * Before reading the link, check if the source path is a link or a
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 66ed24e401..63efc55f09 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -6800,10 +6800,10 @@ RelationCacheInitFilePostInvalidate(void)
 void
 RelationCacheInitFileRemove(void)
 {
-	const char *tblspcdir = "pg_tblspc";
+	const char *tblspcdir = PG_TBLSPC_DIR;
 	DIR		   *dir;
 	struct dirent *de;
-	char		path[MAXPGPATH + 10 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
+	char		path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
 
 	snprintf(path, sizeof(path), "global/%s",
 			 RELCACHE_INIT_FILENAME);
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index b5bb0e7887..ea2c2346ca 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -383,12 +383,12 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly)
 		else if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
 		{
 			/*
-			 * If going through the entries of pg_tblspc, we assume to operate
+			 * If going through the entries of PG_TBLSPC_DIR, we assume to operate
 			 * on tablespace locations where only TABLESPACE_VERSION_DIRECTORY
 			 * is valid, resolving the linked locations and dive into them
 			 * directly.
 			 */
-			if (strncmp("pg_tblspc", subdir, strlen("pg_tblspc")) == 0)
+			if (strncmp(PG_TBLSPC_DIR, subdir, strlen(PG_TBLSPC_DIR)) == 0)
 			{
 				char		tblspc_path[MAXPGPATH];
 				struct stat tblspc_st;
@@ -593,12 +593,12 @@ main(int argc, char *argv[])
 		{
 			total_size = scan_directory(DataDir, "global", true);
 			total_size += scan_directory(DataDir, "base", true);
-			total_size += scan_directory(DataDir, "pg_tblspc", true);
+			total_size += scan_directory(DataDir, PG_TBLSPC_DIR, true);
 		}
 
 		(void) scan_directory(DataDir, "global", false);
 		(void) scan_directory(DataDir, "base", false);
-		(void) scan_directory(DataDir, "pg_tblspc", false);
+		(void) scan_directory(DataDir, PG_TBLSPC_DIR, false);
 
 		if (showprogress)
 			progress_report(true);
diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c
index 9ded5a2140..307a8c7fc1 100644
--- a/src/bin/pg_combinebackup/pg_combinebackup.c
+++ b/src/bin/pg_combinebackup/pg_combinebackup.c
@@ -318,7 +318,7 @@ main(int argc, char *argv[])
 	 * for those directories to be cleaned up on failure. In-place tablespaces
 	 * aren't handled at this stage because they're located beneath the main
 	 * output directory, and thus the cleanup of that directory will get rid
-	 * of them. Plus, the pg_tblspc directory that needs to contain them
+	 * of them. Plus, the PG_TBLSPC_DIR directory that needs to contain them
 	 * doesn't exist yet.
 	 */
 	atexit(cleanup_directories_atexit);
@@ -366,14 +366,14 @@ main(int argc, char *argv[])
 
 		/*
 		 * If it's a normal tablespace, we need to set up a symbolic link from
-		 * pg_tblspc/${OID} to the target directory; if it's an in-place
-		 * tablespace, we need to create a directory at pg_tblspc/${OID}.
+		 * PG_TBLSPC_DIR/${OID} to the target directory; if it's an in-place
+		 * tablespace, we need to create a directory at PG_TBLSPC_DIR/${OID}.
 		 */
 		if (!ts->in_place)
 		{
 			char		linkpath[MAXPGPATH];
 
-			snprintf(linkpath, MAXPGPATH, "%s/pg_tblspc/%u", opt.output,
+			snprintf(linkpath, MAXPGPATH, "%s/%s/%u", opt.output, PG_TBLSPC_DIR,
 					 ts->oid);
 
 			if (opt.dry_run)
@@ -844,8 +844,9 @@ process_directory_recursively(Oid tsoid,
 	/*
 	 * Classify this directory.
 	 *
-	 * We set is_pg_tblspc only for the toplevel pg_tblspc directory, because
-	 * the symlinks in that specific directory require special handling.
+	 * We set is_pg_tblspc only for the toplevel PG_TBLSPC_DIR directory,
+	 * because the symlinks in that specific directory require special
+	 * handling.
 	 *
 	 * We set is_pg_wal for the toplevel WAL directory and all of its
 	 * subdirectories, because those files are not included in the backup
@@ -860,19 +861,19 @@ process_directory_recursively(Oid tsoid,
 	 * strange name like INCREMENTAL.config and then complaining that
 	 * incremental backups don't work properly. The test here is a bit tricky:
 	 * incremental files occur in subdirectories of base, in pg_global itself,
-	 * and in subdirectories of pg_tblspc only if in-place tablespaces are
+	 * and in subdirectories of PG_TBLSPC_DIR only if in-place tablespaces are
 	 * used.
 	 */
 	if (OidIsValid(tsoid))
 		is_incremental_dir = true;
 	else if (relative_path != NULL)
 	{
-		is_pg_tblspc = strcmp(relative_path, "pg_tblspc") == 0;
+		is_pg_tblspc = strcmp(relative_path, PG_TBLSPC_DIR) == 0;
 		is_pg_wal = (strcmp(relative_path, "pg_wal") == 0 ||
 					 strncmp(relative_path, "pg_wal/", 7) == 0);
 		is_incremental_dir = strncmp(relative_path, "base/", 5) == 0 ||
 			strcmp(relative_path, "global") == 0 ||
-			strncmp(relative_path, "pg_tblspc/", 10) == 0;
+			strncmp(relative_path, PG_TBLSPC_DIR_SLASH, 10) == 0;
 	}
 
 	/*
@@ -895,7 +896,7 @@ process_directory_recursively(Oid tsoid,
 		strlcpy(ifulldir, input_directory, MAXPGPATH);
 		strlcpy(ofulldir, output_directory, MAXPGPATH);
 		if (OidIsValid(tsoid))
-			snprintf(manifest_prefix, MAXPGPATH, "pg_tblspc/%u/", tsoid);
+			snprintf(manifest_prefix, MAXPGPATH, "%s/%u/", PG_TBLSPC_DIR, tsoid);
 		else
 			manifest_prefix[0] = '\0';
 	}
@@ -906,8 +907,8 @@ process_directory_recursively(Oid tsoid,
 		snprintf(ofulldir, MAXPGPATH, "%s/%s", output_directory,
 				 relative_path);
 		if (OidIsValid(tsoid))
-			snprintf(manifest_prefix, MAXPGPATH, "pg_tblspc/%u/%s/",
-					 tsoid, relative_path);
+			snprintf(manifest_prefix, MAXPGPATH, "%s/%u/%s/",
+					 PG_TBLSPC_DIR, tsoid, relative_path);
 		else
 			snprintf(manifest_prefix, MAXPGPATH, "%s/", relative_path);
 	}
@@ -956,7 +957,7 @@ process_directory_recursively(Oid tsoid,
 			exit(1);
 
 		/*
-		 * If we're processing pg_tblspc, then check whether the filename
+		 * If we're processing PG_TBLSPC_DIR, then check whether the filename
 		 * looks like it could be a tablespace OID. If so, and if the
 		 * directory entry is a symbolic link or a directory, skip it.
 		 *
@@ -1235,7 +1236,7 @@ reset_directory_cleanup_list(void)
 }
 
 /*
- * Scan the pg_tblspc directory of the final input backup to get a canonical
+ * Scan the PG_TBLSPC_DIR directory of the final input backup to get a canonical
  * list of what tablespaces are part of the backup.
  *
  * 'pathname' should be the path to the toplevel backup directory for the
@@ -1249,7 +1250,7 @@ scan_for_existing_tablespaces(char *pathname, cb_options *opt)
 	struct dirent *de;
 	cb_tablespace *tslist = NULL;
 
-	snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pathname);
+	snprintf(pg_tblspc, MAXPGPATH, "%s/%s", pathname, PG_TBLSPC_DIR);
 	pg_log_debug("scanning \"%s\"", pg_tblspc);
 
 	if ((dir = opendir(pg_tblspc)) == NULL)
@@ -1344,8 +1345,8 @@ scan_for_existing_tablespaces(char *pathname, cb_options *opt)
 			 * we just record the paths within the data directories.
 			 */
 			snprintf(ts->old_dir, MAXPGPATH, "%s/%s", pg_tblspc, de->d_name);
-			snprintf(ts->new_dir, MAXPGPATH, "%s/pg_tblspc/%s", opt->output,
-					 de->d_name);
+			snprintf(ts->new_dir, MAXPGPATH, "%s/%s/%s", opt->output,
+					 PG_TBLSPC_DIR, de->d_name);
 			ts->in_place = true;
 		}
 
diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c
index d93580bb41..762b60d3ab 100644
--- a/src/bin/pg_rewind/file_ops.c
+++ b/src/bin/pg_rewind/file_ops.c
@@ -448,11 +448,11 @@ recurse_dir(const char *datadir, const char *parentpath,
 			callback(path, FILE_TYPE_SYMLINK, 0, link_target);
 
 			/*
-			 * If it's a symlink within pg_tblspc, we need to recurse into it,
+			 * If it's a symlink within PG_TBLSPC_DIR, we need to recurse into it,
 			 * to process all the tablespaces.  We also follow a symlink if
 			 * it's for pg_wal.  Symlinks elsewhere are ignored.
 			 */
-			if ((parentpath && strcmp(parentpath, "pg_tblspc") == 0) ||
+			if ((parentpath && strcmp(parentpath, PG_TBLSPC_DIR) == 0) ||
 				strcmp(path, "pg_wal") == 0)
 				recurse_dir(datadir, path, callback);
 		}
diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c
index 058530ab3e..78db321ace 100644
--- a/src/bin/pg_upgrade/exec.c
+++ b/src/bin/pg_upgrade/exec.c
@@ -350,7 +350,7 @@ check_data_dir(ClusterInfo *cluster)
 	check_single_dir(pg_data, "global");
 	check_single_dir(pg_data, "pg_multixact");
 	check_single_dir(pg_data, "pg_subtrans");
-	check_single_dir(pg_data, "pg_tblspc");
+	check_single_dir(pg_data, PG_TBLSPC_DIR);
 	check_single_dir(pg_data, "pg_twophase");
 
 	/* pg_xlog has been renamed to pg_wal in v10 */
diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index 6bac537a1e..c045831bbc 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 
 #include "common/file_utils.h"
+#include "common/relpath.h"
 #ifdef FRONTEND
 #include "common/logging.h"
 #endif
@@ -87,7 +88,7 @@ do_syncfs(const char *path)
  * Synchronize PGDATA and all its contents.
  *
  * We sync regular files and directories wherever they are, but we follow
- * symlinks only for pg_wal (or pg_xlog) and immediately under pg_tblspc.
+ * symlinks only for pg_wal (or pg_xlog) and immediately under PG_TBLSPC_DIR.
  * Other symlinks are presumed to point at files we're not responsible for
  * syncing, and might not have privileges to write at all.
  *
@@ -105,7 +106,7 @@ sync_pgdata(const char *pg_data,
 	/* handle renaming of pg_xlog to pg_wal in post-10 clusters */
 	snprintf(pg_wal, MAXPGPATH, "%s/%s", pg_data,
 			 serverVersion < MINIMUM_VERSION_FOR_PG_WAL ? "pg_xlog" : "pg_wal");
-	snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pg_data);
+	snprintf(pg_tblspc, MAXPGPATH, "%s/%s", pg_data, PG_TBLSPC_DIR);
 
 	/*
 	 * If pg_wal is a symlink, we'll need to recurse into it separately,
@@ -196,9 +197,9 @@ sync_pgdata(const char *pg_data,
 				 * Now we do the fsync()s in the same order.
 				 *
 				 * The main call ignores symlinks, so in addition to specially
-				 * processing pg_wal if it's a symlink, pg_tblspc has to be
+				 * processing pg_wal if it's a symlink, PG_TBLSPC_DIR has to be
 				 * visited separately with process_symlinks = true.  Note that
-				 * if there are any plain directories in pg_tblspc, they'll
+				 * if there are any plain directories in PG_TBLSPC_DIR, they'll
 				 * get fsync'd twice. That's not an expected case so we don't
 				 * worry about optimizing it.
 				 */
diff --git a/src/common/relpath.c b/src/common/relpath.c
index f54c36ef7a..426a0114f8 100644
--- a/src/common/relpath.c
+++ b/src/common/relpath.c
@@ -123,8 +123,8 @@ GetDatabasePath(Oid dbOid, Oid spcOid)
 	else
 	{
 		/* All other tablespaces are accessed via symlinks */
-		return psprintf("pg_tblspc/%u/%s/%u",
-						spcOid, TABLESPACE_VERSION_DIRECTORY, dbOid);
+		return psprintf("%s/%u/%s/%u",
+						PG_TBLSPC_DIR, spcOid, TABLESPACE_VERSION_DIRECTORY, dbOid);
 	}
 }
 
@@ -184,25 +184,25 @@ GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
 		if (procNumber == INVALID_PROC_NUMBER)
 		{
 			if (forkNumber != MAIN_FORKNUM)
-				path = psprintf("pg_tblspc/%u/%s/%u/%u_%s",
-								spcOid, TABLESPACE_VERSION_DIRECTORY,
+				path = psprintf("%s/%u/%s/%u/%u_%s",
+								PG_TBLSPC_DIR, spcOid, TABLESPACE_VERSION_DIRECTORY,
 								dbOid, relNumber,
 								forkNames[forkNumber]);
 			else
-				path = psprintf("pg_tblspc/%u/%s/%u/%u",
-								spcOid, TABLESPACE_VERSION_DIRECTORY,
+				path = psprintf("%s/%u/%s/%u/%u",
+								PG_TBLSPC_DIR, spcOid, TABLESPACE_VERSION_DIRECTORY,
 								dbOid, relNumber);
 		}
 		else
 		{
 			if (forkNumber != MAIN_FORKNUM)
-				path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u_%s",
-								spcOid, TABLESPACE_VERSION_DIRECTORY,
+				path = psprintf("%s/%u/%s/%u/t%d_%u_%s",
+								PG_TBLSPC_DIR, spcOid, TABLESPACE_VERSION_DIRECTORY,
 								dbOid, procNumber, relNumber,
 								forkNames[forkNumber]);
 			else
-				path = psprintf("pg_tblspc/%u/%s/%u/t%d_%u",
-								spcOid, TABLESPACE_VERSION_DIRECTORY,
+				path = psprintf("%s/%u/%s/%u/t%d_%u",
+								PG_TBLSPC_DIR, spcOid, TABLESPACE_VERSION_DIRECTORY,
 								dbOid, procNumber, relNumber);
 		}
 	}
diff --git a/src/fe_utils/astreamer_file.c b/src/fe_utils/astreamer_file.c
index c9a030853b..9824009873 100644
--- a/src/fe_utils/astreamer_file.c
+++ b/src/fe_utils/astreamer_file.c
@@ -19,6 +19,7 @@
 
 #include "common/file_perm.h"
 #include "common/logging.h"
+#include "common/relpath.h"
 #include "common/string.h"
 #include "fe_utils/astreamer.h"
 
@@ -289,29 +290,31 @@ astreamer_extractor_content(astreamer *streamer, astreamer_member *member,
  * link before starting the actual backup.  So just ignore creation failures
  * on related directories.
  *
- * If in-place tablespaces are used, pg_tblspc and subdirectories may already
+ * If in-place tablespaces are used, PG_TBLSPC_DIR and subdirectories may already
  * exist when we get here. So tolerate that case, too.
  */
 static bool
 should_allow_existing_directory(const char *pathname)
 {
+#define PG_TBLSPC_DIR_CONCAT "/" PG_TBLSPC_DIR "/"
 	const char *filename = last_dir_separator(pathname) + 1;
 
 	if (strcmp(filename, "pg_wal") == 0 ||
 		strcmp(filename, "pg_xlog") == 0 ||
 		strcmp(filename, "archive_status") == 0 ||
 		strcmp(filename, "summaries") == 0 ||
-		strcmp(filename, "pg_tblspc") == 0)
+		strcmp(filename, PG_TBLSPC_DIR) == 0)
 		return true;
 
 	if (strspn(filename, "0123456789") == strlen(filename))
 	{
-		const char *pg_tblspc = strstr(pathname, "/pg_tblspc/");
+		const char *pg_tblspc = strstr(pathname, PG_TBLSPC_DIR_CONCAT);
 
 		return pg_tblspc != NULL && pg_tblspc + 11 == filename;
 	}
 
 	return false;
+#undef PG_TBLSPC_DIR_CONCAT
 }
 
 /*
@@ -335,10 +338,10 @@ extract_directory(const char *filename, mode_t mode)
 /*
  * Create a symbolic link.
  *
- * It's most likely a link in pg_tblspc directory, to the location of a
+ * It's most likely a link in PG_TBLSPC_DIR directory, to the location of a
  * tablespace. Apply any tablespace mapping given on the command line
  * (--tablespace-mapping). (We blindly apply the mapping without checking that
- * the link really is inside pg_tblspc. We don't expect there to be other
+ * the link really is inside PG_TBLSPC_DIR. We don't expect there to be other
  * symlinks in a data directory, but if there are, you can call it an
  * undocumented feature that you can map them too.)
  */
diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h
index 6f006d5a93..a6cb091635 100644
--- a/src/include/common/relpath.h
+++ b/src/include/common/relpath.h
@@ -33,6 +33,10 @@ typedef Oid RelFileNumber;
 #define TABLESPACE_VERSION_DIRECTORY	"PG_" PG_MAJORVERSION "_" \
 									CppAsString2(CATALOG_VERSION_NO)
 
+#define PG_TBLSPC_DIR "pg_tblspc"
+#define RELATIVE_PG_TBLSPC_DIR "./" PG_TBLSPC_DIR
+#define PG_TBLSPC_DIR_SLASH PG_TBLSPC_DIR "/"
+
 /* Characters to allow for an OID in a relation path */
 #define OIDCHARS		10		/* max chars printed by %u */
 
-- 
2.34.1

Reply via email to