agora inbox for pgsql-hackers@postgresql.org
help / color / mirror / Atom feedFrom: Andres Freund <andres@anarazel.de>
Subject: [PATCH v1] relpath-by-value
Date: Tue, 18 Feb 2025 20:39:11 -0500
---
src/include/common/relpath.h | 40 +++++
src/common/relpath.c | 162 +++++++++++--------
src/backend/storage/buffer/bufmgr.c | 39 ++---
src/test/regress/expected/misc_functions.out | 13 ++
src/test/regress/regress.c | 14 ++
src/test/regress/sql/misc_functions.sql | 10 ++
src/tools/pgindent/typedefs.list | 1 +
7 files changed, 183 insertions(+), 96 deletions(-)
diff --git a/src/include/common/relpath.h b/src/include/common/relpath.h
index 5162362e7d8..9e06ecceba5 100644
--- a/src/include/common/relpath.h
+++ b/src/include/common/relpath.h
@@ -77,11 +77,51 @@ extern PGDLLIMPORT const char *const forkNames[];
extern ForkNumber forkname_to_number(const char *forkName);
extern int forkname_chars(const char *str, ForkNumber *fork);
+/*
+ * The longest possible relation path lengths is from the following format:
+ * sprintf(rp.path, "%s/%u/%s/%u/t%d_%u",
+ * PG_TBLSPC_DIR, spcOid,
+ * TABLESPACE_VERSION_DIRECTORY,
+ * dbOid, procNumber, relNumber);
+ */
+#define REL_PATH_STRING_MAXLEN \
+ ( \
+ sizeof(PG_TBLSPC_DIR) - 1 \
+ + sizeof((char)'/') \
+ + OIDCHARS /* spcOid */ \
+ + sizeof((char)'/') \
+ + sizeof(TABLESPACE_VERSION_DIRECTORY) - 1 \
+ + sizeof((char)'/') \
+ + OIDCHARS /* dbOid */ \
+ + sizeof((char)'/') \
+ + sizeof((char)'t') /* temporary table indicator */ \
+ + 6 /* procNumber */ \
+ + sizeof((char)'_') \
+ + OIDCHARS /* relNumber */ \
+ + sizeof((char)'_') \
+ + FORKNAMECHARS /* forkNames[forkNumber] */ \
+ )
+
+typedef struct RelPathString
+{
+ char path[REL_PATH_STRING_MAXLEN + 1];
+} RelPathString;
+
/*
* Stuff for computing filesystem pathnames for relations.
*/
extern char *GetDatabasePath(Oid dbOid, Oid spcOid);
+extern RelPathString RelationPathFor(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
+ int procNumber, ForkNumber forkNumber);
+#define relpathforperm(rlocator, forknum) \
+ RelationPathFor((rlocator).dbOid, (rlocator).spcOid, (rlocator).relNumber, \
+ INVALID_PROC_NUMBER, forknum)
+#define relpathforbackend(rlocator, backend, forknum) \
+ RelationPathFor((rlocator).dbOid, (rlocator).spcOid, (rlocator).relNumber, \
+ backend, forknum)
+
+
extern char *GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
int procNumber, ForkNumber forkNumber);
diff --git a/src/common/relpath.c b/src/common/relpath.c
index 186156a9e44..55c7aa1f11a 100644
--- a/src/common/relpath.c
+++ b/src/common/relpath.c
@@ -129,6 +129,96 @@ GetDatabasePath(Oid dbOid, Oid spcOid)
}
}
+/*
+ * RelationPathFor - construct path to a relation's file
+ *
+ * The result is returned in-place as a struct, to make it suitable for use in
+ * critical sections etc.
+ *
+ * See also GetRelationPath()
+ */
+RelPathString
+RelationPathFor(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
+ int procNumber, ForkNumber forkNumber)
+{
+ RelPathString rp;
+
+ if (spcOid == GLOBALTABLESPACE_OID)
+ {
+ /* Shared system relations live in {datadir}/global */
+ Assert(dbOid == 0);
+ Assert(procNumber == INVALID_PROC_NUMBER);
+ if (forkNumber != MAIN_FORKNUM)
+ sprintf(rp.path, "global/%u_%s",
+ relNumber, forkNames[forkNumber]);
+ else
+ sprintf(rp.path, "global/%u",
+ relNumber);
+ }
+ else if (spcOid == DEFAULTTABLESPACE_OID)
+ {
+ /* The default tablespace is {datadir}/base */
+ if (procNumber == INVALID_PROC_NUMBER)
+ {
+ if (forkNumber != MAIN_FORKNUM)
+ {
+ sprintf(rp.path, "base/%u/%u_%s",
+ dbOid, relNumber,
+ forkNames[forkNumber]);
+ }
+ else
+ sprintf(rp.path, "base/%u/%u",
+ dbOid, relNumber);
+ }
+ else
+ {
+ if (forkNumber != MAIN_FORKNUM)
+ sprintf(rp.path, "base/%u/t%d_%u_%s",
+ dbOid, procNumber, relNumber,
+ forkNames[forkNumber]);
+ else
+ sprintf(rp.path, "base/%u/t%d_%u",
+ dbOid, procNumber, relNumber);
+ }
+ }
+ else
+ {
+ /* All other tablespaces are accessed via symlinks */
+ if (procNumber == INVALID_PROC_NUMBER)
+ {
+ if (forkNumber != MAIN_FORKNUM)
+ sprintf(rp.path, "%s/%u/%s/%u/%u_%s",
+ PG_TBLSPC_DIR, spcOid,
+ TABLESPACE_VERSION_DIRECTORY,
+ dbOid, relNumber,
+ forkNames[forkNumber]);
+ else
+ sprintf(rp.path, "%s/%u/%s/%u/%u",
+ PG_TBLSPC_DIR, spcOid,
+ TABLESPACE_VERSION_DIRECTORY,
+ dbOid, relNumber);
+ }
+ else
+ {
+ if (forkNumber != MAIN_FORKNUM)
+ sprintf(rp.path, "%s/%u/%s/%u/t%d_%u_%s",
+ PG_TBLSPC_DIR, spcOid,
+ TABLESPACE_VERSION_DIRECTORY,
+ dbOid, procNumber, relNumber,
+ forkNames[forkNumber]);
+ else
+ sprintf(rp.path, "%s/%u/%s/%u/t%d_%u",
+ PG_TBLSPC_DIR, spcOid,
+ TABLESPACE_VERSION_DIRECTORY,
+ dbOid, procNumber, relNumber);
+ }
+ }
+
+ Assert(strnlen(rp.path, REL_PATH_STRING_MAXLEN + 1) <= REL_PATH_STRING_MAXLEN);
+
+ return rp;
+}
+
/*
* GetRelationPath - construct path to a relation's file
*
@@ -142,74 +232,6 @@ char *
GetRelationPath(Oid dbOid, Oid spcOid, RelFileNumber relNumber,
int procNumber, ForkNumber forkNumber)
{
- char *path;
-
- if (spcOid == GLOBALTABLESPACE_OID)
- {
- /* Shared system relations live in {datadir}/global */
- Assert(dbOid == 0);
- Assert(procNumber == INVALID_PROC_NUMBER);
- if (forkNumber != MAIN_FORKNUM)
- path = psprintf("global/%u_%s",
- relNumber, forkNames[forkNumber]);
- else
- path = psprintf("global/%u", relNumber);
- }
- else if (spcOid == DEFAULTTABLESPACE_OID)
- {
- /* The default tablespace is {datadir}/base */
- if (procNumber == INVALID_PROC_NUMBER)
- {
- if (forkNumber != MAIN_FORKNUM)
- path = psprintf("base/%u/%u_%s",
- dbOid, relNumber,
- forkNames[forkNumber]);
- else
- path = psprintf("base/%u/%u",
- dbOid, relNumber);
- }
- else
- {
- if (forkNumber != MAIN_FORKNUM)
- path = psprintf("base/%u/t%d_%u_%s",
- dbOid, procNumber, relNumber,
- forkNames[forkNumber]);
- else
- path = psprintf("base/%u/t%d_%u",
- dbOid, procNumber, relNumber);
- }
- }
- else
- {
- /* All other tablespaces are accessed via symlinks */
- if (procNumber == INVALID_PROC_NUMBER)
- {
- if (forkNumber != MAIN_FORKNUM)
- path = psprintf("%s/%u/%s/%u/%u_%s",
- PG_TBLSPC_DIR, spcOid,
- TABLESPACE_VERSION_DIRECTORY,
- dbOid, relNumber,
- forkNames[forkNumber]);
- else
- path = psprintf("%s/%u/%s/%u/%u",
- PG_TBLSPC_DIR, spcOid,
- TABLESPACE_VERSION_DIRECTORY,
- dbOid, relNumber);
- }
- else
- {
- if (forkNumber != MAIN_FORKNUM)
- 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("%s/%u/%s/%u/t%d_%u",
- PG_TBLSPC_DIR, spcOid,
- TABLESPACE_VERSION_DIRECTORY,
- dbOid, procNumber, relNumber);
- }
- }
- return path;
+ return pstrdup(RelationPathFor(dbOid, spcOid, relNumber,
+ procNumber, forkNumber).path);
}
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 75cfc2b6fe9..5275c06fc2f 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3663,7 +3663,6 @@ DebugPrintBufferRefcount(Buffer buffer)
{
BufferDesc *buf;
int32 loccount;
- char *path;
char *result;
ProcNumber backend;
uint32 buf_state;
@@ -3683,15 +3682,14 @@ DebugPrintBufferRefcount(Buffer buffer)
}
/* theoretically we should lock the bufhdr here */
- path = relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend,
- BufTagGetForkNum(&buf->tag));
buf_state = pg_atomic_read_u32(&buf->state);
result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)",
- buffer, path,
+ buffer,
+ relpathforbackend(BufTagGetRelFileLocator(&buf->tag), backend,
+ BufTagGetForkNum(&buf->tag)).path,
buf->tag.blockNum, buf_state & BUF_FLAG_MASK,
BUF_STATE_GET_REFCOUNT(buf_state), loccount);
- pfree(path);
return result;
}
@@ -5611,16 +5609,13 @@ AbortBufferIO(Buffer buffer)
if (buf_state & BM_IO_ERROR)
{
/* Buffer is pinned, so we can read tag without spinlock */
- char *path;
-
- path = relpathperm(BufTagGetRelFileLocator(&buf_hdr->tag),
- BufTagGetForkNum(&buf_hdr->tag));
ereport(WARNING,
(errcode(ERRCODE_IO_ERROR),
errmsg("could not write block %u of %s",
- buf_hdr->tag.blockNum, path),
+ buf_hdr->tag.blockNum,
+ relpathforperm(BufTagGetRelFileLocator(&buf_hdr->tag),
+ BufTagGetForkNum(&buf_hdr->tag)).path),
errdetail("Multiple failures --- write error might be permanent.")));
- pfree(path);
}
}
@@ -5637,14 +5632,10 @@ shared_buffer_write_error_callback(void *arg)
/* Buffer is pinned, so we can read the tag without locking the spinlock */
if (bufHdr != NULL)
- {
- char *path = relpathperm(BufTagGetRelFileLocator(&bufHdr->tag),
- BufTagGetForkNum(&bufHdr->tag));
-
errcontext("writing block %u of relation %s",
- bufHdr->tag.blockNum, path);
- pfree(path);
- }
+ bufHdr->tag.blockNum,
+ relpathforperm(BufTagGetRelFileLocator(&bufHdr->tag),
+ BufTagGetForkNum(&bufHdr->tag)).path);
}
/*
@@ -5656,15 +5647,11 @@ local_buffer_write_error_callback(void *arg)
BufferDesc *bufHdr = (BufferDesc *) arg;
if (bufHdr != NULL)
- {
- char *path = relpathbackend(BufTagGetRelFileLocator(&bufHdr->tag),
- MyProcNumber,
- BufTagGetForkNum(&bufHdr->tag));
-
errcontext("writing block %u of relation %s",
- bufHdr->tag.blockNum, path);
- pfree(path);
- }
+ bufHdr->tag.blockNum,
+ relpathforbackend(BufTagGetRelFileLocator(&bufHdr->tag),
+ MyProcNumber,
+ BufTagGetForkNum(&bufHdr->tag)).path);
}
/*
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index 106dedb519a..64e4d757ebf 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -903,3 +903,16 @@ SELECT gist_stratnum_common(3);
18
(1 row)
+-- relpath tests
+CREATE FUNCTION test_relpath()
+ RETURNS text
+ AS :'regresslib'
+ LANGUAGE C;
+-- FIXME: This would include version number, which we don't want in the
+-- expected file.
+SELECT test_relpath();
+ test_relpath
+-------------------------------------------------------------------------
+ pg_tblspc/4294967295/PG_18_202502112/4294967295/t262142_4294967295_init
+(1 row)
+
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 667d9835148..b8d2a1725fe 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -1208,3 +1208,17 @@ binary_coercible(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(IsBinaryCoercible(srctype, targettype));
}
+
+#include "postmaster/postmaster.h"
+
+PG_FUNCTION_INFO_V1(test_relpath);
+Datum
+test_relpath(PG_FUNCTION_ARGS)
+{
+ RelPathString rpath;
+
+ rpath = RelationPathFor(OID_MAX, OID_MAX, OID_MAX, MAX_BACKENDS - 1,
+ INIT_FORKNUM);
+
+ PG_RETURN_DATUM(CStringGetTextDatum(rpath.path));
+}
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index 753a0f41c03..e7a2e4fb7c2 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -403,3 +403,13 @@ DROP FUNCTION explain_mask_costs(text, bool, bool, bool, bool);
-- test stratnum support functions
SELECT gist_stratnum_common(7);
SELECT gist_stratnum_common(3);
+
+
+-- relpath tests
+CREATE FUNCTION test_relpath()
+ RETURNS text
+ AS :'regresslib'
+ LANGUAGE C;
+-- FIXME: This would include version number, which we don't want in the
+-- expected file.
+SELECT test_relpath();
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 80aa50d55a4..ce75ce75e8f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2402,6 +2402,7 @@ RelMapFile
RelMapping
RelOptInfo
RelOptKind
+RelPathString
RelToCheck
RelToCluster
RelabelType
--
2.48.1.76.g4e746b1a31.dirty
--3qjrpgqauwembqes--
view thread (62+ messages) latest in thread
Message-ID: <no-message-id-1841328@localhost>
Permalink: ../no-message-id-1841328@localhost/
Also on: postgresql.org/message-id/no-message-id-1841328@localhost
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: andres@anarazel.de
Subject: Re: [PATCH v1] relpath-by-value
In-Reply-To: <no-message-id-1841328@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox