diff options
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 66 |
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 |