=== Applying patches on top of PostgreSQL commit ID d6d8054dc72d4844f52f1552f8d3074c16987e32 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sun Mar 30 11:09:24 UTC 2025 On branch cf/5562 nothing to commit, working tree clean === using 'git am' to apply patch ./v2-0001-HashAgg-use-Bump-allocator-for-hash-TupleHashTabl.patch === Applying: HashAgg: use Bump allocator for hash TupleHashTable entries. Using index info to reconstruct a base tree... M src/backend/executor/execGrouping.c M src/backend/executor/nodeAgg.c M src/include/nodes/execnodes.h Falling back to patching base and 3-way merge... Auto-merging src/include/nodes/execnodes.h CONFLICT (content): Merge conflict in src/include/nodes/execnodes.h Auto-merging src/backend/executor/nodeAgg.c CONFLICT (content): Merge conflict in src/backend/executor/nodeAgg.c Auto-merging src/backend/executor/execGrouping.c CONFLICT (content): Merge conflict in src/backend/executor/execGrouping.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 HashAgg: use Bump allocator for hash TupleHashTable entries. When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M src/backend/executor/execGrouping.c M src/backend/executor/nodeAgg.c M src/include/nodes/execnodes.h === using patch(1) to apply patch ./v2-0001-HashAgg-use-Bump-allocator-for-hash-TupleHashTabl.patch === patch: unrecognized option `--no-backup-if-mismatch' usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory] [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count] [-r rej-name] [-V t | nil | never | none] [-x number] [-z backup-ext] [--posix] [origfile [patchfile]] patch tablecxt); + + /* + * Copy the first tuple into the table context, and request + * additionalsize extra bytes before the allocation. ++======= + MinimalTuple mtup; + MinimalTuple firstTuple; + size_t totalsize; /* including alignment and additionalsize */ + + /* created new entry */ + *isnew = true; + + /* + * Extract the minimal tuple into the temp context, then copy it + * into the table context. + */ + MemoryContextSwitchTo(hashtable->tempcxt); + mtup = ExecCopySlotMinimalTuple(slot); + + /* + * Allocate space for the MinimalTuple followed by empty space of + * size additionalsize. The caller can get a maxaligned pointer to + * this data with TupleHashEntryGetAdditional(), and store + * arbitrary data there. ++>>>>>>> theirs * - * This avoids the need to store an extra pointer or allocate an - * additional chunk, which would waste memory. + * The caller can get a pointer to the additional data with + * TupleHashEntryGetAdditional(), and store arbitrary data there. + * Placing both the tuple and additional data in the same + * allocation avoids the need to store an extra pointer in + * TupleHashEntryData or allocate an additional chunk. */ ++<<<<<<< ours + entry->firstTuple = ExecCopySlotMinimalTupleExtra(slot, + hashtable->additionalsize); ++======= + totalsize = MAXALIGN(mtup->t_len) + hashtable->additionalsize; + firstTuple = MemoryContextAlloc(hashtable->tablecxt, totalsize); + memcpy(firstTuple, mtup, mtup->t_len); + memset((char *) firstTuple + firstTuple->t_len, 0, + totalsize - firstTuple->t_len); + + entry->firstTuple = firstTuple; ++>>>>>>> theirs } } else diff --cc src/backend/executor/nodeAgg.c index f83fc16c5c8,43a90ed6f7a..00000000000 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@@ -1711,7 -1705,7 +1711,11 @@@ hash_agg_entry_size(int numTrans, Size * Entries use the Bump allocator, so the chunk sizes are the same as the * requested sizes. */ ++<<<<<<< ours + tupleChunkSize = MAXALIGN(tupleSize); ++======= + tupleChunkSize = tupleSize; ++>>>>>>> theirs pergroupChunkSize = pergroupSize; /* @@@ -1719,7 -1713,12 +1723,16 @@@ * power-of-two allocations. */ if (transitionSpace > 0) ++<<<<<<< ours + transitionChunkSize = CHUNKHDRSZ + pg_nextpower2_size_t(transitionSpace); ++======= + { + Size pow2 = (Size)1 << my_log2(transitionSpace); + + /* use Max to protect against overflow */ + transitionChunkSize = Max(CHUNKHDRSZ + pow2, transitionSpace); + } ++>>>>>>> theirs else transitionChunkSize = 0; @@@ -1870,22 -1869,10 +1883,29 @@@ hash_agg_check_limits(AggState *aggstat Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true); Size entry_mem = MemoryContextMemAllocated(aggstate->hash_tablecxt, ++<<<<<<< ours + true); + Size tval_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, + true); + Size total_mem = meta_mem + entry_mem + tval_mem; + bool do_spill = false; + +#ifdef USE_INJECTION_POINTS + if (ngroups >= 1000) + { + if (IS_INJECTION_POINT_ATTACHED("hash-aggregate-spill-1000")) + { + do_spill = true; + INJECTION_POINT_CACHED("hash-aggregate-spill-1000"); + } + } +#endif ++======= + true); + Size tval_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, + true); + Size total_mem = meta_mem + entry_mem + tval_mem; ++>>>>>>> theirs /* * Don't spill unless there's at least one group in the hash table so we @@@ -1999,6 -1982,8 +2019,11 @@@ hash_agg_update_metrics(AggState *aggst static void hash_create_memory(AggState *aggstate) { ++<<<<<<< ours ++======= + Size minContextSize = ALLOCSET_DEFAULT_MINSIZE; + Size initBlockSize = ALLOCSET_DEFAULT_INITSIZE; ++>>>>>>> theirs Size maxBlockSize = ALLOCSET_DEFAULT_MAXSIZE; /* @@@ -2030,23 -2015,15 +2055,35 @@@ * Like CreateWorkExprContext(), use smaller sizings for smaller work_mem, * to avoid large jumps in memory usage. */ ++<<<<<<< ours + + /* + * 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_tablecxt = BumpContextCreate(aggstate->ss.ps.state->es_query_cxt, + "HashAgg table context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, ++======= + while (16 * maxBlockSize > work_mem * 1024L) + maxBlockSize >>= 1; + + if (maxBlockSize < ALLOCSET_DEFAULT_INITSIZE) + maxBlockSize = ALLOCSET_DEFAULT_INITSIZE; + + aggstate->hash_tablecxt = BumpContextCreate(aggstate->ss.ps.state->es_query_cxt, + "HashAgg table context", + minContextSize, initBlockSize, ++>>>>>>> theirs maxBlockSize); } diff --cc src/include/nodes/execnodes.h index 5b6cadb5a6c,fcbdcebbebe..00000000000 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@@ -2567,7 -2527,7 +2567,11 @@@ typedef struct AggStat bool table_filled; /* hash table filled yet? */ int num_hashes; MemoryContext hash_metacxt; /* memory for hash table bucket array */ ++<<<<<<< ours + MemoryContext hash_tablecxt; /* memory for hash table entries */ ++======= + MemoryContext hash_tablecxt; /* memory for hash table entries */ ++>>>>>>> theirs struct LogicalTapeSet *hash_tapeset; /* tape set for hash spill tapes */ struct HashAggSpill *hash_spills; /* HashAggSpill for each grouping set, * exists only during first pass */