Fix local plan cache growth for prepared statements - #8824
Fix local plan cache growth for prepared statements#8824Hamid Akhtar (hqakhtar) wants to merge 2 commits into
Conversation
PR #8371 made cache lookup reject plans whose task list did not contain exactly one task. Deferred-pruning plans keep the persistent plan's task list empty, so every execution missed the existing local plan and added another one. This caused unbounded memory growth. Separate cache eligibility from lookup. Use the current job for eligibility and the persistent distributed plan for cache storage. Keep the multi-shard reuse guard and allocate cache entries in the persistent plan's memory context. Add a regression helper that reads the generic plan's cache size. Verify that repeated single-shard executions retain one entry and a multi-shard execution does not add another.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8824 +/- ##
==========================================
- Coverage 88.73% 88.73% -0.01%
==========================================
Files 289 290 +1
Lines 65013 65072 +59
Branches 8203 8212 +9
==========================================
+ Hits 57691 57740 +49
- Misses 4954 4958 +4
- Partials 2368 2374 +6 🚀 New features to boost your workflow:
|
078d7dc to
0a10bdd
Compare
| { | ||
| PlannedStmt *localPlan = GetCachedLocalPlan(task, originalDistributedPlan); | ||
| if (localPlan != NULL) | ||
| Assert(planAddedToCache); |
There was a problem hiding this comment.
Do we ever consume planAddedToCache, or should this actually be?:
| Assert(planAddedToCache); | |
| Assert(*planAddedToCache); |
There was a problem hiding this comment.
The calling functions neither consume planAddedtoCache nor the return value of CacheLocalPlanForShardQuery function, however, from an API interface perspective, this seems to be a fair design where the relevant plan is return with an indicator if it was returned from cache or newly created.
| /* | ||
| * CacheLocalPlanForShardQuery replaces the relation OIDs in the job query | ||
| * with shard relation OIDs and then plans the query and caches the result | ||
| * in the originalDistributedPlan (which may be preserved across executions). |
There was a problem hiding this comment.
Consider updating the comment for this function - given that it now does eligibility checking, and returns either NULL when caching is not supported, or a plan when it is, and also returns whether or not a plan was added to the cache.
| DistributedPlan * | ||
| originalDistributedPlan, | ||
| ParamListInfo paramListInfo, | ||
| bool *planAddedToCached); |
There was a problem hiding this comment.
nit: planAddedToCached -> planAddedToCache
Copy the updated local plan cache to the per-execution plan after adding a new entry, avoiding redundant shard-query planning. Also clarify the cache function documentation and fix the planAddedToCache parameter name.
da87bec to
7b10b7a
Compare
PR #8371 made cache lookup reject plans whose task list did not contain exactly one task. Deferred-pruning plans keep the persistent plan's task list empty, so every execution missed the existing local plan and added another one. This caused unbounded memory growth.
Separate cache eligibility from lookup. Use the current job for eligibility and the persistent distributed plan for cache storage. Keep the multi-shard reuse guard and allocate cache entries in the persistent plan's memory context.
Add a regression helper that reads the generic plan's cache size. Verify that repeated single-shard executions retain one entry and a multi-shard execution does not add another.