]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Create accessor functions for TupleHashEntry.
authorJeff Davis <jdavis@postgresql.org>
Tue, 25 Mar 2025 05:05:41 +0000 (22:05 -0700)
committerJeff Davis <jdavis@postgresql.org>
Tue, 25 Mar 2025 05:05:41 +0000 (22:05 -0700)
Refactor for upcoming optimizations.

Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/1cc3b400a0e8eead18ff967436fa9e42c0c14cfb.camel@j-davis.com

src/backend/executor/execGrouping.c
src/backend/executor/nodeAgg.c
src/backend/executor/nodeSetOp.c
src/backend/executor/nodeSubplan.c
src/include/executor/executor.h
src/include/nodes/execnodes.h

index 33b124fbb0a5014c451a83ef27325775d18c0b9d..a9d212aaec60cbf83a3a3618b5cffc6396c24cc3 100644 (file)
@@ -174,13 +174,15 @@ BuildTupleHashTable(PlanState *parent,
                                        bool use_variable_hash_iv)
 {
        TupleHashTable hashtable;
-       Size            entrysize = sizeof(TupleHashEntryData) + additionalsize;
+       Size            entrysize;
        Size            hash_mem_limit;
        MemoryContext oldcontext;
        bool            allow_jit;
        uint32          hash_iv = 0;
 
        Assert(nbuckets > 0);
+       additionalsize = MAXALIGN(additionalsize);
+       entrysize = sizeof(TupleHashEntryData) + additionalsize;
 
        /* Limit initial table size request to not more than hash_mem */
        hash_mem_limit = get_hash_memory_limit() / entrysize;
@@ -196,6 +198,7 @@ BuildTupleHashTable(PlanState *parent,
        hashtable->tab_collations = collations;
        hashtable->tablecxt = tablecxt;
        hashtable->tempcxt = tempcxt;
+       hashtable->additionalsize = additionalsize;
        hashtable->tableslot = NULL;    /* will be made on first lookup */
        hashtable->inputslot = NULL;
        hashtable->in_hash_expr = NULL;
@@ -479,11 +482,14 @@ LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot,
                {
                        /* 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);
+                       if (hashtable->additionalsize > 0)
+                               entry->additional = palloc0(hashtable->additionalsize);
+                       else
+                               entry->additional = NULL;
                }
        }
        else
index beccbfdc6fe5fe755ef9ab886d3d91c72d304e7d..f83fc16c5c8e2906146b8f77965ce059bfdbcd95 100644 (file)
@@ -1491,7 +1491,7 @@ build_hash_tables(AggState *aggstate)
 #ifdef USE_INJECTION_POINTS
                if (IS_INJECTION_POINT_ATTACHED("hash-aggregate-oversize-table"))
                {
-                       nbuckets = memory / sizeof(TupleHashEntryData);
+                       nbuckets = memory / TupleHashEntrySize();
                        INJECTION_POINT_CACHED("hash-aggregate-oversize-table");
                }
 #endif
@@ -1724,7 +1724,7 @@ hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
                transitionChunkSize = 0;
 
        return
-               sizeof(TupleHashEntryData) +
+               TupleHashEntrySize() +
                tupleChunkSize +
                pergroupChunkSize +
                transitionChunkSize;
@@ -1988,7 +1988,7 @@ hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
        if (aggstate->hash_ngroups_current > 0)
        {
                aggstate->hashentrysize =
-                       sizeof(TupleHashEntryData) +
+                       TupleHashEntrySize() +
                        (hashkey_mem / (double) aggstate->hash_ngroups_current);
        }
 }
@@ -2147,11 +2147,7 @@ initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable,
        if (aggstate->numtrans == 0)
                return;
 
-       pergroup = (AggStatePerGroup)
-               MemoryContextAlloc(hashtable->tablecxt,
-                                                  sizeof(AggStatePerGroupData) * aggstate->numtrans);
-
-       entry->additional = pergroup;
+       pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(hashtable, entry);
 
        /*
         * Initialize aggregates for new tuple group, lookup_hash_entries()
@@ -2213,7 +2209,7 @@ lookup_hash_entries(AggState *aggstate)
                {
                        if (isnew)
                                initialize_hash_entry(aggstate, hashtable, entry);
-                       pergroup[setno] = entry->additional;
+                       pergroup[setno] = TupleHashEntryGetAdditional(hashtable, entry);
                }
                else
                {
@@ -2748,6 +2744,7 @@ agg_refill_hash_table(AggState *aggstate)
        {
                TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
                TupleTableSlot *hashslot = perhash->hashslot;
+               TupleHashTable hashtable = perhash->hashtable;
                TupleHashEntry entry;
                MinimalTuple tuple;
                uint32          hash;
@@ -2766,14 +2763,14 @@ agg_refill_hash_table(AggState *aggstate)
                prepare_hash_slot(perhash,
                                                  aggstate->tmpcontext->ecxt_outertuple,
                                                  hashslot);
-               entry = LookupTupleHashEntryHash(perhash->hashtable, hashslot,
+               entry = LookupTupleHashEntryHash(hashtable, hashslot,
                                                                                 p_isnew, hash);
 
                if (entry != NULL)
                {
                        if (isnew)
-                               initialize_hash_entry(aggstate, perhash->hashtable, entry);
-                       aggstate->hash_pergroup[batch->setno] = entry->additional;
+                               initialize_hash_entry(aggstate, hashtable, entry);
+                       aggstate->hash_pergroup[batch->setno] = TupleHashEntryGetAdditional(hashtable, entry);
                        advance_aggregates(aggstate);
                }
                else
@@ -2865,7 +2862,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
        ExprContext *econtext;
        AggStatePerAgg peragg;
        AggStatePerGroup pergroup;
-       TupleHashEntryData *entry;
+       TupleHashEntry entry;
        TupleTableSlot *firstSlot;
        TupleTableSlot *result;
        AggStatePerHash perhash;
@@ -2892,6 +2889,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
        for (;;)
        {
                TupleTableSlot *hashslot = perhash->hashslot;
+               TupleHashTable hashtable = perhash->hashtable;
                int                     i;
 
                CHECK_FOR_INTERRUPTS();
@@ -2899,7 +2897,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
                /*
                 * Find the next entry in the hash table
                 */
-               entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
+               entry = ScanTupleHashTable(hashtable, &perhash->hashiter);
                if (entry == NULL)
                {
                        int                     nextset = aggstate->current_set + 1;
@@ -2914,7 +2912,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
 
                                perhash = &aggstate->perhash[aggstate->current_set];
 
-                               ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
+                               ResetTupleHashIterator(hashtable, &perhash->hashiter);
 
                                continue;
                        }
@@ -2937,7 +2935,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
                 * Transform representative tuple back into one with the right
                 * columns.
                 */
-               ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
+               ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashslot, false);
                slot_getallattrs(hashslot);
 
                ExecClearTuple(firstSlot);
@@ -2953,7 +2951,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
                }
                ExecStoreVirtualTuple(firstSlot);
 
-               pergroup = (AggStatePerGroup) entry->additional;
+               pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(hashtable, entry);
 
                /*
                 * Use the representative input tuple for any references to
index 5b7ff9c374850db6ab451252bbada724a39d39bc..4068481a52392a37b924423334bba8824312667e 100644 (file)
@@ -424,7 +424,9 @@ setop_fill_hash_table(SetOpState *setopstate)
        for (;;)
        {
                TupleTableSlot *outerslot;
+               TupleHashTable hashtable = setopstate->hashtable;
                TupleHashEntryData *entry;
+               SetOpStatePerGroup pergroup;
                bool            isnew;
 
                outerslot = ExecProcNode(outerPlan);
@@ -433,20 +435,20 @@ setop_fill_hash_table(SetOpState *setopstate)
                have_tuples = true;
 
                /* Find or build hashtable entry for this tuple's group */
-               entry = LookupTupleHashEntry(setopstate->hashtable,
+               entry = LookupTupleHashEntry(hashtable,
                                                                         outerslot,
                                                                         &isnew, NULL);
 
+               pergroup = TupleHashEntryGetAdditional(hashtable, entry);
                /* If new tuple group, initialize counts to zero */
                if (isnew)
                {
-                       entry->additional = (SetOpStatePerGroup)
-                               MemoryContextAllocZero(setopstate->hashtable->tablecxt,
-                                                                          sizeof(SetOpStatePerGroupData));
+                       pergroup->numLeft = 0;
+                       pergroup->numRight = 0;
                }
 
                /* Advance the counts */
-               ((SetOpStatePerGroup) entry->additional)->numLeft++;
+               pergroup->numLeft++;
 
                /* Must reset expression context after each hashtable lookup */
                ResetExprContext(econtext);
@@ -465,6 +467,7 @@ setop_fill_hash_table(SetOpState *setopstate)
                for (;;)
                {
                        TupleTableSlot *innerslot;
+                       TupleHashTable hashtable = setopstate->hashtable;
                        TupleHashEntryData *entry;
 
                        innerslot = ExecProcNode(innerPlan);
@@ -472,13 +475,17 @@ setop_fill_hash_table(SetOpState *setopstate)
                                break;
 
                        /* For tuples not seen previously, do not make hashtable entry */
-                       entry = LookupTupleHashEntry(setopstate->hashtable,
+                       entry = LookupTupleHashEntry(hashtable,
                                                                                 innerslot,
                                                                                 NULL, NULL);
 
                        /* Advance the counts if entry is already present */
                        if (entry)
-                               ((SetOpStatePerGroup) entry->additional)->numRight++;
+                       {
+                               SetOpStatePerGroup pergroup = TupleHashEntryGetAdditional(hashtable, entry);
+
+                               pergroup->numRight++;
+                       }
 
                        /* Must reset expression context after each hashtable lookup */
                        ResetExprContext(econtext);
@@ -496,7 +503,7 @@ setop_fill_hash_table(SetOpState *setopstate)
 static TupleTableSlot *
 setop_retrieve_hash_table(SetOpState *setopstate)
 {
-       TupleHashEntryData *entry;
+       TupleHashEntry entry;
        TupleTableSlot *resultTupleSlot;
 
        /*
@@ -509,12 +516,15 @@ setop_retrieve_hash_table(SetOpState *setopstate)
         */
        while (!setopstate->setop_done)
        {
+               TupleHashTable hashtable = setopstate->hashtable;
+               SetOpStatePerGroup pergroup;
+
                CHECK_FOR_INTERRUPTS();
 
                /*
                 * Find the next entry in the hash table
                 */
-               entry = ScanTupleHashTable(setopstate->hashtable, &setopstate->hashiter);
+               entry = ScanTupleHashTable(hashtable, &setopstate->hashiter);
                if (entry == NULL)
                {
                        /* No more entries in hashtable, so done */
@@ -526,12 +536,13 @@ setop_retrieve_hash_table(SetOpState *setopstate)
                 * See if we should emit any copies of this tuple, and if so return
                 * the first copy.
                 */
-               set_output_count(setopstate, (SetOpStatePerGroup) entry->additional);
+               pergroup = TupleHashEntryGetAdditional(hashtable, entry);
+               set_output_count(setopstate, pergroup);
 
                if (setopstate->numOutput > 0)
                {
                        setopstate->numOutput--;
-                       return ExecStoreMinimalTuple(entry->firstTuple,
+                       return ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry),
                                                                                 resultTupleSlot,
                                                                                 false);
                }
index 49767ed6a52af813cb4efb72f65ad33a4f842d29..f7f6fc2da0b95b48f7159fb976505dd00d6d76d0 100644 (file)
@@ -753,7 +753,7 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
        {
                CHECK_FOR_INTERRUPTS();
 
-               ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
+               ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashtable->tableslot, false);
                if (!execTuplesUnequal(slot, hashtable->tableslot,
                                                           numCols, keyColIdx,
                                                           eqfunctions,
index 0db5d18ba2232b1ea1bef50eefb01c4239a3762a..69396a9d7f8952b15f078432e64ec5f3ff565c4c 100644 (file)
@@ -158,6 +158,40 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
                                                                                 ExprState *hashexpr);
 extern void ResetTupleHashTable(TupleHashTable hashtable);
 
+#ifndef FRONTEND
+/*
+ * Return size of the hash bucket. Useful for estimating memory usage.
+ */
+static inline size_t
+TupleHashEntrySize(void)
+{
+       return sizeof(TupleHashEntryData);
+}
+
+/*
+ * Return tuple from hash entry.
+ */
+static inline MinimalTuple
+TupleHashEntryGetTuple(TupleHashEntry entry)
+{
+       return entry->firstTuple;
+}
+
+/*
+ * Get a pointer into the additional space allocated for this entry. The
+ * memory will be maxaligned and zeroed.
+ *
+ * The amount of space available is the additionalsize requested in the call
+ * to BuildTupleHashTable(). If additionalsize was specified as zero, return
+ * NULL.
+ */
+static inline void *
+TupleHashEntryGetAdditional(TupleHashTable hashtable, TupleHashEntry entry)
+{
+       return entry->additional;
+}
+#endif
+
 /*
  * prototypes from functions in execJunk.c
  */
index b5539ddb41ee6d9d7285d847f90fb2e06e9e5a43..7df25d7e64f13cd5ebf8b3fe6b0f0852537e9a6d 100644 (file)
@@ -863,6 +863,7 @@ typedef struct TupleHashTableData
        Oid                *tab_collations; /* collations for hash and comparison */
        MemoryContext tablecxt;         /* memory context containing table */
        MemoryContext tempcxt;          /* context for function evaluations */
+       Size            additionalsize; /* size of additional data */
        TupleTableSlot *tableslot;      /* slot for referencing table entries */
        /* The following fields are set transiently for each table search: */
        TupleTableSlot *inputslot;      /* current input tuple's slot */