PostgreSQL Source Code  git master
nodeHash.h File Reference
#include "access/parallel.h"
#include "nodes/execnodes.h"
Include dependency graph for nodeHash.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

HashStateExecInitHash (Hash *node, EState *estate, int eflags)
 
NodeMultiExecHash (HashState *node)
 
void ExecEndHash (HashState *node)
 
void ExecReScanHash (HashState *node)
 
HashJoinTable ExecHashTableCreate (HashState *state, List *hashOperators, bool keepNulls)
 
void ExecParallelHashTableAlloc (HashJoinTable hashtable, int batchno)
 
void ExecHashTableDestroy (HashJoinTable hashtable)
 
void ExecHashTableDetach (HashJoinTable hashtable)
 
void ExecHashTableDetachBatch (HashJoinTable hashtable)
 
void ExecParallelHashTableSetCurrentBatch (HashJoinTable hashtable, int batchno)
 
void ExecHashTableInsert (HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue)
 
void ExecParallelHashTableInsert (HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue)
 
void ExecParallelHashTableInsertCurrentBatch (HashJoinTable hashtable, TupleTableSlot *slot, uint32 hashvalue)
 
bool ExecHashGetHashValue (HashJoinTable hashtable, ExprContext *econtext, List *hashkeys, bool outer_tuple, bool keep_nulls, uint32 *hashvalue)
 
void ExecHashGetBucketAndBatch (HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
 
bool ExecScanHashBucket (HashJoinState *hjstate, ExprContext *econtext)
 
bool ExecParallelScanHashBucket (HashJoinState *hjstate, ExprContext *econtext)
 
void ExecPrepHashTableForUnmatched (HashJoinState *hjstate)
 
bool ExecScanHashTableForUnmatched (HashJoinState *hjstate, ExprContext *econtext)
 
void ExecHashTableReset (HashJoinTable hashtable)
 
void ExecHashTableResetMatchFlags (HashJoinTable hashtable)
 
void ExecChooseHashTableSize (double ntuples, int tupwidth, bool useskew, bool try_combined_work_mem, int parallel_workers, size_t *space_allowed, int *numbuckets, int *numbatches, int *num_skew_mcvs)
 
int ExecHashGetSkewBucket (HashJoinTable hashtable, uint32 hashvalue)
 
void ExecHashEstimate (HashState *node, ParallelContext *pcxt)
 
void ExecHashInitializeDSM (HashState *node, ParallelContext *pcxt)
 
void ExecHashInitializeWorker (HashState *node, ParallelWorkerContext *pwcxt)
 
void ExecHashRetrieveInstrumentation (HashState *node)
 
void ExecShutdownHash (HashState *node)
 
void ExecHashGetInstrumentation (HashInstrumentation *instrument, HashJoinTable hashtable)
 

Function Documentation

◆ ExecChooseHashTableSize()

void ExecChooseHashTableSize ( double  ntuples,
int  tupwidth,
bool  useskew,
bool  try_combined_work_mem,
int  parallel_workers,
size_t *  space_allowed,
int *  numbuckets,
int *  numbatches,
int *  num_skew_mcvs 
)

Definition at line 662 of file nodeHash.c.

References Assert, ExecChooseHashTableSize(), HJTUPLE_OVERHEAD, Max, MAXALIGN, MaxAllocSize, Min, my_log2(), NTUP_PER_BUCKET, SizeofMinimalTupleHeader, SKEW_BUCKET_OVERHEAD, SKEW_WORK_MEM_PERCENT, and work_mem.

Referenced by ExecChooseHashTableSize(), ExecHashTableCreate(), and initial_cost_hashjoin().

669 {
670  int tupsize;
671  double inner_rel_bytes;
672  long bucket_bytes;
673  long hash_table_bytes;
674  long skew_table_bytes;
675  long max_pointers;
676  long mppow2;
677  int nbatch = 1;
678  int nbuckets;
679  double dbuckets;
680 
681  /* Force a plausible relation size if no info */
682  if (ntuples <= 0.0)
683  ntuples = 1000.0;
684 
685  /*
686  * Estimate tupsize based on footprint of tuple in hashtable... note this
687  * does not allow for any palloc overhead. The manipulations of spaceUsed
688  * don't count palloc overhead either.
689  */
690  tupsize = HJTUPLE_OVERHEAD +
692  MAXALIGN(tupwidth);
693  inner_rel_bytes = ntuples * tupsize;
694 
695  /*
696  * Target in-memory hashtable size is work_mem kilobytes.
697  */
698  hash_table_bytes = work_mem * 1024L;
699 
700  /*
701  * Parallel Hash tries to use the combined work_mem of all workers to
702  * avoid the need to batch. If that won't work, it falls back to work_mem
703  * per worker and tries to process batches in parallel.
704  */
705  if (try_combined_work_mem)
706  hash_table_bytes += hash_table_bytes * parallel_workers;
707 
708  *space_allowed = hash_table_bytes;
709 
710  /*
711  * If skew optimization is possible, estimate the number of skew buckets
712  * that will fit in the memory allowed, and decrement the assumed space
713  * available for the main hash table accordingly.
714  *
715  * We make the optimistic assumption that each skew bucket will contain
716  * one inner-relation tuple. If that turns out to be low, we will recover
717  * at runtime by reducing the number of skew buckets.
718  *
719  * hashtable->skewBucket will have up to 8 times as many HashSkewBucket
720  * pointers as the number of MCVs we allow, since ExecHashBuildSkewHash
721  * will round up to the next power of 2 and then multiply by 4 to reduce
722  * collisions.
723  */
724  if (useskew)
725  {
726  skew_table_bytes = hash_table_bytes * SKEW_WORK_MEM_PERCENT / 100;
727 
728  /*----------
729  * Divisor is:
730  * size of a hash tuple +
731  * worst-case size of skewBucket[] per MCV +
732  * size of skewBucketNums[] entry +
733  * size of skew bucket struct itself
734  *----------
735  */
736  *num_skew_mcvs = skew_table_bytes / (tupsize +
737  (8 * sizeof(HashSkewBucket *)) +
738  sizeof(int) +
740  if (*num_skew_mcvs > 0)
741  hash_table_bytes -= skew_table_bytes;
742  }
743  else
744  *num_skew_mcvs = 0;
745 
746  /*
747  * Set nbuckets to achieve an average bucket load of NTUP_PER_BUCKET when
748  * memory is filled, assuming a single batch; but limit the value so that
749  * the pointer arrays we'll try to allocate do not exceed work_mem nor
750  * MaxAllocSize.
751  *
752  * Note that both nbuckets and nbatch must be powers of 2 to make
753  * ExecHashGetBucketAndBatch fast.
754  */
755  max_pointers = *space_allowed / sizeof(HashJoinTuple);
756  max_pointers = Min(max_pointers, MaxAllocSize / sizeof(HashJoinTuple));
757  /* If max_pointers isn't a power of 2, must round it down to one */
758  mppow2 = 1L << my_log2(max_pointers);
759  if (max_pointers != mppow2)
760  max_pointers = mppow2 / 2;
761 
762  /* Also ensure we avoid integer overflow in nbatch and nbuckets */
763  /* (this step is redundant given the current value of MaxAllocSize) */
764  max_pointers = Min(max_pointers, INT_MAX / 2);
765 
766  dbuckets = ceil(ntuples / NTUP_PER_BUCKET);
767  dbuckets = Min(dbuckets, max_pointers);
768  nbuckets = (int) dbuckets;
769  /* don't let nbuckets be really small, though ... */
770  nbuckets = Max(nbuckets, 1024);
771  /* ... and force it to be a power of 2. */
772  nbuckets = 1 << my_log2(nbuckets);
773 
774  /*
775  * If there's not enough space to store the projected number of tuples and
776  * the required bucket headers, we will need multiple batches.
777  */
778  bucket_bytes = sizeof(HashJoinTuple) * nbuckets;
779  if (inner_rel_bytes + bucket_bytes > hash_table_bytes)
780  {
781  /* We'll need multiple batches */
782  long lbuckets;
783  double dbatch;
784  int minbatch;
785  long bucket_size;
786 
787  /*
788  * If Parallel Hash with combined work_mem would still need multiple
789  * batches, we'll have to fall back to regular work_mem budget.
790  */
791  if (try_combined_work_mem)
792  {
793  ExecChooseHashTableSize(ntuples, tupwidth, useskew,
794  false, parallel_workers,
795  space_allowed,
796  numbuckets,
797  numbatches,
798  num_skew_mcvs);
799  return;
800  }
801 
802  /*
803  * Estimate the number of buckets we'll want to have when work_mem is
804  * entirely full. Each bucket will contain a bucket pointer plus
805  * NTUP_PER_BUCKET tuples, whose projected size already includes
806  * overhead for the hash code, pointer to the next tuple, etc.
807  */
808  bucket_size = (tupsize * NTUP_PER_BUCKET + sizeof(HashJoinTuple));
809  lbuckets = 1L << my_log2(hash_table_bytes / bucket_size);
810  lbuckets = Min(lbuckets, max_pointers);
811  nbuckets = (int) lbuckets;
812  nbuckets = 1 << my_log2(nbuckets);
813  bucket_bytes = nbuckets * sizeof(HashJoinTuple);
814 
815  /*
816  * Buckets are simple pointers to hashjoin tuples, while tupsize
817  * includes the pointer, hash code, and MinimalTupleData. So buckets
818  * should never really exceed 25% of work_mem (even for
819  * NTUP_PER_BUCKET=1); except maybe for work_mem values that are not
820  * 2^N bytes, where we might get more because of doubling. So let's
821  * look for 50% here.
822  */
823  Assert(bucket_bytes <= hash_table_bytes / 2);
824 
825  /* Calculate required number of batches. */
826  dbatch = ceil(inner_rel_bytes / (hash_table_bytes - bucket_bytes));
827  dbatch = Min(dbatch, max_pointers);
828  minbatch = (int) dbatch;
829  nbatch = 2;
830  while (nbatch < minbatch)
831  nbatch <<= 1;
832  }
833 
834  Assert(nbuckets > 0);
835  Assert(nbatch > 0);
836 
837  *numbuckets = nbuckets;
838  *numbatches = nbatch;
839 }
#define SKEW_BUCKET_OVERHEAD
Definition: hashjoin.h:108
#define Min(x, y)
Definition: c.h:857
struct HashJoinTupleData * HashJoinTuple
Definition: execnodes.h:1784
int my_log2(long num)
Definition: dynahash.c:1718
#define MaxAllocSize
Definition: memutils.h:40
#define SizeofMinimalTupleHeader
Definition: htup_details.h:667
#define NTUP_PER_BUCKET
Definition: nodeHash.c:659
int work_mem
Definition: globals.c:122
#define HJTUPLE_OVERHEAD
Definition: hashjoin.h:79
#define Max(x, y)
Definition: c.h:851
#define Assert(condition)
Definition: c.h:699
#define MAXALIGN(LEN)
Definition: c.h:652
#define SKEW_WORK_MEM_PERCENT
Definition: hashjoin.h:110
void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, bool try_combined_work_mem, int parallel_workers, size_t *space_allowed, int *numbuckets, int *numbatches, int *num_skew_mcvs)
Definition: nodeHash.c:662

◆ ExecEndHash()

void ExecEndHash ( HashState node)

Definition at line 404 of file nodeHash.c.

References ExecEndNode(), ExecFreeExprContext(), outerPlan, outerPlanState, and HashState::ps.

Referenced by ExecEndNode().

405 {
407 
408  /*
409  * free exprcontext
410  */
411  ExecFreeExprContext(&node->ps);
412 
413  /*
414  * shut down the subplan
415  */
416  outerPlan = outerPlanState(node);
417  ExecEndNode(outerPlan);
418 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:539
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:566
#define outerPlanState(node)
Definition: execnodes.h:965
PlanState ps
Definition: execnodes.h:2127
#define outerPlan(node)
Definition: plannodes.h:176

◆ ExecHashEstimate()

void ExecHashEstimate ( HashState node,
ParallelContext pcxt 
)

Definition at line 2544 of file nodeHash.c.

References add_size(), ParallelContext::estimator, PlanState::instrument, mul_size(), ParallelContext::nworkers, offsetof, HashState::ps, shm_toc_estimate_chunk, and shm_toc_estimate_keys.

Referenced by ExecParallelEstimate().

2545 {
2546  size_t size;
2547 
2548  /* don't need this if not instrumenting or no workers */
2549  if (!node->ps.instrument || pcxt->nworkers == 0)
2550  return;
2551 
2552  size = mul_size(pcxt->nworkers, sizeof(HashInstrumentation));
2553  size = add_size(size, offsetof(SharedHashInfo, hinstrument));
2554  shm_toc_estimate_chunk(&pcxt->estimator, size);
2555  shm_toc_estimate_keys(&pcxt->estimator, 1);
2556 }
Instrumentation * instrument
Definition: execnodes.h:921
shm_toc_estimator estimator
Definition: parallel.h:41
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
PlanState ps
Definition: execnodes.h:2127
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:622

◆ ExecHashGetBucketAndBatch()

void ExecHashGetBucketAndBatch ( HashJoinTable  hashtable,
uint32  hashvalue,
int *  bucketno,
int *  batchno 
)

Definition at line 1875 of file nodeHash.c.

References HashJoinTableData::log2_nbuckets, HashJoinTableData::nbatch, and HashJoinTableData::nbuckets.

Referenced by ExecHashIncreaseNumBatches(), ExecHashIncreaseNumBuckets(), ExecHashJoinImpl(), ExecHashRemoveNextSkewBucket(), ExecHashTableInsert(), ExecParallelHashIncreaseNumBuckets(), ExecParallelHashJoinPartitionOuter(), ExecParallelHashRepartitionFirst(), ExecParallelHashRepartitionRest(), ExecParallelHashTableInsert(), and ExecParallelHashTableInsertCurrentBatch().

1879 {
1880  uint32 nbuckets = (uint32) hashtable->nbuckets;
1881  uint32 nbatch = (uint32) hashtable->nbatch;
1882 
1883  if (nbatch > 1)
1884  {
1885  /* we can do MOD by masking, DIV by shifting */
1886  *bucketno = hashvalue & (nbuckets - 1);
1887  *batchno = (hashvalue >> hashtable->log2_nbuckets) & (nbatch - 1);
1888  }
1889  else
1890  {
1891  *bucketno = hashvalue & (nbuckets - 1);
1892  *batchno = 0;
1893  }
1894 }
unsigned int uint32
Definition: c.h:325

◆ ExecHashGetHashValue()

bool ExecHashGetHashValue ( HashJoinTable  hashtable,
ExprContext econtext,
List hashkeys,
bool  outer_tuple,
bool  keep_nulls,
uint32 hashvalue 
)

Definition at line 1771 of file nodeHash.c.

References DatumGetUInt32, ExprContext::ecxt_per_tuple_memory, ExecEvalExpr(), FunctionCall1, HashJoinTableData::hashStrict, i, HashJoinTableData::inner_hashfunctions, lfirst, MemoryContextSwitchTo(), HashJoinTableData::outer_hashfunctions, and ResetExprContext.

Referenced by ExecHashJoinOuterGetTuple(), ExecParallelHashJoinOuterGetTuple(), ExecParallelHashJoinPartitionOuter(), MultiExecParallelHash(), and MultiExecPrivateHash().

1777 {
1778  uint32 hashkey = 0;
1779  FmgrInfo *hashfunctions;
1780  ListCell *hk;
1781  int i = 0;
1782  MemoryContext oldContext;
1783 
1784  /*
1785  * We reset the eval context each time to reclaim any memory leaked in the
1786  * hashkey expressions.
1787  */
1788  ResetExprContext(econtext);
1789 
1790  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
1791 
1792  if (outer_tuple)
1793  hashfunctions = hashtable->outer_hashfunctions;
1794  else
1795  hashfunctions = hashtable->inner_hashfunctions;
1796 
1797  foreach(hk, hashkeys)
1798  {
1799  ExprState *keyexpr = (ExprState *) lfirst(hk);
1800  Datum keyval;
1801  bool isNull;
1802 
1803  /* rotate hashkey left 1 bit at each step */
1804  hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
1805 
1806  /*
1807  * Get the join attribute value of the tuple
1808  */
1809  keyval = ExecEvalExpr(keyexpr, econtext, &isNull);
1810 
1811  /*
1812  * If the attribute is NULL, and the join operator is strict, then
1813  * this tuple cannot pass the join qual so we can reject it
1814  * immediately (unless we're scanning the outside of an outer join, in
1815  * which case we must not reject it). Otherwise we act like the
1816  * hashcode of NULL is zero (this will support operators that act like
1817  * IS NOT DISTINCT, though not any more-random behavior). We treat
1818  * the hash support function as strict even if the operator is not.
1819  *
1820  * Note: currently, all hashjoinable operators must be strict since
1821  * the hash index AM assumes that. However, it takes so little extra
1822  * code here to allow non-strict that we may as well do it.
1823  */
1824  if (isNull)
1825  {
1826  if (hashtable->hashStrict[i] && !keep_nulls)
1827  {
1828  MemoryContextSwitchTo(oldContext);
1829  return false; /* cannot match */
1830  }
1831  /* else, leave hashkey unmodified, equivalent to hashcode 0 */
1832  }
1833  else
1834  {
1835  /* Compute the hash function */
1836  uint32 hkey;
1837 
1838  hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i], keyval));
1839  hashkey ^= hkey;
1840  }
1841 
1842  i++;
1843  }
1844 
1845  MemoryContextSwitchTo(oldContext);
1846 
1847  *hashvalue = hashkey;
1848  return true;
1849 }
#define DatumGetUInt32(X)
Definition: postgres.h:469
Definition: fmgr.h:56
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:226
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FmgrInfo * inner_hashfunctions
Definition: hashjoin.h:338
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
unsigned int uint32
Definition: c.h:325
FmgrInfo * outer_hashfunctions
Definition: hashjoin.h:337
uintptr_t Datum
Definition: postgres.h:365
#define lfirst(lc)
Definition: pg_list.h:106
int i
#define FunctionCall1(flinfo, arg1)
Definition: fmgr.h:608
bool * hashStrict
Definition: hashjoin.h:339
#define ResetExprContext(econtext)
Definition: executor.h:483

◆ ExecHashGetInstrumentation()

void ExecHashGetInstrumentation ( HashInstrumentation instrument,
HashJoinTable  hashtable 
)

◆ ExecHashGetSkewBucket()

int ExecHashGetSkewBucket ( HashJoinTable  hashtable,
uint32  hashvalue 
)

Definition at line 2343 of file nodeHash.c.

References HashSkewBucket::hashvalue, INVALID_SKEW_BUCKET_NO, HashJoinTableData::skewBucket, HashJoinTableData::skewBucketLen, and HashJoinTableData::skewEnabled.

Referenced by ExecHashJoinImpl(), and MultiExecPrivateHash().

2344 {
2345  int bucket;
2346 
2347  /*
2348  * Always return INVALID_SKEW_BUCKET_NO if not doing skew optimization (in
2349  * particular, this happens after the initial batch is done).
2350  */
2351  if (!hashtable->skewEnabled)
2352  return INVALID_SKEW_BUCKET_NO;
2353 
2354  /*
2355  * Since skewBucketLen is a power of 2, we can do a modulo by ANDing.
2356  */
2357  bucket = hashvalue & (hashtable->skewBucketLen - 1);
2358 
2359  /*
2360  * While we have not hit a hole in the hashtable and have not hit the
2361  * desired bucket, we have collided with some other hash value, so try the
2362  * next bucket location.
2363  */
2364  while (hashtable->skewBucket[bucket] != NULL &&
2365  hashtable->skewBucket[bucket]->hashvalue != hashvalue)
2366  bucket = (bucket + 1) & (hashtable->skewBucketLen - 1);
2367 
2368  /*
2369  * Found the desired bucket?
2370  */
2371  if (hashtable->skewBucket[bucket] != NULL)
2372  return bucket;
2373 
2374  /*
2375  * There must not be any hashtable entry for this hash value.
2376  */
2377  return INVALID_SKEW_BUCKET_NO;
2378 }
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:109
HashSkewBucket ** skewBucket
Definition: hashjoin.h:305
uint32 hashvalue
Definition: hashjoin.h:104

◆ ExecHashInitializeDSM()

void ExecHashInitializeDSM ( HashState node,
ParallelContext pcxt 
)

Definition at line 2563 of file nodeHash.c.

References PlanState::instrument, SharedHashInfo::num_workers, ParallelContext::nworkers, offsetof, PlanState::plan, Plan::plan_node_id, HashState::ps, HashState::shared_info, shm_toc_allocate(), shm_toc_insert(), and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

2564 {
2565  size_t size;
2566 
2567  /* don't need this if not instrumenting or no workers */
2568  if (!node->ps.instrument || pcxt->nworkers == 0)
2569  return;
2570 
2571  size = offsetof(SharedHashInfo, hinstrument) +
2572  pcxt->nworkers * sizeof(HashInstrumentation);
2573  node->shared_info = (SharedHashInfo *) shm_toc_allocate(pcxt->toc, size);
2574  memset(node->shared_info, 0, size);
2575  node->shared_info->num_workers = pcxt->nworkers;
2576  shm_toc_insert(pcxt->toc, node->ps.plan->plan_node_id,
2577  node->shared_info);
2578 }
Instrumentation * instrument
Definition: execnodes.h:921
struct HashInstrumentation HashInstrumentation
int plan_node_id
Definition: plannodes.h:145
SharedHashInfo * shared_info
Definition: execnodes.h:2132
PlanState ps
Definition: execnodes.h:2127
Plan * plan
Definition: execnodes.h:911
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
#define offsetof(type, field)
Definition: c.h:622
shm_toc * toc
Definition: parallel.h:44

◆ ExecHashInitializeWorker()

void ExecHashInitializeWorker ( HashState node,
ParallelWorkerContext pwcxt 
)

Definition at line 2585 of file nodeHash.c.

References SharedHashInfo::hinstrument, HashState::hinstrument, PlanState::instrument, ParallelWorkerNumber, PlanState::plan, Plan::plan_node_id, HashState::ps, shm_toc_lookup(), and ParallelWorkerContext::toc.

Referenced by ExecParallelInitializeWorker().

2586 {
2587  SharedHashInfo *shared_info;
2588 
2589  /* don't need this if not instrumenting */
2590  if (!node->ps.instrument)
2591  return;
2592 
2593  shared_info = (SharedHashInfo *)
2594  shm_toc_lookup(pwcxt->toc, node->ps.plan->plan_node_id, false);
2595  node->hinstrument = &shared_info->hinstrument[ParallelWorkerNumber];
2596 }
Instrumentation * instrument
Definition: execnodes.h:921
int plan_node_id
Definition: plannodes.h:145
int ParallelWorkerNumber
Definition: parallel.c:103
PlanState ps
Definition: execnodes.h:2127
HashInstrumentation * hinstrument
Definition: execnodes.h:2133
HashInstrumentation hinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2118
Plan * plan
Definition: execnodes.h:911
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecHashRetrieveInstrumentation()

void ExecHashRetrieveInstrumentation ( HashState node)

Definition at line 2616 of file nodeHash.c.

References SharedHashInfo::num_workers, offsetof, palloc(), and HashState::shared_info.

Referenced by ExecParallelRetrieveInstrumentation().

2617 {
2618  SharedHashInfo *shared_info = node->shared_info;
2619  size_t size;
2620 
2621  if (shared_info == NULL)
2622  return;
2623 
2624  /* Replace node->shared_info with a copy in backend-local memory. */
2625  size = offsetof(SharedHashInfo, hinstrument) +
2626  shared_info->num_workers * sizeof(HashInstrumentation);
2627  node->shared_info = palloc(size);
2628  memcpy(node->shared_info, shared_info, size);
2629 }
struct HashInstrumentation HashInstrumentation
SharedHashInfo * shared_info
Definition: execnodes.h:2132
void * palloc(Size size)
Definition: mcxt.c:924
#define offsetof(type, field)
Definition: c.h:622

◆ ExecHashTableCreate()

HashJoinTable ExecHashTableCreate ( HashState state,
List hashOperators,
bool  keepNulls 
)

Definition at line 428 of file nodeHash.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, HashJoinTableData::area, Assert, BarrierArriveAndWait(), BarrierAttach(), BarrierPhase(), HashJoinTableData::batchCxt, HashJoinTableData::batches, HashJoinTableData::buckets, ParallelHashJoinState::build_barrier, HashJoinTableData::chunks, HashJoinTableData::curbatch, HashJoinTableData::current_chunk, CurrentMemoryContext, elog, ERROR, EState::es_query_dsa, ExecChooseHashTableSize(), ExecHashBuildSkewHash(), ExecParallelHashJoinSetUpBatches(), ExecParallelHashTableAlloc(), fmgr_info(), get_op_hash_functions(), HashJoinTableData::growEnabled, ParallelHashJoinState::growth, HashJoinTableData::hashCxt, HashJoinTableData::hashStrict, i, HashJoinTableData::inner_hashfunctions, HashJoinTableData::innerBatchFile, HashJoinTableData::keepNulls, lfirst_oid, list_length(), HashJoinTableData::log2_nbuckets, HashJoinTableData::log2_nbuckets_optimal, MemoryContextSwitchTo(), my_log2(), ParallelHashJoinState::nbatch, HashJoinTableData::nbatch, HashJoinTableData::nbatch_original, HashJoinTableData::nbatch_outstart, ParallelHashJoinState::nbuckets, HashJoinTableData::nbuckets, HashJoinTableData::nbuckets_optimal, HashJoinTableData::nbuckets_original, ParallelHashJoinState::nparticipants, HashJoinTableData::nSkewBuckets, OidIsValid, op_strict(), HashJoinTableData::outer_hashfunctions, HashJoinTableData::outerBatchFile, outerPlan, palloc(), palloc0(), Plan::parallel_aware, HashJoinTableData::parallel_state, HashState::parallel_state, HashJoinTableData::partialTuples, PHJ_BUILD_ELECTING, PHJ_GROWTH_OK, Hash::plan, PlanState::plan, Plan::plan_rows, Plan::plan_width, PrepareTempTablespaces(), HashState::ps, Hash::rows_total, SKEW_WORK_MEM_PERCENT, HashJoinTableData::skewBucket, HashJoinTableData::skewBucketLen, HashJoinTableData::skewBucketNums, HashJoinTableData::skewEnabled, Hash::skewTable, HashJoinTableData::skewTuples, ParallelHashJoinState::space_allowed, HashJoinTableData::spaceAllowed, HashJoinTableData::spaceAllowedSkew, HashJoinTableData::spacePeak, HashJoinTableData::spaceUsed, HashJoinTableData::spaceUsedSkew, PlanState::state, HashJoinTableData::totalTuples, HashJoinTableData::unshared, and WAIT_EVENT_HASH_BUILD_ELECTING.

Referenced by ExecHashJoinImpl().

429 {
430  Hash *node;
431  HashJoinTable hashtable;
432  Plan *outerNode;
433  size_t space_allowed;
434  int nbuckets;
435  int nbatch;
436  double rows;
437  int num_skew_mcvs;
438  int log2_nbuckets;
439  int nkeys;
440  int i;
441  ListCell *ho;
442  MemoryContext oldcxt;
443 
444  /*
445  * Get information about the size of the relation to be hashed (it's the
446  * "outer" subtree of this node, but the inner relation of the hashjoin).
447  * Compute the appropriate size of the hash table.
448  */
449  node = (Hash *) state->ps.plan;
450  outerNode = outerPlan(node);
451 
452  /*
453  * If this is shared hash table with a partial plan, then we can't use
454  * outerNode->plan_rows to estimate its size. We need an estimate of the
455  * total number of rows across all copies of the partial plan.
456  */
457  rows = node->plan.parallel_aware ? node->rows_total : outerNode->plan_rows;
458 
459  ExecChooseHashTableSize(rows, outerNode->plan_width,
460  OidIsValid(node->skewTable),
461  state->parallel_state != NULL,
462  state->parallel_state != NULL ?
463  state->parallel_state->nparticipants - 1 : 0,
464  &space_allowed,
465  &nbuckets, &nbatch, &num_skew_mcvs);
466 
467  /* nbuckets must be a power of 2 */
468  log2_nbuckets = my_log2(nbuckets);
469  Assert(nbuckets == (1 << log2_nbuckets));
470 
471  /*
472  * Initialize the hash table control block.
473  *
474  * The hashtable control block is just palloc'd from the executor's
475  * per-query memory context. Everything else should be kept inside the
476  * subsidiary hashCxt or batchCxt.
477  */
478  hashtable = (HashJoinTable) palloc(sizeof(HashJoinTableData));
479  hashtable->nbuckets = nbuckets;
480  hashtable->nbuckets_original = nbuckets;
481  hashtable->nbuckets_optimal = nbuckets;
482  hashtable->log2_nbuckets = log2_nbuckets;
483  hashtable->log2_nbuckets_optimal = log2_nbuckets;
484  hashtable->buckets.unshared = NULL;
485  hashtable->keepNulls = keepNulls;
486  hashtable->skewEnabled = false;
487  hashtable->skewBucket = NULL;
488  hashtable->skewBucketLen = 0;
489  hashtable->nSkewBuckets = 0;
490  hashtable->skewBucketNums = NULL;
491  hashtable->nbatch = nbatch;
492  hashtable->curbatch = 0;
493  hashtable->nbatch_original = nbatch;
494  hashtable->nbatch_outstart = nbatch;
495  hashtable->growEnabled = true;
496  hashtable->totalTuples = 0;
497  hashtable->partialTuples = 0;
498  hashtable->skewTuples = 0;
499  hashtable->innerBatchFile = NULL;
500  hashtable->outerBatchFile = NULL;
501  hashtable->spaceUsed = 0;
502  hashtable->spacePeak = 0;
503  hashtable->spaceAllowed = space_allowed;
504  hashtable->spaceUsedSkew = 0;
505  hashtable->spaceAllowedSkew =
506  hashtable->spaceAllowed * SKEW_WORK_MEM_PERCENT / 100;
507  hashtable->chunks = NULL;
508  hashtable->current_chunk = NULL;
509  hashtable->parallel_state = state->parallel_state;
510  hashtable->area = state->ps.state->es_query_dsa;
511  hashtable->batches = NULL;
512 
513 #ifdef HJDEBUG
514  printf("Hashjoin %p: initial nbatch = %d, nbuckets = %d\n",
515  hashtable, nbatch, nbuckets);
516 #endif
517 
518  /*
519  * Create temporary memory contexts in which to keep the hashtable working
520  * storage. See notes in executor/hashjoin.h.
521  */
523  "HashTableContext",
525 
526  hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
527  "HashBatchContext",
529 
530  /* Allocate data that will live for the life of the hashjoin */
531 
532  oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
533 
534  /*
535  * Get info about the hash functions to be used for each hash key. Also
536  * remember whether the join operators are strict.
537  */
538  nkeys = list_length(hashOperators);
539  hashtable->outer_hashfunctions =
540  (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
541  hashtable->inner_hashfunctions =
542  (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
543  hashtable->hashStrict = (bool *) palloc(nkeys * sizeof(bool));
544  i = 0;
545  foreach(ho, hashOperators)
546  {
547  Oid hashop = lfirst_oid(ho);
548  Oid left_hashfn;
549  Oid right_hashfn;
550 
551  if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
552  elog(ERROR, "could not find hash function for hash operator %u",
553  hashop);
554  fmgr_info(left_hashfn, &hashtable->outer_hashfunctions[i]);
555  fmgr_info(right_hashfn, &hashtable->inner_hashfunctions[i]);
556  hashtable->hashStrict[i] = op_strict(hashop);
557  i++;
558  }
559 
560  if (nbatch > 1 && hashtable->parallel_state == NULL)
561  {
562  /*
563  * allocate and initialize the file arrays in hashCxt (not needed for
564  * parallel case which uses shared tuplestores instead of raw files)
565  */
566  hashtable->innerBatchFile = (BufFile **)
567  palloc0(nbatch * sizeof(BufFile *));
568  hashtable->outerBatchFile = (BufFile **)
569  palloc0(nbatch * sizeof(BufFile *));
570  /* The files will not be opened until needed... */
571  /* ... but make sure we have temp tablespaces established for them */
573  }
574 
575  MemoryContextSwitchTo(oldcxt);
576 
577  if (hashtable->parallel_state)
578  {
579  ParallelHashJoinState *pstate = hashtable->parallel_state;
580  Barrier *build_barrier;
581 
582  /*
583  * Attach to the build barrier. The corresponding detach operation is
584  * in ExecHashTableDetach. Note that we won't attach to the
585  * batch_barrier for batch 0 yet. We'll attach later and start it out
586  * in PHJ_BATCH_PROBING phase, because batch 0 is allocated up front
587  * and then loaded while hashing (the standard hybrid hash join
588  * algorithm), and we'll coordinate that using build_barrier.
589  */
590  build_barrier = &pstate->build_barrier;
591  BarrierAttach(build_barrier);
592 
593  /*
594  * So far we have no idea whether there are any other participants,
595  * and if so, what phase they are working on. The only thing we care
596  * about at this point is whether someone has already created the
597  * SharedHashJoinBatch objects and the hash table for batch 0. One
598  * backend will be elected to do that now if necessary.
599  */
600  if (BarrierPhase(build_barrier) == PHJ_BUILD_ELECTING &&
602  {
603  pstate->nbatch = nbatch;
604  pstate->space_allowed = space_allowed;
605  pstate->growth = PHJ_GROWTH_OK;
606 
607  /* Set up the shared state for coordinating batches. */
608  ExecParallelHashJoinSetUpBatches(hashtable, nbatch);
609 
610  /*
611  * Allocate batch 0's hash table up front so we can load it
612  * directly while hashing.
613  */
614  pstate->nbuckets = nbuckets;
615  ExecParallelHashTableAlloc(hashtable, 0);
616  }
617 
618  /*
619  * The next Parallel Hash synchronization point is in
620  * MultiExecParallelHash(), which will progress it all the way to
621  * PHJ_BUILD_DONE. The caller must not return control from this
622  * executor node between now and then.
623  */
624  }
625  else
626  {
627  /*
628  * Prepare context for the first-scan space allocations; allocate the
629  * hashbucket array therein, and set each bucket "empty".
630  */
631  MemoryContextSwitchTo(hashtable->batchCxt);
632 
633  hashtable->buckets.unshared = (HashJoinTuple *)
634  palloc0(nbuckets * sizeof(HashJoinTuple));
635 
636  /*
637  * Set up for skew optimization, if possible and there's a need for
638  * more than one batch. (In a one-batch join, there's no point in
639  * it.)
640  */
641  if (nbatch > 1)
642  ExecHashBuildSkewHash(hashtable, node, num_skew_mcvs);
643 
644  MemoryContextSwitchTo(oldcxt);
645  }
646 
647  return hashtable;
648 }
int log2_nbuckets_optimal
Definition: hashjoin.h:291
double rows_total
Definition: plannodes.h:902
Oid skewTable
Definition: plannodes.h:898
struct ParallelHashJoinState * parallel_state
Definition: execnodes.h:2136
double skewTuples
Definition: hashjoin.h:320
Definition: fmgr.h:56
struct dsa_area * es_query_dsa
Definition: execnodes.h:565
double plan_rows
Definition: plannodes.h:133
bool op_strict(Oid opno)
Definition: lsyscache.c:1266
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:507
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
FmgrInfo * inner_hashfunctions
Definition: hashjoin.h:338
void ExecParallelHashTableAlloc(HashJoinTable hashtable, int batchno)
Definition: nodeHash.c:3036
EState * state
Definition: execnodes.h:913
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse)
Definition: nodeHash.c:2189
double partialTuples
Definition: hashjoin.h:319
dsa_area * area
Definition: hashjoin.h:355
int * skewBucketNums
Definition: hashjoin.h:308
#define ERROR
Definition: elog.h:43
void PrepareTempTablespaces(void)
Definition: tablespace.c:1289
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:123
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
BufFile ** outerBatchFile
Definition: hashjoin.h:330
Size spaceAllowedSkew
Definition: hashjoin.h:345
bool parallel_aware
Definition: plannodes.h:139
PlanState ps
Definition: execnodes.h:2127
#define PHJ_BUILD_ELECTING
Definition: hashjoin.h:257
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
MemoryContext batchCxt
Definition: hashjoin.h:348
struct HashJoinTableData * HashJoinTable
Definition: execnodes.h:1785
int my_log2(long num)
Definition: dynahash.c:1718
#define outerPlan(node)
Definition: plannodes.h:176
FmgrInfo * outer_hashfunctions
Definition: hashjoin.h:337
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
HashSkewBucket ** skewBucket
Definition: hashjoin.h:305
int BarrierAttach(Barrier *barrier)
Definition: barrier.c:214
void * palloc0(Size size)
Definition: mcxt.c:955
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:356
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:357
Plan * plan
Definition: execnodes.h:911
double totalTuples
Definition: hashjoin.h:318
int plan_width
Definition: plannodes.h:134
#define Assert(condition)
Definition: c.h:699
ParallelHashGrowth growth
Definition: hashjoin.h:241
BufFile ** innerBatchFile
Definition: hashjoin.h:329
static int list_length(const List *l)
Definition: pg_list.h:89
int BarrierPhase(Barrier *barrier)
Definition: barrier.c:243
union HashJoinTableData::@97 buckets
bool BarrierArriveAndWait(Barrier *barrier, uint32 wait_event_info)
Definition: barrier.c:125
HashMemoryChunk chunks
Definition: hashjoin.h:351
Plan plan
Definition: plannodes.h:897
void * palloc(Size size)
Definition: mcxt.c:924
static void ExecParallelHashJoinSetUpBatches(HashJoinTable hashtable, int nbatch)
Definition: nodeHash.c:2875
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:297
HashMemoryChunk current_chunk
Definition: hashjoin.h:354
int i
bool * hashStrict
Definition: hashjoin.h:339
MemoryContext hashCxt
Definition: hashjoin.h:347
#define elog
Definition: elog.h:219
#define SKEW_WORK_MEM_PERCENT
Definition: hashjoin.h:110
void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, bool try_combined_work_mem, int parallel_workers, size_t *space_allowed, int *numbuckets, int *numbatches, int *num_skew_mcvs)
Definition: nodeHash.c:662
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ ExecHashTableDestroy()

void ExecHashTableDestroy ( HashJoinTable  hashtable)

Definition at line 849 of file nodeHash.c.

References BufFileClose(), HashJoinTableData::hashCxt, i, HashJoinTableData::innerBatchFile, MemoryContextDelete(), HashJoinTableData::nbatch, HashJoinTableData::outerBatchFile, and pfree().

Referenced by ExecEndHashJoin(), and ExecReScanHashJoin().

850 {
851  int i;
852 
853  /*
854  * Make sure all the temp files are closed. We skip batch 0, since it
855  * can't have any temp files (and the arrays might not even exist if
856  * nbatch is only 1). Parallel hash joins don't use these files.
857  */
858  if (hashtable->innerBatchFile != NULL)
859  {
860  for (i = 1; i < hashtable->nbatch; i++)
861  {
862  if (hashtable->innerBatchFile[i])
863  BufFileClose(hashtable->innerBatchFile[i]);
864  if (hashtable->outerBatchFile[i])
865  BufFileClose(hashtable->outerBatchFile[i]);
866  }
867  }
868 
869  /* Release working memory (batchCxt is a child, so it goes away too) */
870  MemoryContextDelete(hashtable->hashCxt);
871 
872  /* And drop the control block */
873  pfree(hashtable);
874 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void BufFileClose(BufFile *file)
Definition: buffile.c:397
void pfree(void *pointer)
Definition: mcxt.c:1031
BufFile ** outerBatchFile
Definition: hashjoin.h:330
BufFile ** innerBatchFile
Definition: hashjoin.h:329
int i
MemoryContext hashCxt
Definition: hashjoin.h:347

◆ ExecHashTableDetach()

void ExecHashTableDetach ( HashJoinTable  hashtable)

Definition at line 3113 of file nodeHash.c.

References HashJoinTableData::area, BarrierDetach(), ParallelHashJoinState::batches, HashJoinTableData::batches, ParallelHashJoinState::build_barrier, dsa_free(), DsaPointerIsValid, i, ParallelHashJoinBatchAccessor::inner_tuples, InvalidDsaPointer, HashJoinTableData::nbatch, ParallelHashJoinBatchAccessor::outer_tuples, HashJoinTableData::parallel_state, sts_end_parallel_scan(), and sts_end_write().

Referenced by ExecHashJoinReInitializeDSM(), and ExecShutdownHashJoin().

3114 {
3115  if (hashtable->parallel_state)
3116  {
3117  ParallelHashJoinState *pstate = hashtable->parallel_state;
3118  int i;
3119 
3120  /* Make sure any temporary files are closed. */
3121  if (hashtable->batches)
3122  {
3123  for (i = 0; i < hashtable->nbatch; ++i)
3124  {
3125  sts_end_write(hashtable->batches[i].inner_tuples);
3126  sts_end_write(hashtable->batches[i].outer_tuples);
3129  }
3130  }
3131 
3132  /* If we're last to detach, clean up shared memory. */
3133  if (BarrierDetach(&pstate->build_barrier))
3134  {
3135  if (DsaPointerIsValid(pstate->batches))
3136  {
3137  dsa_free(hashtable->area, pstate->batches);
3138  pstate->batches = InvalidDsaPointer;
3139  }
3140  }
3141 
3142  hashtable->parallel_state = NULL;
3143  }
3144 }
SharedTuplestoreAccessor * outer_tuples
Definition: hashjoin.h:209
#define InvalidDsaPointer
Definition: dsa.h:78
SharedTuplestoreAccessor * inner_tuples
Definition: hashjoin.h:208
dsa_area * area
Definition: hashjoin.h:355
dsa_pointer batches
Definition: hashjoin.h:236
void sts_end_parallel_scan(SharedTuplestoreAccessor *accessor)
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:356
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:357
bool BarrierDetach(Barrier *barrier)
Definition: barrier.c:234
#define DsaPointerIsValid(x)
Definition: dsa.h:81
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:812
int i
void sts_end_write(SharedTuplestoreAccessor *accessor)

◆ ExecHashTableDetachBatch()

void ExecHashTableDetachBatch ( HashJoinTable  hashtable)

Definition at line 3056 of file nodeHash.c.

References HashJoinTableData::area, Assert, BarrierArriveAndDetach(), BarrierPhase(), ParallelHashJoinBatch::batch_barrier, HashJoinTableData::batches, ParallelHashJoinBatch::buckets, ParallelHashJoinBatch::chunks, HashJoinTableData::curbatch, dsa_free(), dsa_get_address(), DsaPointerIsValid, ParallelHashJoinBatchAccessor::inner_tuples, InvalidDsaPointer, Max, HashJoinTableData::nbuckets, HashMemoryChunkData::next, next, ParallelHashJoinBatchAccessor::outer_tuples, HashJoinTableData::parallel_state, PHJ_BATCH_DONE, HashMemoryChunkData::shared, ParallelHashJoinBatchAccessor::shared, ParallelHashJoinBatch::size, HashJoinTableData::spacePeak, and sts_end_parallel_scan().

Referenced by ExecHashJoinReInitializeDSM(), ExecParallelHashJoinNewBatch(), and ExecShutdownHashJoin().

3057 {
3058  if (hashtable->parallel_state != NULL &&
3059  hashtable->curbatch >= 0)
3060  {
3061  int curbatch = hashtable->curbatch;
3062  ParallelHashJoinBatch *batch = hashtable->batches[curbatch].shared;
3063 
3064  /* Make sure any temporary files are closed. */
3065  sts_end_parallel_scan(hashtable->batches[curbatch].inner_tuples);
3066  sts_end_parallel_scan(hashtable->batches[curbatch].outer_tuples);
3067 
3068  /* Detach from the batch we were last working on. */
3070  {
3071  /*
3072  * Technically we shouldn't access the barrier because we're no
3073  * longer attached, but since there is no way it's moving after
3074  * this point it seems safe to make the following assertion.
3075  */
3077 
3078  /* Free shared chunks and buckets. */
3079  while (DsaPointerIsValid(batch->chunks))
3080  {
3081  HashMemoryChunk chunk =
3082  dsa_get_address(hashtable->area, batch->chunks);
3083  dsa_pointer next = chunk->next.shared;
3084 
3085  dsa_free(hashtable->area, batch->chunks);
3086  batch->chunks = next;
3087  }
3088  if (DsaPointerIsValid(batch->buckets))
3089  {
3090  dsa_free(hashtable->area, batch->buckets);
3091  batch->buckets = InvalidDsaPointer;
3092  }
3093  }
3094 
3095  /*
3096  * Track the largest batch we've been attached to. Though each
3097  * backend might see a different subset of batches, explain.c will
3098  * scan the results from all backends to find the largest value.
3099  */
3100  hashtable->spacePeak =
3101  Max(hashtable->spacePeak,
3102  batch->size + sizeof(dsa_pointer_atomic) * hashtable->nbuckets);
3103 
3104  /* Remember that we are not attached to a batch. */
3105  hashtable->curbatch = -1;
3106  }
3107 }
SharedTuplestoreAccessor * outer_tuples
Definition: hashjoin.h:209
#define PHJ_BATCH_DONE
Definition: hashjoin.h:268
static int32 next
Definition: blutils.c:211
#define InvalidDsaPointer
Definition: dsa.h:78
dsa_pointer chunks
Definition: hashjoin.h:156
uint64 dsa_pointer
Definition: dsa.h:62
SharedTuplestoreAccessor * inner_tuples
Definition: hashjoin.h:208
dsa_area * area
Definition: hashjoin.h:355
dsa_pointer shared
Definition: hashjoin.h:127
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
union HashMemoryChunkData::@96 next
void sts_end_parallel_scan(SharedTuplestoreAccessor *accessor)
bool BarrierArriveAndDetach(Barrier *barrier)
Definition: barrier.c:203
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:356
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:357
#define Max(x, y)
Definition: c.h:851
#define Assert(condition)
Definition: c.h:699
int BarrierPhase(Barrier *barrier)
Definition: barrier.c:243
ParallelHashJoinBatch * shared
Definition: hashjoin.h:197
#define DsaPointerIsValid(x)
Definition: dsa.h:81
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:812
dsa_pointer buckets
Definition: hashjoin.h:153

◆ ExecHashTableInsert()

void ExecHashTableInsert ( HashJoinTable  hashtable,
TupleTableSlot slot,
uint32  hashvalue 
)

Definition at line 1589 of file nodeHash.c.

References Assert, HashJoinTableData::buckets, HashJoinTableData::curbatch, dense_alloc(), ExecFetchSlotMinimalTuple(), ExecHashGetBucketAndBatch(), ExecHashIncreaseNumBatches(), ExecHashJoinSaveTuple(), HashJoinTupleData::hashvalue, HeapTupleHeaderClearMatch, HJTUPLE_MINTUPLE, HJTUPLE_OVERHEAD, HashJoinTableData::innerBatchFile, HashJoinTableData::log2_nbuckets_optimal, MaxAllocSize, HashJoinTableData::nbatch, HashJoinTableData::nbuckets_optimal, HashJoinTupleData::next, NTUP_PER_BUCKET, HashJoinTableData::skewTuples, HashJoinTableData::spaceAllowed, HashJoinTableData::spacePeak, HashJoinTableData::spaceUsed, MinimalTupleData::t_len, HashJoinTableData::totalTuples, HashJoinTupleData::unshared, and HashJoinTableData::unshared.

Referenced by ExecHashJoinNewBatch(), and MultiExecPrivateHash().

1592 {
1594  int bucketno;
1595  int batchno;
1596 
1597  ExecHashGetBucketAndBatch(hashtable, hashvalue,
1598  &bucketno, &batchno);
1599 
1600  /*
1601  * decide whether to put the tuple in the hash table or a temp file
1602  */
1603  if (batchno == hashtable->curbatch)
1604  {
1605  /*
1606  * put the tuple in hash table
1607  */
1608  HashJoinTuple hashTuple;
1609  int hashTupleSize;
1610  double ntuples = (hashtable->totalTuples - hashtable->skewTuples);
1611 
1612  /* Create the HashJoinTuple */
1613  hashTupleSize = HJTUPLE_OVERHEAD + tuple->t_len;
1614  hashTuple = (HashJoinTuple) dense_alloc(hashtable, hashTupleSize);
1615 
1616  hashTuple->hashvalue = hashvalue;
1617  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1618 
1619  /*
1620  * We always reset the tuple-matched flag on insertion. This is okay
1621  * even when reloading a tuple from a batch file, since the tuple
1622  * could not possibly have been matched to an outer tuple before it
1623  * went into the batch file.
1624  */
1626 
1627  /* Push it onto the front of the bucket's list */
1628  hashTuple->next.unshared = hashtable->buckets.unshared[bucketno];
1629  hashtable->buckets.unshared[bucketno] = hashTuple;
1630 
1631  /*
1632  * Increase the (optimal) number of buckets if we just exceeded the
1633  * NTUP_PER_BUCKET threshold, but only when there's still a single
1634  * batch.
1635  */
1636  if (hashtable->nbatch == 1 &&
1637  ntuples > (hashtable->nbuckets_optimal * NTUP_PER_BUCKET))
1638  {
1639  /* Guard against integer overflow and alloc size overflow */
1640  if (hashtable->nbuckets_optimal <= INT_MAX / 2 &&
1641  hashtable->nbuckets_optimal * 2 <= MaxAllocSize / sizeof(HashJoinTuple))
1642  {
1643  hashtable->nbuckets_optimal *= 2;
1644  hashtable->log2_nbuckets_optimal += 1;
1645  }
1646  }
1647 
1648  /* Account for space used, and back off if we've used too much */
1649  hashtable->spaceUsed += hashTupleSize;
1650  if (hashtable->spaceUsed > hashtable->spacePeak)
1651  hashtable->spacePeak = hashtable->spaceUsed;
1652  if (hashtable->spaceUsed +
1653  hashtable->nbuckets_optimal * sizeof(HashJoinTuple)
1654  > hashtable->spaceAllowed)
1655  ExecHashIncreaseNumBatches(hashtable);
1656  }
1657  else
1658  {
1659  /*
1660  * put the tuple into a temp file for later batches
1661  */
1662  Assert(batchno > hashtable->curbatch);
1663  ExecHashJoinSaveTuple(tuple,
1664  hashvalue,
1665  &hashtable->innerBatchFile[batchno]);
1666  }
1667 }
int log2_nbuckets_optimal
Definition: hashjoin.h:291
double skewTuples
Definition: hashjoin.h:320
union HashJoinTupleData::@95 next
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
Definition: execTuples.c:708
static void ExecHashIncreaseNumBatches(HashJoinTable hashtable)
Definition: nodeHash.c:882
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
Definition: nodeHash.c:1875
struct HashJoinTupleData * unshared
Definition: hashjoin.h:72
struct HashJoinTupleData * HashJoinTuple
Definition: execnodes.h:1784
#define MaxAllocSize
Definition: memutils.h:40
static void * dense_alloc(HashJoinTable hashtable, Size size)
Definition: nodeHash.c:2650
#define NTUP_PER_BUCKET
Definition: nodeHash.c:659
#define HJTUPLE_OVERHEAD
Definition: hashjoin.h:79
double totalTuples
Definition: hashjoin.h:318
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
#define Assert(condition)
Definition: c.h:699
BufFile ** innerBatchFile
Definition: hashjoin.h:329
#define HeapTupleHeaderClearMatch(tup)
Definition: htup_details.h:544
union HashJoinTableData::@97 buckets
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:297
void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
uint32 hashvalue
Definition: hashjoin.h:75

◆ ExecHashTableReset()

void ExecHashTableReset ( HashJoinTable  hashtable)

Definition at line 2114 of file nodeHash.c.

References HashJoinTableData::batchCxt, HashJoinTableData::buckets, HashJoinTableData::chunks, MemoryContextReset(), MemoryContextSwitchTo(), HashJoinTableData::nbuckets, palloc0(), HashJoinTableData::spaceUsed, and HashJoinTableData::unshared.

Referenced by ExecHashJoinNewBatch().

2115 {
2116  MemoryContext oldcxt;
2117  int nbuckets = hashtable->nbuckets;
2118 
2119  /*
2120  * Release all the hash buckets and tuples acquired in the prior pass, and
2121  * reinitialize the context for a new pass.
2122  */
2123  MemoryContextReset(hashtable->batchCxt);
2124  oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
2125 
2126  /* Reallocate and reinitialize the hash bucket headers. */
2127  hashtable->buckets.unshared = (HashJoinTuple *)
2128  palloc0(nbuckets * sizeof(HashJoinTuple));
2129 
2130  hashtable->spaceUsed = 0;
2131 
2132  MemoryContextSwitchTo(oldcxt);
2133 
2134  /* Forget the chunks (the memory was freed by the context reset above). */
2135  hashtable->chunks = NULL;
2136 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
MemoryContext batchCxt
Definition: hashjoin.h:348
void * palloc0(Size size)
Definition: mcxt.c:955
union HashJoinTableData::@97 buckets
HashMemoryChunk chunks
Definition: hashjoin.h:351
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:297

◆ ExecHashTableResetMatchFlags()

void ExecHashTableResetMatchFlags ( HashJoinTable  hashtable)

Definition at line 2143 of file nodeHash.c.

References HashJoinTableData::buckets, HeapTupleHeaderClearMatch, HJTUPLE_MINTUPLE, i, HashJoinTableData::nbuckets, HashJoinTupleData::next, HashJoinTableData::nSkewBuckets, HashJoinTableData::skewBucket, HashJoinTableData::skewBucketNums, HashSkewBucket::tuples, HashJoinTupleData::unshared, and HashJoinTableData::unshared.

Referenced by ExecReScanHashJoin().

2144 {
2145  HashJoinTuple tuple;
2146  int i;
2147 
2148  /* Reset all flags in the main table ... */
2149  for (i = 0; i < hashtable->nbuckets; i++)
2150  {
2151  for (tuple = hashtable->buckets.unshared[i]; tuple != NULL;
2152  tuple = tuple->next.unshared)
2154  }
2155 
2156  /* ... and the same for the skew buckets, if any */
2157  for (i = 0; i < hashtable->nSkewBuckets; i++)
2158  {
2159  int j = hashtable->skewBucketNums[i];
2160  HashSkewBucket *skewBucket = hashtable->skewBucket[j];
2161 
2162  for (tuple = skewBucket->tuples; tuple != NULL; tuple = tuple->next.unshared)
2164  }
2165 }
union HashJoinTupleData::@95 next
int * skewBucketNums
Definition: hashjoin.h:308
struct HashJoinTupleData * unshared
Definition: hashjoin.h:72
HashJoinTuple tuples
Definition: hashjoin.h:105
HashSkewBucket ** skewBucket
Definition: hashjoin.h:305
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
#define HeapTupleHeaderClearMatch(tup)
Definition: htup_details.h:544
union HashJoinTableData::@97 buckets
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:297
int i

◆ ExecInitHash()

HashState* ExecInitHash ( Hash node,
EState estate,
int  eflags 
)

Definition at line 352 of file nodeHash.c.

References Assert, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecHash(), ExecInitNode(), ExecInitQual(), ExecInitResultTupleSlotTL(), PlanState::ExecProcNode, HashState::hashkeys, HashState::hashtable, makeNode, NIL, outerPlan, outerPlanState, Hash::plan, PlanState::plan, HashState::ps, PlanState::ps_ProjInfo, Plan::qual, PlanState::qual, and PlanState::state.

Referenced by ExecInitNode().

353 {
354  HashState *hashstate;
355 
356  /* check for unsupported flags */
357  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
358 
359  /*
360  * create state structure
361  */
362  hashstate = makeNode(HashState);
363  hashstate->ps.plan = (Plan *) node;
364  hashstate->ps.state = estate;
365  hashstate->ps.ExecProcNode = ExecHash;
366  hashstate->hashtable = NULL;
367  hashstate->hashkeys = NIL; /* will be set by parent HashJoin */
368 
369  /*
370  * Miscellaneous initialization
371  *
372  * create expression context for node
373  */
374  ExecAssignExprContext(estate, &hashstate->ps);
375 
376  /*
377  * initialize child nodes
378  */
379  outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate, eflags);
380 
381  /*
382  * initialize our result slot and type. No need to build projection
383  * because this node doesn't do projections.
384  */
385  ExecInitResultTupleSlotTL(estate, &hashstate->ps);
386  hashstate->ps.ps_ProjInfo = NULL;
387 
388  /*
389  * initialize child expressions
390  */
391  hashstate->ps.qual =
392  ExecInitQual(node->plan.qual, (PlanState *) hashstate);
393 
394  return hashstate;
395 }
#define NIL
Definition: pg_list.h:69
List * qual
Definition: plannodes.h:147
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:947
HashJoinTable hashtable
Definition: execnodes.h:2128
EState * state
Definition: execnodes.h:913
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:205
#define EXEC_FLAG_BACKWARD
Definition: executor.h:60
#define outerPlanState(node)
Definition: execnodes.h:965
List * hashkeys
Definition: execnodes.h:2129
PlanState ps
Definition: execnodes.h:2127
#define outerPlan(node)
Definition: plannodes.h:176
static TupleTableSlot * ExecHash(PlanState *pstate)
Definition: nodeHash.c:91
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:917
void ExecInitResultTupleSlotTL(EState *estate, PlanState *planstate)
Definition: execTuples.c:890
Plan * plan
Definition: execnodes.h:911
#define makeNode(_type_)
Definition: nodes.h:565
#define Assert(condition)
Definition: c.h:699
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:428
ExprState * qual
Definition: execnodes.h:929
Plan plan
Definition: plannodes.h:897
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139

◆ ExecParallelHashTableAlloc()

void ExecParallelHashTableAlloc ( HashJoinTable  hashtable,
int  batchno 
)

Definition at line 3036 of file nodeHash.c.

References HashJoinTableData::area, HashJoinTableData::batches, ParallelHashJoinBatch::buckets, dsa_allocate, dsa_get_address(), dsa_pointer_atomic_init, i, InvalidDsaPointer, ParallelHashJoinState::nbuckets, HashJoinTableData::parallel_state, and ParallelHashJoinBatchAccessor::shared.

Referenced by ExecHashTableCreate(), and ExecParallelHashJoinNewBatch().

3037 {
3038  ParallelHashJoinBatch *batch = hashtable->batches[batchno].shared;
3039  dsa_pointer_atomic *buckets;
3040  int nbuckets = hashtable->parallel_state->nbuckets;
3041  int i;
3042 
3043  batch->buckets =
3044  dsa_allocate(hashtable->area, sizeof(dsa_pointer_atomic) * nbuckets);
3045  buckets = (dsa_pointer_atomic *)
3046  dsa_get_address(hashtable->area, batch->buckets);
3047  for (i = 0; i < nbuckets; ++i)
3049 }
#define InvalidDsaPointer
Definition: dsa.h:78
dsa_area * area
Definition: hashjoin.h:355
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:356
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:357
ParallelHashJoinBatch * shared
Definition: hashjoin.h:197
#define dsa_pointer_atomic_init
Definition: dsa.h:64
int i
#define dsa_allocate(area, size)
Definition: dsa.h:84
dsa_pointer buckets
Definition: hashjoin.h:153

◆ ExecParallelHashTableInsert()

void ExecParallelHashTableInsert ( HashJoinTable  hashtable,
TupleTableSlot slot,
uint32  hashvalue 
)

Definition at line 1674 of file nodeHash.c.

References Assert, BarrierPhase(), HashJoinTableData::batches, HashJoinTableData::buckets, ParallelHashJoinState::build_barrier, ExecFetchSlotMinimalTuple(), ExecHashGetBucketAndBatch(), ExecParallelHashPushTuple(), ExecParallelHashTupleAlloc(), ExecParallelHashTuplePrealloc(), HashJoinTupleData::hashvalue, HJTUPLE_MINTUPLE, HJTUPLE_OVERHEAD, ParallelHashJoinBatchAccessor::inner_tuples, MAXALIGN, ParallelHashJoinBatchAccessor::ntuples, HashJoinTableData::parallel_state, PHJ_BUILD_HASHING_INNER, ParallelHashJoinBatchAccessor::preallocated, HashJoinTableData::shared, sts_puttuple(), and MinimalTupleData::t_len.

Referenced by MultiExecParallelHash().

1677 {
1679  dsa_pointer shared;
1680  int bucketno;
1681  int batchno;
1682 
1683 retry:
1684  ExecHashGetBucketAndBatch(hashtable, hashvalue, &bucketno, &batchno);
1685 
1686  if (batchno == 0)
1687  {
1688  HashJoinTuple hashTuple;
1689 
1690  /* Try to load it into memory. */
1693  hashTuple = ExecParallelHashTupleAlloc(hashtable,
1694  HJTUPLE_OVERHEAD + tuple->t_len,
1695  &shared);
1696  if (hashTuple == NULL)
1697  goto retry;
1698 
1699  /* Store the hash value in the HashJoinTuple header. */
1700  hashTuple->hashvalue = hashvalue;
1701  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1702 
1703  /* Push it onto the front of the bucket's list */
1704  ExecParallelHashPushTuple(&hashtable->buckets.shared[bucketno],
1705  hashTuple, shared);
1706  }
1707  else
1708  {
1709  size_t tuple_size = MAXALIGN(HJTUPLE_OVERHEAD + tuple->t_len);
1710 
1711  Assert(batchno > 0);
1712 
1713  /* Try to preallocate space in the batch if necessary. */
1714  if (hashtable->batches[batchno].preallocated < tuple_size)
1715  {
1716  if (!ExecParallelHashTuplePrealloc(hashtable, batchno, tuple_size))
1717  goto retry;
1718  }
1719 
1720  Assert(hashtable->batches[batchno].preallocated >= tuple_size);
1721  hashtable->batches[batchno].preallocated -= tuple_size;
1722  sts_puttuple(hashtable->batches[batchno].inner_tuples, &hashvalue,
1723  tuple);
1724  }
1725  ++hashtable->batches[batchno].ntuples;
1726 }
dsa_pointer_atomic * shared
Definition: hashjoin.h:299
void sts_puttuple(SharedTuplestoreAccessor *accessor, void *meta_data, MinimalTuple tuple)
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
Definition: execTuples.c:708
uint64 dsa_pointer
Definition: dsa.h:62
SharedTuplestoreAccessor * inner_tuples
Definition: hashjoin.h:208
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
Definition: nodeHash.c:1875
static bool ExecParallelHashTuplePrealloc(HashJoinTable hashtable, int batchno, size_t size)
Definition: nodeHash.c:3260
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:356
#define HJTUPLE_OVERHEAD
Definition: hashjoin.h:79
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:357
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
#define Assert(condition)
Definition: c.h:699
int BarrierPhase(Barrier *barrier)
Definition: barrier.c:243
#define MAXALIGN(LEN)
Definition: c.h:652
union HashJoinTableData::@97 buckets
static void ExecParallelHashPushTuple(dsa_pointer_atomic *head, HashJoinTuple tuple, dsa_pointer tuple_shared)
Definition: nodeHash.c:3180
#define PHJ_BUILD_HASHING_INNER
Definition: hashjoin.h:259
static HashJoinTuple ExecParallelHashTupleAlloc(HashJoinTable hashtable, size_t size, dsa_pointer *shared)
Definition: nodeHash.c:2730
uint32 hashvalue
Definition: hashjoin.h:75

◆ ExecParallelHashTableInsertCurrentBatch()

void ExecParallelHashTableInsertCurrentBatch ( HashJoinTable  hashtable,
TupleTableSlot slot,
uint32  hashvalue 
)

Definition at line 1735 of file nodeHash.c.

References Assert, HashJoinTableData::buckets, HashJoinTableData::curbatch, ExecFetchSlotMinimalTuple(), ExecHashGetBucketAndBatch(), ExecParallelHashPushTuple(), ExecParallelHashTupleAlloc(), HashJoinTupleData::hashvalue, HeapTupleHeaderClearMatch, HJTUPLE_MINTUPLE, HJTUPLE_OVERHEAD, HashJoinTableData::shared, and MinimalTupleData::t_len.

Referenced by ExecParallelHashJoinNewBatch().

1738 {
1740  HashJoinTuple hashTuple;
1741  dsa_pointer shared;
1742  int batchno;
1743  int bucketno;
1744 
1745  ExecHashGetBucketAndBatch(hashtable, hashvalue, &bucketno, &batchno);
1746  Assert(batchno == hashtable->curbatch);
1747  hashTuple = ExecParallelHashTupleAlloc(hashtable,
1748  HJTUPLE_OVERHEAD + tuple->t_len,
1749  &shared);
1750  hashTuple->hashvalue = hashvalue;
1751  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1753  ExecParallelHashPushTuple(&hashtable->buckets.shared[bucketno],
1754  hashTuple, shared);
1755 }
dsa_pointer_atomic * shared
Definition: hashjoin.h:299
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
Definition: execTuples.c:708
uint64 dsa_pointer
Definition: dsa.h:62
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
Definition: nodeHash.c:1875
#define HJTUPLE_OVERHEAD
Definition: hashjoin.h:79
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
#define Assert(condition)
Definition: c.h:699
#define HeapTupleHeaderClearMatch(tup)
Definition: htup_details.h:544
union HashJoinTableData::@97 buckets
static void ExecParallelHashPushTuple(dsa_pointer_atomic *head, HashJoinTuple tuple, dsa_pointer tuple_shared)
Definition: nodeHash.c:3180
static HashJoinTuple ExecParallelHashTupleAlloc(HashJoinTable hashtable, size_t size, dsa_pointer *shared)
Definition: nodeHash.c:2730
uint32 hashvalue
Definition: hashjoin.h:75

◆ ExecParallelHashTableSetCurrentBatch()

void ExecParallelHashTableSetCurrentBatch ( HashJoinTable  hashtable,
int  batchno 
)

Definition at line 3198 of file nodeHash.c.

References HashJoinTableData::area, Assert, ParallelHashJoinBatchAccessor::at_least_one_chunk, HashJoinTableData::batches, ParallelHashJoinBatch::buckets, HashJoinTableData::buckets, HashJoinTableData::curbatch, HashJoinTableData::current_chunk, HashJoinTableData::current_chunk_shared, dsa_get_address(), InvalidDsaPointer, HashJoinTableData::log2_nbuckets, my_log2(), ParallelHashJoinState::nbuckets, HashJoinTableData::nbuckets, HashJoinTableData::parallel_state, ParallelHashJoinBatchAccessor::shared, and HashJoinTableData::shared.

Referenced by ExecParallelHashIncreaseNumBatches(), ExecParallelHashIncreaseNumBuckets(), ExecParallelHashJoinNewBatch(), and MultiExecParallelHash().

3199 {
3200  Assert(hashtable->batches[batchno].shared->buckets != InvalidDsaPointer);
3201 
3202  hashtable->curbatch = batchno;
3203  hashtable->buckets.shared = (dsa_pointer_atomic *)
3204  dsa_get_address(hashtable->area,
3205  hashtable->batches[batchno].shared->buckets);
3206  hashtable->nbuckets = hashtable->parallel_state->nbuckets;
3207  hashtable->log2_nbuckets = my_log2(hashtable->nbuckets);
3208  hashtable->current_chunk = NULL;
3210  hashtable->batches[batchno].at_least_one_chunk = false;
3211 }
dsa_pointer current_chunk_shared
Definition: hashjoin.h:358
dsa_pointer_atomic * shared
Definition: hashjoin.h:299
#define InvalidDsaPointer
Definition: dsa.h:78
dsa_area * area
Definition: hashjoin.h:355
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:924
int my_log2(long num)
Definition: dynahash.c:1718
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:356
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:357
#define Assert(condition)
Definition: c.h:699
union HashJoinTableData::@97 buckets
ParallelHashJoinBatch * shared
Definition: hashjoin.h:197
HashMemoryChunk current_chunk
Definition: hashjoin.h:354
dsa_pointer buckets
Definition: hashjoin.h:153

◆ ExecParallelScanHashBucket()

bool ExecParallelScanHashBucket ( HashJoinState hjstate,
ExprContext econtext 
)

Definition at line 1968 of file nodeHash.c.

References ExprContext::ecxt_innertuple, ExecParallelHashFirstTuple(), ExecParallelHashNextTuple(), ExecQualAndReset(), ExecStoreMinimalTuple(), HashJoinState::hashclauses, HashJoinTupleData::hashvalue, HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurHashValue, HashJoinState::hj_CurTuple, HashJoinState::hj_HashTable, HashJoinState::hj_HashTupleSlot, and HJTUPLE_MINTUPLE.

Referenced by ExecHashJoinImpl().

1970 {
1971  ExprState *hjclauses = hjstate->hashclauses;
1972  HashJoinTable hashtable = hjstate->hj_HashTable;
1973  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
1974  uint32 hashvalue = hjstate->hj_CurHashValue;
1975 
1976  /*
1977  * hj_CurTuple is the address of the tuple last returned from the current
1978  * bucket, or NULL if it's time to start scanning a new bucket.
1979  */
1980  if (hashTuple != NULL)
1981  hashTuple = ExecParallelHashNextTuple(hashtable, hashTuple);
1982  else
1983  hashTuple = ExecParallelHashFirstTuple(hashtable,
1984  hjstate->hj_CurBucketNo);
1985 
1986  while (hashTuple != NULL)
1987  {
1988  if (hashTuple->hashvalue == hashvalue)
1989  {
1990  TupleTableSlot *inntuple;
1991 
1992  /* insert hashtable's tuple into exec slot so ExecQual sees it */
1993  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
1994  hjstate->hj_HashTupleSlot,
1995  false); /* do not pfree */
1996  econtext->ecxt_innertuple = inntuple;
1997 
1998  if (ExecQualAndReset(hjclauses, econtext))
1999  {
2000  hjstate->hj_CurTuple = hashTuple;
2001  return true;
2002  }
2003  }
2004 
2005  hashTuple = ExecParallelHashNextTuple(hashtable, hashTuple);
2006  }
2007 
2008  /*
2009  * no match
2010  */
2011  return false;
2012 }
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:420
uint32 hj_CurHashValue
Definition: execnodes.h:1795
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1798
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:220
unsigned int uint32
Definition: c.h:325
int hj_CurBucketNo
Definition: execnodes.h:1796
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:388
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
static HashJoinTuple ExecParallelHashFirstTuple(HashJoinTable table, int bucketno)
Definition: nodeHash.c:3150
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1800
static HashJoinTuple ExecParallelHashNextTuple(HashJoinTable table, HashJoinTuple tuple)
Definition: nodeHash.c:3166
HashJoinTable hj_HashTable
Definition: execnodes.h:1794
uint32 hashvalue
Definition: hashjoin.h:75
ExprState * hashclauses
Definition: execnodes.h:1790

◆ ExecPrepHashTableForUnmatched()

void ExecPrepHashTableForUnmatched ( HashJoinState hjstate)

Definition at line 2019 of file nodeHash.c.

References HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurSkewBucketNo, and HashJoinState::hj_CurTuple.

Referenced by ExecHashJoinImpl().

2020 {
2021  /*----------
2022  * During this scan we use the HashJoinState fields as follows:
2023  *
2024  * hj_CurBucketNo: next regular bucket to scan
2025  * hj_CurSkewBucketNo: next skew bucket (an index into skewBucketNums)
2026  * hj_CurTuple: last tuple returned, or NULL to start next bucket
2027  *----------
2028  */
2029  hjstate->hj_CurBucketNo = 0;
2030  hjstate->hj_CurSkewBucketNo = 0;
2031  hjstate->hj_CurTuple = NULL;
2032 }
int hj_CurSkewBucketNo
Definition: execnodes.h:1797
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1798
int hj_CurBucketNo
Definition: execnodes.h:1796

◆ ExecReScanHash()

void ExecReScanHash ( HashState node)

Definition at line 2169 of file nodeHash.c.

References PlanState::chgParam, ExecReScan(), PlanState::lefttree, and HashState::ps.

Referenced by ExecReScan().

2170 {
2171  /*
2172  * if chgParam of subnode is not null then plan will be re-scanned by
2173  * first ExecProcNode.
2174  */
2175  if (node->ps.lefttree->chgParam == NULL)
2176  ExecReScan(node->ps.lefttree);
2177 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
struct PlanState * lefttree
Definition: execnodes.h:930
PlanState ps
Definition: execnodes.h:2127
Bitmapset * chgParam
Definition: execnodes.h:940

◆ ExecScanHashBucket()

bool ExecScanHashBucket ( HashJoinState hjstate,
ExprContext econtext 
)

Definition at line 1907 of file nodeHash.c.

References HashJoinTableData::buckets, ExprContext::ecxt_innertuple, ExecQualAndReset(), ExecStoreMinimalTuple(), HashJoinState::hashclauses, HashJoinTupleData::hashvalue, HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurHashValue, HashJoinState::hj_CurSkewBucketNo, HashJoinState::hj_CurTuple, HashJoinState::hj_HashTable, HashJoinState::hj_HashTupleSlot, HJTUPLE_MINTUPLE, INVALID_SKEW_BUCKET_NO, HashJoinTupleData::next, HashJoinTableData::skewBucket, HashSkewBucket::tuples, HashJoinTupleData::unshared, and HashJoinTableData::unshared.

Referenced by ExecHashJoinImpl().

1909 {
1910  ExprState *hjclauses = hjstate->hashclauses;
1911  HashJoinTable hashtable = hjstate->hj_HashTable;
1912  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
1913  uint32 hashvalue = hjstate->hj_CurHashValue;
1914 
1915  /*
1916  * hj_CurTuple is the address of the tuple last returned from the current
1917  * bucket, or NULL if it's time to start scanning a new bucket.
1918  *
1919  * If the tuple hashed to a skew bucket then scan the skew bucket
1920  * otherwise scan the standard hashtable bucket.
1921  */
1922  if (hashTuple != NULL)
1923  hashTuple = hashTuple->next.unshared;
1924  else if (hjstate->hj_CurSkewBucketNo != INVALID_SKEW_BUCKET_NO)
1925  hashTuple = hashtable->skewBucket[hjstate->hj_CurSkewBucketNo]->tuples;
1926  else
1927  hashTuple = hashtable->buckets.unshared[hjstate->hj_CurBucketNo];
1928 
1929  while (hashTuple != NULL)
1930  {
1931  if (hashTuple->hashvalue == hashvalue)
1932  {
1933  TupleTableSlot *inntuple;
1934 
1935  /* insert hashtable's tuple into exec slot so ExecQual sees it */
1936  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
1937  hjstate->hj_HashTupleSlot,
1938  false); /* do not pfree */
1939  econtext->ecxt_innertuple = inntuple;
1940 
1941  if (ExecQualAndReset(hjclauses, econtext))
1942  {
1943  hjstate->hj_CurTuple = hashTuple;
1944  return true;
1945  }
1946  }
1947 
1948  hashTuple = hashTuple->next.unshared;
1949  }
1950 
1951  /*
1952  * no match
1953  */
1954  return false;
1955 }
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:109
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:420
union HashJoinTupleData::@95 next
uint32 hj_CurHashValue
Definition: execnodes.h:1795
int hj_CurSkewBucketNo
Definition: execnodes.h:1797
struct HashJoinTupleData * unshared
Definition: hashjoin.h:72
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1798
HashJoinTuple tuples
Definition: hashjoin.h:105
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:220
unsigned int uint32
Definition: c.h:325
int hj_CurBucketNo
Definition: execnodes.h:1796
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:388
HashSkewBucket ** skewBucket
Definition: hashjoin.h:305
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
union HashJoinTableData::@97 buckets
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1800
HashJoinTable hj_HashTable
Definition: execnodes.h:1794
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:297
uint32 hashvalue
Definition: hashjoin.h:75
ExprState * hashclauses
Definition: execnodes.h:1790

◆ ExecScanHashTableForUnmatched()

bool ExecScanHashTableForUnmatched ( HashJoinState hjstate,
ExprContext econtext 
)

Definition at line 2043 of file nodeHash.c.

References HashJoinTableData::buckets, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_innertuple, ExecStoreMinimalTuple(), HeapTupleHeaderHasMatch, HashJoinState::hj_CurBucketNo, HashJoinState::hj_CurSkewBucketNo, HashJoinState::hj_CurTuple, HashJoinState::hj_HashTable, HashJoinState::hj_HashTupleSlot, HJTUPLE_MINTUPLE, HashJoinTableData::nbuckets, HashJoinTupleData::next, HashJoinTableData::nSkewBuckets, ResetExprContext, HashJoinTableData::skewBucket, HashJoinTableData::skewBucketNums, HashSkewBucket::tuples, HashJoinTupleData::unshared, and HashJoinTableData::unshared.

Referenced by ExecHashJoinImpl().

2044 {
2045  HashJoinTable hashtable = hjstate->hj_HashTable;
2046  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
2047 
2048  for (;;)
2049  {
2050  /*
2051  * hj_CurTuple is the address of the tuple last returned from the
2052  * current bucket, or NULL if it's time to start scanning a new
2053  * bucket.
2054  */
2055  if (hashTuple != NULL)
2056  hashTuple = hashTuple->next.unshared;
2057  else if (hjstate->hj_CurBucketNo < hashtable->nbuckets)
2058  {
2059  hashTuple = hashtable->buckets.unshared[hjstate->hj_CurBucketNo];
2060  hjstate->hj_CurBucketNo++;
2061  }
2062  else if (hjstate->hj_CurSkewBucketNo < hashtable->nSkewBuckets)
2063  {
2064  int j = hashtable->skewBucketNums[hjstate->hj_CurSkewBucketNo];
2065 
2066  hashTuple = hashtable->skewBucket[j]->tuples;
2067  hjstate->hj_CurSkewBucketNo++;
2068  }
2069  else
2070  break; /* finished all buckets */
2071 
2072  while (hashTuple != NULL)
2073  {
2074  if (!HeapTupleHeaderHasMatch(HJTUPLE_MINTUPLE(hashTuple)))
2075  {
2076  TupleTableSlot *inntuple;
2077 
2078  /* insert hashtable's tuple into exec slot */
2079  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
2080  hjstate->hj_HashTupleSlot,
2081  false); /* do not pfree */
2082  econtext->ecxt_innertuple = inntuple;
2083 
2084  /*
2085  * Reset temp memory each time; although this function doesn't
2086  * do any qual eval, the caller will, so let's keep it
2087  * parallel to ExecScanHashBucket.
2088  */
2089  ResetExprContext(econtext);
2090 
2091  hjstate->hj_CurTuple = hashTuple;
2092  return true;
2093  }
2094 
2095  hashTuple = hashTuple->next.unshared;
2096  }
2097 
2098  /* allow this loop to be cancellable */
2100  }
2101 
2102  /*
2103  * no more unmatched tuples
2104  */
2105  return false;
2106 }
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:420
union HashJoinTupleData::@95 next
int * skewBucketNums
Definition: hashjoin.h:308
int hj_CurSkewBucketNo
Definition: execnodes.h:1797
struct HashJoinTupleData * unshared
Definition: hashjoin.h:72
HashJoinTuple hj_CurTuple
Definition: execnodes.h:1798
HashJoinTuple tuples
Definition: hashjoin.h:105
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:220
int hj_CurBucketNo
Definition: execnodes.h:1796
HashSkewBucket ** skewBucket
Definition: hashjoin.h:305
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
#define HeapTupleHeaderHasMatch(tup)
Definition: htup_details.h:534
union HashJoinTableData::@97 buckets
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:1800
HashJoinTable hj_HashTable
Definition: execnodes.h:1794
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:297
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define ResetExprContext(econtext)
Definition: executor.h:483

◆ ExecShutdownHash()

void ExecShutdownHash ( HashState node)

Definition at line 2605 of file nodeHash.c.

References ExecHashGetInstrumentation(), HashState::hashtable, and HashState::hinstrument.

Referenced by ExecShutdownNode().

2606 {
2607  if (node->hinstrument && node->hashtable)
2609 }
void ExecHashGetInstrumentation(HashInstrumentation *instrument, HashJoinTable hashtable)
Definition: nodeHash.c:2636
HashJoinTable hashtable
Definition: execnodes.h:2128
HashInstrumentation * hinstrument
Definition: execnodes.h:2133

◆ MultiExecHash()

Node* MultiExecHash ( HashState node)

Definition at line 105 of file nodeHash.c.

References HashState::hashtable, InstrStartNode(), InstrStopNode(), PlanState::instrument, MultiExecParallelHash(), MultiExecPrivateHash(), HashState::parallel_state, HashJoinTableData::partialTuples, and HashState::ps.

Referenced by MultiExecProcNode().

106 {
107  /* must provide our own instrumentation support */
108  if (node->ps.instrument)
110 
111  if (node->parallel_state != NULL)
112  MultiExecParallelHash(node);
113  else
114  MultiExecPrivateHash(node);
115 
116  /* must provide our own instrumentation support */
117  if (node->ps.instrument)
119 
120  /*
121  * We do not return the hash table directly because it's not a subtype of
122  * Node, and so would violate the MultiExecProcNode API. Instead, our
123  * parent Hashjoin node is expected to know how to fish it out of our node
124  * state. Ugly but not really worth cleaning up, since Hashjoin knows
125  * quite a bit more about Hash besides that.
126  */
127  return NULL;
128 }
struct ParallelHashJoinState * parallel_state
Definition: execnodes.h:2136
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:80
Instrumentation * instrument
Definition: execnodes.h:921
HashJoinTable hashtable
Definition: execnodes.h:2128
static void MultiExecPrivateHash(HashState *node)
Definition: nodeHash.c:138
double partialTuples
Definition: hashjoin.h:319
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:63
PlanState ps
Definition: execnodes.h:2127
static void MultiExecParallelHash(HashState *node)
Definition: nodeHash.c:213