Skip to content

Commit 4d14350

Browse files
committed
Create accessor functions for TupleHashEntry.
Refactor for upcoming optimizations. Reviewed-by: David Rowley <dgrowleyml@gmail.com> Discussion: https://postgr.es/m/1cc3b400a0e8eead18ff967436fa9e42c0c14cfb.camel@j-davis.com
1 parent cc721c4 commit 4d14350

File tree

6 files changed

+83
-33
lines changed

6 files changed

+83
-33
lines changed

src/backend/executor/execGrouping.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,15 @@ BuildTupleHashTable(PlanState *parent,
174174
bool use_variable_hash_iv)
175175
{
176176
TupleHashTable hashtable;
177-
Size entrysize = sizeof(TupleHashEntryData) + additionalsize;
177+
Size entrysize;
178178
Size hash_mem_limit;
179179
MemoryContext oldcontext;
180180
bool allow_jit;
181181
uint32 hash_iv = 0;
182182

183183
Assert(nbuckets > 0);
184+
additionalsize = MAXALIGN(additionalsize);
185+
entrysize = sizeof(TupleHashEntryData) + additionalsize;
184186

185187
/* Limit initial table size request to not more than hash_mem */
186188
hash_mem_limit = get_hash_memory_limit() / entrysize;
@@ -196,6 +198,7 @@ BuildTupleHashTable(PlanState *parent,
196198
hashtable->tab_collations = collations;
197199
hashtable->tablecxt = tablecxt;
198200
hashtable->tempcxt = tempcxt;
201+
hashtable->additionalsize = additionalsize;
199202
hashtable->tableslot = NULL; /* will be made on first lookup */
200203
hashtable->inputslot = NULL;
201204
hashtable->in_hash_expr = NULL;
@@ -479,11 +482,14 @@ LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot,
479482
{
480483
/* created new entry */
481484
*isnew = true;
482-
/* zero caller data */
483-
entry->additional = NULL;
485+
484486
MemoryContextSwitchTo(hashtable->tablecxt);
485-
/* Copy the first tuple into the table context */
487+
486488
entry->firstTuple = ExecCopySlotMinimalTuple(slot);
489+
if (hashtable->additionalsize > 0)
490+
entry->additional = palloc0(hashtable->additionalsize);
491+
else
492+
entry->additional = NULL;
487493
}
488494
}
489495
else

src/backend/executor/nodeAgg.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,7 @@ build_hash_tables(AggState *aggstate)
14911491
#ifdef USE_INJECTION_POINTS
14921492
if (IS_INJECTION_POINT_ATTACHED("hash-aggregate-oversize-table"))
14931493
{
1494-
nbuckets = memory / sizeof(TupleHashEntryData);
1494+
nbuckets = memory / TupleHashEntrySize();
14951495
INJECTION_POINT_CACHED("hash-aggregate-oversize-table");
14961496
}
14971497
#endif
@@ -1724,7 +1724,7 @@ hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
17241724
transitionChunkSize = 0;
17251725

17261726
return
1727-
sizeof(TupleHashEntryData) +
1727+
TupleHashEntrySize() +
17281728
tupleChunkSize +
17291729
pergroupChunkSize +
17301730
transitionChunkSize;
@@ -1988,7 +1988,7 @@ hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
19881988
if (aggstate->hash_ngroups_current > 0)
19891989
{
19901990
aggstate->hashentrysize =
1991-
sizeof(TupleHashEntryData) +
1991+
TupleHashEntrySize() +
19921992
(hashkey_mem / (double) aggstate->hash_ngroups_current);
19931993
}
19941994
}
@@ -2147,11 +2147,7 @@ initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable,
21472147
if (aggstate->numtrans == 0)
21482148
return;
21492149

2150-
pergroup = (AggStatePerGroup)
2151-
MemoryContextAlloc(hashtable->tablecxt,
2152-
sizeof(AggStatePerGroupData) * aggstate->numtrans);
2153-
2154-
entry->additional = pergroup;
2150+
pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(hashtable, entry);
21552151

21562152
/*
21572153
* Initialize aggregates for new tuple group, lookup_hash_entries()
@@ -2213,7 +2209,7 @@ lookup_hash_entries(AggState *aggstate)
22132209
{
22142210
if (isnew)
22152211
initialize_hash_entry(aggstate, hashtable, entry);
2216-
pergroup[setno] = entry->additional;
2212+
pergroup[setno] = TupleHashEntryGetAdditional(hashtable, entry);
22172213
}
22182214
else
22192215
{
@@ -2748,6 +2744,7 @@ agg_refill_hash_table(AggState *aggstate)
27482744
{
27492745
TupleTableSlot *spillslot = aggstate->hash_spill_rslot;
27502746
TupleTableSlot *hashslot = perhash->hashslot;
2747+
TupleHashTable hashtable = perhash->hashtable;
27512748
TupleHashEntry entry;
27522749
MinimalTuple tuple;
27532750
uint32 hash;
@@ -2766,14 +2763,14 @@ agg_refill_hash_table(AggState *aggstate)
27662763
prepare_hash_slot(perhash,
27672764
aggstate->tmpcontext->ecxt_outertuple,
27682765
hashslot);
2769-
entry = LookupTupleHashEntryHash(perhash->hashtable, hashslot,
2766+
entry = LookupTupleHashEntryHash(hashtable, hashslot,
27702767
p_isnew, hash);
27712768

27722769
if (entry != NULL)
27732770
{
27742771
if (isnew)
2775-
initialize_hash_entry(aggstate, perhash->hashtable, entry);
2776-
aggstate->hash_pergroup[batch->setno] = entry->additional;
2772+
initialize_hash_entry(aggstate, hashtable, entry);
2773+
aggstate->hash_pergroup[batch->setno] = TupleHashEntryGetAdditional(hashtable, entry);
27772774
advance_aggregates(aggstate);
27782775
}
27792776
else
@@ -2865,7 +2862,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
28652862
ExprContext *econtext;
28662863
AggStatePerAgg peragg;
28672864
AggStatePerGroup pergroup;
2868-
TupleHashEntryData *entry;
2865+
TupleHashEntry entry;
28692866
TupleTableSlot *firstSlot;
28702867
TupleTableSlot *result;
28712868
AggStatePerHash perhash;
@@ -2892,14 +2889,15 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
28922889
for (;;)
28932890
{
28942891
TupleTableSlot *hashslot = perhash->hashslot;
2892+
TupleHashTable hashtable = perhash->hashtable;
28952893
int i;
28962894

28972895
CHECK_FOR_INTERRUPTS();
28982896

28992897
/*
29002898
* Find the next entry in the hash table
29012899
*/
2902-
entry = ScanTupleHashTable(perhash->hashtable, &perhash->hashiter);
2900+
entry = ScanTupleHashTable(hashtable, &perhash->hashiter);
29032901
if (entry == NULL)
29042902
{
29052903
int nextset = aggstate->current_set + 1;
@@ -2914,7 +2912,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
29142912

29152913
perhash = &aggstate->perhash[aggstate->current_set];
29162914

2917-
ResetTupleHashIterator(perhash->hashtable, &perhash->hashiter);
2915+
ResetTupleHashIterator(hashtable, &perhash->hashiter);
29182916

29192917
continue;
29202918
}
@@ -2937,7 +2935,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
29372935
* Transform representative tuple back into one with the right
29382936
* columns.
29392937
*/
2940-
ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2938+
ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashslot, false);
29412939
slot_getallattrs(hashslot);
29422940

29432941
ExecClearTuple(firstSlot);
@@ -2953,7 +2951,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
29532951
}
29542952
ExecStoreVirtualTuple(firstSlot);
29552953

2956-
pergroup = (AggStatePerGroup) entry->additional;
2954+
pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(hashtable, entry);
29572955

29582956
/*
29592957
* Use the representative input tuple for any references to

src/backend/executor/nodeSetOp.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,9 @@ setop_fill_hash_table(SetOpState *setopstate)
424424
for (;;)
425425
{
426426
TupleTableSlot *outerslot;
427+
TupleHashTable hashtable = setopstate->hashtable;
427428
TupleHashEntryData *entry;
429+
SetOpStatePerGroup pergroup;
428430
bool isnew;
429431

430432
outerslot = ExecProcNode(outerPlan);
@@ -433,20 +435,20 @@ setop_fill_hash_table(SetOpState *setopstate)
433435
have_tuples = true;
434436

435437
/* Find or build hashtable entry for this tuple's group */
436-
entry = LookupTupleHashEntry(setopstate->hashtable,
438+
entry = LookupTupleHashEntry(hashtable,
437439
outerslot,
438440
&isnew, NULL);
439441

442+
pergroup = TupleHashEntryGetAdditional(hashtable, entry);
440443
/* If new tuple group, initialize counts to zero */
441444
if (isnew)
442445
{
443-
entry->additional = (SetOpStatePerGroup)
444-
MemoryContextAllocZero(setopstate->hashtable->tablecxt,
445-
sizeof(SetOpStatePerGroupData));
446+
pergroup->numLeft = 0;
447+
pergroup->numRight = 0;
446448
}
447449

448450
/* Advance the counts */
449-
((SetOpStatePerGroup) entry->additional)->numLeft++;
451+
pergroup->numLeft++;
450452

451453
/* Must reset expression context after each hashtable lookup */
452454
ResetExprContext(econtext);
@@ -465,20 +467,25 @@ setop_fill_hash_table(SetOpState *setopstate)
465467
for (;;)
466468
{
467469
TupleTableSlot *innerslot;
470+
TupleHashTable hashtable = setopstate->hashtable;
468471
TupleHashEntryData *entry;
469472

470473
innerslot = ExecProcNode(innerPlan);
471474
if (TupIsNull(innerslot))
472475
break;
473476

474477
/* For tuples not seen previously, do not make hashtable entry */
475-
entry = LookupTupleHashEntry(setopstate->hashtable,
478+
entry = LookupTupleHashEntry(hashtable,
476479
innerslot,
477480
NULL, NULL);
478481

479482
/* Advance the counts if entry is already present */
480483
if (entry)
481-
((SetOpStatePerGroup) entry->additional)->numRight++;
484+
{
485+
SetOpStatePerGroup pergroup = TupleHashEntryGetAdditional(hashtable, entry);
486+
487+
pergroup->numRight++;
488+
}
482489

483490
/* Must reset expression context after each hashtable lookup */
484491
ResetExprContext(econtext);
@@ -496,7 +503,7 @@ setop_fill_hash_table(SetOpState *setopstate)
496503
static TupleTableSlot *
497504
setop_retrieve_hash_table(SetOpState *setopstate)
498505
{
499-
TupleHashEntryData *entry;
506+
TupleHashEntry entry;
500507
TupleTableSlot *resultTupleSlot;
501508

502509
/*
@@ -509,12 +516,15 @@ setop_retrieve_hash_table(SetOpState *setopstate)
509516
*/
510517
while (!setopstate->setop_done)
511518
{
519+
TupleHashTable hashtable = setopstate->hashtable;
520+
SetOpStatePerGroup pergroup;
521+
512522
CHECK_FOR_INTERRUPTS();
513523

514524
/*
515525
* Find the next entry in the hash table
516526
*/
517-
entry = ScanTupleHashTable(setopstate->hashtable, &setopstate->hashiter);
527+
entry = ScanTupleHashTable(hashtable, &setopstate->hashiter);
518528
if (entry == NULL)
519529
{
520530
/* No more entries in hashtable, so done */
@@ -526,12 +536,13 @@ setop_retrieve_hash_table(SetOpState *setopstate)
526536
* See if we should emit any copies of this tuple, and if so return
527537
* the first copy.
528538
*/
529-
set_output_count(setopstate, (SetOpStatePerGroup) entry->additional);
539+
pergroup = TupleHashEntryGetAdditional(hashtable, entry);
540+
set_output_count(setopstate, pergroup);
530541

531542
if (setopstate->numOutput > 0)
532543
{
533544
setopstate->numOutput--;
534-
return ExecStoreMinimalTuple(entry->firstTuple,
545+
return ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry),
535546
resultTupleSlot,
536547
false);
537548
}

src/backend/executor/nodeSubplan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
753753
{
754754
CHECK_FOR_INTERRUPTS();
755755

756-
ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
756+
ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashtable->tableslot, false);
757757
if (!execTuplesUnequal(slot, hashtable->tableslot,
758758
numCols, keyColIdx,
759759
eqfunctions,

src/include/executor/executor.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,40 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
158158
ExprState *hashexpr);
159159
extern void ResetTupleHashTable(TupleHashTable hashtable);
160160

161+
#ifndef FRONTEND
162+
/*
163+
* Return size of the hash bucket. Useful for estimating memory usage.
164+
*/
165+
static inline size_t
166+
TupleHashEntrySize(void)
167+
{
168+
return sizeof(TupleHashEntryData);
169+
}
170+
171+
/*
172+
* Return tuple from hash entry.
173+
*/
174+
static inline MinimalTuple
175+
TupleHashEntryGetTuple(TupleHashEntry entry)
176+
{
177+
return entry->firstTuple;
178+
}
179+
180+
/*
181+
* Get a pointer into the additional space allocated for this entry. The
182+
* memory will be maxaligned and zeroed.
183+
*
184+
* The amount of space available is the additionalsize requested in the call
185+
* to BuildTupleHashTable(). If additionalsize was specified as zero, return
186+
* NULL.
187+
*/
188+
static inline void *
189+
TupleHashEntryGetAdditional(TupleHashTable hashtable, TupleHashEntry entry)
190+
{
191+
return entry->additional;
192+
}
193+
#endif
194+
161195
/*
162196
* prototypes from functions in execJunk.c
163197
*/

src/include/nodes/execnodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ typedef struct TupleHashTableData
863863
Oid *tab_collations; /* collations for hash and comparison */
864864
MemoryContext tablecxt; /* memory context containing table */
865865
MemoryContext tempcxt; /* context for function evaluations */
866+
Size additionalsize; /* size of additional data */
866867
TupleTableSlot *tableslot; /* slot for referencing table entries */
867868
/* The following fields are set transiently for each table search: */
868869
TupleTableSlot *inputslot; /* current input tuple's slot */

0 commit comments

Comments
 (0)