62 elog(
ERROR,
"Hash node does not support ExecProcNode call convention");
139 printf(
"Increasing nbuckets %d => %d\n",
278 &nbuckets, &nbatch, &num_skew_mcvs);
281 printf(
"nbatch = %d, nbuckets = %d\n", nbatch, nbuckets);
285 log2_nbuckets =
my_log2(nbuckets);
286 Assert(nbuckets == (1 << log2_nbuckets));
307 hashtable->
nbatch = nbatch;
335 foreach(ho, hashOperators)
342 elog(
ERROR,
"could not find hash function for hash operator %u",
414 #define NTUP_PER_BUCKET 1
423 double inner_rel_bytes;
425 long hash_table_bytes;
426 long skew_table_bytes;
444 inner_rel_bytes = ntuples * tupsize;
449 hash_table_bytes =
work_mem * 1024L;
477 *num_skew_mcvs = skew_table_bytes / (tupsize +
481 if (*num_skew_mcvs > 0)
482 hash_table_bytes -= skew_table_bytes;
493 max_pointers = (
work_mem * 1024L) /
sizeof(
void *);
495 max_pointers =
Min(max_pointers, INT_MAX / 2);
497 dbuckets =
Min(dbuckets, max_pointers);
498 nbuckets =
Max((
int) dbuckets, 1024);
499 nbuckets = 1 <<
my_log2(nbuckets);
506 if (inner_rel_bytes + bucket_bytes > hash_table_bytes)
521 lbuckets = 1L <<
my_log2(hash_table_bytes / bucket_size);
522 lbuckets =
Min(lbuckets, max_pointers);
523 nbuckets = (int) lbuckets;
534 Assert(bucket_bytes <= hash_table_bytes / 2);
537 dbatch = ceil(inner_rel_bytes / (hash_table_bytes - bucket_bytes));
538 dbatch =
Min(dbatch, max_pointers);
539 minbatch = (int) dbatch;
541 while (nbatch < minbatch)
548 *numbuckets = nbuckets;
549 *numbatches = nbatch;
569 for (i = 1; i < hashtable->
nbatch; i++)
592 int oldnbatch = hashtable->
nbatch;
608 nbatch = oldnbatch * 2;
612 printf(
"Increasing nbatch to %d because space = %lu\n",
613 nbatch, (
unsigned long) hashtable->
spaceUsed);
636 (nbatch - oldnbatch) *
sizeof(
BufFile *));
638 (nbatch - oldnbatch) *
sizeof(
BufFile *));
643 hashtable->
nbatch = nbatch;
649 ninmemory = nfreed = 0;
670 oldchunks = hashtable->
chunks;
674 while (oldchunks !=
NULL)
682 while (idx < oldchunks->used)
692 &bucketno, &batchno);
694 if (batchno == curbatch)
700 memcpy(copyTuple, hashTuple, hashTupleSize);
704 hashtable->
buckets[bucketno] = copyTuple;
709 Assert(batchno > curbatch);
724 oldchunks = nextchunk;
728 printf(
"Freed %ld of %ld tuples, space now %lu\n",
729 nfreed, ninmemory, (
unsigned long) hashtable->
spaceUsed);
740 if (nfreed == 0 || nfreed == ninmemory)
744 printf(
"Disabling further increase of nbatch\n");
775 printf(
"Increasing nbuckets to %d\n", hashtable->
nbuckets);
791 for (chunk = hashtable->
chunks; chunk !=
NULL; chunk = chunk->
next)
796 while (idx < chunk->used)
803 &bucketno, &batchno);
807 hashtable->
buckets[bucketno] = hashTuple;
816 printf(
"Nbuckets increased to %d, average items per bucket %.1f\n",
843 &bucketno, &batchno);
874 hashtable->
buckets[bucketno] = hashTuple;
881 if ((hashtable->
nbatch == 1) &&
950 foreach(hk, hashkeys)
957 hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
1000 *hashvalue = hashkey;
1039 *bucketno = hashvalue & (nbuckets - 1);
1040 *batchno = (hashvalue >> hashtable->
log2_nbuckets) & (nbatch - 1);
1044 *bucketno = hashvalue & (nbuckets - 1);
1075 if (hashTuple !=
NULL)
1076 hashTuple = hashTuple->
next;
1082 while (hashTuple !=
NULL)
1097 if (
ExecQual(hjclauses, econtext,
false))
1104 hashTuple = hashTuple->
next;
1153 if (hashTuple !=
NULL)
1154 hashTuple = hashTuple->
next;
1170 while (hashTuple !=
NULL)
1193 hashTuple = hashTuple->
next;
1212 int nbuckets = hashtable->
nbuckets;
1244 for (i = 0; i < hashtable->
nbuckets; i++)
1246 for (tuple = hashtable->
buckets[i]; tuple !=
NULL; tuple = tuple->
next)
1256 for (tuple = skewBucket->
tuples; tuple !=
NULL; tuple = tuple->
next)
1312 &numbers, &nnumbers))
1319 if (mcvsToUse > nvalues)
1320 mcvsToUse = nvalues;
1328 for (i = 0; i < mcvsToUse; i++)
1333 values, nvalues, numbers, nnumbers);
1351 while (nbuckets <= mcvsToUse)
1369 mcvsToUse *
sizeof(
int));
1372 + mcvsToUse *
sizeof(
int);
1374 + mcvsToUse *
sizeof(
int);
1389 for (i = 0; i < mcvsToUse; i++)
1403 bucket = hashvalue & (nbuckets - 1);
1406 bucket = (bucket + 1) & (nbuckets - 1);
1430 values, nvalues, numbers, nnumbers);
1542 bucket = hashtable->
skewBucket[bucketToRemove];
1554 hashTuple = bucket->
tuples;
1555 while (hashTuple !=
NULL)
1570 if (batchno == hashtable->
curbatch)
1574 hashtable->
buckets[bucketno] = hashTuple;
1589 hashTuple = nextHashTuple;
1663 hashtable->
chunks = newChunk;
1666 newChunk->
used += size;
1669 return newChunk->
data;
1684 newChunk->
used = size;
1688 hashtable->
chunks = newChunk;
1690 return newChunk->
data;
int log2_nbuckets_optimal
#define DatumGetUInt32(X)
void InstrStopNode(Instrumentation *instr, double nTuples)
#define SKEW_BUCKET_OVERHEAD
#define INVALID_SKEW_BUCKET_NO
TupleTableSlot * ExecProcNode(PlanState *node)
void MemoryContextDelete(MemoryContext context)
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
HashJoinTable ExecHashTableCreate(Hash *node, List *hashOperators, bool keepNulls)
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
static void ExecHashRemoveNextSkewBucket(HashJoinTable hashtable)
#define SKEW_MIN_OUTER_FRACTION
struct HashJoinTupleData ** buckets
ProjectionInfo * ps_ProjInfo
Instrumentation * instrument
void ExecEndNode(PlanState *node)
bool ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
void ExecPrepHashTableForUnmatched(HashJoinState *hjstate)
ExprContext * ps_ExprContext
HashState * ExecInitHash(Hash *node, EState *estate, int eflags)
void ExecHashTableReset(HashJoinTable hashtable)
MemoryContext ecxt_per_tuple_memory
void ExecReScan(PlanState *node)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
#define MemSet(start, val, len)
Node * MultiExecHash(HashState *node)
Datum idx(PG_FUNCTION_ARGS)
void MemoryContextReset(MemoryContext context)
FmgrInfo * inner_hashfunctions
bool get_attstatsslot(HeapTuple statstuple, Oid atttype, int32 atttypmod, int reqkind, Oid reqop, Oid *actualop, Datum **values, int *nvalues, float4 **numbers, int *nnumbers)
static void ExecHashIncreaseNumBatches(HashJoinTable hashtable)
void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, int *numbuckets, int *numbatches, int *num_skew_mcvs)
#define OidIsValid(objectId)
void ExecFreeExprContext(PlanState *planstate)
void BufFileClose(BufFile *file)
#define ALLOCSET_DEFAULT_MINSIZE
int ExecHashGetSkewBucket(HashJoinTable hashtable, uint32 hashvalue)
void ExecAssignResultTypeFromTL(PlanState *planstate)
static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse)
struct PlanState * lefttree
void ExecHashTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue)
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
void ExecReScanHash(HashState *node)
void pfree(void *pointer)
#define ObjectIdGetDatum(X)
void PrepareTempTablespaces(void)
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
static void ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
void InstrStartNode(Instrumentation *instr)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
#define HASH_CHUNK_THRESHOLD
struct HashJoinTupleData * HashJoinTuple
#define EXEC_FLAG_BACKWARD
BufFile ** outerBatchFile
#define outerPlanState(node)
HashJoinTuple hj_CurTuple
bool ExecScanHashBucket(HashJoinState *hjstate, ExprContext *econtext)
TupleTableSlot * ecxt_innertuple
bool ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
struct HashMemoryChunkData * next
MemoryContext CurrentMemoryContext
#define STATISTIC_KIND_MCV
struct HashJoinTableData * HashJoinTable
FmgrInfo * outer_hashfunctions
#define SizeofMinimalTupleHeader
HashSkewBucket ** skewBucket
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
void * palloc0(Size size)
static void * dense_alloc(HashJoinTable hashtable, Size size)
void ReleaseSysCache(HeapTuple tuple)
struct HashMemoryChunkData * HashMemoryChunk
void * MemoryContextAllocZero(MemoryContext context, Size size)
#define HJTUPLE_MINTUPLE(hjtup)
#define HeapTupleHeaderHasMatch(tup)
#define HeapTupleIsValid(tuple)
#define Assert(condition)
static void ExecHashSkewTableInsert(HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue, int bucketNumber)
char data[FLEXIBLE_ARRAY_MEMBER]
void ExecAssignExprContext(EState *estate, PlanState *planstate)
BufFile ** innerBatchFile
struct HashJoinTupleData * next
static int list_length(const List *l)
#define HeapTupleHeaderClearMatch(tup)
void * repalloc(void *pointer, Size size)
static Datum values[MAXATTR]
TupleTableSlot * hj_HashTupleSlot
HashJoinTable hj_HashTable
void * MemoryContextAlloc(MemoryContext context, Size size)
#define SearchSysCache3(cacheId, key1, key2, key3)
#define ALLOCSET_DEFAULT_INITSIZE
void ExecEndHash(HashState *node)
#define FunctionCall1(flinfo, arg1)
void ExecHashTableResetMatchFlags(HashJoinTable hashtable)
bool ExecHashGetHashValue(HashJoinTable hashtable, ExprContext *econtext, List *hashkeys, bool outer_tuple, bool keep_nulls, uint32 *hashvalue)
#define ALLOCSET_DEFAULT_MAXSIZE
#define SKEW_WORK_MEM_PERCENT
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
void free_attstatsslot(Oid atttype, Datum *values, int nvalues, float4 *numbers, int nnumbers)
TupleTableSlot * ExecHash(HashState *node)
void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
void ExecHashTableDestroy(HashJoinTable hashtable)
#define offsetof(type, field)
#define ResetExprContext(econtext)
#define ExecEvalExpr(expr, econtext, isNull, isDone)