v7-0002-Refactor-accessors-for-TupleHashEntryData.patch
text/x-patch
Filename: v7-0002-Refactor-accessors-for-TupleHashEntryData.patch
Type: text/x-patch
Part: 1
Patch
Format: format-patch
Series: patch v7-0002
Subject: Refactor: accessors for TupleHashEntryData.
| File | + | − |
|---|---|---|
| src/backend/executor/execGrouping.c | 5 | 2 |
| src/backend/executor/nodeAgg.c | 15 | 17 |
| src/backend/executor/nodeSetOp.c | 13 | 10 |
| src/backend/executor/nodeSubplan.c | 1 | 1 |
| src/include/executor/executor.h | 33 | 0 |
| src/include/nodes/execnodes.h | 1 | 0 |
From d76e51114cb4e50fd36905ffcb446652fa64a62c Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Mon, 13 Jan 2025 14:37:02 -0800
Subject: [PATCH v7 2/4] Refactor: accessors for TupleHashEntryData.
Previously, callers were accessing fields directly, making it more
difficult to optimize.
A subsequent patch will combine firstTuple and the additionalsize into
a single allocation.
Discussion: https://postgr.es/m/817d244237878cebdff0bc363718feaf49a1ea7d.camel%40j-davis.com
---
src/backend/executor/execGrouping.c | 7 ++++--
src/backend/executor/nodeAgg.c | 32 +++++++++++++---------------
src/backend/executor/nodeSetOp.c | 23 +++++++++++---------
src/backend/executor/nodeSubplan.c | 2 +-
src/include/executor/executor.h | 33 +++++++++++++++++++++++++++++
src/include/nodes/execnodes.h | 1 +
6 files changed, 68 insertions(+), 30 deletions(-)
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 33b124fbb0a..450fe74bec5 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -196,6 +196,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 +480,13 @@ 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);
+
+ entry->additional = palloc0(hashtable->additionalsize);
}
}
else
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 340a2010101..af0b7b27383 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1494,7 +1494,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
@@ -1732,7 +1732,7 @@ hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
transitionChunkSize = 0;
return
- sizeof(TupleHashEntryData) +
+ TupleHashEntrySize() +
tupleChunkSize +
pergroupChunkSize +
transitionChunkSize;
@@ -1996,7 +1996,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);
}
}
@@ -2149,11 +2149,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()
@@ -2217,7 +2213,7 @@ lookup_hash_entries(AggState *aggstate)
{
if (isnew)
initialize_hash_entry(aggstate, hashtable, entry);
- pergroup[setno] = entry->additional;
+ pergroup[setno] = TupleHashEntryGetAdditional(hashtable, entry);
}
else
{
@@ -2750,6 +2746,7 @@ agg_refill_hash_table(AggState *aggstate)
INJECTION_POINT("hash-aggregate-process-batch");
for (;;)
{
+ TupleHashTable hashtable = perhash->hashtable;
TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
TupleTableSlot *hashslot = perhash->hashslot;
TupleHashEntry entry;
@@ -2770,14 +2767,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
@@ -2869,7 +2866,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;
@@ -2895,6 +2892,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
*/
for (;;)
{
+ TupleHashTable hashtable = perhash->hashtable;
TupleTableSlot *hashslot = perhash->hashslot;
int i;
@@ -2903,7 +2901,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;
@@ -2918,7 +2916,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;
}
@@ -2941,7 +2939,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);
@@ -2957,7 +2955,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
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 5b7ff9c3748..cbdc717850c 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -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);
@@ -464,6 +466,7 @@ setop_fill_hash_table(SetOpState *setopstate)
*/
for (;;)
{
+ TupleHashTable hashtable = setopstate->hashtable;
TupleTableSlot *innerslot;
TupleHashEntryData *entry;
@@ -472,13 +475,13 @@ 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) TupleHashEntryGetAdditional(hashtable, entry))->numRight++;
/* Must reset expression context after each hashtable lookup */
ResetExprContext(econtext);
@@ -496,7 +499,7 @@ setop_fill_hash_table(SetOpState *setopstate)
static TupleTableSlot *
setop_retrieve_hash_table(SetOpState *setopstate)
{
- TupleHashEntryData *entry;
+ TupleHashEntry entry;
TupleTableSlot *resultTupleSlot;
/*
@@ -526,12 +529,12 @@ 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);
+ set_output_count(setopstate, (SetOpStatePerGroup) TupleHashEntryGetAdditional(setopstate->hashtable, entry));
if (setopstate->numOutput > 0)
{
setopstate->numOutput--;
- return ExecStoreMinimalTuple(entry->firstTuple,
+ return ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry),
resultTupleSlot,
false);
}
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 49767ed6a52..f7f6fc2da0b 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -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,
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 30e2a82346f..ee93b479c92 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -157,6 +157,39 @@ 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
+ * amount of space available is the additionalsize specified to
+ * BuildTupleHashTable(). If additionalsize was specified as zero, no
+ * additional space is available and this function should not be called.
+ */
+static inline void *
+TupleHashEntryGetAdditional(TupleHashTable hashtable, TupleHashEntry entry)
+{
+ Assert(entry->additional != NULL);
+ return entry->additional;
+}
+#endif
+
/*
* prototypes from functions in execJunk.c
*/
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 1aacad936af..11aa110cf9c 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -860,6 +860,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 */
--
2.34.1