From 9b1a35aa768749a7c823df64c761cef60fbb22a7 Mon Sep 17 00:00:00 2001
From: John Naylor <jcnaylor@gmail.com>
Date: Wed, 31 Oct 2018 14:28:03 +0700
Subject: [PATCH v7 2/2] During pg_upgrade, skip transfer of FSMs if they
 wouldn't have been created on the new cluster.

---
 src/bin/pg_upgrade/info.c        | 11 +++++--
 src/bin/pg_upgrade/pg_upgrade.h  |  6 +++-
 src/bin/pg_upgrade/relfilenode.c | 55 +++++++++++++++++++-------------
 3 files changed, 47 insertions(+), 25 deletions(-)

diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index fd0b44c3ce..31a24e0bec 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -200,6 +200,7 @@ create_rel_filename_map(const char *old_data, const char *new_data,
 
 	map->old_db_oid = old_db->db_oid;
 	map->new_db_oid = new_db->db_oid;
+	map->relkind = old_rel->relkind;
 
 	/*
 	 * old_relfilenode might differ from pg_class.oid (and hence
@@ -418,6 +419,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 	char	   *nspname = NULL;
 	char	   *relname = NULL;
 	char	   *tablespace = NULL;
+	char	   *relkind = NULL;
 	int			i_spclocation,
 				i_nspname,
 				i_relname,
@@ -425,7 +427,8 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 				i_indtable,
 				i_toastheap,
 				i_relfilenode,
-				i_reltablespace;
+				i_reltablespace,
+				i_relkind;
 	char		query[QUERY_ALLOC];
 	char	   *last_namespace = NULL,
 			   *last_tablespace = NULL;
@@ -497,7 +500,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 	 */
 	snprintf(query + strlen(query), sizeof(query) - strlen(query),
 			 "SELECT all_rels.*, n.nspname, c.relname, "
-			 "  c.relfilenode, c.reltablespace, %s "
+			 "  c.relfilenode, c.reltablespace, c.relkind, %s "
 			 "FROM (SELECT * FROM regular_heap "
 			 "      UNION ALL "
 			 "      SELECT * FROM toast_heap "
@@ -529,6 +532,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 	i_relfilenode = PQfnumber(res, "relfilenode");
 	i_reltablespace = PQfnumber(res, "reltablespace");
 	i_spclocation = PQfnumber(res, "spclocation");
+	i_relkind = PQfnumber(res, "relkind");
 
 	for (relnum = 0; relnum < ntups; relnum++)
 	{
@@ -558,6 +562,9 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 		relname = PQgetvalue(res, relnum, i_relname);
 		curr->relname = pg_strdup(relname);
 
+		relkind = PQgetvalue(res, relnum, i_relkind);
+		curr->relkind = relkind[0];
+
 		curr->relfilenode = atooid(PQgetvalue(res, relnum, i_relfilenode));
 		curr->tblsp_alloc = false;
 
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index f83a3eeb67..78df636a2a 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -147,6 +147,7 @@ typedef struct
 	char	   *tablespace;		/* tablespace path; "" for cluster default */
 	bool		nsp_alloc;		/* should nspname be freed? */
 	bool		tblsp_alloc;	/* should tablespace be freed? */
+	char		relkind;		/* relation relkind -- see pg_class.h */
 } RelInfo;
 
 typedef struct
@@ -173,9 +174,12 @@ typedef struct
 	 */
 	Oid			old_relfilenode;
 	Oid			new_relfilenode;
-	/* the rest are used only for logging and error reporting */
+
+	/* These are used only for logging and error reporting. */
 	char	   *nspname;		/* namespaces */
 	char	   *relname;
+
+	char		relkind;		/* relation relkind -- see pg_class.h */
 } FileNameMap;
 
 /*
diff --git a/src/bin/pg_upgrade/relfilenode.c b/src/bin/pg_upgrade/relfilenode.c
index ed604f26ca..7a7f6ab244 100644
--- a/src/bin/pg_upgrade/relfilenode.c
+++ b/src/bin/pg_upgrade/relfilenode.c
@@ -14,10 +14,11 @@
 #include <sys/stat.h>
 #include "catalog/pg_class_d.h"
 #include "access/transam.h"
+#include "storage/freespace.h"
 
 
 static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace);
-static void transfer_relfile(FileNameMap *map, const char *suffix, bool vm_must_add_frozenbit);
+static Size transfer_relfile(FileNameMap *map, const char *suffix, bool vm_must_add_frozenbit);
 
 
 /*
@@ -136,6 +137,7 @@ transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
 	int			mapnum;
 	bool		vm_crashsafe_match = true;
 	bool		vm_must_add_frozenbit = false;
+	Size		first_seg_size = 0;
 
 	/*
 	 * Do the old and new cluster disagree on the crash-safetiness of the vm
@@ -157,18 +159,22 @@ transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
 		if (old_tablespace == NULL ||
 			strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0)
 		{
-			/* transfer primary file */
-			transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit);
+			/* Transfer main fork and return size of the first segment. */
+			first_seg_size = transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit);
 
 			/* fsm/vm files added in PG 8.4 */
 			if (GET_MAJOR_VERSION(old_cluster.major_version) >= 804)
 			{
 				/*
-				 * Copy/link any fsm and vm files, if they exist
+				 * Copy/link any fsm and vm files, if they exist and if they would
+				 * be created in the new cluster.
 				 */
-				transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
+				if (maps[mapnum].relkind != RELKIND_RELATION ||
+					first_seg_size > HEAP_FSM_CREATION_THRESHOLD * BLCKSZ ||
+					GET_MAJOR_VERSION(new_cluster.major_version) <= 1100)
+					(void) transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
 				if (vm_crashsafe_match)
-					transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
+					(void) transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
 			}
 		}
 	}
@@ -182,7 +188,7 @@ transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
  * is true, visibility map forks are converted and rewritten, even in link
  * mode.
  */
-static void
+static Size
 transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit)
 {
 	char		old_file[MAXPGPATH];
@@ -190,6 +196,8 @@ transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_fro
 	int			segno;
 	char		extent_suffix[65];
 	struct stat statbuf;
+	int			sret;
+	Size		first_seg_size = 0;
 
 	/*
 	 * Now copy/link any related segments as well. Remember, PG breaks large
@@ -218,26 +226,29 @@ transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_fro
 				 type_suffix,
 				 extent_suffix);
 
-		/* Is it an extent, fsm, or vm file? */
-		if (type_suffix[0] != '\0' || segno != 0)
-		{
-			/* Did file open fail? */
-			if (stat(old_file, &statbuf) != 0)
-			{
-				/* File does not exist?  That's OK, just return */
-				if (errno == ENOENT)
-					return;
-				else
-					pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
-							 map->nspname, map->relname, old_file, new_file,
-							 strerror(errno));
-			}
+		sret = stat(old_file, &statbuf);
 
+		/* Save the size of the first segment of the main fork. */
+		if (type_suffix[0] == '\0' && segno == 0)
+			first_seg_size = statbuf.st_size;
+
+		/* The file must be an extent, fsm, or vm. */
+		else if (sret == 0)
+		{
 			/* If file is empty, just return */
 			if (statbuf.st_size == 0)
-				return;
+				return first_seg_size;
 		}
 
+		/* Did file open fail? */
+		else if (errno == ENOENT)
+			/* File does not exist?  That's OK, just return */
+			return first_seg_size;
+		else
+			pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\" to \"%s\"): %s\n",
+					 map->nspname, map->relname, old_file, new_file,
+					 strerror(errno));
+
 		unlink(new_file);
 
 		/* Copying files might take some time, so give feedback. */
-- 
2.17.1

