Fix query-lifespan memory leakage in repeatedly executed hash joins.
ExecHashTableCreate allocated some memory that wasn't freed by ExecHashTableDestroy, specifically the per-hash-key function information. That's not a huge amount of data, but if one runs a query that repeats a hash join enough times, it builds up. Fix by arranging for the data in question to be kept in the hashtable's hashCxt instead of leaving it "loose" in the query-lifespan executor context. (This ensures that we'll also clean up anything that the hash functions allocate in fn_mcxt.) Per report from Amit Khandekar. It's been like this forever, so back-patch to all supported branches. Discussion: https://postgr.es/m/CAJ3gD9cFofAWGvcxLOxDHC=B0hjtW8yGmUsF2hdGh97CM38=7g@mail.gmail.com
This commit is contained in:
parent
013c0baadd
commit
9e17bdb8a5
@ -472,7 +472,8 @@ ExecHashTableCreate(HashState *state, List *hashOperators, bool keepNulls)
|
|||||||
* Initialize the hash table control block.
|
* Initialize the hash table control block.
|
||||||
*
|
*
|
||||||
* The hashtable control block is just palloc'd from the executor's
|
* The hashtable control block is just palloc'd from the executor's
|
||||||
* per-query memory context.
|
* per-query memory context. Everything else should be kept inside the
|
||||||
|
* subsidiary hashCxt or batchCxt.
|
||||||
*/
|
*/
|
||||||
hashtable = (HashJoinTable) palloc(sizeof(HashJoinTableData));
|
hashtable = (HashJoinTable) palloc(sizeof(HashJoinTableData));
|
||||||
hashtable->nbuckets = nbuckets;
|
hashtable->nbuckets = nbuckets;
|
||||||
@ -514,6 +515,22 @@ ExecHashTableCreate(HashState *state, List *hashOperators, bool keepNulls)
|
|||||||
hashtable, nbatch, nbuckets);
|
hashtable, nbatch, nbuckets);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create temporary memory contexts in which to keep the hashtable working
|
||||||
|
* storage. See notes in executor/hashjoin.h.
|
||||||
|
*/
|
||||||
|
hashtable->hashCxt = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
|
"HashTableContext",
|
||||||
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
|
||||||
|
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
|
||||||
|
"HashBatchContext",
|
||||||
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
|
||||||
|
/* Allocate data that will live for the life of the hashjoin */
|
||||||
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get info about the hash functions to be used for each hash key. Also
|
* Get info about the hash functions to be used for each hash key. Also
|
||||||
* remember whether the join operators are strict.
|
* remember whether the join operators are strict.
|
||||||
@ -540,22 +557,6 @@ ExecHashTableCreate(HashState *state, List *hashOperators, bool keepNulls)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Create temporary memory contexts in which to keep the hashtable working
|
|
||||||
* storage. See notes in executor/hashjoin.h.
|
|
||||||
*/
|
|
||||||
hashtable->hashCxt = AllocSetContextCreate(CurrentMemoryContext,
|
|
||||||
"HashTableContext",
|
|
||||||
ALLOCSET_DEFAULT_SIZES);
|
|
||||||
|
|
||||||
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
|
|
||||||
"HashBatchContext",
|
|
||||||
ALLOCSET_DEFAULT_SIZES);
|
|
||||||
|
|
||||||
/* Allocate data that will live for the life of the hashjoin */
|
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
|
|
||||||
|
|
||||||
if (nbatch > 1 && hashtable->parallel_state == NULL)
|
if (nbatch > 1 && hashtable->parallel_state == NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user