0001-Check-the-duplicated-relfilenode-when-create-table-o.patch
text/x-patch
Filename: 0001-Check-the-duplicated-relfilenode-when-create-table-o.patch
Type: text/x-patch
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: Check the duplicated relfilenode when create table or truncate table.
| File | + | − |
|---|---|---|
| src/backend/catalog/catalog.c | 78 | 24 |
From bc3a756e71bef744f1c9cf652c0eb0e4933c965b Mon Sep 17 00:00:00 2001
From: Shenhao Wang <wangsh.fnst@fujitsu.com>
Date: Sat, 2 Apr 2022 11:03:44 +0800
Subject: [PATCH] Check the duplicated relfilenode when create table or
truncate table.
---
src/backend/catalog/catalog.c | 102 ++++++++++++++++++++++++++--------
1 file changed, 78 insertions(+), 24 deletions(-)
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index dfd5fb669e..7f51445573 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -55,6 +55,8 @@
#define GETNEWOID_LOG_THRESHOLD 1000000
#define GETNEWOID_LOG_MAX_INTERVAL 128000000
+static bool isRelNodeCollision(RelFileNodeBackend rnode, Relation relation);
+
/*
* IsSystemRelation
* True iff the relation is either a system catalog or a toast table.
@@ -490,8 +492,7 @@ Oid
GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
{
RelFileNodeBackend rnode;
- char *rpath;
- bool collides;
+ bool usedAsOID;
BackendId backend;
/*
@@ -515,6 +516,16 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
return InvalidOid; /* placate compiler */
}
+ if (pg_class != NULL)
+ {
+ usedAsOID = true;
+ }
+ else
+ {
+ pg_class = table_open(RelationRelationId, AccessShareLock);
+ usedAsOID = false;
+ }
+
/* This logic should match RelationInitPhysicalAddr */
rnode.node.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace;
rnode.node.dbNode = (rnode.node.spcNode == GLOBALTABLESPACE_OID) ? InvalidOid : MyDatabaseId;
@@ -531,34 +542,16 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
CHECK_FOR_INTERRUPTS();
/* Generate the OID */
- if (pg_class)
+ if (usedAsOID)
rnode.node.relNode = GetNewOidWithIndex(pg_class, ClassOidIndexId,
Anum_pg_class_oid);
else
rnode.node.relNode = GetNewObjectId();
- /* Check for existing file of same name */
- rpath = relpath(rnode, MAIN_FORKNUM);
+ } while (isRelNodeCollision(rnode, pg_class));
- if (access(rpath, F_OK) == 0)
- {
- /* definite collision */
- collides = true;
- }
- else
- {
- /*
- * Here we have a little bit of a dilemma: if errno is something
- * other than ENOENT, should we declare a collision and loop? In
- * practice it seems best to go ahead regardless of the errno. If
- * there is a colliding file we will get an smgr failure when we
- * attempt to create the new relation file.
- */
- collides = false;
- }
-
- pfree(rpath);
- } while (collides);
+ if (!usedAsOID)
+ table_close(pg_class, AccessShareLock);
return rnode.node.relNode;
}
@@ -666,3 +659,64 @@ pg_stop_making_pinned_objects(PG_FUNCTION_ARGS)
PG_RETURN_VOID();
}
+
+/*
+ * isRelNodeCollision
+ * Checking the rnode collides with existing one.
+ */
+static bool
+isRelNodeCollision(RelFileNodeBackend rnode, Relation relation)
+{
+ char *rpath;
+ bool collides;
+ SysScanDesc scandesc;
+ static ScanKeyData skey[2];
+
+ /* Check for existing file of same name */
+ rpath = relpath(rnode, MAIN_FORKNUM);
+
+ if (access(rpath, F_OK) == 0)
+ {
+ /* definite collision */
+ collides = true;
+ }
+ else
+ {
+ ScanKeyInit(&skey[0],
+ Anum_pg_class_reltablespace,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(
+ rnode.node.spcNode == MyDatabaseTableSpace ?
+ InvalidOid : MyDatabaseTableSpace));
+ ScanKeyInit(&skey[1],
+ Anum_pg_class_relfilenode,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(rnode.node.relNode));
+
+ scandesc = systable_beginscan(relation,
+ ClassTblspcRelfilenodeIndexId,
+ true, NULL, 2, skey);
+
+ if (HeapTupleIsValid(systable_getnext(scandesc)))
+ {
+ /* duplicate tablespace and relfilenode in pg_class */
+ collides = true;
+ }
+ else
+ {
+ /*
+ * Here we have a little bit of a dilemma: if errno is something
+ * other than ENOENT, should we declare a collision and loop? In
+ * practice it seems best to go ahead regardless of the errno. If
+ * there is a colliding file we will get an smgr failure when we
+ * attempt to create the new relation file.
+ */
+ collides = false;
+ }
+
+ systable_endscan(scandesc);
+ }
+
+ pfree(rpath);
+ return collides;
+}
--
2.32.0