summaryrefslogtreecommitdiff
path: root/src/backend/partitioning
diff options
context:
space:
mode:
authorTom Lane2019-04-13 17:22:26 +0000
committerTom Lane2019-04-13 17:22:26 +0000
commit5f1433ac5e7f943b29ef01266b6b8fc915e6b917 (patch)
tree748d40ab1b1ca5508b9250bdac695932a15dc0a3 /src/backend/partitioning
parentc098509927f9a49ebceb301a2cb6a477ecd4ac3c (diff)
Prevent memory leaks associated with relcache rd_partcheck structures.
The original coding of generate_partition_qual() just copied the list of predicate expressions into the global CacheMemoryContext, making it effectively impossible to clean up when the owning relcache entry is destroyed --- the relevant code in RelationDestroyRelation() only managed to free the topmost List header :-(. This resulted in a session-lifespan memory leak whenever a table partition's relcache entry is rebuilt. Fortunately, that's not normally a large data structure, and rebuilds shouldn't occur all that often in production situations; but this is still a bug worth fixing back to v10 where the code was introduced. To fix, put the cached expression tree into its own small memory context, as we do with other complicated substructures of relcache entries. Also, deal more honestly with the case that a partition has an empty partcheck list; while that probably isn't a case that's very interesting for production use, it's legal. In passing, clarify comments about how partitioning-related relcache data structures are managed, and add some Asserts that we're not leaking old copies when we overwrite these data fields. Amit Langote and Tom Lane Discussion: https://postgr.es/m/7961.1552498252@sss.pgh.pa.us
Diffstat (limited to 'src/backend/partitioning')
-rw-r--r--src/backend/partitioning/partdesc.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index e436d1ed345..4d6595b2497 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -49,10 +49,13 @@ typedef struct PartitionDirectoryEntry
/*
* RelationBuildPartitionDesc
- * Form rel's partition descriptor
+ * Form rel's partition descriptor, and store in relcache entry
*
- * Not flushed from the cache by RelationClearRelation() unless changed because
- * of addition or removal of partition.
+ * Note: the descriptor won't be flushed from the cache by
+ * RelationClearRelation() unless it's changed because of
+ * addition or removal of a partition. Hence, code holding a lock
+ * that's sufficient to prevent that can assume that rd_partdesc
+ * won't change underneath it.
*/
void
RelationBuildPartitionDesc(Relation rel)
@@ -173,7 +176,19 @@ RelationBuildPartitionDesc(Relation rel)
++i;
}
- /* Now build the actual relcache partition descriptor */
+ /* Assert we aren't about to leak any old data structure */
+ Assert(rel->rd_pdcxt == NULL);
+ Assert(rel->rd_partdesc == NULL);
+
+ /*
+ * Now build the actual relcache partition descriptor. Note that the
+ * order of operations here is fairly critical. If we fail partway
+ * through this code, we won't have leaked memory because the rd_pdcxt is
+ * attached to the relcache entry immediately, so it'll be freed whenever
+ * the entry is rebuilt or destroyed. However, we don't assign to
+ * rd_partdesc until the cached data structure is fully complete and
+ * valid, so that no other code might try to use it.
+ */
rel->rd_pdcxt = AllocSetContextCreate(CacheMemoryContext,
"partition descriptor",
ALLOCSET_SMALL_SIZES);