aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r--src/backend/utils/cache/relcache.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 0e8fda97f86..f8d9f5fa485 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -41,6 +41,7 @@
#include "access/tupdesc_details.h"
#include "access/xact.h"
#include "access/xlog.h"
+#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
@@ -3707,9 +3708,36 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
TransactionId freezeXid = InvalidTransactionId;
RelFileNode newrnode;
- /* Allocate a new relfilenode */
- newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
- persistence);
+ if (!IsBinaryUpgrade)
+ {
+ /* Allocate a new relfilenode */
+ newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace,
+ NULL, persistence);
+ }
+ else if (relation->rd_rel->relkind == RELKIND_INDEX)
+ {
+ if (!OidIsValid(binary_upgrade_next_index_pg_class_relfilenode))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("index relfilenode value not set when in binary upgrade mode")));
+
+ newrelfilenode = binary_upgrade_next_index_pg_class_relfilenode;
+ binary_upgrade_next_index_pg_class_relfilenode = InvalidOid;
+ }
+ else if (relation->rd_rel->relkind == RELKIND_RELATION)
+ {
+ if (!OidIsValid(binary_upgrade_next_heap_pg_class_relfilenode))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("heap relfilenode value not set when in binary upgrade mode")));
+
+ newrelfilenode = binary_upgrade_next_heap_pg_class_relfilenode;
+ binary_upgrade_next_heap_pg_class_relfilenode = InvalidOid;
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unexpected request for new relfilenode in binary upgrade mode")));
/*
* Get a writable copy of the pg_class tuple for the given relation.
@@ -3724,9 +3752,37 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
classform = (Form_pg_class) GETSTRUCT(tuple);
/*
- * Schedule unlinking of the old storage at transaction commit.
+ * Schedule unlinking of the old storage at transaction commit, except
+ * when performing a binary upgrade, when we must do it immediately.
*/
- RelationDropStorage(relation);
+ if (IsBinaryUpgrade)
+ {
+ SMgrRelation srel;
+
+ /*
+ * During a binary upgrade, we use this code path to ensure that
+ * pg_largeobject and its index have the same relfilenode values as in
+ * the old cluster. This is necessary because pg_upgrade treats
+ * pg_largeobject like a user table, not a system table. It is however
+ * possible that a table or index may need to end up with the same
+ * relfilenode in the new cluster as what it had in the old cluster.
+ * Hence, we can't wait until commit time to remove the old storage.
+ *
+ * In general, this function needs to have transactional semantics,
+ * and removing the old storage before commit time surely isn't.
+ * However, it doesn't really matter, because if a binary upgrade
+ * fails at this stage, the new cluster will need to be recreated
+ * anyway.
+ */
+ srel = smgropen(relation->rd_node, relation->rd_backend);
+ smgrdounlinkall(&srel, 1, false);
+ smgrclose(srel);
+ }
+ else
+ {
+ /* Not a binary upgrade, so just schedule it to happen later. */
+ RelationDropStorage(relation);
+ }
/*
* Create storage for the main fork of the new relfilenode. If it's a