Allow to reset execGrouping.c style tuple hashtables.
authorAndres Freund <andres@anarazel.de>
Sat, 9 Feb 2019 08:35:57 +0000 (00:35 -0800)
committerAndres Freund <andres@anarazel.de>
Sat, 9 Feb 2019 09:05:49 +0000 (01:05 -0800)
This has the advantage that the comparator expression, the table's
slot, etc do not have to be rebuilt. Additionally the simplehash.h
hashtable within the tuple hashtable now keeps its previous size and
doesn't need to be reallocated. That both reduces allocator overhead,
and improves performance in cases where the input estimation was off
by a significant factor.

To avoid an API/ABI break, the new parameter is exposed via the new
BuildTupleHashTableExt(), and BuildTupleHashTable() now is a wrapper
around the former, that continues to allocate the table itself in the
tablecxt.

Using this fixes performance issues discovered in the two bugs
referenced. This commit however has not converted the callers, that's
done in a separate commit.

Bug: #15592 #15486
Reported-By: Jakub Janeček, Dmitry Marakasov
Author: Andres Freund
Discussion:
    https://postgr.es/m/15486-05850f065da42931@postgresql.org
    https://postgr.es/m/20190114180423.ywhdg2iagzvh43we@alap3.anarazel.de
Backpatch: 11, this is a prerequisite for other fixes

src/backend/executor/execGrouping.c
src/include/executor/executor.h

index 7cf001518a14cf6cc2b720f18c2b240553ffd7a0..a9d80e692b5913bc1f5d0b7289fe22efa6025c64 100644 (file)
@@ -139,7 +139,8 @@ execTuplesHashPrepare(int numCols,
  * hashfunctions: datatype-specific hashing functions to use
  * nbuckets: initial estimate of hashtable size
  * additionalsize: size of data stored in ->additional
- * tablecxt: memory context in which to store table and table entries
+ * metacxt: memory context for long-lived allocation, but not per-entry data
+ * tablecxt: memory context in which to store table entries
  * tempcxt: short-lived context for evaluation hash and comparison functions
  *
  * The function arrays may be made with execTuplesHashPrepare().  Note they
@@ -150,14 +151,16 @@ execTuplesHashPrepare(int numCols,
  * storage that will live as long as the hashtable does.
  */
 TupleHashTable
-BuildTupleHashTable(PlanState *parent,
-                   TupleDesc inputDesc,
-                   int numCols, AttrNumber *keyColIdx,
-                   const Oid *eqfuncoids,
-                   FmgrInfo *hashfunctions,
-                   long nbuckets, Size additionalsize,
-                   MemoryContext tablecxt, MemoryContext tempcxt,
-                   bool use_variable_hash_iv)
+BuildTupleHashTableExt(PlanState *parent,
+                      TupleDesc inputDesc,
+                      int numCols, AttrNumber *keyColIdx,
+                      const Oid *eqfuncoids,
+                      FmgrInfo *hashfunctions,
+                      long nbuckets, Size additionalsize,
+                      MemoryContext metacxt,
+                      MemoryContext tablecxt,
+                      MemoryContext tempcxt,
+                      bool use_variable_hash_iv)
 {
    TupleHashTable hashtable;
    Size        entrysize = sizeof(TupleHashEntryData) + additionalsize;
@@ -168,8 +171,9 @@ BuildTupleHashTable(PlanState *parent,
    /* Limit initial table size request to not more than work_mem */
    nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize));
 
-   hashtable = (TupleHashTable)
-       MemoryContextAlloc(tablecxt, sizeof(TupleHashTableData));
+   oldcontext = MemoryContextSwitchTo(metacxt);
+
+   hashtable = (TupleHashTable) palloc(sizeof(TupleHashTableData));
 
    hashtable->numCols = numCols;
    hashtable->keyColIdx = keyColIdx;
@@ -195,9 +199,7 @@ BuildTupleHashTable(PlanState *parent,
    else
        hashtable->hash_iv = 0;
 
-   hashtable->hashtab = tuplehash_create(tablecxt, nbuckets, hashtable);
-
-   oldcontext = MemoryContextSwitchTo(hashtable->tablecxt);
+   hashtable->hashtab = tuplehash_create(metacxt, nbuckets, hashtable);
 
    /*
     * We copy the input tuple descriptor just for safety --- we assume all
@@ -227,6 +229,46 @@ BuildTupleHashTable(PlanState *parent,
    return hashtable;
 }
 
+/*
+ * BuildTupleHashTable is a backwards-compatibilty wrapper for
+ * BuildTupleHashTableExt(), that allocates the hashtable's metadata in
+ * tablecxt. Note that hashtables created this way cannot be reset leak-free
+ * with ResetTupleHashTable().
+ */
+TupleHashTable
+BuildTupleHashTable(PlanState *parent,
+                   TupleDesc inputDesc,
+                   int numCols, AttrNumber *keyColIdx,
+                   const Oid *eqfuncoids,
+                   FmgrInfo *hashfunctions,
+                   long nbuckets, Size additionalsize,
+                   MemoryContext tablecxt,
+                   MemoryContext tempcxt,
+                   bool use_variable_hash_iv)
+{
+   return BuildTupleHashTableExt(parent,
+                                 inputDesc,
+                                 numCols, keyColIdx,
+                                 eqfuncoids,
+                                 hashfunctions,
+                                 nbuckets, additionalsize,
+                                 tablecxt,
+                                 tablecxt,
+                                 tempcxt,
+                                 use_variable_hash_iv);
+}
+
+/*
+ * Reset contents of the hashtable to be empty, preserving all the non-content
+ * state. Note that the tablecxt passed to BuildTupleHashTableExt() should
+ * also be reset, otherwise there will be leaks.
+ */
+void
+ResetTupleHashTable(TupleHashTable hashtable)
+{
+   tuplehash_reset(hashtable->hashtab);
+}
+
 /*
  * Find or create a hashtable entry for the tuple group containing the
  * given tuple.  The tuple must be the same type as the hashtable entries.
index 537fe5cef0946872d6e6055c8d0341f5c76d4c6e..7a63e9a7cc370bae0c4b333768418558bcde14fc 100644 (file)
@@ -124,6 +124,15 @@ extern TupleHashTable BuildTupleHashTable(PlanState *parent,
                    long nbuckets, Size additionalsize,
                    MemoryContext tablecxt,
                    MemoryContext tempcxt, bool use_variable_hash_iv);
+extern TupleHashTable BuildTupleHashTableExt(PlanState *parent,
+                   TupleDesc inputDesc,
+                   int numCols, AttrNumber *keyColIdx,
+                   const Oid *eqfuncoids,
+                   FmgrInfo *hashfunctions,
+                   long nbuckets, Size additionalsize,
+                   MemoryContext metacxt,
+                   MemoryContext tablecxt,
+                   MemoryContext tempcxt, bool use_variable_hash_iv);
 extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
                     TupleTableSlot *slot,
                     bool *isnew);
@@ -131,6 +140,7 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
                   TupleTableSlot *slot,
                   ExprState *eqcomp,
                   FmgrInfo *hashfunctions);
+extern void ResetTupleHashTable(TupleHashTable hashtable);
 
 /*
  * prototypes from functions in execJunk.c