mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Flush Memoize cache when non-key parameters change
It's possible that a subplan below a Memoize node contains a parameter from above the Memoize node. If this parameter changes then cache entries may become out-dated due to the new parameter value. Previously Memoize was mistakenly not aware of this. We fix this here by flushing the cache whenever a parameter that's not part of the cache key changes. Bug: #17213 Reported by: Elvis Pranskevichus Author: David Rowley Discussion: https://postgr.es/m/17213-988ed34b225a2862@postgresql.org Backpatch-through: 14, where Memoize was added
This commit is contained in:
@ -367,6 +367,37 @@ remove_cache_entry(MemoizeState *mstate, MemoizeEntry *entry)
|
||||
pfree(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* cache_purge_all
|
||||
* Remove all items from the cache
|
||||
*/
|
||||
static void
|
||||
cache_purge_all(MemoizeState *mstate)
|
||||
{
|
||||
uint64 evictions = mstate->hashtable->members;
|
||||
PlanState *pstate = (PlanState *) mstate;
|
||||
|
||||
/*
|
||||
* Likely the most efficient way to remove all items is to just reset the
|
||||
* memory context for the cache and then rebuild a fresh hash table. This
|
||||
* saves having to remove each item one by one and pfree each cached tuple
|
||||
*/
|
||||
MemoryContextReset(mstate->tableContext);
|
||||
|
||||
/* Make the hash table the same size as the original size */
|
||||
build_hash_table(mstate, ((Memoize *) pstate->plan)->est_entries);
|
||||
|
||||
/* reset the LRU list */
|
||||
dlist_init(&mstate->lru_list);
|
||||
mstate->last_tuple = NULL;
|
||||
mstate->entry = NULL;
|
||||
|
||||
mstate->mem_used = 0;
|
||||
|
||||
/* XXX should we add something new to track these purges? */
|
||||
mstate->stats.cache_evictions += evictions; /* Update Stats */
|
||||
}
|
||||
|
||||
/*
|
||||
* cache_reduce_memory
|
||||
* Evict older and less recently used items from the cache in order to
|
||||
@ -979,6 +1010,7 @@ ExecInitMemoize(Memoize *node, EState *estate, int eflags)
|
||||
* getting the first tuple. This allows us to mark it as so.
|
||||
*/
|
||||
mstate->singlerow = node->singlerow;
|
||||
mstate->keyparamids = node->keyparamids;
|
||||
|
||||
/*
|
||||
* Record if the cache keys should be compared bit by bit, or logically
|
||||
@ -1082,6 +1114,12 @@ ExecReScanMemoize(MemoizeState *node)
|
||||
if (outerPlan->chgParam == NULL)
|
||||
ExecReScan(outerPlan);
|
||||
|
||||
/*
|
||||
* Purge the entire cache if a parameter changed that is not part of the
|
||||
* cache key.
|
||||
*/
|
||||
if (bms_nonempty_difference(outerPlan->chgParam, node->keyparamids))
|
||||
cache_purge_all(node);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user