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 1034 of file nodeMemoize.c.

1036 {
1037 #ifdef USE_ASSERT_CHECKING
1038  /* Validate the memory accounting code is correct in assert builds. */
1039  {
1040  int count;
1041  uint64 mem = 0;
1042  memoize_iterator i;
1043  MemoizeEntry *entry;
1044 
1045  memoize_start_iterate(node->hashtable, &i);
1046 
1047  count = 0;
1048  while ((entry = memoize_iterate(node->hashtable, &i)) != NULL)
1049  {
1050  MemoizeTuple *tuple = entry->tuplehead;
1051 
1052  mem += EMPTY_ENTRY_MEMORY_BYTES(entry);
1053  while (tuple != NULL)
1054  {
1055  mem += CACHE_TUPLE_BYTES(tuple);
1056  tuple = tuple->next;
1057  }
1058  count++;
1059  }
1060 
1061  Assert(count == node->hashtable->members);
1062  Assert(mem == node->mem_used);
1063  }
1064 #endif
1065 
1066  /*
1067  * When ending a parallel worker, copy the statistics gathered by the
1068  * worker back into shared memory so that it can be picked up by the main
1069  * process to report in EXPLAIN ANALYZE.
1070  */
1071  if (node->shared_info != NULL && IsParallelWorker())
1072  {
1074 
1075  /* Make mem_peak available for EXPLAIN */
1076  if (node->stats.mem_peak == 0)
1077  node->stats.mem_peak = node->mem_used;
1078 
1079  Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
1081  memcpy(si, &node->stats, sizeof(MemoizeInstrumentation));
1082  }
1083 
1084  /* Remove the cache context */
1086 
1088  /* must drop pointer to cache result tuple */
1090 
1091  /*
1092  * free exprcontext
1093  */
1094  ExecFreeExprContext(&node->ss.ps);
1095 
1096  /*
1097  * shut down the subplan
1098  */
1099  ExecEndNode(outerPlanState(node));
int ParallelWorkerNumber
Definition: parallel.c:113
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:557
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:654
#define outerPlanState(node)
Definition: execnodes.h:1126
#define IsParallelWorker()
Definition: parallel.h:61
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:376
#define CACHE_TUPLE_BYTES(t)
Definition: nodeMemoize.c:89
#define EMPTY_ENTRY_MEMORY_BYTES(e)
Definition: nodeMemoize.c:86
MemoizeTuple * tuplehead
Definition: nodeMemoize.c:117
uint64 mem_used
Definition: execnodes.h:2178
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2193
MemoizeInstrumentation stats
Definition: execnodes.h:2192
MemoryContext tableContext
Definition: execnodes.h:2180
ScanState ss
Definition: execnodes.h:2166
struct memoize_hash * hashtable
Definition: execnodes.h:2169
struct MemoizeTuple * next
Definition: nodeMemoize.c:96
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1068
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1458
PlanState ps
Definition: execnodes.h:1455
MemoizeInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2154
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:433

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

◆ ExecEstimateCacheEntryOverheadBytes()

double ExecEstimateCacheEntryOverheadBytes ( double  ntuples)

Definition at line 1134 of file nodeMemoize.c.

1136 {
1137  return sizeof(MemoizeEntry) + sizeof(MemoizeKey) + sizeof(MemoizeTuple) *
1138  ntuples;
struct MemoizeTuple MemoizeTuple
struct MemoizeEntry MemoizeEntry

Referenced by cost_memoize_rescan().

◆ ExecInitMemoize()

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

Definition at line 909 of file nodeMemoize.c.

911 {
913  Plan *outerNode;
914  int i;
915  int nkeys;
916  Oid *eqfuncoids;
917 
918  /* check for unsupported flags */
919  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
920 
921  mstate->ss.ps.plan = (Plan *) node;
922  mstate->ss.ps.state = estate;
923  mstate->ss.ps.ExecProcNode = ExecMemoize;
924 
925  /*
926  * Miscellaneous initialization
927  *
928  * create expression context for node
929  */
930  ExecAssignExprContext(estate, &mstate->ss.ps);
931 
932  outerNode = outerPlan(node);
933  outerPlanState(mstate) = ExecInitNode(outerNode, estate, eflags);
934 
935  /*
936  * Initialize return slot and type. No need to initialize projection info
937  * because this node doesn't do projections.
938  */
940  mstate->ss.ps.ps_ProjInfo = NULL;
941 
942  /*
943  * Initialize scan slot and type.
944  */
946 
947  /*
948  * Set the state machine to lookup the cache. We won't find anything
949  * until we cache something, but this saves a special case to create the
950  * first entry.
951  */
952  mstate->mstatus = MEMO_CACHE_LOOKUP;
953 
954  mstate->nkeys = nkeys = node->numKeys;
959  &TTSOpsVirtual);
960 
961  mstate->param_exprs = (ExprState **) palloc(nkeys * sizeof(ExprState *));
962  mstate->collations = node->collations; /* Just point directly to the plan
963  * data */
964  mstate->hashfunctions = (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
965 
966  eqfuncoids = palloc(nkeys * sizeof(Oid));
967 
968  for (i = 0; i < nkeys; i++)
969  {
970  Oid hashop = node->hashOperators[i];
971  Oid left_hashfn;
972  Oid right_hashfn;
973  Expr *param_expr = (Expr *) list_nth(node->param_exprs, i);
974 
975  if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
976  elog(ERROR, "could not find hash function for hash operator %u",
977  hashop);
978 
979  fmgr_info(left_hashfn, &mstate->hashfunctions[i]);
980 
981  mstate->param_exprs[i] = ExecInitExpr(param_expr, (PlanState *) mstate);
982  eqfuncoids[i] = get_opcode(hashop);
983  }
984 
987  &TTSOpsVirtual,
988  eqfuncoids,
989  node->collations,
990  node->param_exprs,
991  (PlanState *) mstate);
992 
993  pfree(eqfuncoids);
994  mstate->mem_used = 0;
995 
996  /* Limit the total memory consumed by the cache to this */
997  mstate->mem_limit = get_hash_memory_limit();
998 
999  /* A memory context dedicated for the cache */
1001  "MemoizeHashTable",
1003 
1004  dlist_init(&mstate->lru_list);
1005  mstate->last_tuple = NULL;
1006  mstate->entry = NULL;
1007 
1008  /*
1009  * Mark if we can assume the cache entry is completed after we get the
1010  * first record for it. Some callers might not call us again after
1011  * getting the first match. e.g. A join operator performing a unique join
1012  * is able to skip to the next outer tuple after getting the first
1013  * matching inner tuple. In this case, the cache entry is complete after
1014  * getting the first tuple. This allows us to mark it as so.
1015  */
1016  mstate->singlerow = node->singlerow;
1017  mstate->keyparamids = node->keyparamids;
1018 
1019  /*
1020  * Record if the cache keys should be compared bit by bit, or logically
1021  * using the type's hash equality operator
1022  */
1023  mstate->binary_mode = node->binary_mode;
1024 
1025  /* Zero the statistics counters */
1026  memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation));
1027 
1028  /* Allocate and set up the actual cache */
1029  build_hash_table(mstate, node->est_entries);
1030 
1031  return mstate;
#define ERROR
Definition: elog.h:35
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:124
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:3876
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1799
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:1997
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1238
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:686
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:484
#define EXEC_FLAG_BACKWARD
Definition: executor.h:58
#define EXEC_FLAG_MARK
Definition: executor.h:59
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:126
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1267
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:509
void pfree(void *pointer)
Definition: mcxt.c:1306
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
void * palloc(Size size)
Definition: mcxt.c:1199
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3390
#define MEMO_CACHE_LOOKUP
Definition: nodeMemoize.c:78
static void build_hash_table(MemoizeState *mstate, uint32 size)
Definition: nodeMemoize.c:264
static TupleTableSlot * ExecMemoize(PlanState *pstate)
Definition: nodeMemoize.c:667
#define makeNode(_type_)
Definition: nodes.h:165
static void * list_nth(const List *list, int n)
Definition: pg_list.h:297
#define outerPlan(node)
Definition: plannodes.h:186
unsigned int Oid
Definition: postgres_ext.h:31
Definition: fmgr.h:57
TupleDesc hashkeydesc
Definition: execnodes.h:2170
FmgrInfo * hashfunctions
Definition: execnodes.h:2176
Oid * collations
Definition: execnodes.h:2177
TupleTableSlot * probeslot
Definition: execnodes.h:2172
struct MemoizeEntry * entry
Definition: execnodes.h:2186
ExprState * cache_eq_expr
Definition: execnodes.h:2173
bool singlerow
Definition: execnodes.h:2188
dlist_head lru_list
Definition: execnodes.h:2181
bool binary_mode
Definition: execnodes.h:2190
Bitmapset * keyparamids
Definition: execnodes.h:2194
uint64 mem_limit
Definition: execnodes.h:2179
ExprState ** param_exprs
Definition: execnodes.h:2174
TupleTableSlot * tableslot
Definition: execnodes.h:2171
struct MemoizeTuple * last_tuple
Definition: execnodes.h:2182
bool singlerow
Definition: plannodes.h:908
Bitmapset * keyparamids
Definition: plannodes.h:923
bool binary_mode
Definition: plannodes.h:914
int numKeys
Definition: plannodes.h:893
List * param_exprs
Definition: plannodes.h:902
uint32 est_entries
Definition: plannodes.h:920
Plan * plan
Definition: execnodes.h:1030
EState * state
Definition: execnodes.h:1032
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1070
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1036

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), MemoizeState::binary_mode, Memoize::binary_mode, build_hash_table(), MemoizeState::cache_eq_expr, MemoizeState::collations, CurrentMemoryContext, dlist_init(), elog(), MemoizeState::entry, 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, i, MemoizeState::keyparamids, Memoize::keyparamids, MemoizeState::last_tuple, list_nth(), MemoizeState::lru_list, makeNode, MakeSingleTupleTableSlot(), MemoizeState::mem_limit, MemoizeState::mem_used, MEMO_CACHE_LOOKUP, MemoizeState::mstatus, MemoizeState::nkeys, Memoize::numKeys, outerPlan, outerPlanState, palloc(), MemoizeState::param_exprs, Memoize::param_exprs, pfree(), PlanState::plan, MemoizeState::probeslot, ScanState::ps, PlanState::ps_ProjInfo, MemoizeState::singlerow, Memoize::singlerow, MemoizeState::ss, PlanState::state, MemoizeState::stats, MemoizeState::tableContext, MemoizeState::tableslot, TTSOpsMinimalTuple, and TTSOpsVirtual.

Referenced by ExecInitNode().

◆ ExecMemoizeEstimate()

void ExecMemoizeEstimate ( MemoizeState node,
ParallelContext pcxt 
)

Definition at line 1152 of file nodeMemoize.c.

1154 {
1155  Size size;
1156 
1157  /* don't need this if not instrumenting or no workers */
1158  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
1159  return;
1160 
1161  size = mul_size(pcxt->nworkers, sizeof(MemoizeInstrumentation));
1162  size = add_size(size, offsetof(SharedMemoizeInfo, sinstrument));
1163  shm_toc_estimate_chunk(&pcxt->estimator, size);
1164  shm_toc_estimate_keys(&pcxt->estimator, 1);
size_t Size
Definition: c.h:541
#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:1040

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

Referenced by ExecParallelEstimate().

◆ ExecMemoizeInitializeDSM()

void ExecMemoizeInitializeDSM ( MemoizeState node,
ParallelContext pcxt 
)

Definition at line 1173 of file nodeMemoize.c.

1175 {
1176  Size size;
1177 
1178  /* don't need this if not instrumenting or no workers */
1179  if (!node->ss.ps.instrument || pcxt->nworkers == 0)
1180  return;
1181 
1182  size = offsetof(SharedMemoizeInfo, sinstrument)
1183  + pcxt->nworkers * sizeof(MemoizeInstrumentation);
1184  node->shared_info = shm_toc_allocate(pcxt->toc, size);
1185  /* ensure any unfilled slots will contain zeroes */
1186  memset(node->shared_info, 0, size);
1187  node->shared_info->num_workers = pcxt->nworkers;
1188  shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
1189  node->shared_info);
struct MemoizeInstrumentation MemoizeInstrumentation
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
shm_toc * toc
Definition: parallel.h:45
int plan_node_id
Definition: plannodes.h:155

References PlanState::instrument, SharedMemoizeInfo::num_workers, ParallelContext::nworkers, 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().

◆ ExecMemoizeInitializeWorker()

void ExecMemoizeInitializeWorker ( MemoizeState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1198 of file nodeMemoize.c.

1200 {
1201  node->shared_info =
1202  shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
Definition: shm_toc.c:232

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

Referenced by ExecParallelInitializeWorker().

◆ ExecMemoizeRetrieveInstrumentation()

void ExecMemoizeRetrieveInstrumentation ( MemoizeState node)

Definition at line 1211 of file nodeMemoize.c.

1213 {
1214  Size size;
1215  SharedMemoizeInfo *si;
1216 
1217  if (node->shared_info == NULL)
1218  return;
1219 
1220  size = offsetof(SharedMemoizeInfo, sinstrument)
1221  + node->shared_info->num_workers * sizeof(MemoizeInstrumentation);
1222  si = palloc(size);
1223  memcpy(si, node->shared_info, size);
1224  node->shared_info = si;

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecReScanMemoize()

void ExecReScanMemoize ( MemoizeState node)

Definition at line 1102 of file nodeMemoize.c.

1104 {
1106 
1107  /* Mark that we must lookup the cache for a new set of parameters */
1108  node->mstatus = MEMO_CACHE_LOOKUP;
1109 
1110  /* nullify pointers used for the last scan */
1111  node->entry = NULL;
1112  node->last_tuple = NULL;
1113 
1114  /*
1115  * if chgParam of subnode is not null then plan will be re-scanned by
1116  * first ExecProcNode.
1117  */
1118  if (outerPlan->chgParam == NULL)
1120 
1121  /*
1122  * Purge the entire cache if a parameter changed that is not part of the
1123  * cache key.
1124  */
1125  if (bms_nonempty_difference(outerPlan->chgParam, node->keyparamids))
1126  cache_purge_all(node);
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:548
void ExecReScan(PlanState *node)
Definition: execAmi.c:78
static void cache_purge_all(MemoizeState *mstate)
Definition: nodeMemoize.c:374

References bms_nonempty_difference(), cache_purge_all(), MemoizeState::entry, ExecReScan(), MemoizeState::keyparamids, MemoizeState::last_tuple, MEMO_CACHE_LOOKUP, MemoizeState::mstatus, outerPlan, and outerPlanState.

Referenced by ExecReScan().