v4-0003-Update-Hash-Aggregation-to-use-memory-pools.patch
text/x-patch
Filename: v4-0003-Update-Hash-Aggregation-to-use-memory-pools.patch
Type: text/x-patch
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v4-0003
Subject: Update Hash Aggregation to use memory pools.
| File | + | − |
|---|---|---|
| src/backend/executor/execUtils.c | 15 | 54 |
| src/backend/executor/nodeAgg.c | 9 | 28 |
| src/include/executor/executor.h | 0 | 1 |
From baf0e7b28111337c6b9f138ddea7c2ef137fd930 Mon Sep 17 00:00:00 2001
From: Jeff Davis <jeff@j-davis.com>
Date: Mon, 4 May 2026 14:29:35 -0700
Subject: [PATCH v4 3/3] Update Hash Aggregation to use memory pools.
This reverts commit 50a38f65177ea7858bc97f71ba0757ba04c1c167, which is
no longer needed.
---
src/backend/executor/execUtils.c | 69 +++++++-------------------------
src/backend/executor/nodeAgg.c | 37 +++++------------
src/include/executor/executor.h | 1 -
3 files changed, 24 insertions(+), 83 deletions(-)
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 1eb6b9f1f40..4b8d1c900b3 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -234,13 +234,21 @@ FreeExecutorState(EState *estate)
MemoryContextDelete(estate->es_query_cxt);
}
-/*
- * Internal implementation for CreateExprContext() and CreateWorkExprContext()
- * that allows control over the AllocSet parameters.
+/* ----------------
+ * CreateExprContext
+ *
+ * Create a context for expression evaluation within an EState.
+ *
+ * An executor run may require multiple ExprContexts (we usually make one
+ * for each Plan node, and a separate one for per-output-tuple processing
+ * such as constraint checking). Each ExprContext has its own "per-tuple"
+ * memory context.
+ *
+ * Note we make no assumption about the caller's memory context.
+ * ----------------
*/
-static ExprContext *
-CreateExprContextInternal(EState *estate, Size minContextSize,
- Size initBlockSize, Size maxBlockSize)
+ExprContext *
+CreateExprContext(EState *estate)
{
ExprContext *econtext;
MemoryContext oldcontext;
@@ -263,9 +271,7 @@ CreateExprContextInternal(EState *estate, Size minContextSize,
econtext->ecxt_per_tuple_memory =
AllocSetContextCreate(estate->es_query_cxt,
"ExprContext",
- minContextSize,
- initBlockSize,
- maxBlockSize);
+ ALLOCSET_DEFAULT_SIZES);
econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
econtext->ecxt_param_list_info = estate->es_param_list_info;
@@ -295,51 +301,6 @@ CreateExprContextInternal(EState *estate, Size minContextSize,
return econtext;
}
-/* ----------------
- * CreateExprContext
- *
- * Create a context for expression evaluation within an EState.
- *
- * An executor run may require multiple ExprContexts (we usually make one
- * for each Plan node, and a separate one for per-output-tuple processing
- * such as constraint checking). Each ExprContext has its own "per-tuple"
- * memory context.
- *
- * Note we make no assumption about the caller's memory context.
- * ----------------
- */
-ExprContext *
-CreateExprContext(EState *estate)
-{
- return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_SIZES);
-}
-
-
-/* ----------------
- * CreateWorkExprContext
- *
- * Like CreateExprContext, but specifies the AllocSet sizes to be reasonable
- * in proportion to work_mem. If the maximum block allocation size is too
- * large, it's easy to skip right past work_mem with a single allocation.
- * ----------------
- */
-ExprContext *
-CreateWorkExprContext(EState *estate)
-{
- Size maxBlockSize;
-
- maxBlockSize = pg_prevpower2_size_t(work_mem * (Size) 1024 / 16);
-
- /* But no bigger than ALLOCSET_DEFAULT_MAXSIZE */
- maxBlockSize = Min(maxBlockSize, ALLOCSET_DEFAULT_MAXSIZE);
-
- /* and no smaller than ALLOCSET_DEFAULT_INITSIZE */
- maxBlockSize = Max(maxBlockSize, ALLOCSET_DEFAULT_INITSIZE);
-
- return CreateExprContextInternal(estate, ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE, maxBlockSize);
-}
-
/* ----------------
* CreateStandaloneExprContext
*
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 925caadd2ce..01334d6012e 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1866,12 +1866,9 @@ static void
hash_agg_check_limits(AggState *aggstate)
{
uint64 ngroups = aggstate->hash_ngroups_current;
- Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt,
- true);
- Size entry_mem = MemoryContextMemAllocated(aggstate->hash_tuplescxt,
- true);
- Size tval_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory,
- true);
+ Size meta_mem = MemoryContextGetPool(aggstate->hash_metacxt)->allocated;
+ Size entry_mem = MemoryContextGetPool(aggstate->hash_tuplescxt)->allocated;
+ Size tval_mem = MemoryContextGetPool(aggstate->hashcontext->ecxt_per_tuple_memory)->allocated;
Size total_mem = meta_mem + entry_mem + tval_mem;
bool do_spill = false;
@@ -1998,13 +1995,13 @@ hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
static void
hash_create_memory(AggState *aggstate)
{
- Size maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE;
-
/*
* The hashcontext's per-tuple memory will be used for byref transition
* values and returned by AggCheckCallContext().
*/
- aggstate->hashcontext = CreateWorkExprContext(aggstate->ss.ps.state);
+ aggstate->hashcontext = CreateExprContext(aggstate->ss.ps.state);
+ MemoryContextCreatePool(aggstate->hashcontext->ecxt_per_tuple_memory,
+ work_mem * (Size) 1024);
/*
* The meta context will be used for the bucket array of
@@ -2017,6 +2014,7 @@ hash_create_memory(AggState *aggstate)
aggstate->hash_metacxt = AllocSetContextCreate(aggstate->ss.ps.state->es_query_cxt,
"HashAgg meta context",
ALLOCSET_DEFAULT_SIZES);
+ MemoryContextCreatePool(aggstate->hash_metacxt, work_mem * (Size) 1024);
/*
* The hash entries themselves, which include the grouping key
@@ -2025,29 +2023,12 @@ hash_create_memory(AggState *aggstate)
* entire hash table is reset. The bump allocator is faster for
* allocations and avoids wasting space on the chunk header or
* power-of-two allocations.
- *
- * Like CreateWorkExprContext(), use smaller sizings for smaller work_mem,
- * to avoid large jumps in memory usage.
- */
-
- /*
- * Like CreateWorkExprContext(), use smaller sizings for smaller work_mem,
- * to avoid large jumps in memory usage.
*/
- maxBlockSize = pg_prevpower2_size_t(work_mem * (Size) 1024 / 16);
-
- /* But no bigger than ALLOCSET_DEFAULT_MAXSIZE */
- maxBlockSize = Min(maxBlockSize, ALLOCSET_DEFAULT_MAXSIZE);
-
- /* and no smaller than ALLOCSET_DEFAULT_INITSIZE */
- maxBlockSize = Max(maxBlockSize, ALLOCSET_DEFAULT_INITSIZE);
aggstate->hash_tuplescxt = BumpContextCreate(aggstate->ss.ps.state->es_query_cxt,
"HashAgg hashed tuples",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- maxBlockSize);
-
+ ALLOCSET_DEFAULT_SIZES);
+ MemoryContextCreatePool(aggstate->hash_tuplescxt, work_mem * (Size) 1024);
}
/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 33bbdbfeffb..1e72fbef6f9 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -653,7 +653,6 @@ extern void end_tup_output(TupOutputState *tstate);
extern EState *CreateExecutorState(void);
extern void FreeExecutorState(EState *estate);
extern ExprContext *CreateExprContext(EState *estate);
-extern ExprContext *CreateWorkExprContext(EState *estate);
extern ExprContext *CreateStandaloneExprContext(void);
extern void FreeExprContext(ExprContext *econtext, bool isCommit);
extern void ReScanExprContext(ExprContext *econtext);
--
2.43.0