diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2b992d7832..4fb6ec60d4 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1179,6 +1179,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) relation->rd_partkeycxt = NULL; relation->rd_partdesc = NULL; relation->rd_pdcxt = NULL; + relation->rd_pdoldcxt = NULL; } /* ... but partcheck is not loaded till asked for */ relation->rd_partcheck = NIL; @@ -2073,6 +2074,11 @@ RelationDecrementReferenceCount(Relation rel) rel->rd_refcnt -= 1; if (!IsBootstrapProcessingMode()) ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel); + if (rel->rd_refcnt == 0 && rel->rd_pdoldcxt != NULL) + { + MemoryContextDelete(rel->rd_pdoldcxt); + rel->rd_pdoldcxt = NULL; + } } /* @@ -2368,6 +2374,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) MemoryContextDelete(relation->rd_partkeycxt); if (relation->rd_pdcxt) MemoryContextDelete(relation->rd_pdcxt); + if (relation->rd_pdoldcxt) + MemoryContextDelete(relation->rd_pdoldcxt); if (relation->rd_partcheckcxt) MemoryContextDelete(relation->rd_partcheckcxt); if (relation->rd_fdwroutine) @@ -2622,6 +2630,7 @@ RelationClearRelation(Relation relation, bool rebuild) { SWAPFIELD(PartitionDesc, rd_partdesc); SWAPFIELD(MemoryContext, rd_pdcxt); + SWAPFIELD(MemoryContext, rd_pdoldcxt); } else if (rebuild && newrel->rd_pdcxt != NULL) { @@ -2629,17 +2638,25 @@ RelationClearRelation(Relation relation, bool rebuild) * We are rebuilding a partitioned relation with a non-zero * reference count, so keep the old partition descriptor around, * in case there's a PartitionDirectory with a pointer to it. - * Attach it to the new rd_pdcxt so that it gets cleaned up - * eventually. In the case where the reference count is 0, this - * code is not reached, which should be OK because in that case - * there should be no PartitionDirectory with a pointer to the old - * entry. + * In the case where the reference count is 0, this code is not + * reached, which should be OK because in that case there should be + * no PartitionDirectory with a pointer to the old entry. + * + * To avoid leaking memory, we've got to make sure that the next + * time rd_pdoldcxt is destroyed, the old context will be freed. + * If rd_pdoldcxt is NULL, we can just make it point to the + * old descriptor's context; otherwise, we make this context of + * the previous one. * * Note that newrel and relation have already been swapped, so the * "old" partition descriptor is actually the one hanging off of * newrel. */ - MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt); + if (relation->rd_pdoldcxt == NULL) + relation->rd_pdoldcxt = newrel->rd_pdcxt; + else + MemoryContextSetParent(newrel->rd_pdcxt, + relation->rd_pdoldcxt); newrel->rd_partdesc = NULL; newrel->rd_pdcxt = NULL; } @@ -5580,6 +5597,7 @@ load_relcache_init_file(bool shared) rel->rd_partkeycxt = NULL; rel->rd_partdesc = NULL; rel->rd_pdcxt = NULL; + rel->rd_pdoldcxt = NULL; rel->rd_partcheck = NIL; rel->rd_partcheckvalid = false; rel->rd_partcheckcxt = NULL; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index d7f33abce3..09abcdf030 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -99,6 +99,7 @@ typedef struct RelationData MemoryContext rd_partkeycxt; /* private context for rd_partkey, if any */ struct PartitionDescData *rd_partdesc; /* partitions, or NULL */ MemoryContext rd_pdcxt; /* private context for rd_partdesc, if any */ + MemoryContext rd_pdoldcxt; /* context for older PartitionDescs, if any */ List *rd_partcheck; /* partition CHECK quals */ bool rd_partcheckvalid; /* true if list has been computed */ MemoryContext rd_partcheckcxt; /* private cxt for rd_partcheck, if any */