PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 1079 of file nodeMemoize.c.

1081{
1082#ifdef USE_ASSERT_CHECKING
1083 /* Validate the memory accounting code is correct in assert builds. */
1084 if (node->hashtable != NULL)
1085 {
1086 int count;
1087 uint64 mem = 0;
1088 memoize_iterator i;
1089 MemoizeEntry *entry;
1090
1091 memoize_start_iterate(node->hashtable, &i);
1092
1093 count = 0;
1094 while ((entry = memoize_iterate(node->hashtable, &i)) != NULL)
1095 {
1096 MemoizeTuple *tuple = entry->tuplehead;
1097
1098 mem += EMPTY_ENTRY_MEMORY_BYTES(entry);
1099 while (tuple != NULL)
1100 {
1101 mem += CACHE_TUPLE_BYTES(tuple);
1102 tuple = tuple->next;
1103 }
1104 count++;
1105 }
1106
1107 Assert(count == node->hashtable->members);
1108 Assert(mem == node->mem_used);
1109 }
1110#endif
1111
1112 /*
1113 * When ending a parallel worker, copy the statistics gathered by the
1114 * worker back into shared memory so that it can be picked up by the main
1115 * process to report in EXPLAIN ANALYZE.
1116 */
1117 if (node->shared_info != NULL && IsParallelWorker())
1118 {
1120
1121 /* Make mem_peak available for EXPLAIN */
1122 if (node->stats.mem_peak == 0)
1123 node->stats.mem_peak = node->mem_used;
1124
1125 Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
1127 memcpy(si, &node->stats, sizeof(MemoizeInstrumentation));
1128 }
1129
1130 /* Remove the cache context */
1132
1133 /*
1134 * shut down the subplan
1135 */
int ParallelWorkerNumber
Definition: parallel.c:114
#define Assert(condition)
Definition: c.h:812
uint64_t uint64
Definition: c.h:486
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
#define outerPlanState(node)
Definition: execnodes.h:1221
#define IsParallelWorker()
Definition: parallel.h:60
int i
Definition: isn.c:72
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#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:2312
SharedMemoizeInfo * shared_info
Definition: execnodes.h:2327
MemoizeInstrumentation stats
Definition: execnodes.h:2326
MemoryContext tableContext
Definition: execnodes.h:2314
struct memoize_hash * hashtable
Definition: execnodes.h:2303
struct MemoizeTuple * next
Definition: nodeMemoize.c:96
MemoizeInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER]
Definition: execnodes.h:2288

References Assert, CACHE_TUPLE_BYTES, EMPTY_ENTRY_MEMORY_BYTES, ExecEndNode(), MemoizeState::hashtable, i, IsParallelWorker, MemoizeInstrumentation::mem_peak, MemoizeState::mem_used, MemoryContextDelete(), MemoizeTuple::next, outerPlanState, ParallelWorkerNumber, MemoizeState::shared_info, SharedMemoizeInfo::sinstrument, MemoizeState::stats, MemoizeState::tableContext, and MemoizeEntry::tuplehead.

Referenced by ExecEndNode().

◆ ExecEstimateCacheEntryOverheadBytes()

double ExecEstimateCacheEntryOverheadBytes ( double  ntuples)

Definition at line 1171 of file nodeMemoize.c.

1173{
1174 return sizeof(MemoizeEntry) + sizeof(MemoizeKey) + sizeof(MemoizeTuple) *
1175 ntuples;
struct MemoizeTuple MemoizeTuple
struct MemoizeEntry MemoizeEntry

Referenced by cost_memoize_rescan().

◆ ExecInitMemoize()

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

Definition at line 951 of file nodeMemoize.c.

953{
955 Plan *outerNode;
956 int i;
957 int nkeys;
958 Oid *eqfuncoids;
959
960 /* check for unsupported flags */
962
963 mstate->ss.ps.plan = (Plan *) node;
964 mstate->ss.ps.state = estate;
965 mstate->ss.ps.ExecProcNode = ExecMemoize;
966
967 /*
968 * Miscellaneous initialization
969 *
970 * create expression context for node
971 */
972 ExecAssignExprContext(estate, &mstate->ss.ps);
973
974 outerNode = outerPlan(node);
975 outerPlanState(mstate) = ExecInitNode(outerNode, estate, eflags);
976
977 /*
978 * Initialize return slot and type. No need to initialize projection info
979 * because this node doesn't do projections.
980 */
982 mstate->ss.ps.ps_ProjInfo = NULL;
983
984 /*
985 * Initialize scan slot and type.
986 */
988
989 /*
990 * Set the state machine to lookup the cache. We won't find anything
991 * until we cache something, but this saves a special case to create the
992 * first entry.
993 */
994 mstate->mstatus = MEMO_CACHE_LOOKUP;
995
996 mstate->nkeys = nkeys = node->numKeys;
1001 &TTSOpsVirtual);
1002
1003 mstate->param_exprs = (ExprState **) palloc(nkeys * sizeof(ExprState *));
1004 mstate->collations = node->collations; /* Just point directly to the plan
1005 * data */
1006 mstate->hashfunctions = (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
1007
1008 eqfuncoids = palloc(nkeys * sizeof(Oid));
1009
1010 for (i = 0; i < nkeys; i++)
1011 {
1012 Oid hashop = node->hashOperators[i];
1013 Oid left_hashfn;
1014 Oid right_hashfn;
1015 Expr *param_expr = (Expr *) list_nth(node->param_exprs, i);
1016
1017 if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
1018 elog(ERROR, "could not find hash function for hash operator %u",
1019 hashop);
1020
1021 fmgr_info(left_hashfn, &mstate->hashfunctions[i]);
1022
1023 mstate->param_exprs[i] = ExecInitExpr(param_expr, (PlanState *) mstate);
1024 eqfuncoids[i] = get_opcode(hashop);
1025 }
1026
1030 eqfuncoids,
1031 node->collations,
1032 node->param_exprs,
1033 (PlanState *) mstate);
1034
1035 pfree(eqfuncoids);
1036 mstate->mem_used = 0;
1037
1038 /* Limit the total memory consumed by the cache to this */
1039 mstate->mem_limit = get_hash_memory_limit();
1040
1041 /* A memory context dedicated for the cache */
1043 "MemoizeHashTable",
1045
1046 dlist_init(&mstate->lru_list);
1047 mstate->last_tuple = NULL;
1048 mstate->entry = NULL;
1049
1050 /*
1051 * Mark if we can assume the cache entry is completed after we get the
1052 * first record for it. Some callers might not call us again after
1053 * getting the first match. e.g. A join operator performing a unique join
1054 * is able to skip to the next outer tuple after getting the first
1055 * matching inner tuple. In this case, the cache entry is complete after
1056 * getting the first tuple. This allows us to mark it as so.
1057 */
1058 mstate->singlerow = node->singlerow;
1059 mstate->keyparamids = node->keyparamids;
1060
1061 /*
1062 * Record if the cache keys should be compared bit by bit, or logically
1063 * using the type's hash equality operator
1064 */
1065 mstate->binary_mode = node->binary_mode;
1066
1067 /* Zero the statistics counters */
1068 memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation));
1069
1070 /*
1071 * Because it may require a large allocation, we delay building of the
1072 * hash table until executor run.
1073 */
1074 mstate->hashtable = NULL;
1075
1076 return mstate;
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:138
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:4478
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void ExecInitResultTupleSlotTL(PlanState *planstate, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1986
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:2184
void ExecCreateScanSlotFromOuterPlan(EState *estate, ScanState *scanstate, const TupleTableSlotOps *tts_ops)
Definition: execUtils.c:704
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:485
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_MARK
Definition: executor.h:69
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno)
Definition: lsyscache.c:510
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
size_t get_hash_memory_limit(void)
Definition: nodeHash.c:3487
#define MEMO_CACHE_LOOKUP
Definition: nodeMemoize.c:78
static TupleTableSlot * ExecMemoize(PlanState *pstate)
Definition: nodeMemoize.c:696
#define makeNode(_type_)
Definition: nodes.h:155
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
#define outerPlan(node)
Definition: plannodes.h:183
unsigned int Oid
Definition: postgres_ext.h:31
Definition: fmgr.h:57
TupleDesc hashkeydesc
Definition: execnodes.h:2304
FmgrInfo * hashfunctions
Definition: execnodes.h:2310
Oid * collations
Definition: execnodes.h:2311
TupleTableSlot * probeslot
Definition: execnodes.h:2306
struct MemoizeEntry * entry
Definition: execnodes.h:2320
ExprState * cache_eq_expr
Definition: execnodes.h:2307
bool singlerow
Definition: execnodes.h:2322
dlist_head lru_list
Definition: execnodes.h:2315
bool binary_mode
Definition: execnodes.h:2324
Bitmapset * keyparamids
Definition: execnodes.h:2328
ScanState ss
Definition: execnodes.h:2300
uint64 mem_limit
Definition: execnodes.h:2313
ExprState ** param_exprs
Definition: execnodes.h:2308
TupleTableSlot * tableslot
Definition: execnodes.h:2305
struct MemoizeTuple * last_tuple
Definition: execnodes.h:2316
bool singlerow
Definition: plannodes.h:910
Bitmapset * keyparamids
Definition: plannodes.h:925
bool binary_mode
Definition: plannodes.h:916
int numKeys
Definition: plannodes.h:895
List * param_exprs
Definition: plannodes.h:904
Plan * plan
Definition: execnodes.h:1125
EState * state
Definition: execnodes.h:1127
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1165
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1131
PlanState ps
Definition: execnodes.h:1572

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, MemoizeState::binary_mode, Memoize::binary_mode, MemoizeState::cache_eq_expr, MemoizeState::collations, CurrentMemoryContext, dlist_init(), elog, MemoizeState::entry, ERROR, 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, MemoizeState::hashtable, 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 1189 of file nodeMemoize.c.

1191{
1192 Size size;
1193
1194 /* don't need this if not instrumenting or no workers */
1195 if (!node->ss.ps.instrument || pcxt->nworkers == 0)
1196 return;
1197
1198 size = mul_size(pcxt->nworkers, sizeof(MemoizeInstrumentation));
1199 size = add_size(size, offsetof(SharedMemoizeInfo, sinstrument));
size_t Size
Definition: c.h:559
#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:488
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
static pg_noinline void Size size
Definition: slab.c:607
shm_toc_estimator estimator
Definition: parallel.h:41
Instrumentation * instrument
Definition: execnodes.h:1135

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

Referenced by ExecParallelEstimate().

◆ ExecMemoizeInitializeDSM()

void ExecMemoizeInitializeDSM ( MemoizeState node,
ParallelContext pcxt 
)

Definition at line 1210 of file nodeMemoize.c.

1212{
1213 Size size;
1214
1215 /* don't need this if not instrumenting or no workers */
1216 if (!node->ss.ps.instrument || pcxt->nworkers == 0)
1217 return;
1218
1219 size = offsetof(SharedMemoizeInfo, sinstrument)
1220 + pcxt->nworkers * sizeof(MemoizeInstrumentation);
1221 node->shared_info = shm_toc_allocate(pcxt->toc, size);
1222 /* ensure any unfilled slots will contain zeroes */
1223 memset(node->shared_info, 0, size);
1224 node->shared_info->num_workers = pcxt->nworkers;
1225 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
1226 node->shared_info);
struct MemoizeInstrumentation MemoizeInstrumentation
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Definition: shm_toc.c:88
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
Definition: shm_toc.c:171
shm_toc * toc
Definition: parallel.h:44
int plan_node_id
Definition: plannodes.h:152

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(), size, MemoizeState::ss, and ParallelContext::toc.

Referenced by ExecParallelInitializeDSM().

◆ ExecMemoizeInitializeWorker()

void ExecMemoizeInitializeWorker ( MemoizeState node,
ParallelWorkerContext pwcxt 
)

Definition at line 1235 of file nodeMemoize.c.

1237{
1238 node->shared_info =
1239 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 1248 of file nodeMemoize.c.

1250{
1251 Size size;
1253
1254 if (node->shared_info == NULL)
1255 return;
1256
1257 size = offsetof(SharedMemoizeInfo, sinstrument)
1259 si = palloc(size);
1260 memcpy(si, node->shared_info, size);
1261 node->shared_info = si;

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

Referenced by ExecParallelRetrieveInstrumentation().

◆ ExecReScanMemoize()

void ExecReScanMemoize ( MemoizeState node)

Definition at line 1139 of file nodeMemoize.c.

1141{
1143
1144 /* Mark that we must lookup the cache for a new set of parameters */
1145 node->mstatus = MEMO_CACHE_LOOKUP;
1146
1147 /* nullify pointers used for the last scan */
1148 node->entry = NULL;
1149 node->last_tuple = NULL;
1150
1151 /*
1152 * if chgParam of subnode is not null then plan will be re-scanned by
1153 * first ExecProcNode.
1154 */
1155 if (outerPlan->chgParam == NULL)
1157
1158 /*
1159 * Purge the entire cache if a parameter changed that is not part of the
1160 * cache key.
1161 */
1162 if (bms_nonempty_difference(outerPlan->chgParam, node->keyparamids))
1163 cache_purge_all(node);
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:641
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
static void cache_purge_all(MemoizeState *mstate)
Definition: nodeMemoize.c:401

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