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

Go to the source code of this file.

Functions

MemoizeStateExecInitMemoize (Memoize *node, EState *estate, int eflags)
 
void ExecEndMemoize (MemoizeState *node)
 
void ExecReScanMemoize (MemoizeState *node)
 
double ExecEstimateCacheEntryOverheadBytes (double ntuples)
 
void ExecMemoizeEstimate (MemoizeState *node, ParallelContext *pcxt)
 
void ExecMemoizeInitializeDSM (MemoizeState *node, ParallelContext *pcxt)
 
void ExecMemoizeInitializeWorker (MemoizeState *node, ParallelWorkerContext *pwcxt)
 
void ExecMemoizeRetrieveInstrumentation (MemoizeState *node)
 

Function Documentation

◆ ExecEndMemoize()

void ExecEndMemoize ( MemoizeState node)

Definition at line 939 of file nodeMemoize.c.

References Assert, CACHE_TUPLE_BYTES, EMPTY_ENTRY_MEMORY_BYTES, ExecClearTuple(), ExecEndNode(), ExecFreeExprContext(), MemoizeState::hashtable, i, IsParallelWorker, MemoizeInstrumentation::mem_peak, MemoizeState::mem_used, MemoryContextDelete(), MemoizeTuple::next, outerPlanState, ParallelWorkerNumber, ScanState::ps, PlanState::ps_ResultTupleSlot, MemoizeState::shared_info, SharedMemoizeInfo::sinstrument, MemoizeState::ss, ScanState::ss_ScanTupleSlot, MemoizeState::stats, MemoizeState::tableContext, and MemoizeEntry::tuplehead.

Referenced by ExecEndNode().

940 {
941 #ifdef USE_ASSERT_CHECKING
942  /* Validate the memory accounting code is correct in assert builds. */
943  {
944  int count;
945  uint64 mem = 0;
946  memoize_iterator i;
947  MemoizeEntry *entry;
948 
949  memoize_start_iterate(node->hashtable, &i);
950 
951  count = 0;
952  while ((entry = memoize_iterate(node->hashtable, &i)) != NULL)
953  {
954  MemoizeTuple *tuple = entry->tuplehead;
955 
956  mem += EMPTY_ENTRY_MEMORY_BYTES(entry);
957  while (tuple != NULL)
958  {
959  mem += CACHE_TUPLE_BYTES(tuple);
960  tuple = tuple->next;
961  }
962  count++;
963  }
964 
965  Assert(count == node->hashtable->members);
966  Assert(mem == node->mem_used);
967  }
968 #endif
969 
970  /*
971  * When ending a parallel worker, copy the statistics gathered by the
972  * worker back into shared memory so that it can be picked up by the main
973  * process to report in EXPLAIN ANALYZE.
974  */
975  if (node->shared_info != NULL && IsParallelWorker())
976  {
978 
979  /* Make mem_peak available for EXPLAIN */
980  if (node->stats.mem_peak == 0)
981  node->stats.mem_peak = node->mem_used;
982 
983  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
985  memcpy(si, &node->stats, sizeof(MemoizeInstrumentation));
986  }
987 
988  /* Remove the cache context */
990 
992  /* must drop pointer to cache result tuple */
994 
995  /*
996  * free exprcontext
997  */
998  ExecFreeExprContext(&node->ss.ps);
999 
1000  /*
1001  * shut down the subplan
1002  */
1003  ExecEndNode(outerPlanState(node));
1004 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
struct MemoizeTuple * next
Definition: nodeMemoize.c:96
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:556
MemoryContext tableContext
Definition: execnodes.h:2101
#define EMPTY_ENTRY_MEMORY_BYTES(e)
Definition: nodeMemoize.c:86
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1380
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:650
PlanState ps
Definition: execnodes.h:1377
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1004
MemoizeTuple * tuplehead
Definition: nodeMemoize.c:117
#define outerPlanState(node)
Definition: execnodes.h:1062
int ParallelWorkerNumber
Definition: parallel.c:112
#define IsParallelWorker()
Definition: parallel.h:61
ScanState ss
Definition: execnodes.h:2087
#define Assert(condition)
Definition: c.h:804
struct memoize_hash * hashtable
Definition: execnodes.h:2090
#define CACHE_TUPLE_BYTES(t)
Definition: nodeMemoize.c:89
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2112
MemoizeInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2075
int i
MemoizeInstrumentation stats
Definition: execnodes.h:2111
uint64 mem_used
Definition: execnodes.h:2099

◆ ExecEstimateCacheEntryOverheadBytes()

double ExecEstimateCacheEntryOverheadBytes ( double  ntuples)

Definition at line 1033 of file nodeMemoize.c.

Referenced by cost_memoize_rescan().

1034 {
1035  return sizeof(MemoizeEntry) + sizeof(MemoizeKey) + sizeof(MemoizeTuple) *
1036  ntuples;
1037 }
struct MemoizeTuple MemoizeTuple
struct MemoizeEntry MemoizeEntry

◆ ExecInitMemoize()

MemoizeState* ExecInitMemoize ( Memoize node,
EState estate,
int  eflags 
)

Definition at line 821 of file nodeMemoize.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, build_hash_table(), MemoizeState::cache_eq_expr, Memoize::collations, MemoizeState::collations, CurrentMemoryContext, dlist_init(), elog, ERROR, Memoize::est_entries, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecBuildParamSetEqual(), ExecCreateScanSlotFromOuterPlan(), ExecInitExpr(), ExecInitNode(), ExecInitResultTupleSlotTL(), ExecMemoize(), PlanState::ExecProcNode, ExecTypeFromExprList(), fmgr_info(), get_hash_memory_limit(), get_op_hash_functions(), get_opcode(), MemoizeState::hashfunctions, MemoizeState::hashkeydesc, Memoize::hashOperators, i, list_nth(), makeNode, MakeSingleTupleTableSlot(), MEMO_CACHE_LOOKUP, MemoizeState::mstatus, MemoizeState::nkeys, Memoize::numKeys, outerPlan, outerPlanState, palloc(), Memoize::param_exprs, MemoizeState::param_exprs, pfree(), PlanState::plan, MemoizeState::probeslot, ScanState::ps, PlanState::ps_ProjInfo, Memoize::singlerow, MemoizeState::ss, PlanState::state, MemoizeState::tableslot, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

822 {
824  Plan *outerNode;
825  int i;
826  int nkeys;
827  Oid *eqfuncoids;
828 
829  /* check for unsupported flags */
830  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
831 
832  mstate->ss.ps.plan = (Plan *) node;
833  mstate->ss.ps.state = estate;
834  mstate->ss.ps.ExecProcNode = ExecMemoize;
835 
836  /*
837  * Miscellaneous initialization
838  *
839  * create expression context for node
840  */
841  ExecAssignExprContext(estate, &mstate->ss.ps);
842 
843  outerNode = outerPlan(node);
844  outerPlanState(mstate) = ExecInitNode(outerNode, estate, eflags);
845 
846  /*
847  * Initialize return slot and type. No need to initialize projection info
848  * because this node doesn't do projections.
849  */
851  mstate->ss.ps.ps_ProjInfo = NULL;
852 
853  /*
854  * Initialize scan slot and type.
855  */
857 
858  /*
859  * Set the state machine to lookup the cache. We won't find anything
860  * until we cache something, but this saves a special case to create the
861  * first entry.
862  */
863  mstate->mstatus = MEMO_CACHE_LOOKUP;
864 
865  mstate->nkeys = nkeys = node->numKeys;
870  &TTSOpsVirtual);
871 
872  mstate->param_exprs = (ExprState **) palloc(nkeys * sizeof(ExprState *));
873  mstate->collations = node->collations; /* Just point directly to the plan
874  * data */
875  mstate->hashfunctions = (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
876 
877  eqfuncoids = palloc(nkeys * sizeof(Oid));
878 
879  for (i = 0; i < nkeys; i++)
880  {
881  Oid hashop = node->hashOperators[i];
882  Oid left_hashfn;
883  Oid right_hashfn;
884  Expr *param_expr = (Expr *) list_nth(node->param_exprs, i);
885 
886  if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
887  elog(ERROR, "could not find hash function for hash operator %u",
888  hashop);
889 
890  fmgr_info(left_hashfn, &mstate->hashfunctions[i]);
891 
892  mstate->param_exprs[i] = ExecInitExpr(param_expr, (PlanState *) mstate);
893  eqfuncoids[i] = get_opcode(hashop);
894  }
895 
898  &TTSOpsVirtual,
899  eqfuncoids,
900  node->collations,
901  node->param_exprs,
902  (PlanState *) mstate);
903 
904  pfree(eqfuncoids);
905  mstate->mem_used = 0;
906 
907  /* Limit the total memory consumed by the cache to this */
908  mstate->mem_limit = get_hash_memory_limit();
909 
910  /* A memory context dedicated for the cache */
912  "MemoizeHashTable",
914 
915  dlist_init(&mstate->lru_list);
916  mstate->last_tuple = NULL;
917  mstate->entry = NULL;
918 
919  /*
920  * Mark if we can assume the cache entry is completed after we get the
921  * first record for it. Some callers might not call us again after
922  * getting the first match. e.g. A join operator performing a unique join
923  * is able to skip to the next outer tuple after getting the first
924  * matching inner tuple. In this case, the cache entry is complete after
925  * getting the first tuple. This allows us to mark it as so.
926  */
927  mstate->singlerow = node->singlerow;
928 
929  /* Zero the statistics counters */
930  memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation));
931 
932  /* Allocate and set up the actual cache */
933  build_hash_table(mstate, node->est_entries);
934 
935  return mstate;
936 }
Definition: fmgr.h:56
#define AllocSetContextCreate
Definition: memutils.h:173
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:508
bool singlerow
Definition: execnodes.h:2109
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1006
Oid * collations
Definition: plannodes.h:797
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1238
MemoryContext tableContext
Definition: execnodes.h:2101
ExprState * ExecBuildParamSetEqual(TupleDesc desc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, const Oid *eqfunctions, const Oid *collations, const List *param_exprs, PlanState *parent)
Definition: execExpr.c:3856
ExprState * cache_eq_expr
Definition: execnodes.h:2094
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
static void build_hash_table(MemoizeState *mstate, uint32 size)
Definition: nodeMemoize.c:211
static TupleTableSlot * ExecMemoize(PlanState *pstate)
Definition: nodeMemoize.c:579
TupleTableSlot * probeslot
Definition: execnodes.h:2093
EState * state
Definition: execnodes.h:968
int numKeys
Definition: plannodes.h:794
unsigned int Oid
Definition: postgres_ext.h:31
PlanState ps
Definition: execnodes.h:1377
List * param_exprs
Definition: plannodes.h:798
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
ExprState ** param_exprs
Definition: execnodes.h:2095
static void * list_nth(const List *list, int n)
Definition: pg_list.h:278
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define outerPlanState(node)
Definition: execnodes.h:1062
uint64 mem_limit
Definition: execnodes.h:2100
struct MemoizeTuple * last_tuple
Definition: execnodes.h:2103
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
#define outerPlan(node)
Definition: plannodes.h:171
Oid * collations
Definition: execnodes.h:2098
ScanState ss
Definition: execnodes.h:2087
TupleTableSlot * tableslot
Definition: execnodes.h:2092
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:972
FmgrInfo * hashfunctions
Definition: execnodes.h:2097
bool singlerow
Definition: plannodes.h:799
Plan * plan
Definition: execnodes.h:966
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1256
#define makeNode(_type_)
Definition: nodes.h:584
#define Assert(condition)
Definition: c.h:804
struct MemoizeEntry * entry
Definition: execnodes.h:2107
#define EXEC_FLAG_MARK
Definition: executor.h:59
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:480
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3401
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
TupleDesc hashkeydesc
Definition: execnodes.h:2091
uint32 est_entries
Definition: plannodes.h:802
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:1997
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
#define MEMO_CACHE_LOOKUP
Definition: nodeMemoize.c:77
MemoizeInstrumentation stats
Definition: execnodes.h:2111
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:123
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:682
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:141
dlist_head lru_list
Definition: execnodes.h:2102
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
Oid * hashOperators
Definition: plannodes.h:796
uint64 mem_used
Definition: execnodes.h:2099

◆ ExecMemoizeEstimate()

void ExecMemoizeEstimate ( MemoizeState node,
ParallelContext pcxt 
)

Definition at line 1051 of file nodeMemoize.c.

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

Referenced by ExecParallelEstimate().

1052 {
1053  Size size;
1054 
1055  /* don't need this if not instrumenting or no workers */
1056  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
1057  return;
1058 
1059  size = mul_size(pcxt->nworkers, sizeof(MemoizeInstrumentation));
1060  size = add_size(size, offsetof(SharedMemoizeInfo, sinstrument));
1061  shm_toc_estimate_chunk(&pcxt->estimator, size);
1062  shm_toc_estimate_keys(&pcxt->estimator, 1);
1063 }
Instrumentation * instrument
Definition: execnodes.h:976
shm_toc_estimator estimator
Definition: parallel.h:42
#define shm_toc_estimate_chunk(e, sz)
Definition: shm_toc.h:51
PlanState ps
Definition: execnodes.h:1377
ScanState ss
Definition: execnodes.h:2087
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
size_t Size
Definition: c.h:540
#define shm_toc_estimate_keys(e, cnt)
Definition: shm_toc.h:53
#define offsetof(type, field)
Definition: c.h:727

◆ ExecMemoizeInitializeDSM()

void ExecMemoizeInitializeDSM ( MemoizeState node,
ParallelContext pcxt 
)

Definition at line 1072 of file nodeMemoize.c.

References PlanState::instrument, SharedMemoizeInfo::num_workers, ParallelContext::nworkers, offsetof, PlanState::plan, Plan::plan_node_id, ScanState::ps, MemoizeState::shared_info, shm_toc_allocate(), shm_toc_insert(), MemoizeState::ss, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

1073 {
1074  Size size;
1075 
1076  /* don't need this if not instrumenting or no workers */
1077  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
1078  return;
1079 
1080  size = offsetof(SharedMemoizeInfo, sinstrument)
1081  + pcxt->nworkers * sizeof(MemoizeInstrumentation);
1082  node->shared_info = shm_toc_allocate(pcxt->toc, size);
1083  /* ensure any unfilled slots will contain zeroes */
1084  memset(node->shared_info, 0, size);
1085  node->shared_info->num_workers = pcxt->nworkers;
1086  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
1087  node->shared_info);
1088 }
Instrumentation * instrument
Definition: execnodes.h:976
struct MemoizeInstrumentation MemoizeInstrumentation
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1377
ScanState ss
Definition: execnodes.h:2087
Plan * plan
Definition: execnodes.h:966
size_t Size
Definition: c.h:540
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2112
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
#define offsetof(type, field)
Definition: c.h:727
shm_toc * toc
Definition: parallel.h:45

◆ ExecMemoizeInitializeWorker()

void ExecMemoizeInitializeWorker ( MemoizeState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1097 of file nodeMemoize.c.

References PlanState::plan, Plan::plan_node_id, ScanState::ps, MemoizeState::shared_info, shm_toc_lookup(), MemoizeState::ss, and ParallelWorkerContext::toc.

Referenced by ExecParallelInitializeWorker().

1098 {
1099  node->shared_info =
1100  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
1101 }
int plan_node_id
Definition: plannodes.h:140
PlanState ps
Definition: execnodes.h:1377
ScanState ss
Definition: execnodes.h:2087
Plan * plan
Definition: execnodes.h:966
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2112
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

◆ ExecMemoizeRetrieveInstrumentation()

void ExecMemoizeRetrieveInstrumentation ( MemoizeState node)

Definition at line 1110 of file nodeMemoize.c.

References SharedMemoizeInfo::num_workers, offsetof, palloc(), and MemoizeState::shared_info.

Referenced by ExecParallelRetrieveInstrumentation().

1111 {
1112  Size size;
1113  SharedMemoizeInfo *si;
1114 
1115  if (node->shared_info == NULL)
1116  return;
1117 
1118  size = offsetof(SharedMemoizeInfo, sinstrument)
1119  + node->shared_info->num_workers * sizeof(MemoizeInstrumentation);
1120  si = palloc(size);
1121  memcpy(si, node->shared_info, size);
1122  node->shared_info = si;
1123 }
struct MemoizeInstrumentation MemoizeInstrumentation
size_t Size
Definition: c.h:540
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2112
void * palloc(Size size)
Definition: mcxt.c:1062
#define offsetof(type, field)
Definition: c.h:727

◆ ExecReScanMemoize()

void ExecReScanMemoize ( MemoizeState node)

Definition at line 1007 of file nodeMemoize.c.

References PlanState::chgParam, MemoizeState::entry, ExecReScan(), MemoizeState::last_tuple, MEMO_CACHE_LOOKUP, MemoizeState::mstatus, outerPlan, and outerPlanState.

Referenced by ExecReScan().

1008 {
1010 
1011  /* Mark that we must lookup the cache for a new set of parameters */
1012  node->mstatus = MEMO_CACHE_LOOKUP;
1013 
1014  /* nullify pointers used for the last scan */
1015  node->entry = NULL;
1016  node->last_tuple = NULL;
1017 
1018  /*
1019  * if chgParam of subnode is not null then plan will be re-scanned by
1020  * first ExecProcNode.
1021  */
1022  if (outerPlan->chgParam == NULL)
1023  ExecReScan(outerPlan);
1024 
1025 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
#define outerPlanState(node)
Definition: execnodes.h:1062
struct MemoizeTuple * last_tuple
Definition: execnodes.h:2103
Bitmapset * chgParam
Definition: execnodes.h:998
#define outerPlan(node)
Definition: plannodes.h:171
struct MemoizeEntry * entry
Definition: execnodes.h:2107
#define MEMO_CACHE_LOOKUP
Definition: nodeMemoize.c:77