-
Type:
Improvement
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
Query Execution
-
200
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Overview
AddFieldsProjectionExecutor built its output MutableDocument from the input, which shares storage and raises the refcount to two. Since $addFields always writes at least one field, that guaranteed a copy-on-write clone of the entire field cache for every document: an allocation, a memcpy, a walk over every element to fix up refcounts, and a further allocation to copy the metadata holder.
Scope of Work
* transformer_interface.h, projection_executor.h and implementors — take the document by mutable reference and transform in place rather than returning a new one
* {{projection_node.
}} — add applyExpressionsInPlace(), which evaluates every expression against the unmodified document before writing any result, removing the need for a separate snapshot
* add_fields_projection_executor.cpp — use the in-place path when applicable
Notes
Nested projections keep the previous path: applyExpressions reads the output as it recurses, and array elements re-evaluate expressions per element, so hoisting the evaluations would change results for non-deterministic expressions and alter memory tracker accounting. Projections with a root-replacement expression are excluded too, since that expression reads the untransformed input after applyProjection returns.
On the profiled workload this removed DocumentStorage::clone (1.07% of cycles) and MutableDocument::clonedStorage (0.73%) from the profile entirely, plus the allocator and metadata-holder traffic behind them.
Acceptance Criteria
* No change in query results for $addFields, $set, $project, $replaceRoot or metadata propagation
* Coverage for self-referencing expressions, e.g. {$addFields: {a: {$mod: ["$a", 3]}, c: "$a"}}, where c must observe the original a