Introduce TupleHashTableHash() and LookupTupleHashEntryHash().
authorJeff Davis <jdavis@postgresql.org>
Fri, 7 Feb 2020 03:39:47 +0000 (19:39 -0800)
committerJeff Davis <jdavis@postgresql.org>
Fri, 7 Feb 2020 04:34:01 +0000 (20:34 -0800)
Expose two new entry points: one for only calculating the hash value
of a tuple, and another for looking up a hash entry when the hash
value is already known. This will be useful for disk-based Hash
Aggregation to avoid recomputing the hash value for the same tuple
after saving and restoring it from disk.

Discussion: https://postgr.es/m/37091115219dd522fd9ed67333ee8ed1b7e09443.camel%40j-davis.com

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

index 3603c58b63ec63f459331cdec20921450a831fd7..f0737fecca8acb479f2d371b2300a6c0b384d2a7 100644 (file)
@@ -25,8 +25,9 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 
-static uint32 TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple);
 static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2);
+static TupleHashEntry LookupTupleHashEntry_internal(
+   TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash);
 
 /*
  * Define parameters for tuple hash table code generation. The interface is
@@ -300,10 +301,9 @@ TupleHashEntry
 LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
                     bool *isnew)
 {
-   TupleHashEntryData *entry;
-   MemoryContext oldContext;
-   bool        found;
-   MinimalTuple key;
+   TupleHashEntry  entry;
+   MemoryContext   oldContext;
+   uint32          hash;
 
    /* Need to run the hash functions in short-lived context */
    oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
@@ -313,32 +313,34 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
    hashtable->in_hash_funcs = hashtable->tab_hash_funcs;
    hashtable->cur_eq_func = hashtable->tab_eq_func;
 
-   key = NULL;                 /* flag to reference inputslot */
+   hash = TupleHashTableHash(hashtable->hashtab, NULL);
+   entry = LookupTupleHashEntry_internal(hashtable, slot, isnew, hash);
 
-   if (isnew)
-   {
-       entry = tuplehash_insert(hashtable->hashtab, key, &found);
+   MemoryContextSwitchTo(oldContext);
 
-       if (found)
-       {
-           /* found pre-existing entry */
-           *isnew = false;
-       }
-       else
-       {
-           /* created new entry */
-           *isnew = true;
-           /* zero caller data */
-           entry->additional = NULL;
-           MemoryContextSwitchTo(hashtable->tablecxt);
-           /* Copy the first tuple into the table context */
-           entry->firstTuple = ExecCopySlotMinimalTuple(slot);
-       }
-   }
-   else
-   {
-       entry = tuplehash_lookup(hashtable->hashtab, key);
-   }
+   return entry;
+}
+
+/*
+ * A variant of LookupTupleHashEntry for callers that have already computed
+ * the hash value.
+ */
+TupleHashEntry
+LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot,
+                        bool *isnew, uint32 hash)
+{
+   TupleHashEntry  entry;
+   MemoryContext   oldContext;
+
+   /* Need to run the hash functions in short-lived context */
+   oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
+
+   /* set up data needed by hash and match functions */
+   hashtable->inputslot = slot;
+   hashtable->in_hash_funcs = hashtable->tab_hash_funcs;
+   hashtable->cur_eq_func = hashtable->tab_eq_func;
+
+   entry = LookupTupleHashEntry_internal(hashtable, slot, isnew, hash);
 
    MemoryContextSwitchTo(oldContext);
 
@@ -389,7 +391,7 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
  * Also, the caller must select an appropriate memory context for running
  * the hash functions. (dynahash.c doesn't change CurrentMemoryContext.)
  */
-static uint32
+uint32
 TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple)
 {
    TupleHashTable hashtable = (TupleHashTable) tb->private_data;
@@ -450,6 +452,52 @@ TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple)
    return murmurhash32(hashkey);
 }
 
+/*
+ * Does the work of LookupTupleHashEntry and LookupTupleHashEntryHash. Useful
+ * so that we can avoid switching the memory context multiple times for
+ * LookupTupleHashEntry.
+ *
+ * NB: This function may or may not change the memory context. Caller is
+ * expected to change it back.
+ */
+static TupleHashEntry
+LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot,
+                             bool *isnew, uint32 hash)
+{
+   TupleHashEntryData *entry;
+   bool        found;
+   MinimalTuple key;
+
+   key = NULL;                 /* flag to reference inputslot */
+
+   if (isnew)
+   {
+       entry = tuplehash_insert_hash(hashtable->hashtab, key, hash, &found);
+
+       if (found)
+       {
+           /* found pre-existing entry */
+           *isnew = false;
+       }
+       else
+       {
+           /* created new entry */
+           *isnew = true;
+           /* zero caller data */
+           entry->additional = NULL;
+           MemoryContextSwitchTo(hashtable->tablecxt);
+           /* Copy the first tuple into the table context */
+           entry->firstTuple = ExecCopySlotMinimalTuple(slot);
+       }
+   }
+   else
+   {
+       entry = tuplehash_lookup_hash(hashtable->hashtab, key, hash);
+   }
+
+   return entry;
+}
+
 /*
  * See whether two tuples (presumably of the same hash value) match
  */
index 6ef3e1fe0691e5df6f60d073d2e31699ebef5adc..e49cb11046150feebd573364293fb9bd541c2f1f 100644 (file)
@@ -140,6 +140,11 @@ extern TupleHashTable BuildTupleHashTableExt(PlanState *parent,
 extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
                                           TupleTableSlot *slot,
                                           bool *isnew);
+extern uint32 TupleHashTableHash(struct tuplehash_hash *tb,
+                                const MinimalTuple tuple);
+extern TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable,
+                                              TupleTableSlot *slot,
+                                              bool *isnew, uint32 hash);
 extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
                                         TupleTableSlot *slot,
                                         ExprState *eqcomp,