map->old_db_oid = old_db->db_oid;
map->new_db_oid = new_db->db_oid;
+ map->relpages = old_rel->relpages;
+ map->relkind = old_rel->relkind;
/*
* old_relfilenode might differ from pg_class.oid (and hence
char *nspname = NULL;
char *relname = NULL;
char *tablespace = NULL;
+ char *relkind = NULL;
int i_spclocation,
i_nspname,
i_relname,
i_indtable,
i_toastheap,
i_relfilenode,
- i_reltablespace;
+ i_reltablespace,
+ i_relpages,
+ i_relkind;
char query[QUERY_ALLOC];
char *last_namespace = NULL,
*last_tablespace = NULL;
*/
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.relpages, c.relkind, %s "
"FROM (SELECT * FROM regular_heap "
" UNION ALL "
" SELECT * FROM toast_heap "
i_relname = PQfnumber(res, "relname");
i_relfilenode = PQfnumber(res, "relfilenode");
i_reltablespace = PQfnumber(res, "reltablespace");
+ i_relpages = PQfnumber(res, "relpages");
+ i_relkind = PQfnumber(res, "relkind");
i_spclocation = PQfnumber(res, "spclocation");
for (relnum = 0; relnum < ntups; relnum++)
curr->relname = pg_strdup(relname);
curr->relfilenode = atooid(PQgetvalue(res, relnum, i_relfilenode));
+ curr->relpages = atoi(PQgetvalue(res, relnum, i_relpages));
+
+ relkind = PQgetvalue(res, relnum, i_relkind);
+ curr->relkind = relkind[0];
+
curr->tblsp_alloc = false;
/* Is the tablespace oid non-default? */
char *tablespace; /* tablespace path; "" for cluster default */
bool nsp_alloc; /* should nspname be freed? */
bool tblsp_alloc; /* should tablespace be freed? */
+ int32 relpages; /* # of pages -- see pg_class.h */
+ char relkind; /* relation kind -- see pg_class.h */
} RelInfo;
typedef struct
*/
Oid old_relfilenode;
Oid new_relfilenode;
+
+ int32 relpages; /* # of pages -- see pg_class.h */
+ char relkind; /* relation kind -- see pg_class.h */
+
/* the rest are used only for logging and error reporting */
char *nspname; /* namespaces */
char *relname;
#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 bool new_cluster_needs_fsm(FileNameMap *map);
/*
/*
* Copy/link any fsm and vm files, if they exist
*/
- transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
+ if (new_cluster_needs_fsm(&maps[mapnum]))
+ transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
if (vm_crashsafe_match)
transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
}
}
}
}
+
+/*
+ * new_cluster_needs_fsm()
+ *
+ * Return false for small heaps if we're upgrading across PG 12, the first
+ * version where small heap relations don't have FSMs by default.
+ */
+static bool
+new_cluster_needs_fsm(FileNameMap *map)
+{
+ char old_primary_file[MAXPGPATH];
+ struct stat statbuf;
+
+ /* fsm/vm files added in PG 8.4 */
+ Assert(GET_MAJOR_VERSION(old_cluster.major_version) >= 804);
+
+ if (!(GET_MAJOR_VERSION(old_cluster.major_version) <= 1100 &&
+ GET_MAJOR_VERSION(new_cluster.major_version) >= 1200))
+ return true;
+
+ /* Always transfer FSMs of non-heap relations. */
+ if (map->relkind != RELKIND_RELATION &&
+ map->relkind != RELKIND_TOASTVALUE)
+ return true;
+
+ /*
+ * If pg_class.relpages falsely reports that the heap is above the
+ * threshold, we will transfer a FSM when we don't need to, but this is
+ * harmless.
+ */
+ if (map->relpages > HEAP_FSM_CREATION_THRESHOLD)
+ return true;
+
+ /* Determine path of the primary file. */
+ snprintf(old_primary_file, sizeof(old_primary_file), "%s%s/%u/%u",
+ map->old_tablespace,
+ map->old_tablespace_suffix,
+ map->old_db_oid,
+ map->old_relfilenode);
+
+ /*
+ * If pg_class.relpages falsely reports that the heap is below the
+ * threshold, a FSM would be skipped when we actually need it. To guard
+ * against this, we verify the size of the primary file.
+ */
+ if (stat(old_primary_file, &statbuf) != 0)
+ {
+ pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\"): %s\n",
+ map->nspname, map->relname, old_primary_file, strerror(errno));
+
+ /* Keep compiler quiet. */
+ return false;
+ }
+ else if (statbuf.st_size > HEAP_FSM_CREATION_THRESHOLD * BLCKSZ)
+ return true;
+ else
+ return false;
+}