From 9ac491515cb9fcc91ff9d7bb768d459cb87a30d0 Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@cancellar.hu>
Date: Sat, 12 Oct 2024 22:01:28 +0100
Subject: [PATCH v6 4/6] Refactor smgr API: mdcreate needs the old
 relfilelocator

Sometimes mdcreate creates a new file because we are moving the data
into a new location. For example an ALTER TABLE can cause a complete
rewrite, creating a new file, writing new data, then deleting the
original file, or TRUNCATE can simply create a new file and not copy
anything from the previous file.

With the extensions being able to modify the SMGR, some of them might
want to track these changes - if they stored additional metadata
previously using the old RelFileLocator, they might want to reuse/move
that data with the new RelFileLocator.

With this change, mdcreate receives the old relfilelocator along
with the new for operations that create a new file for an existing
relation.
---
 src/backend/access/heap/heapam_handler.c | 10 ++++---
 src/backend/access/transam/xlogutils.c   |  2 +-
 src/backend/bootstrap/bootparse.y        |  3 +-
 src/backend/catalog/heap.c               | 38 +++++++++++++++++++++---
 src/backend/catalog/index.c              |  5 ++--
 src/backend/catalog/storage.c            |  8 ++---
 src/backend/commands/sequence.c          |  2 +-
 src/backend/commands/tablecmds.c         |  4 +--
 src/backend/storage/buffer/bufmgr.c      |  7 +++--
 src/backend/storage/smgr/md.c            |  2 +-
 src/backend/storage/smgr/smgr.c          |  4 +--
 src/backend/utils/cache/relcache.c       |  2 +-
 src/include/catalog/heap.h               |  4 ++-
 src/include/catalog/storage.h            |  3 +-
 src/include/storage/md.h                 |  2 +-
 src/include/storage/smgr.h               |  4 +--
 16 files changed, 69 insertions(+), 31 deletions(-)

diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index cbef73e5d4b..4466d926a44 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -588,6 +588,8 @@ heapam_relation_set_new_filelocator(Relation rel,
 {
 	SMgrRelation srel;
 
+	RelFileLocator oldlocator = rel->rd_locator;
+
 	/*
 	 * Initialize to the minimum XID that could put tuples in the table. We
 	 * know that no xacts older than RecentXmin are still running, so that
@@ -605,7 +607,7 @@ heapam_relation_set_new_filelocator(Relation rel,
 	 */
 	*minmulti = GetOldestMultiXactId();
 
-	srel = RelationCreateStorage(*newrlocator, persistence, true);
+	srel = RelationCreateStorage(oldlocator, *newrlocator, persistence, true);
 
 	/*
 	 * If required, set up an init fork for an unlogged table so that it can
@@ -615,7 +617,7 @@ heapam_relation_set_new_filelocator(Relation rel,
 	{
 		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
 			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
-		smgrcreate(srel, INIT_FORKNUM, false);
+		smgrcreate(oldlocator, srel, INIT_FORKNUM, false);
 		log_smgrcreate(newrlocator, INIT_FORKNUM);
 	}
 
@@ -648,7 +650,7 @@ heapam_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
 	 * NOTE: any conflict in relfilenumber value will be caught in
 	 * RelationCreateStorage().
 	 */
-	dstrel = RelationCreateStorage(*newrlocator, rel->rd_rel->relpersistence, true);
+	dstrel = RelationCreateStorage(rel->rd_locator, *newrlocator, rel->rd_rel->relpersistence, true);
 
 	/* copy main fork */
 	RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM,
@@ -660,7 +662,7 @@ heapam_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
 	{
 		if (smgrexists(RelationGetSmgr(rel), forkNum))
 		{
-			smgrcreate(dstrel, forkNum, false);
+			smgrcreate(rel->rd_locator, dstrel, forkNum, false);
 
 			/*
 			 * WAL log creation if the relation is persistent, or this is the
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 5fbe39133b8..42ff9f7820e 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -487,7 +487,7 @@ XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum,
 	 * filesystem loses an inode during a crash.  Better to write the data
 	 * until we are actually told to delete the file.)
 	 */
-	smgrcreate(smgr, forknum, true);
+	smgrcreate(rlocator, smgr, forknum, true);
 
 	lastblock = smgrnblocks(smgr, forknum);
 
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 943ff4733d3..ed93625f9bf 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -217,7 +217,8 @@ Boot_CreateStmt:
 												   true,
 												   &relfrozenxid,
 												   &relminmxid,
-												   true);
+												   true,
+												   NULL);
 						elog(DEBUG4, "bootstrap relation created");
 					}
 					else
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a6ed9849e77..f8e626fb4ec 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -296,7 +296,8 @@ heap_create(const char *relname,
 			bool allow_system_table_mods,
 			TransactionId *relfrozenxid,
 			MultiXactId *relminmxid,
-			bool create_storage)
+			bool create_storage,
+			RelFileLocator *old_rlocator)
 {
 	Relation	rel;
 
@@ -381,14 +382,31 @@ heap_create(const char *relname,
 	 */
 	if (create_storage)
 	{
+		RelFileLocator prev_rlocator = rel->rd_locator;
+		RelFileLocator new_rlocator = rel->rd_locator;
+
+		if (old_rlocator != NULL)
+		{
+			prev_rlocator = *old_rlocator;
+
+			/*
+			 * table_relation_set_new_filelocator() takes old_rlocator from
+			 * rel->rd_locator
+			 */
+			rel->rd_locator = prev_rlocator;
+		}
+
 		if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
-			table_relation_set_new_filelocator(rel, &rel->rd_locator,
+			table_relation_set_new_filelocator(rel, &new_rlocator,
 											   relpersistence,
 											   relfrozenxid, relminmxid);
 		else if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
-			RelationCreateStorage(rel->rd_locator, relpersistence, true);
+			RelationCreateStorage(prev_rlocator, new_rlocator, relpersistence, true);
 		else
 			Assert(false);
+
+		/* restore the original rel's locator */
+		rel->rd_locator = new_rlocator;
 	}
 
 	/*
@@ -1147,6 +1165,8 @@ heap_create_with_catalog(const char *relname,
 	Oid			existing_relid;
 	Oid			old_type_oid;
 	Oid			new_type_oid;
+	RelFileLocator *old_rlocator = NULL;
+	Relation	old_rel;
 
 	/* By default set to InvalidOid unless overridden by binary-upgrade */
 	RelFileNumber relfilenumber = InvalidRelFileNumber;
@@ -1301,6 +1321,12 @@ heap_create_with_catalog(const char *relname,
 	else
 		relacl = NULL;
 
+	if (relrewrite != InvalidOid)
+	{
+		old_rel = table_open(relrewrite, AccessShareLock);
+		old_rlocator = &old_rel->rd_locator;
+	}
+
 	/*
 	 * Create the relcache entry (mostly dummy at this point) and the physical
 	 * disk file.  (If we fail further down, it's the smgr's responsibility to
@@ -1324,7 +1350,11 @@ heap_create_with_catalog(const char *relname,
 							   allow_system_table_mods,
 							   &relfrozenxid,
 							   &relminmxid,
-							   true);
+							   true,
+							   old_rlocator);
+
+	if (relrewrite != InvalidOid)
+		table_close(old_rel, AccessShareLock);
 
 	Assert(relid == RelationGetRelid(new_rel_desc));
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 43de42ce39e..f6a3e915335 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -985,7 +985,8 @@ index_create(Relation heapRelation,
 								allow_system_table_mods,
 								&relfrozenxid,
 								&relminmxid,
-								create_storage);
+								create_storage,
+								NULL);
 
 	Assert(relfrozenxid == InvalidTransactionId);
 	Assert(relminmxid == InvalidMultiXactId);
@@ -3087,7 +3088,7 @@ index_build(Relation heapRelation,
 	if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
 		!smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
 	{
-		smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
+		smgrcreate(indexRelation->rd_locator, RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
 		log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
 		indexRelation->rd_indam->ambuildempty(indexRelation);
 	}
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index e443a4993c5..9b1b0f3a44a 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -119,7 +119,7 @@ AddPendingSync(const RelFileLocator *rlocator)
  * pass register_delete = false.
  */
 SMgrRelation
-RelationCreateStorage(RelFileLocator rlocator, char relpersistence,
+RelationCreateStorage(RelFileLocator oldlocator, RelFileLocator rlocator, char relpersistence,
 					  bool register_delete)
 {
 	SMgrRelation srel;
@@ -148,7 +148,7 @@ RelationCreateStorage(RelFileLocator rlocator, char relpersistence,
 	}
 
 	srel = smgropen(rlocator, procNumber);
-	smgrcreate(srel, MAIN_FORKNUM, false);
+	smgrcreate(oldlocator, srel, MAIN_FORKNUM, false);
 
 	if (needs_wal)
 		log_smgrcreate(&srel->smgr_rlocator.locator, MAIN_FORKNUM);
@@ -992,7 +992,7 @@ smgr_redo(XLogReaderState *record)
 		SMgrRelation reln;
 
 		reln = smgropen(xlrec->rlocator, INVALID_PROC_NUMBER);
-		smgrcreate(reln, xlrec->forkNum, true);
+		smgrcreate(xlrec->rlocator, reln, xlrec->forkNum, true);
 	}
 	else if (info == XLOG_SMGR_TRUNCATE)
 	{
@@ -1013,7 +1013,7 @@ smgr_redo(XLogReaderState *record)
 		 * XLogReadBufferForRedo, we prefer to recreate the rel and replay the
 		 * log as best we can until the drop is seen.
 		 */
-		smgrcreate(reln, MAIN_FORKNUM, true);
+		smgrcreate(xlrec->rlocator, reln, MAIN_FORKNUM, true);
 
 		/*
 		 * Before we perform the truncation, update minimum recovery point to
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index e1b808bbb60..9b3f2384720 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -337,7 +337,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 		SMgrRelation srel;
 
 		srel = smgropen(rel->rd_locator, INVALID_PROC_NUMBER);
-		smgrcreate(srel, INIT_FORKNUM, false);
+		smgrcreate(rel->rd_locator, srel, INIT_FORKNUM, false);
 		log_smgrcreate(&rel->rd_locator, INIT_FORKNUM);
 		fill_seq_fork_with_data(rel, tuple, INIT_FORKNUM);
 		FlushRelationBuffers(rel);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f976c0e5c7e..f7f4b29551d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -17193,7 +17193,7 @@ index_copy_data(Relation rel, RelFileLocator newrlocator)
 	 * NOTE: any conflict in relfilenumber value will be caught in
 	 * RelationCreateStorage().
 	 */
-	dstrel = RelationCreateStorage(newrlocator, rel->rd_rel->relpersistence, true);
+	dstrel = RelationCreateStorage(rel->rd_locator, newrlocator, rel->rd_rel->relpersistence, true);
 
 	/* copy main fork */
 	RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM,
@@ -17205,7 +17205,7 @@ index_copy_data(Relation rel, RelFileLocator newrlocator)
 	{
 		if (smgrexists(RelationGetSmgr(rel), forkNum))
 		{
-			smgrcreate(dstrel, forkNum, false);
+			smgrcreate(rel->rd_locator, dstrel, forkNum, false);
 
 			/*
 			 * WAL log creation if the relation is persistent, or this is the
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 7241477cac0..2fd735e0e36 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -1055,7 +1055,7 @@ ExtendBufferedRelTo(BufferManagerRelation bmr,
 
 		/* recheck, fork might have been created concurrently */
 		if (!smgrexists(BMR_GET_SMGR(bmr), fork))
-			smgrcreate(BMR_GET_SMGR(bmr), fork, flags & EB_PERFORMING_RECOVERY);
+			smgrcreate(bmr.rel->rd_locator, BMR_GET_SMGR(bmr), fork, flags & EB_PERFORMING_RECOVERY);
 
 		UnlockRelationForExtension(bmr.rel, ExclusiveLock);
 	}
@@ -5394,7 +5394,7 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator,
 	 * directory.  Therefore, each individual relation doesn't need to be
 	 * registered for cleanup.
 	 */
-	RelationCreateStorage(dst_rlocator, relpersistence, false);
+	RelationCreateStorage(src_rlocator, dst_rlocator, relpersistence, false);
 
 	/* copy main fork. */
 	RelationCopyStorageUsingBuffer(src_rlocator, dst_rlocator, MAIN_FORKNUM,
@@ -5406,7 +5406,8 @@ CreateAndCopyRelationData(RelFileLocator src_rlocator,
 	{
 		if (smgrexists(src_rel, forkNum))
 		{
-			smgrcreate(dst_rel, forkNum, false);
+			/* TODO: for sure? */
+			smgrcreate(src_rel->smgr_rlocator.locator, dst_rel, forkNum, false);
 
 			/*
 			 * WAL log creation if the relation is persistent, or this is the
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index d6822ff03f3..310bcba27df 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -266,7 +266,7 @@ mdexists(SMgrRelation reln, ForkNumber forknum)
  * If isRedo is true, it's okay for the relation to exist already.
  */
 void
-mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
+mdcreate(RelFileLocator /* reln */, SMgrRelation reln, ForkNumber forknum, bool isRedo)
 {
 	MdSMgrRelation mdreln = (MdSMgrRelation) reln;
 	MdfdVec    *mdfd;
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 36e0b4f4a54..6f9eee8c652 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -470,10 +470,10 @@ smgrexists(SMgrRelation reln, ForkNumber forknum)
  * to be created.
  */
 void
-smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
+smgrcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo)
 {
 	HOLD_INTERRUPTS();
-	smgrsw[reln->smgr_which].smgr_create(reln, forknum, isRedo);
+	smgrsw[reln->smgr_which].smgr_create(relold, reln, forknum, isRedo);
 	RESUME_INTERRUPTS();
 }
 
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 6b634c9fff1..8ad1d27b4f1 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3875,7 +3875,7 @@ RelationSetNewRelfilenumber(Relation relation, char persistence)
 		/* handle these directly, at least for now */
 		SMgrRelation srel;
 
-		srel = RelationCreateStorage(newrlocator, persistence, true);
+		srel = RelationCreateStorage(relation->rd_locator, newrlocator, persistence, true);
 		smgrclose(srel);
 	}
 	else
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 624c415dadb..1492c4ac2ab 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -17,6 +17,7 @@
 #include "catalog/indexing.h"
 #include "catalog/objectaddress.h"
 #include "parser/parse_node.h"
+#include "storage/relfilelocator.h"
 
 
 /* flag bits for CheckAttributeType/CheckAttributeNamesTypes */
@@ -62,7 +63,8 @@ extern Relation heap_create(const char *relname,
 							bool allow_system_table_mods,
 							TransactionId *relfrozenxid,
 							MultiXactId *relminmxid,
-							bool create_storage);
+							bool create_storage,
+							RelFileLocator *old_rlocator);
 
 extern Oid	heap_create_with_catalog(const char *relname,
 									 Oid relnamespace,
diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h
index 70f619a6d6f..ecb4ba91bfc 100644
--- a/src/include/catalog/storage.h
+++ b/src/include/catalog/storage.h
@@ -22,7 +22,8 @@
 /* GUC variables */
 extern PGDLLIMPORT int wal_skip_threshold;
 
-extern SMgrRelation RelationCreateStorage(RelFileLocator rlocator,
+extern SMgrRelation RelationCreateStorage(RelFileLocator oldlocator,
+										  RelFileLocator rlocator,
 										  char relpersistence,
 										  bool register_delete);
 extern void RelationDropStorage(Relation rel);
diff --git a/src/include/storage/md.h b/src/include/storage/md.h
index c6958d92a68..77be1f39b73 100644
--- a/src/include/storage/md.h
+++ b/src/include/storage/md.h
@@ -30,7 +30,7 @@ extern SMgrId MdSMgrId;
 extern void mdinit(void);
 extern void mdopen(SMgrRelation reln);
 extern void mdclose(SMgrRelation reln, ForkNumber forknum);
-extern void mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
+extern void mdcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo);
 extern bool mdexists(SMgrRelation reln, ForkNumber forknum);
 extern void mdunlink(RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo);
 extern void mdextend(SMgrRelation reln, ForkNumber forknum,
diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h
index b170038708a..3b844aa8e2e 100644
--- a/src/include/storage/smgr.h
+++ b/src/include/storage/smgr.h
@@ -90,7 +90,7 @@ typedef struct f_smgr
 	void		(*smgr_shutdown) (void);	/* may be NULL */
 	void		(*smgr_open) (SMgrRelation reln);
 	void		(*smgr_close) (SMgrRelation reln, ForkNumber forknum);
-	void		(*smgr_create) (SMgrRelation reln, ForkNumber forknum,
+	void		(*smgr_create) (RelFileLocator relold, SMgrRelation reln, ForkNumber forknum,
 								bool isRedo);
 	bool		(*smgr_exists) (SMgrRelation reln, ForkNumber forknum);
 	void		(*smgr_unlink) (RelFileLocatorBackend rlocator, ForkNumber forknum,
@@ -136,7 +136,7 @@ extern void smgrdestroyall(void);
 extern void smgrrelease(SMgrRelation reln);
 extern void smgrreleaseall(void);
 extern void smgrreleaserellocator(RelFileLocatorBackend rlocator);
-extern void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo);
+extern void smgrcreate(RelFileLocator relold, SMgrRelation reln, ForkNumber forknum, bool isRedo);
 extern void smgrdosyncall(SMgrRelation *rels, int nrels);
 extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo);
 extern void smgrextend(SMgrRelation reln, ForkNumber forknum,
-- 
2.43.0

