dont_destroy_original_partdesc_on_rel_inval.patch
application/octet-stream
Filename: dont_destroy_original_partdesc_on_rel_inval.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/utils/cache/relcache.c | 41 | 1 |
| src/include/utils/rel.h | 6 | 0 |
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index feca620cff..a25ead01d4 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1202,6 +1202,9 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
relation->rd_pdcxt = NULL;
}
+ relation->rd_partdesc_orig = NULL;
+ relation->rd_pdcxt_orig = NULL;
+
/*
* if it's an index, initialize index-related information
*/
@@ -2012,6 +2015,20 @@ RelationClose(Relation relation)
/* Note: no locking manipulations needed */
RelationDecrementReferenceCount(relation);
+ /*
+ * If the partdesc has been changed while the relation had a non-zero
+ * ref count we'll have stored the original partdesc. When the ref
+ * count reaches 0 we must get rid of the original partdesc and destroy
+ * the memory context it was stored in.
+ */
+ if (relation->rd_partdesc_orig &&
+ RelationHasReferenceCountZero(relation))
+ {
+ MemoryContextDelete(relation->rd_pdcxt_orig);
+ relation->rd_partdesc_orig = NULL;
+ relation->rd_pdcxt_orig = NULL;
+ }
+
#ifdef RELCACHE_FORCE_RELEASE
if (RelationHasReferenceCountZero(relation) &&
relation->rd_createSubid == InvalidSubTransactionId &&
@@ -2288,7 +2305,7 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
MemoryContextDelete(relation->rd_rsdesc->rscxt);
if (relation->rd_partkeycxt)
MemoryContextDelete(relation->rd_partkeycxt);
- if (relation->rd_pdcxt)
+ if (relation->rd_pdcxt && !relation->rd_pdcxt_orig)
MemoryContextDelete(relation->rd_pdcxt);
if (relation->rd_partcheck)
pfree(relation->rd_partcheck);
@@ -2546,6 +2563,27 @@ RelationClearRelation(Relation relation, bool rebuild)
SWAPFIELD(MemoryContext, rd_pdcxt);
}
+ /*
+ * When the partdesc changes while the refcount is > 0 then we must
+ * keep the original partdesc intact as it might currently be getting
+ * used by some code. We store the original partdesc in
+ * rd_partdesc_orig. If it changes multiple times we don't need to
+ * keep the intermediate ones, just the original. This gets cleared
+ * up and set to NULL again when the ref count reaches 0.
+ */
+ else if (relation->rd_partdesc != NULL && newrel->rd_partdesc != NULL &&
+ relation->rd_partdesc_orig == NULL)
+ {
+ relation->rd_partdesc_orig = newrel->rd_partdesc;
+ relation->rd_pdcxt_orig = newrel->rd_pdcxt;
+
+ /*
+ * Set this so that RelationDestroyRelation does not destroy the
+ * memory context of the original partdesc.
+ */
+ newrel->rd_pdcxt_orig = newrel->rd_pdcxt;
+ }
+
#undef SWAPFIELD
/* And now we can throw away the temporary entry */
@@ -5652,6 +5690,8 @@ load_relcache_init_file(bool shared)
rel->rd_partkey = NULL;
rel->rd_pdcxt = NULL;
rel->rd_partdesc = NULL;
+ rel->rd_pdcxt_orig = NULL;
+ rel->rd_partdesc_orig = NULL;
rel->rd_partcheck = NIL;
rel->rd_indexprs = NIL;
rel->rd_indpred = NIL;
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index eb1858aa92..7724d8da15 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -99,6 +99,12 @@ typedef struct RelationData
struct PartitionKeyData *rd_partkey; /* partition key, or NULL */
MemoryContext rd_pdcxt; /* private context for partdesc */
struct PartitionDescData *rd_partdesc; /* partitions, or NULL */
+ MemoryContext rd_pdcxt_orig; /* private context for rd_partdesc_orig */
+ struct PartitionDescData *rd_partdesc_orig; /* original partitions, or
+ * NULL if not partitioned or
+ * the rd_partdesc has not
+ * changed while the ref count
+ * was non-zero */
List *rd_partcheck; /* partition CHECK quals */
/* data managed by RelationGetIndexList: */