Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e0ece2a

Browse files
committed
TupleHashTable: store additional data along with tuple.
Previously, the caller needed to allocate the memory and the TupleHashTable would store a pointer to it. That wastes space for the palloc overhead as well as the size of the pointer itself. Now, the TupleHashTable relies on the caller to correctly specify the additionalsize, and allocates that amount of space. The caller can then request a pointer into that space. Discussion: https://postgr.es/m/b9cbf0219a9859dc8d240311643ff4362fd9602c.camel@j-davis.com Reviewed-by: Heikki Linnakangas
1 parent 34c6e65 commit e0ece2a

File tree

6 files changed

+78
-31
lines changed

6 files changed

+78
-31
lines changed

src/backend/executor/execGrouping.c

+55-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
#include "miscadmin.h"
2121
#include "utils/lsyscache.h"
2222

23+
typedef struct TupleHashEntryData
24+
{
25+
MinimalTuple firstTuple; /* copy of first tuple in this group */
26+
uint32 status; /* hash status */
27+
uint32 hash; /* hash value (cached) */
28+
} TupleHashEntryData;
29+
2330
static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2);
2431
static inline uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb,
2532
const MinimalTuple tuple);
@@ -196,6 +203,7 @@ BuildTupleHashTable(PlanState *parent,
196203
hashtable->tab_collations = collations;
197204
hashtable->tablecxt = tablecxt;
198205
hashtable->tempcxt = tempcxt;
206+
hashtable->additionalsize = additionalsize;
199207
hashtable->tableslot = NULL; /* will be made on first lookup */
200208
hashtable->inputslot = NULL;
201209
hashtable->in_hash_expr = NULL;
@@ -273,6 +281,15 @@ ResetTupleHashTable(TupleHashTable hashtable)
273281
tuplehash_reset(hashtable->hashtab);
274282
}
275283

284+
/*
285+
* Return size of the hash bucket. Useful for estimating memory usage.
286+
*/
287+
size_t
288+
TupleHashEntrySize(void)
289+
{
290+
return sizeof(TupleHashEntryData);
291+
}
292+
276293
/*
277294
* Find or create a hashtable entry for the tuple group containing the
278295
* given tuple. The tuple must be the same type as the hashtable entries.
@@ -339,6 +356,24 @@ TupleHashTableHash(TupleHashTable hashtable, TupleTableSlot *slot)
339356
return hash;
340357
}
341358

359+
MinimalTuple
360+
TupleHashEntryGetTuple(TupleHashEntry entry)
361+
{
362+
return entry->firstTuple;
363+
}
364+
365+
/*
366+
* Get a pointer into the additional space allocated for this entry. The
367+
* amount of space available is the additionalsize specified to
368+
* BuildTupleHashTable(). If additionalsize was specified as zero, no
369+
* additional space is available and this function should not be called.
370+
*/
371+
void *
372+
TupleHashEntryGetAdditional(TupleHashEntry entry)
373+
{
374+
return (char *) entry->firstTuple + MAXALIGN(entry->firstTuple->t_len);
375+
}
376+
342377
/*
343378
* A variant of LookupTupleHashEntry for callers that have already computed
344379
* the hash value.
@@ -477,13 +512,31 @@ LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot,
477512
}
478513
else
479514
{
515+
MinimalTuple firstTuple;
516+
size_t totalsize; /* including alignment and additionalsize */
517+
480518
/* created new entry */
481519
*isnew = true;
482520
/* zero caller data */
483-
entry->additional = NULL;
484521
MemoryContextSwitchTo(hashtable->tablecxt);
522+
485523
/* Copy the first tuple into the table context */
486-
entry->firstTuple = ExecCopySlotMinimalTuple(slot);
524+
firstTuple = ExecCopySlotMinimalTuple(slot);
525+
526+
/*
527+
* Allocate additional space right after the MinimalTuple of size
528+
* additionalsize. The caller can get a pointer to this data with
529+
* TupleHashEntryGetAdditional(), and store arbitrary data there.
530+
*
531+
* This avoids the need to store an extra pointer or allocate an
532+
* additional chunk, which would waste memory.
533+
*/
534+
totalsize = MAXALIGN(firstTuple->t_len) + hashtable->additionalsize;
535+
firstTuple = repalloc(firstTuple, totalsize);
536+
memset((char *) firstTuple + firstTuple->t_len, 0,
537+
totalsize - firstTuple->t_len);
538+
539+
entry->firstTuple = firstTuple;
487540
}
488541
}
489542
else

src/backend/executor/nodeAgg.c

+8-12
Original file line numberDiff line numberDiff line change
@@ -1713,7 +1713,7 @@ hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
17131713
transitionChunkSize = 0;
17141714

17151715
return
1716-
sizeof(TupleHashEntryData) +
1716+
TupleHashEntrySize() +
17171717
tupleChunkSize +
17181718
pergroupChunkSize +
17191719
transitionChunkSize;
@@ -1954,7 +1954,7 @@ hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
19541954
if (aggstate->hash_ngroups_current > 0)
19551955
{
19561956
aggstate->hashentrysize =
1957-
sizeof(TupleHashEntryData) +
1957+
TupleHashEntrySize() +
19581958
(hashkey_mem / (double) aggstate->hash_ngroups_current);
19591959
}
19601960
}
@@ -2055,11 +2055,7 @@ initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable,
20552055
if (aggstate->numtrans == 0)
20562056
return;
20572057

2058-
pergroup = (AggStatePerGroup)
2059-
MemoryContextAlloc(hashtable->tablecxt,
2060-
sizeof(AggStatePerGroupData) * aggstate->numtrans);
2061-
2062-
entry->additional = pergroup;
2058+
pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(entry);
20632059

20642060
/*
20652061
* Initialize aggregates for new tuple group, lookup_hash_entries()
@@ -2123,7 +2119,7 @@ lookup_hash_entries(AggState *aggstate)
21232119
{
21242120
if (isnew)
21252121
initialize_hash_entry(aggstate, hashtable, entry);
2126-
pergroup[setno] = entry->additional;
2122+
pergroup[setno] = TupleHashEntryGetAdditional(entry);
21272123
}
21282124
else
21292125
{
@@ -2681,7 +2677,7 @@ agg_refill_hash_table(AggState *aggstate)
26812677
{
26822678
if (isnew)
26832679
initialize_hash_entry(aggstate, perhash->hashtable, entry);
2684-
aggstate->hash_pergroup[batch->setno] = entry->additional;
2680+
aggstate->hash_pergroup[batch->setno] = TupleHashEntryGetAdditional(entry);
26852681
advance_aggregates(aggstate);
26862682
}
26872683
else
@@ -2773,7 +2769,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
27732769
ExprContext *econtext;
27742770
AggStatePerAgg peragg;
27752771
AggStatePerGroup pergroup;
2776-
TupleHashEntryData *entry;
2772+
TupleHashEntry entry;
27772773
TupleTableSlot *firstSlot;
27782774
TupleTableSlot *result;
27792775
AggStatePerHash perhash;
@@ -2845,7 +2841,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
28452841
* Transform representative tuple back into one with the right
28462842
* columns.
28472843
*/
2848-
ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
2844+
ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashslot, false);
28492845
slot_getallattrs(hashslot);
28502846

28512847
ExecClearTuple(firstSlot);
@@ -2861,7 +2857,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
28612857
}
28622858
ExecStoreVirtualTuple(firstSlot);
28632859

2864-
pergroup = (AggStatePerGroup) entry->additional;
2860+
pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(entry);
28652861

28662862
/*
28672863
* Use the representative input tuple for any references to

src/backend/executor/nodeSetOp.c

+9-8
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ setop_fill_hash_table(SetOpState *setopstate)
425425
{
426426
TupleTableSlot *outerslot;
427427
TupleHashEntryData *entry;
428+
SetOpStatePerGroup pergroup;
428429
bool isnew;
429430

430431
outerslot = ExecProcNode(outerPlan);
@@ -437,16 +438,16 @@ setop_fill_hash_table(SetOpState *setopstate)
437438
outerslot,
438439
&isnew, NULL);
439440

441+
pergroup = TupleHashEntryGetAdditional(entry);
440442
/* If new tuple group, initialize counts to zero */
441443
if (isnew)
442444
{
443-
entry->additional = (SetOpStatePerGroup)
444-
MemoryContextAllocZero(setopstate->hashtable->tablecxt,
445-
sizeof(SetOpStatePerGroupData));
445+
pergroup->numLeft = 0;
446+
pergroup->numRight = 0;
446447
}
447448

448449
/* Advance the counts */
449-
((SetOpStatePerGroup) entry->additional)->numLeft++;
450+
pergroup->numLeft++;
450451

451452
/* Must reset expression context after each hashtable lookup */
452453
ResetExprContext(econtext);
@@ -478,7 +479,7 @@ setop_fill_hash_table(SetOpState *setopstate)
478479

479480
/* Advance the counts if entry is already present */
480481
if (entry)
481-
((SetOpStatePerGroup) entry->additional)->numRight++;
482+
((SetOpStatePerGroup) TupleHashEntryGetAdditional(entry))->numRight++;
482483

483484
/* Must reset expression context after each hashtable lookup */
484485
ResetExprContext(econtext);
@@ -496,7 +497,7 @@ setop_fill_hash_table(SetOpState *setopstate)
496497
static TupleTableSlot *
497498
setop_retrieve_hash_table(SetOpState *setopstate)
498499
{
499-
TupleHashEntryData *entry;
500+
TupleHashEntry entry;
500501
TupleTableSlot *resultTupleSlot;
501502

502503
/*
@@ -526,12 +527,12 @@ setop_retrieve_hash_table(SetOpState *setopstate)
526527
* See if we should emit any copies of this tuple, and if so return
527528
* the first copy.
528529
*/
529-
set_output_count(setopstate, (SetOpStatePerGroup) entry->additional);
530+
set_output_count(setopstate, (SetOpStatePerGroup) TupleHashEntryGetAdditional(entry));
530531

531532
if (setopstate->numOutput > 0)
532533
{
533534
setopstate->numOutput--;
534-
return ExecStoreMinimalTuple(entry->firstTuple,
535+
return ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry),
535536
resultTupleSlot,
536537
false);
537538
}

src/backend/executor/nodeSubplan.c

+1-1
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

+3
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,12 @@ extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
148148
bool *isnew, uint32 *hash);
149149
extern uint32 TupleHashTableHash(TupleHashTable hashtable,
150150
TupleTableSlot *slot);
151+
extern size_t TupleHashEntrySize(void);
151152
extern TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable,
152153
TupleTableSlot *slot,
153154
bool *isnew, uint32 hash);
155+
extern MinimalTuple TupleHashEntryGetTuple(TupleHashEntry entry);
156+
extern void *TupleHashEntryGetAdditional(TupleHashEntry entry);
154157
extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
155158
TupleTableSlot *slot,
156159
ExprState *eqcomp,

src/include/nodes/execnodes.h

+2-8
Original file line numberDiff line numberDiff line change
@@ -806,17 +806,10 @@ typedef struct ExecAuxRowMark
806806
* point to tab_hash_expr and tab_eq_func respectively.
807807
* ----------------------------------------------------------------
808808
*/
809+
typedef struct TupleHashEntryData TupleHashEntryData;
809810
typedef struct TupleHashEntryData *TupleHashEntry;
810811
typedef struct TupleHashTableData *TupleHashTable;
811812

812-
typedef struct TupleHashEntryData
813-
{
814-
MinimalTuple firstTuple; /* copy of first tuple in this group */
815-
void *additional; /* user data */
816-
uint32 status; /* hash status */
817-
uint32 hash; /* hash value (cached) */
818-
} TupleHashEntryData;
819-
820813
/* define parameters necessary to generate the tuple hash table interface */
821814
#define SH_PREFIX tuplehash
822815
#define SH_ELEMENT_TYPE TupleHashEntryData
@@ -835,6 +828,7 @@ typedef struct TupleHashTableData
835828
Oid *tab_collations; /* collations for hash and comparison */
836829
MemoryContext tablecxt; /* memory context containing table */
837830
MemoryContext tempcxt; /* context for function evaluations */
831+
Size additionalsize; /* size of additional data */
838832
TupleTableSlot *tableslot; /* slot for referencing table entries */
839833
/* The following fields are set transiently for each table search: */
840834
TupleTableSlot *inputslot; /* current input tuple's slot */

0 commit comments

Comments
 (0)