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, List *hashCollations, 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_hash_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 ExecHashAccumInstrumentation (HashInstrumentation *instrument, HashJoinTable hashtable)
 

Function Documentation

◆ ExecChooseHashTableSize()

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

Definition at line 670 of file nodeHash.c.

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

References Assert(), get_hash_memory_limit(), HJTUPLE_OVERHEAD, Max, MAXALIGN, MaxAllocSize, Min, NTUP_PER_BUCKET, pg_nextpower2_32(), pg_nextpower2_size_t, pg_prevpower2_size_t, SizeofMinimalTupleHeader, SKEW_BUCKET_OVERHEAD, and SKEW_HASH_MEM_PERCENT.

Referenced by ExecHashTableCreate(), and initial_cost_hashjoin().

◆ ExecEndHash()

void ExecEndHash ( HashState node)

Definition at line 414 of file nodeHash.c.

415 {
417 
418  /*
419  * free exprcontext
420  */
421  ExecFreeExprContext(&node->ps);
422 
423  /*
424  * shut down the subplan
425  */
426  outerPlan = outerPlanState(node);
428 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:658
#define outerPlanState(node)
Definition: execnodes.h:1131
#define outerPlan(node)
Definition: plannodes.h:186
PlanState ps
Definition: execnodes.h:2647

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

Referenced by ExecEndNode().

◆ ExecHashAccumInstrumentation()

void ExecHashAccumInstrumentation ( HashInstrumentation instrument,
HashJoinTable  hashtable 
)

Definition at line 2704 of file nodeHash.c.

2706 {
2707  instrument->nbuckets = Max(instrument->nbuckets,
2708  hashtable->nbuckets);
2709  instrument->nbuckets_original = Max(instrument->nbuckets_original,
2710  hashtable->nbuckets_original);
2711  instrument->nbatch = Max(instrument->nbatch,
2712  hashtable->nbatch);
2713  instrument->nbatch_original = Max(instrument->nbatch_original,
2714  hashtable->nbatch_original);
2715  instrument->space_peak = Max(instrument->space_peak,
2716  hashtable->spacePeak);
2717 }

References Max, HashJoinTableData::nbatch, HashInstrumentation::nbatch, HashJoinTableData::nbatch_original, HashInstrumentation::nbatch_original, HashJoinTableData::nbuckets, HashInstrumentation::nbuckets, HashJoinTableData::nbuckets_original, HashInstrumentation::nbuckets_original, HashInstrumentation::space_peak, and HashJoinTableData::spacePeak.

Referenced by ExecReScanHashJoin(), and ExecShutdownHash().

◆ ExecHashEstimate()

void ExecHashEstimate ( HashState node,
ParallelContext pcxt 
)

Definition at line 2588 of file nodeHash.c.

2589 {
2590  size_t size;
2591 
2592  /* don't need this if not instrumenting or no workers */
2593  if (!node->ps.instrument || pcxt->nworkers == 0)
2594  return;
2595 
2596  size = mul_size(pcxt->nworkers, sizeof(HashInstrumentation));
2597  size = add_size(size, offsetof(SharedHashInfo, hinstrument));
2598  shm_toc_estimate_chunk(&pcxt->estimator, size);
2599  shm_toc_estimate_keys(&pcxt->estimator, 1);
2600 }
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
shm_toc_estimator estimator
Definition: parallel.h:42
Instrumentation * instrument
Definition: execnodes.h:1045

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

Referenced by ExecParallelEstimate().

◆ ExecHashGetBucketAndBatch()

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

Definition at line 1915 of file nodeHash.c.

1919 {
1920  uint32 nbuckets = (uint32) hashtable->nbuckets;
1921  uint32 nbatch = (uint32) hashtable->nbatch;
1922 
1923  if (nbatch > 1)
1924  {
1925  *bucketno = hashvalue & (nbuckets - 1);
1926  *batchno = pg_rotate_right32(hashvalue,
1927  hashtable->log2_nbuckets) & (nbatch - 1);
1928  }
1929  else
1930  {
1931  *bucketno = hashvalue & (nbuckets - 1);
1932  *batchno = 0;
1933  }
1934 }
unsigned int uint32
Definition: c.h:490
static uint32 pg_rotate_right32(uint32 word, int n)
Definition: pg_bitutils.h:316

References HashJoinTableData::log2_nbuckets, HashJoinTableData::nbatch, HashJoinTableData::nbuckets, and pg_rotate_right32().

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

◆ ExecHashGetHashValue()

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

Definition at line 1807 of file nodeHash.c.

1813 {
1814  uint32 hashkey = 0;
1815  FmgrInfo *hashfunctions;
1816  ListCell *hk;
1817  int i = 0;
1818  MemoryContext oldContext;
1819 
1820  /*
1821  * We reset the eval context each time to reclaim any memory leaked in the
1822  * hashkey expressions.
1823  */
1824  ResetExprContext(econtext);
1825 
1826  oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
1827 
1828  if (outer_tuple)
1829  hashfunctions = hashtable->outer_hashfunctions;
1830  else
1831  hashfunctions = hashtable->inner_hashfunctions;
1832 
1833  foreach(hk, hashkeys)
1834  {
1835  ExprState *keyexpr = (ExprState *) lfirst(hk);
1836  Datum keyval;
1837  bool isNull;
1838 
1839  /* combine successive hashkeys by rotating */
1840  hashkey = pg_rotate_left32(hashkey, 1);
1841 
1842  /*
1843  * Get the join attribute value of the tuple
1844  */
1845  keyval = ExecEvalExpr(keyexpr, econtext, &isNull);
1846 
1847  /*
1848  * If the attribute is NULL, and the join operator is strict, then
1849  * this tuple cannot pass the join qual so we can reject it
1850  * immediately (unless we're scanning the outside of an outer join, in
1851  * which case we must not reject it). Otherwise we act like the
1852  * hashcode of NULL is zero (this will support operators that act like
1853  * IS NOT DISTINCT, though not any more-random behavior). We treat
1854  * the hash support function as strict even if the operator is not.
1855  *
1856  * Note: currently, all hashjoinable operators must be strict since
1857  * the hash index AM assumes that. However, it takes so little extra
1858  * code here to allow non-strict that we may as well do it.
1859  */
1860  if (isNull)
1861  {
1862  if (hashtable->hashStrict[i] && !keep_nulls)
1863  {
1864  MemoryContextSwitchTo(oldContext);
1865  return false; /* cannot match */
1866  }
1867  /* else, leave hashkey unmodified, equivalent to hashcode 0 */
1868  }
1869  else
1870  {
1871  /* Compute the hash function */
1872  uint32 hkey;
1873 
1874  hkey = DatumGetUInt32(FunctionCall1Coll(&hashfunctions[i], hashtable->collations[i], keyval));
1875  hashkey ^= hkey;
1876  }
1877 
1878  i++;
1879  }
1880 
1881  MemoryContextSwitchTo(oldContext);
1882 
1883  *hashvalue = hashkey;
1884  return true;
1885 }
#define ResetExprContext(econtext)
Definition: executor.h:542
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1116
int i
Definition: isn.c:73
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
static uint32 pg_rotate_left32(uint32 word, int n)
Definition: pg_bitutils.h:322
#define lfirst(lc)
Definition: pg_list.h:172
static uint32 DatumGetUInt32(Datum X)
Definition: postgres.h:222
uintptr_t Datum
Definition: postgres.h:64
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:257
Definition: fmgr.h:57
FmgrInfo * outer_hashfunctions
Definition: hashjoin.h:338
bool * hashStrict
Definition: hashjoin.h:340
FmgrInfo * inner_hashfunctions
Definition: hashjoin.h:339

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

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

◆ ExecHashGetSkewBucket()

int ExecHashGetSkewBucket ( HashJoinTable  hashtable,
uint32  hashvalue 
)

Definition at line 2383 of file nodeHash.c.

2384 {
2385  int bucket;
2386 
2387  /*
2388  * Always return INVALID_SKEW_BUCKET_NO if not doing skew optimization (in
2389  * particular, this happens after the initial batch is done).
2390  */
2391  if (!hashtable->skewEnabled)
2392  return INVALID_SKEW_BUCKET_NO;
2393 
2394  /*
2395  * Since skewBucketLen is a power of 2, we can do a modulo by ANDing.
2396  */
2397  bucket = hashvalue & (hashtable->skewBucketLen - 1);
2398 
2399  /*
2400  * While we have not hit a hole in the hashtable and have not hit the
2401  * desired bucket, we have collided with some other hash value, so try the
2402  * next bucket location.
2403  */
2404  while (hashtable->skewBucket[bucket] != NULL &&
2405  hashtable->skewBucket[bucket]->hashvalue != hashvalue)
2406  bucket = (bucket + 1) & (hashtable->skewBucketLen - 1);
2407 
2408  /*
2409  * Found the desired bucket?
2410  */
2411  if (hashtable->skewBucket[bucket] != NULL)
2412  return bucket;
2413 
2414  /*
2415  * There must not be any hashtable entry for this hash value.
2416  */
2417  return INVALID_SKEW_BUCKET_NO;
2418 }
#define INVALID_SKEW_BUCKET_NO
Definition: hashjoin.h:109
HashSkewBucket ** skewBucket
Definition: hashjoin.h:306
uint32 hashvalue
Definition: hashjoin.h:104

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

Referenced by ExecHashJoinImpl(), and MultiExecPrivateHash().

◆ ExecHashInitializeDSM()

void ExecHashInitializeDSM ( HashState node,
ParallelContext pcxt 
)

Definition at line 2607 of file nodeHash.c.

2608 {
2609  size_t size;
2610 
2611  /* don't need this if not instrumenting or no workers */
2612  if (!node->ps.instrument || pcxt->nworkers == 0)
2613  return;
2614 
2615  size = offsetof(SharedHashInfo, hinstrument) +
2616  pcxt->nworkers * sizeof(HashInstrumentation);
2617  node->shared_info = (SharedHashInfo *) shm_toc_allocate(pcxt->toc, size);
2618 
2619  /* Each per-worker area must start out as zeroes. */
2620  memset(node->shared_info, 0, size);
2621 
2622  node->shared_info->num_workers = pcxt->nworkers;
2623  shm_toc_insert(pcxt->toc, node->ps.plan->plan_node_id,
2624  node->shared_info);
2625 }
struct HashInstrumentation HashInstrumentation
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
SharedHashInfo * shared_info
Definition: execnodes.h:2657
shm_toc * toc
Definition: parallel.h:45
Plan * plan
Definition: execnodes.h:1035
int plan_node_id
Definition: plannodes.h:155

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

Referenced by ExecParallelInitializeDSM().

◆ ExecHashInitializeWorker()

void ExecHashInitializeWorker ( HashState node,
ParallelWorkerContext pwcxt 
)

Definition at line 2632 of file nodeHash.c.

2633 {
2634  SharedHashInfo *shared_info;
2635 
2636  /* don't need this if not instrumenting */
2637  if (!node->ps.instrument)
2638  return;
2639 
2640  /*
2641  * Find our entry in the shared area, and set up a pointer to it so that
2642  * we'll accumulate stats there when shutting down or rebuilding the hash
2643  * table.
2644  */
2645  shared_info = (SharedHashInfo *)
2646  shm_toc_lookup(pwcxt->toc, node->ps.plan->plan_node_id, false);
2647  node->hinstrument = &shared_info->hinstrument[ParallelWorkerNumber];
2648 }
int ParallelWorkerNumber
Definition: parallel.c:113
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232
HashInstrumentation * hinstrument
Definition: execnodes.h:2664
HashInstrumentation hinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2638

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().

◆ ExecHashRetrieveInstrumentation()

void ExecHashRetrieveInstrumentation ( HashState node)

Definition at line 2673 of file nodeHash.c.

2674 {
2675  SharedHashInfo *shared_info = node->shared_info;
2676  size_t size;
2677 
2678  if (shared_info == NULL)
2679  return;
2680 
2681  /* Replace node->shared_info with a copy in backend-local memory. */
2682  size = offsetof(SharedHashInfo, hinstrument) +
2683  shared_info->num_workers * sizeof(HashInstrumentation);
2684  node->shared_info = palloc(size);
2685  memcpy(node->shared_info, shared_info, size);
2686 }
void * palloc(Size size)
Definition: mcxt.c:1210

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecHashTableCreate()

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

Definition at line 438 of file nodeHash.c.

439 {
440  Hash *node;
441  HashJoinTable hashtable;
442  Plan *outerNode;
443  size_t space_allowed;
444  int nbuckets;
445  int nbatch;
446  double rows;
447  int num_skew_mcvs;
448  int log2_nbuckets;
449  int nkeys;
450  int i;
451  ListCell *ho;
452  ListCell *hc;
453  MemoryContext oldcxt;
454 
455  /*
456  * Get information about the size of the relation to be hashed (it's the
457  * "outer" subtree of this node, but the inner relation of the hashjoin).
458  * Compute the appropriate size of the hash table.
459  */
460  node = (Hash *) state->ps.plan;
461  outerNode = outerPlan(node);
462 
463  /*
464  * If this is shared hash table with a partial plan, then we can't use
465  * outerNode->plan_rows to estimate its size. We need an estimate of the
466  * total number of rows across all copies of the partial plan.
467  */
468  rows = node->plan.parallel_aware ? node->rows_total : outerNode->plan_rows;
469 
470  ExecChooseHashTableSize(rows, outerNode->plan_width,
471  OidIsValid(node->skewTable),
472  state->parallel_state != NULL,
473  state->parallel_state != NULL ?
474  state->parallel_state->nparticipants - 1 : 0,
475  &space_allowed,
476  &nbuckets, &nbatch, &num_skew_mcvs);
477 
478  /* nbuckets must be a power of 2 */
479  log2_nbuckets = my_log2(nbuckets);
480  Assert(nbuckets == (1 << log2_nbuckets));
481 
482  /*
483  * Initialize the hash table control block.
484  *
485  * The hashtable control block is just palloc'd from the executor's
486  * per-query memory context. Everything else should be kept inside the
487  * subsidiary hashCxt or batchCxt.
488  */
489  hashtable = palloc_object(HashJoinTableData);
490  hashtable->nbuckets = nbuckets;
491  hashtable->nbuckets_original = nbuckets;
492  hashtable->nbuckets_optimal = nbuckets;
493  hashtable->log2_nbuckets = log2_nbuckets;
494  hashtable->log2_nbuckets_optimal = log2_nbuckets;
495  hashtable->buckets.unshared = NULL;
496  hashtable->keepNulls = keepNulls;
497  hashtable->skewEnabled = false;
498  hashtable->skewBucket = NULL;
499  hashtable->skewBucketLen = 0;
500  hashtable->nSkewBuckets = 0;
501  hashtable->skewBucketNums = NULL;
502  hashtable->nbatch = nbatch;
503  hashtable->curbatch = 0;
504  hashtable->nbatch_original = nbatch;
505  hashtable->nbatch_outstart = nbatch;
506  hashtable->growEnabled = true;
507  hashtable->totalTuples = 0;
508  hashtable->partialTuples = 0;
509  hashtable->skewTuples = 0;
510  hashtable->innerBatchFile = NULL;
511  hashtable->outerBatchFile = NULL;
512  hashtable->spaceUsed = 0;
513  hashtable->spacePeak = 0;
514  hashtable->spaceAllowed = space_allowed;
515  hashtable->spaceUsedSkew = 0;
516  hashtable->spaceAllowedSkew =
517  hashtable->spaceAllowed * SKEW_HASH_MEM_PERCENT / 100;
518  hashtable->chunks = NULL;
519  hashtable->current_chunk = NULL;
520  hashtable->parallel_state = state->parallel_state;
521  hashtable->area = state->ps.state->es_query_dsa;
522  hashtable->batches = NULL;
523 
524 #ifdef HJDEBUG
525  printf("Hashjoin %p: initial nbatch = %d, nbuckets = %d\n",
526  hashtable, nbatch, nbuckets);
527 #endif
528 
529  /*
530  * Create temporary memory contexts in which to keep the hashtable working
531  * storage. See notes in executor/hashjoin.h.
532  */
534  "HashTableContext",
536 
537  hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
538  "HashBatchContext",
540 
541  /* Allocate data that will live for the life of the hashjoin */
542 
543  oldcxt = MemoryContextSwitchTo(hashtable->hashCxt);
544 
545  /*
546  * Get info about the hash functions to be used for each hash key. Also
547  * remember whether the join operators are strict.
548  */
549  nkeys = list_length(hashOperators);
550  hashtable->outer_hashfunctions = palloc_array(FmgrInfo, nkeys);
551  hashtable->inner_hashfunctions = palloc_array(FmgrInfo, nkeys);
552  hashtable->hashStrict = palloc_array(bool, nkeys);
553  hashtable->collations = palloc_array(Oid, nkeys);
554  i = 0;
555  forboth(ho, hashOperators, hc, hashCollations)
556  {
557  Oid hashop = lfirst_oid(ho);
558  Oid left_hashfn;
559  Oid right_hashfn;
560 
561  if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
562  elog(ERROR, "could not find hash function for hash operator %u",
563  hashop);
564  fmgr_info(left_hashfn, &hashtable->outer_hashfunctions[i]);
565  fmgr_info(right_hashfn, &hashtable->inner_hashfunctions[i]);
566  hashtable->hashStrict[i] = op_strict(hashop);
567  hashtable->collations[i] = lfirst_oid(hc);
568  i++;
569  }
570 
571  if (nbatch > 1 && hashtable->parallel_state == NULL)
572  {
573  /*
574  * allocate and initialize the file arrays in hashCxt (not needed for
575  * parallel case which uses shared tuplestores instead of raw files)
576  */
577  hashtable->innerBatchFile = palloc0_array(BufFile *, nbatch);
578  hashtable->outerBatchFile = palloc0_array(BufFile *, nbatch);
579  /* The files will not be opened until needed... */
580  /* ... but make sure we have temp tablespaces established for them */
582  }
583 
584  MemoryContextSwitchTo(oldcxt);
585 
586  if (hashtable->parallel_state)
587  {
588  ParallelHashJoinState *pstate = hashtable->parallel_state;
589  Barrier *build_barrier;
590 
591  /*
592  * Attach to the build barrier. The corresponding detach operation is
593  * in ExecHashTableDetach. Note that we won't attach to the
594  * batch_barrier for batch 0 yet. We'll attach later and start it out
595  * in PHJ_BATCH_PROBE phase, because batch 0 is allocated up front and
596  * then loaded while hashing (the standard hybrid hash join
597  * algorithm), and we'll coordinate that using build_barrier.
598  */
599  build_barrier = &pstate->build_barrier;
600  BarrierAttach(build_barrier);
601 
602  /*
603  * So far we have no idea whether there are any other participants,
604  * and if so, what phase they are working on. The only thing we care
605  * about at this point is whether someone has already created the
606  * SharedHashJoinBatch objects and the hash table for batch 0. One
607  * backend will be elected to do that now if necessary.
608  */
609  if (BarrierPhase(build_barrier) == PHJ_BUILD_ELECT &&
611  {
612  pstate->nbatch = nbatch;
613  pstate->space_allowed = space_allowed;
614  pstate->growth = PHJ_GROWTH_OK;
615 
616  /* Set up the shared state for coordinating batches. */
617  ExecParallelHashJoinSetUpBatches(hashtable, nbatch);
618 
619  /*
620  * Allocate batch 0's hash table up front so we can load it
621  * directly while hashing.
622  */
623  pstate->nbuckets = nbuckets;
624  ExecParallelHashTableAlloc(hashtable, 0);
625  }
626 
627  /*
628  * The next Parallel Hash synchronization point is in
629  * MultiExecParallelHash(), which will progress it all the way to
630  * PHJ_BUILD_RUN. The caller must not return control from this
631  * executor node between now and then.
632  */
633  }
634  else
635  {
636  /*
637  * Prepare context for the first-scan space allocations; allocate the
638  * hashbucket array therein, and set each bucket "empty".
639  */
640  MemoryContextSwitchTo(hashtable->batchCxt);
641 
642  hashtable->buckets.unshared = palloc0_array(HashJoinTuple, nbuckets);
643 
644  /*
645  * Set up for skew optimization, if possible and there's a need for
646  * more than one batch. (In a one-batch join, there's no point in
647  * it.)
648  */
649  if (nbatch > 1)
650  ExecHashBuildSkewHash(hashtable, node, num_skew_mcvs);
651 
652  MemoryContextSwitchTo(oldcxt);
653  }
654 
655  return hashtable;
656 }
void PrepareTempTablespaces(void)
Definition: tablespace.c:1337
int BarrierAttach(Barrier *barrier)
Definition: barrier.c:236
int BarrierPhase(Barrier *barrier)
Definition: barrier.c:265
bool BarrierArriveAndWait(Barrier *barrier, uint32 wait_event_info)
Definition: barrier.c:125
#define OidIsValid(objectId)
Definition: c.h:759
int my_log2(long num)
Definition: dynahash.c:1760
#define ERROR
Definition: elog.h:39
#define palloc_object(type)
Definition: fe_memutils.h:62
#define palloc_array(type, count)
Definition: fe_memutils.h:64
#define palloc0_array(type, count)
Definition: fe_memutils.h:65
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
@ PHJ_GROWTH_OK
Definition: hashjoin.h:221
#define PHJ_BUILD_ELECT
Definition: hashjoin.h:257
bool op_strict(Oid opno)
Definition: lsyscache.c:1459
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:509
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
static void ExecHashBuildSkewHash(HashJoinTable hashtable, Hash *node, int mcvsToUse)
Definition: nodeHash.c:2230
static void ExecParallelHashJoinSetUpBatches(HashJoinTable hashtable, int nbatch)
Definition: nodeHash.c:2951
void ExecParallelHashTableAlloc(HashJoinTable hashtable, int batchno)
Definition: nodeHash.c:3109
static int list_length(const List *l)
Definition: pg_list.h:152
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define printf(...)
Definition: port.h:244
unsigned int Oid
Definition: postgres_ext.h:31
struct HashJoinTupleData ** unshared
Definition: hashjoin.h:298
union HashJoinTableData::@94 buckets
HashMemoryChunk chunks
Definition: hashjoin.h:353
ParallelHashJoinBatchAccessor * batches
Definition: hashjoin.h:359
MemoryContext hashCxt
Definition: hashjoin.h:349
double totalTuples
Definition: hashjoin.h:319
double partialTuples
Definition: hashjoin.h:320
ParallelHashJoinState * parallel_state
Definition: hashjoin.h:358
HashMemoryChunk current_chunk
Definition: hashjoin.h:356
Size spaceAllowedSkew
Definition: hashjoin.h:347
int * skewBucketNums
Definition: hashjoin.h:309
BufFile ** innerBatchFile
Definition: hashjoin.h:330
int log2_nbuckets_optimal
Definition: hashjoin.h:292
dsa_area * area
Definition: hashjoin.h:357
BufFile ** outerBatchFile
Definition: hashjoin.h:331
MemoryContext batchCxt
Definition: hashjoin.h:350
double skewTuples
Definition: hashjoin.h:321
Oid skewTable
Definition: plannodes.h:1207
Cardinality rows_total
Definition: plannodes.h:1211
Plan plan
Definition: plannodes.h:1200
ParallelHashGrowth growth
Definition: hashjoin.h:241
bool parallel_aware
Definition: plannodes.h:144
int plan_width
Definition: plannodes.h:139
Cardinality plan_rows
Definition: plannodes.h:138
Definition: regguts.h:318
@ WAIT_EVENT_HASH_BUILD_ELECT
Definition: wait_event.h:98

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, HashJoinTableData::area, Assert(), BarrierArriveAndWait(), BarrierAttach(), BarrierPhase(), HashJoinTableData::batchCxt, HashJoinTableData::batches, HashJoinTableData::buckets, ParallelHashJoinState::build_barrier, HashJoinTableData::chunks, HashJoinTableData::collations, HashJoinTableData::curbatch, HashJoinTableData::current_chunk, CurrentMemoryContext, elog(), ERROR, ExecChooseHashTableSize(), ExecHashBuildSkewHash(), ExecParallelHashJoinSetUpBatches(), ExecParallelHashTableAlloc(), fmgr_info(), forboth, 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, HashJoinTableData::nSkewBuckets, OidIsValid, op_strict(), HashJoinTableData::outer_hashfunctions, HashJoinTableData::outerBatchFile, outerPlan, palloc0_array, palloc_array, palloc_object, Plan::parallel_aware, HashJoinTableData::parallel_state, HashJoinTableData::partialTuples, PHJ_BUILD_ELECT, PHJ_GROWTH_OK, Hash::plan, Plan::plan_rows, Plan::plan_width, PrepareTempTablespaces(), printf, Hash::rows_total, SKEW_HASH_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, HashJoinTableData::totalTuples, HashJoinTableData::unshared, and WAIT_EVENT_HASH_BUILD_ELECT.

Referenced by ExecHashJoinImpl().

◆ ExecHashTableDestroy()

void ExecHashTableDestroy ( HashJoinTable  hashtable)

Definition at line 878 of file nodeHash.c.

879 {
880  int i;
881 
882  /*
883  * Make sure all the temp files are closed. We skip batch 0, since it
884  * can't have any temp files (and the arrays might not even exist if
885  * nbatch is only 1). Parallel hash joins don't use these files.
886  */
887  if (hashtable->innerBatchFile != NULL)
888  {
889  for (i = 1; i < hashtable->nbatch; i++)
890  {
891  if (hashtable->innerBatchFile[i])
892  BufFileClose(hashtable->innerBatchFile[i]);
893  if (hashtable->outerBatchFile[i])
894  BufFileClose(hashtable->outerBatchFile[i]);
895  }
896  }
897 
898  /* Release working memory (batchCxt is a child, so it goes away too) */
899  MemoryContextDelete(hashtable->hashCxt);
900 
901  /* And drop the control block */
902  pfree(hashtable);
903 }
void BufFileClose(BufFile *file)
Definition: buffile.c:407
void pfree(void *pointer)
Definition: mcxt.c:1436
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387

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

Referenced by ExecEndHashJoin(), and ExecReScanHashJoin().

◆ ExecHashTableDetach()

void ExecHashTableDetach ( HashJoinTable  hashtable)

Definition at line 3186 of file nodeHash.c.

3187 {
3188  ParallelHashJoinState *pstate = hashtable->parallel_state;
3189 
3190  /*
3191  * If we're involved in a parallel query, we must either have gotten all
3192  * the way to PHJ_BUILD_RUN, or joined too late and be in PHJ_BUILD_FREE.
3193  */
3194  Assert(!pstate ||
3196 
3197  if (pstate && BarrierPhase(&pstate->build_barrier) == PHJ_BUILD_RUN)
3198  {
3199  int i;
3200 
3201  /* Make sure any temporary files are closed. */
3202  if (hashtable->batches)
3203  {
3204  for (i = 0; i < hashtable->nbatch; ++i)
3205  {
3206  sts_end_write(hashtable->batches[i].inner_tuples);
3207  sts_end_write(hashtable->batches[i].outer_tuples);
3210  }
3211  }
3212 
3213  /* If we're last to detach, clean up shared memory. */
3214  if (BarrierArriveAndDetach(&pstate->build_barrier))
3215  {
3216  /*
3217  * Late joining processes will see this state and give up
3218  * immediately.
3219  */
3221 
3222  if (DsaPointerIsValid(pstate->batches))
3223  {
3224  dsa_free(hashtable->area, pstate->batches);
3225  pstate->batches = InvalidDsaPointer;
3226  }
3227  }
3228  }
3229  hashtable->parallel_state = NULL;
3230 }
bool BarrierArriveAndDetach(Barrier *barrier)
Definition: barrier.c:203
void dsa_free(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:832
#define InvalidDsaPointer
Definition: dsa.h:78
#define DsaPointerIsValid(x)
Definition: dsa.h:81
#define PHJ_BUILD_FREE
Definition: hashjoin.h:262
#define PHJ_BUILD_RUN
Definition: hashjoin.h:261
void sts_end_write(SharedTuplestoreAccessor *accessor)
void sts_end_parallel_scan(SharedTuplestoreAccessor *accessor)
SharedTuplestoreAccessor * outer_tuples
Definition: hashjoin.h:209
SharedTuplestoreAccessor * inner_tuples
Definition: hashjoin.h:208
dsa_pointer batches
Definition: hashjoin.h:236

References HashJoinTableData::area, Assert(), BarrierArriveAndDetach(), BarrierPhase(), ParallelHashJoinState::batches, HashJoinTableData::batches, ParallelHashJoinState::build_barrier, dsa_free(), DsaPointerIsValid, i, ParallelHashJoinBatchAccessor::inner_tuples, InvalidDsaPointer, HashJoinTableData::nbatch, ParallelHashJoinBatchAccessor::outer_tuples, HashJoinTableData::parallel_state, PHJ_BUILD_FREE, PHJ_BUILD_RUN, sts_end_parallel_scan(), and sts_end_write().

Referenced by ExecHashJoinReInitializeDSM(), and ExecShutdownHashJoin().

◆ ExecHashTableDetachBatch()

void ExecHashTableDetachBatch ( HashJoinTable  hashtable)

Definition at line 3129 of file nodeHash.c.

3130 {
3131  if (hashtable->parallel_state != NULL &&
3132  hashtable->curbatch >= 0)
3133  {
3134  int curbatch = hashtable->curbatch;
3135  ParallelHashJoinBatch *batch = hashtable->batches[curbatch].shared;
3136 
3137  /* Make sure any temporary files are closed. */
3138  sts_end_parallel_scan(hashtable->batches[curbatch].inner_tuples);
3139  sts_end_parallel_scan(hashtable->batches[curbatch].outer_tuples);
3140 
3141  /* Detach from the batch we were last working on. */
3143  {
3144  /*
3145  * Technically we shouldn't access the barrier because we're no
3146  * longer attached, but since there is no way it's moving after
3147  * this point it seems safe to make the following assertion.
3148  */
3150 
3151  /* Free shared chunks and buckets. */
3152  while (DsaPointerIsValid(batch->chunks))
3153  {
3154  HashMemoryChunk chunk =
3155  dsa_get_address(hashtable->area, batch->chunks);
3156  dsa_pointer next = chunk->next.shared;
3157 
3158  dsa_free(hashtable->area, batch->chunks);
3159  batch->chunks = next;
3160  }
3161  if (DsaPointerIsValid(batch->buckets))
3162  {
3163  dsa_free(hashtable->area, batch->buckets);
3164  batch->buckets = InvalidDsaPointer;
3165  }
3166  }
3167 
3168  /*
3169  * Track the largest batch we've been attached to. Though each
3170  * backend might see a different subset of batches, explain.c will
3171  * scan the results from all backends to find the largest value.
3172  */
3173  hashtable->spacePeak =
3174  Max(hashtable->spacePeak,
3175  batch->size + sizeof(dsa_pointer_atomic) * hashtable->nbuckets);
3176 
3177  /* Remember that we are not attached to a batch. */
3178  hashtable->curbatch = -1;
3179  }
3180 }
static int32 next
Definition: blutils.c:219
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:944
uint64 dsa_pointer
Definition: dsa.h:62
#define PHJ_BATCH_FREE
Definition: hashjoin.h:269
dsa_pointer shared
Definition: hashjoin.h:127
union HashMemoryChunkData::@93 next
ParallelHashJoinBatch * shared
Definition: hashjoin.h:197
dsa_pointer chunks
Definition: hashjoin.h:156
dsa_pointer buckets
Definition: hashjoin.h:153

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, next, HashMemoryChunkData::next, ParallelHashJoinBatchAccessor::outer_tuples, HashJoinTableData::parallel_state, PHJ_BATCH_FREE, HashMemoryChunkData::shared, ParallelHashJoinBatchAccessor::shared, ParallelHashJoinBatch::size, HashJoinTableData::spacePeak, and sts_end_parallel_scan().

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

◆ ExecHashTableInsert()

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

Definition at line 1609 of file nodeHash.c.

1612 {
1613  bool shouldFree;
1614  MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
1615  int bucketno;
1616  int batchno;
1617 
1618  ExecHashGetBucketAndBatch(hashtable, hashvalue,
1619  &bucketno, &batchno);
1620 
1621  /*
1622  * decide whether to put the tuple in the hash table or a temp file
1623  */
1624  if (batchno == hashtable->curbatch)
1625  {
1626  /*
1627  * put the tuple in hash table
1628  */
1629  HashJoinTuple hashTuple;
1630  int hashTupleSize;
1631  double ntuples = (hashtable->totalTuples - hashtable->skewTuples);
1632 
1633  /* Create the HashJoinTuple */
1634  hashTupleSize = HJTUPLE_OVERHEAD + tuple->t_len;
1635  hashTuple = (HashJoinTuple) dense_alloc(hashtable, hashTupleSize);
1636 
1637  hashTuple->hashvalue = hashvalue;
1638  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1639 
1640  /*
1641  * We always reset the tuple-matched flag on insertion. This is okay
1642  * even when reloading a tuple from a batch file, since the tuple
1643  * could not possibly have been matched to an outer tuple before it
1644  * went into the batch file.
1645  */
1647 
1648  /* Push it onto the front of the bucket's list */
1649  hashTuple->next.unshared = hashtable->buckets.unshared[bucketno];
1650  hashtable->buckets.unshared[bucketno] = hashTuple;
1651 
1652  /*
1653  * Increase the (optimal) number of buckets if we just exceeded the
1654  * NTUP_PER_BUCKET threshold, but only when there's still a single
1655  * batch.
1656  */
1657  if (hashtable->nbatch == 1 &&
1658  ntuples > (hashtable->nbuckets_optimal * NTUP_PER_BUCKET))
1659  {
1660  /* Guard against integer overflow and alloc size overflow */
1661  if (hashtable->nbuckets_optimal <= INT_MAX / 2 &&
1662  hashtable->nbuckets_optimal * 2 <= MaxAllocSize / sizeof(HashJoinTuple))
1663  {
1664  hashtable->nbuckets_optimal *= 2;
1665  hashtable->log2_nbuckets_optimal += 1;
1666  }
1667  }
1668 
1669  /* Account for space used, and back off if we've used too much */
1670  hashtable->spaceUsed += hashTupleSize;
1671  if (hashtable->spaceUsed > hashtable->spacePeak)
1672  hashtable->spacePeak = hashtable->spaceUsed;
1673  if (hashtable->spaceUsed +
1674  hashtable->nbuckets_optimal * sizeof(HashJoinTuple)
1675  > hashtable->spaceAllowed)
1676  ExecHashIncreaseNumBatches(hashtable);
1677  }
1678  else
1679  {
1680  /*
1681  * put the tuple into a temp file for later batches
1682  */
1683  Assert(batchno > hashtable->curbatch);
1684  ExecHashJoinSaveTuple(tuple,
1685  hashvalue,
1686  &hashtable->innerBatchFile[batchno]);
1687  }
1688 
1689  if (shouldFree)
1690  heap_free_minimal_tuple(tuple);
1691 }
MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot, bool *shouldFree)
Definition: execTuples.c:1692
#define HJTUPLE_MINTUPLE(hjtup)
Definition: hashjoin.h:80
void heap_free_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1427
#define HeapTupleHeaderClearMatch(tup)
Definition: htup_details.h:524
static void * dense_alloc(HashJoinTable hashtable, Size size)
Definition: nodeHash.c:2723
static void ExecHashIncreaseNumBatches(HashJoinTable hashtable)
Definition: nodeHash.c:911
void ExecHashGetBucketAndBatch(HashJoinTable hashtable, uint32 hashvalue, int *bucketno, int *batchno)
Definition: nodeHash.c:1915
void ExecHashJoinSaveTuple(MinimalTuple tuple, uint32 hashvalue, BufFile **fileptr)
uint32 hashvalue
Definition: hashjoin.h:75
union HashJoinTupleData::@92 next
struct HashJoinTupleData * unshared
Definition: hashjoin.h:72

References Assert(), HashJoinTableData::buckets, HashJoinTableData::curbatch, dense_alloc(), ExecFetchSlotMinimalTuple(), ExecHashGetBucketAndBatch(), ExecHashIncreaseNumBatches(), ExecHashJoinSaveTuple(), HashJoinTupleData::hashvalue, heap_free_minimal_tuple(), 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().

◆ ExecHashTableReset()

void ExecHashTableReset ( HashJoinTable  hashtable)

Definition at line 2154 of file nodeHash.c.

2155 {
2156  MemoryContext oldcxt;
2157  int nbuckets = hashtable->nbuckets;
2158 
2159  /*
2160  * Release all the hash buckets and tuples acquired in the prior pass, and
2161  * reinitialize the context for a new pass.
2162  */
2163  MemoryContextReset(hashtable->batchCxt);
2164  oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
2165 
2166  /* Reallocate and reinitialize the hash bucket headers. */
2167  hashtable->buckets.unshared = palloc0_array(HashJoinTuple, nbuckets);
2168 
2169  hashtable->spaceUsed = 0;
2170 
2171  MemoryContextSwitchTo(oldcxt);
2172 
2173  /* Forget the chunks (the memory was freed by the context reset above). */
2174  hashtable->chunks = NULL;
2175 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:314

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

Referenced by ExecHashJoinNewBatch().

◆ ExecHashTableResetMatchFlags()

void ExecHashTableResetMatchFlags ( HashJoinTable  hashtable)

Definition at line 2182 of file nodeHash.c.

2183 {
2184  HashJoinTuple tuple;
2185  int i;
2186 
2187  /* Reset all flags in the main table ... */
2188  for (i = 0; i < hashtable->nbuckets; i++)
2189  {
2190  for (tuple = hashtable->buckets.unshared[i]; tuple != NULL;
2191  tuple = tuple->next.unshared)
2193  }
2194 
2195  /* ... and the same for the skew buckets, if any */
2196  for (i = 0; i < hashtable->nSkewBuckets; i++)
2197  {
2198  int j = hashtable->skewBucketNums[i];
2199  HashSkewBucket *skewBucket = hashtable->skewBucket[j];
2200 
2201  for (tuple = skewBucket->tuples; tuple != NULL; tuple = tuple->next.unshared)
2203  }
2204 }
int j
Definition: isn.c:74
HashJoinTuple tuples
Definition: hashjoin.h:105

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

Referenced by ExecReScanHashJoin().

◆ ExecInitHash()

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

Definition at line 361 of file nodeHash.c.

362 {
363  HashState *hashstate;
364 
365  /* check for unsupported flags */
366  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
367 
368  /*
369  * create state structure
370  */
371  hashstate = makeNode(HashState);
372  hashstate->ps.plan = (Plan *) node;
373  hashstate->ps.state = estate;
374  hashstate->ps.ExecProcNode = ExecHash;
375  hashstate->hashtable = NULL;
376  hashstate->hashkeys = NIL; /* will be set by parent HashJoin */
377 
378  /*
379  * Miscellaneous initialization
380  *
381  * create expression context for node
382  */
383  ExecAssignExprContext(estate, &hashstate->ps);
384 
385  /*
386  * initialize child nodes
387  */
388  outerPlanState(hashstate) = ExecInitNode(outerPlan(node), estate, eflags);
389 
390  /*
391  * initialize our result slot and type. No need to build projection
392  * because this node doesn't do projections.
393  */
395  hashstate->ps.ps_ProjInfo = NULL;
396 
397  /*
398  * initialize child expressions
399  */
400  Assert(node->plan.qual == NIL);
401  hashstate->hashkeys =
402  ExecInitExprList(node->hashkeys, (PlanState *) hashstate);
403 
404  return hashstate;
405 }
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:322
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:488
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_MARK
Definition: executor.h:69
static TupleTableSlot * ExecHash(PlanState *pstate)
Definition: nodeHash.c:92
#define makeNode(_type_)
Definition: nodes.h:176
#define NIL
Definition: pg_list.h:68
HashJoinTable hashtable
Definition: execnodes.h:2648
List * hashkeys
Definition: execnodes.h:2649
List * hashkeys
Definition: plannodes.h:1206
EState * state
Definition: execnodes.h:1037
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1075
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1041
List * qual
Definition: plannodes.h:157

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

Referenced by ExecInitNode().

◆ ExecParallelHashTableAlloc()

void ExecParallelHashTableAlloc ( HashJoinTable  hashtable,
int  batchno 
)

Definition at line 3109 of file nodeHash.c.

3110 {
3111  ParallelHashJoinBatch *batch = hashtable->batches[batchno].shared;
3112  dsa_pointer_atomic *buckets;
3113  int nbuckets = hashtable->parallel_state->nbuckets;
3114  int i;
3115 
3116  batch->buckets =
3117  dsa_allocate(hashtable->area, sizeof(dsa_pointer_atomic) * nbuckets);
3118  buckets = (dsa_pointer_atomic *)
3119  dsa_get_address(hashtable->area, batch->buckets);
3120  for (i = 0; i < nbuckets; ++i)
3122 }
#define dsa_pointer_atomic_init
Definition: dsa.h:64
#define dsa_allocate(area, size)
Definition: dsa.h:84

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().

◆ ExecParallelHashTableInsert()

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

Definition at line 1698 of file nodeHash.c.

1701 {
1702  bool shouldFree;
1703  MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
1704  dsa_pointer shared;
1705  int bucketno;
1706  int batchno;
1707 
1708 retry:
1709  ExecHashGetBucketAndBatch(hashtable, hashvalue, &bucketno, &batchno);
1710 
1711  if (batchno == 0)
1712  {
1713  HashJoinTuple hashTuple;
1714 
1715  /* Try to load it into memory. */
1718  hashTuple = ExecParallelHashTupleAlloc(hashtable,
1719  HJTUPLE_OVERHEAD + tuple->t_len,
1720  &shared);
1721  if (hashTuple == NULL)
1722  goto retry;
1723 
1724  /* Store the hash value in the HashJoinTuple header. */
1725  hashTuple->hashvalue = hashvalue;
1726  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1727 
1728  /* Push it onto the front of the bucket's list */
1729  ExecParallelHashPushTuple(&hashtable->buckets.shared[bucketno],
1730  hashTuple, shared);
1731  }
1732  else
1733  {
1734  size_t tuple_size = MAXALIGN(HJTUPLE_OVERHEAD + tuple->t_len);
1735 
1736  Assert(batchno > 0);
1737 
1738  /* Try to preallocate space in the batch if necessary. */
1739  if (hashtable->batches[batchno].preallocated < tuple_size)
1740  {
1741  if (!ExecParallelHashTuplePrealloc(hashtable, batchno, tuple_size))
1742  goto retry;
1743  }
1744 
1745  Assert(hashtable->batches[batchno].preallocated >= tuple_size);
1746  hashtable->batches[batchno].preallocated -= tuple_size;
1747  sts_puttuple(hashtable->batches[batchno].inner_tuples, &hashvalue,
1748  tuple);
1749  }
1750  ++hashtable->batches[batchno].ntuples;
1751 
1752  if (shouldFree)
1753  heap_free_minimal_tuple(tuple);
1754 }
#define PHJ_BUILD_HASH_INNER
Definition: hashjoin.h:259
static bool ExecParallelHashTuplePrealloc(HashJoinTable hashtable, int batchno, size_t size)
Definition: nodeHash.c:3346
static HashJoinTuple ExecParallelHashTupleAlloc(HashJoinTable hashtable, size_t size, dsa_pointer *shared)
Definition: nodeHash.c:2803
static void ExecParallelHashPushTuple(dsa_pointer_atomic *head, HashJoinTuple tuple, dsa_pointer tuple_shared)
Definition: nodeHash.c:3266
void sts_puttuple(SharedTuplestoreAccessor *accessor, void *meta_data, MinimalTuple tuple)
dsa_pointer_atomic * shared
Definition: hashjoin.h:300

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

Referenced by MultiExecParallelHash().

◆ ExecParallelHashTableInsertCurrentBatch()

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

Definition at line 1763 of file nodeHash.c.

1766 {
1767  bool shouldFree;
1768  MinimalTuple tuple = ExecFetchSlotMinimalTuple(slot, &shouldFree);
1769  HashJoinTuple hashTuple;
1770  dsa_pointer shared;
1771  int batchno;
1772  int bucketno;
1773 
1774  ExecHashGetBucketAndBatch(hashtable, hashvalue, &bucketno, &batchno);
1775  Assert(batchno == hashtable->curbatch);
1776  hashTuple = ExecParallelHashTupleAlloc(hashtable,
1777  HJTUPLE_OVERHEAD + tuple->t_len,
1778  &shared);
1779  hashTuple->hashvalue = hashvalue;
1780  memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
1782  ExecParallelHashPushTuple(&hashtable->buckets.shared[bucketno],
1783  hashTuple, shared);
1784 
1785  if (shouldFree)
1786  heap_free_minimal_tuple(tuple);
1787 }

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

Referenced by ExecParallelHashJoinNewBatch().

◆ ExecParallelHashTableSetCurrentBatch()

void ExecParallelHashTableSetCurrentBatch ( HashJoinTable  hashtable,
int  batchno 
)

Definition at line 3284 of file nodeHash.c.

3285 {
3286  Assert(hashtable->batches[batchno].shared->buckets != InvalidDsaPointer);
3287 
3288  hashtable->curbatch = batchno;
3289  hashtable->buckets.shared = (dsa_pointer_atomic *)
3290  dsa_get_address(hashtable->area,
3291  hashtable->batches[batchno].shared->buckets);
3292  hashtable->nbuckets = hashtable->parallel_state->nbuckets;
3293  hashtable->log2_nbuckets = my_log2(hashtable->nbuckets);
3294  hashtable->current_chunk = NULL;
3296  hashtable->batches[batchno].at_least_one_chunk = false;
3297 }
dsa_pointer current_chunk_shared
Definition: hashjoin.h:360

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().

◆ ExecParallelScanHashBucket()

bool ExecParallelScanHashBucket ( HashJoinState hjstate,
ExprContext econtext 
)

Definition at line 2008 of file nodeHash.c.

2010 {
2011  ExprState *hjclauses = hjstate->hashclauses;
2012  HashJoinTable hashtable = hjstate->hj_HashTable;
2013  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
2014  uint32 hashvalue = hjstate->hj_CurHashValue;
2015 
2016  /*
2017  * hj_CurTuple is the address of the tuple last returned from the current
2018  * bucket, or NULL if it's time to start scanning a new bucket.
2019  */
2020  if (hashTuple != NULL)
2021  hashTuple = ExecParallelHashNextTuple(hashtable, hashTuple);
2022  else
2023  hashTuple = ExecParallelHashFirstTuple(hashtable,
2024  hjstate->hj_CurBucketNo);
2025 
2026  while (hashTuple != NULL)
2027  {
2028  if (hashTuple->hashvalue == hashvalue)
2029  {
2030  TupleTableSlot *inntuple;
2031 
2032  /* insert hashtable's tuple into exec slot so ExecQual sees it */
2033  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
2034  hjstate->hj_HashTupleSlot,
2035  false); /* do not pfree */
2036  econtext->ecxt_innertuple = inntuple;
2037 
2038  if (ExecQualAndReset(hjclauses, econtext))
2039  {
2040  hjstate->hj_CurTuple = hashTuple;
2041  return true;
2042  }
2043  }
2044 
2045  hashTuple = ExecParallelHashNextTuple(hashtable, hashTuple);
2046  }
2047 
2048  /*
2049  * no match
2050  */
2051  return false;
2052 }
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1446
static bool ExecQualAndReset(ExprState *state, ExprContext *econtext)
Definition: executor.h:438
static HashJoinTuple ExecParallelHashFirstTuple(HashJoinTable hashtable, int bucketno)
Definition: nodeHash.c:3236
static HashJoinTuple ExecParallelHashNextTuple(HashJoinTable hashtable, HashJoinTuple tuple)
Definition: nodeHash.c:3252
TupleTableSlot * ecxt_innertuple
Definition: execnodes.h:251
HashJoinTuple hj_CurTuple
Definition: execnodes.h:2100
ExprState * hashclauses
Definition: execnodes.h:2092
uint32 hj_CurHashValue
Definition: execnodes.h:2097
int hj_CurBucketNo
Definition: execnodes.h:2098
HashJoinTable hj_HashTable
Definition: execnodes.h:2096
TupleTableSlot * hj_HashTupleSlot
Definition: execnodes.h:2102

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().

◆ ExecPrepHashTableForUnmatched()

void ExecPrepHashTableForUnmatched ( HashJoinState hjstate)

Definition at line 2059 of file nodeHash.c.

2060 {
2061  /*----------
2062  * During this scan we use the HashJoinState fields as follows:
2063  *
2064  * hj_CurBucketNo: next regular bucket to scan
2065  * hj_CurSkewBucketNo: next skew bucket (an index into skewBucketNums)
2066  * hj_CurTuple: last tuple returned, or NULL to start next bucket
2067  *----------
2068  */
2069  hjstate->hj_CurBucketNo = 0;
2070  hjstate->hj_CurSkewBucketNo = 0;
2071  hjstate->hj_CurTuple = NULL;
2072 }
int hj_CurSkewBucketNo
Definition: execnodes.h:2099

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

Referenced by ExecHashJoinImpl().

◆ ExecReScanHash()

void ExecReScanHash ( HashState node)

Definition at line 2208 of file nodeHash.c.

2209 {
2211 
2212  /*
2213  * if chgParam of subnode is not null then plan will be re-scanned by
2214  * first ExecProcNode.
2215  */
2216  if (outerPlan->chgParam == NULL)
2218 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:78

References ExecReScan(), outerPlan, and outerPlanState.

Referenced by ExecReScan().

◆ ExecScanHashBucket()

bool ExecScanHashBucket ( HashJoinState hjstate,
ExprContext econtext 
)

Definition at line 1947 of file nodeHash.c.

1949 {
1950  ExprState *hjclauses = hjstate->hashclauses;
1951  HashJoinTable hashtable = hjstate->hj_HashTable;
1952  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
1953  uint32 hashvalue = hjstate->hj_CurHashValue;
1954 
1955  /*
1956  * hj_CurTuple is the address of the tuple last returned from the current
1957  * bucket, or NULL if it's time to start scanning a new bucket.
1958  *
1959  * If the tuple hashed to a skew bucket then scan the skew bucket
1960  * otherwise scan the standard hashtable bucket.
1961  */
1962  if (hashTuple != NULL)
1963  hashTuple = hashTuple->next.unshared;
1964  else if (hjstate->hj_CurSkewBucketNo != INVALID_SKEW_BUCKET_NO)
1965  hashTuple = hashtable->skewBucket[hjstate->hj_CurSkewBucketNo]->tuples;
1966  else
1967  hashTuple = hashtable->buckets.unshared[hjstate->hj_CurBucketNo];
1968 
1969  while (hashTuple != NULL)
1970  {
1971  if (hashTuple->hashvalue == hashvalue)
1972  {
1973  TupleTableSlot *inntuple;
1974 
1975  /* insert hashtable's tuple into exec slot so ExecQual sees it */
1976  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
1977  hjstate->hj_HashTupleSlot,
1978  false); /* do not pfree */
1979  econtext->ecxt_innertuple = inntuple;
1980 
1981  if (ExecQualAndReset(hjclauses, econtext))
1982  {
1983  hjstate->hj_CurTuple = hashTuple;
1984  return true;
1985  }
1986  }
1987 
1988  hashTuple = hashTuple->next.unshared;
1989  }
1990 
1991  /*
1992  * no match
1993  */
1994  return false;
1995 }

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().

◆ ExecScanHashTableForUnmatched()

bool ExecScanHashTableForUnmatched ( HashJoinState hjstate,
ExprContext econtext 
)

Definition at line 2083 of file nodeHash.c.

2084 {
2085  HashJoinTable hashtable = hjstate->hj_HashTable;
2086  HashJoinTuple hashTuple = hjstate->hj_CurTuple;
2087 
2088  for (;;)
2089  {
2090  /*
2091  * hj_CurTuple is the address of the tuple last returned from the
2092  * current bucket, or NULL if it's time to start scanning a new
2093  * bucket.
2094  */
2095  if (hashTuple != NULL)
2096  hashTuple = hashTuple->next.unshared;
2097  else if (hjstate->hj_CurBucketNo < hashtable->nbuckets)
2098  {
2099  hashTuple = hashtable->buckets.unshared[hjstate->hj_CurBucketNo];
2100  hjstate->hj_CurBucketNo++;
2101  }
2102  else if (hjstate->hj_CurSkewBucketNo < hashtable->nSkewBuckets)
2103  {
2104  int j = hashtable->skewBucketNums[hjstate->hj_CurSkewBucketNo];
2105 
2106  hashTuple = hashtable->skewBucket[j]->tuples;
2107  hjstate->hj_CurSkewBucketNo++;
2108  }
2109  else
2110  break; /* finished all buckets */
2111 
2112  while (hashTuple != NULL)
2113  {
2114  if (!HeapTupleHeaderHasMatch(HJTUPLE_MINTUPLE(hashTuple)))
2115  {
2116  TupleTableSlot *inntuple;
2117 
2118  /* insert hashtable's tuple into exec slot */
2119  inntuple = ExecStoreMinimalTuple(HJTUPLE_MINTUPLE(hashTuple),
2120  hjstate->hj_HashTupleSlot,
2121  false); /* do not pfree */
2122  econtext->ecxt_innertuple = inntuple;
2123 
2124  /*
2125  * Reset temp memory each time; although this function doesn't
2126  * do any qual eval, the caller will, so let's keep it
2127  * parallel to ExecScanHashBucket.
2128  */
2129  ResetExprContext(econtext);
2130 
2131  hjstate->hj_CurTuple = hashTuple;
2132  return true;
2133  }
2134 
2135  hashTuple = hashTuple->next.unshared;
2136  }
2137 
2138  /* allow this loop to be cancellable */
2140  }
2141 
2142  /*
2143  * no more unmatched tuples
2144  */
2145  return false;
2146 }
#define HeapTupleHeaderHasMatch(tup)
Definition: htup_details.h:514
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121

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, j, HashJoinTableData::nbuckets, HashJoinTupleData::next, HashJoinTableData::nSkewBuckets, ResetExprContext, HashJoinTableData::skewBucket, HashJoinTableData::skewBucketNums, HashSkewBucket::tuples, HashJoinTupleData::unshared, and HashJoinTableData::unshared.

Referenced by ExecHashJoinImpl().

◆ ExecShutdownHash()

void ExecShutdownHash ( HashState node)

Definition at line 2658 of file nodeHash.c.

2659 {
2660  /* Allocate save space if EXPLAIN'ing and we didn't do so already */
2661  if (node->ps.instrument && !node->hinstrument)
2663  /* Now accumulate data for the current (final) hash table */
2664  if (node->hinstrument && node->hashtable)
2666 }
#define palloc0_object(type)
Definition: fe_memutils.h:63
void ExecHashAccumInstrumentation(HashInstrumentation *instrument, HashJoinTable hashtable)
Definition: nodeHash.c:2704

References ExecHashAccumInstrumentation(), HashState::hashtable, HashState::hinstrument, PlanState::instrument, palloc0_object, and HashState::ps.

Referenced by ExecShutdownNode_walker().

◆ MultiExecHash()

Node* MultiExecHash ( HashState node)

Definition at line 106 of file nodeHash.c.

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

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

Referenced by MultiExecProcNode().