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