1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

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:
Tom Lane
2018-03-16 16:03:45 -04:00
parent a9d0c862d5
commit 574386ddca

View File

@ -267,7 +267,8 @@ ExecHashTableCreate(Hash *node, 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;
@ -294,6 +295,26 @@ ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls)
hashtable->spaceAllowedSkew = hashtable->spaceAllowedSkew =
hashtable->spaceAllowed * SKEW_WORK_MEM_PERCENT / 100; hashtable->spaceAllowed * SKEW_WORK_MEM_PERCENT / 100;
/*
* 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_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
"HashBatchContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* 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.
@ -320,26 +341,6 @@ ExecHashTableCreate(Hash *node, 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_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
"HashBatchContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* Allocate data that will live for the life of the hashjoin */
oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
if (nbatch > 1) if (nbatch > 1)
{ {
/* /*