Make ScalarFn array validity lazy when the function defines a validity expression#8336
Make ScalarFn array validity lazy when the function defines a validity expression#8336joseph-isaacs wants to merge 1 commit into
Conversation
Merging this PR will not alter performance
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
|
Investigated the CodSpeed
The same flavor of noise shows in the rest of the stack: the I can't acknowledge regressions on the CodSpeed dashboard from this session — that needs someone with dashboard access. https://claude.ai/code/session_01VPQ7dfZtijfrsjAipwXvEj Generated by Claude Code |
| /// Transforms the expression into one representing the validity of this expression. | ||
| pub fn validity(&self, expr: &Expression) -> VortexResult<Expression> { | ||
| Ok(self.0.validity(expr)?.unwrap_or_else(|| { | ||
| Ok(self.validity_opt(expr)?.unwrap_or_else(|| { |
There was a problem hiding this comment.
do you want to remove the TODO?
d72800b to
f4e8d62
Compare
5d2c247 to
e515a28
Compare
9673272 to
e9341da
Compare
e507aa3 to
2d2498f
Compare
e9341da to
587baf9
Compare
2d2498f to
a13f0ab
Compare
6fe8231 to
f9b0a16
Compare
|
This PR has been marked as stale because it has been open for 14 days with no activity. Please comment or remove the stale label if you wish to keep it active, otherwise it will be closed in 7 days |
|
This PR was closed because it has been inactive for 7 days since being marked as stale. |
…y expression Previously ValidityVTable<ScalarFn> always eagerly executed the validity expression via the legacy session. Now, when the scalar function provides a validity expression over its inputs, the expression is converted into a lazy ScalarFn array DAG instead: Literal nodes become ConstantArrays, ArrayExpr leaves unwrap to the child arrays they hold, and interior nodes become lazy ScalarFn arrays. Constant results are folded back into AllValid/AllInvalid via child_to_validity. Functions that do not define a validity expression (e.g. Kleene logic and/or, where validity depends on the computed values) keep the eager path. The erased fallback for these is is_not_null over the expression itself, so a lazy representation would be self-referential: resolving the validity of the inner node spawns another is_not_null DAG, which recurses without ever shrinking (this manifested as a stack overflow in element-wise execution paths). ScalarFnRef::validity_opt is added to expose whether a function defines its own validity expression. https://claude.ai/code/session_01VPQ7dfZtijfrsjAipwXvEj Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
f9b0a16 to
5a83d1d
Compare
Summary
Lazy validity for
ScalarFnarrays. (Originally part of a 4-PR stack; the prerequisites —definitely_no_nulls/execute_no_nullsin #8333, themask_eqsemantics fix in #8334, anddefinitely_all_null— have all since landed ondevelop, so this PR is now a single standalone commit rebased onto current develop.)Previously
ValidityVTable<ScalarFn>always eagerly executed the validity expression via the legacy session. Now, when the scalar function provides a validity expression over its inputs, the expression is converted into a lazy ScalarFn array DAG instead:Literalnodes →ConstantArrayArrayExprleaves → unwrap to the child array they holdScalarFnarrays viaArray::<ScalarFn>::try_new_with_lenAllValid/AllInvalidviachild_to_validityWhy the eager path remains for some functions
Functions that don't define a validity expression (Kleene
and/or, where validity depends on the computed values) keep the eager path. The erased fallback for these isis_not_null(expr)— self-referential: lazily materializing it means resolving the validity of the inner node, which spawns anotheris_not_nullDAG over a fresh copy of the same node, recursing without ever shrinking. This manifested as a stack overflow in element-wise execution paths (execute_scalar→is_invalid→validity()), caught bytest_bool_consistency. The newScalarFnRef::validity_optexposes whether a function defines its own validity expression so the vtable can pick the right path.Checks
cargo nextest run -p vortex-array(3197 passed)cargo nextest run -p vortex-file -p vortex-layout -p vortex-scan -p vortex-btrblocks -p vortex-compressor -p vortex-datafusion -p vortex-fastlanes -p vortex-runend -p vortex-sparse -p vortex-fsst -p vortex-alp -p vortex-zstd -p vortex-pco -p vortex-datetime-parts -p vortex-ipc(1429 passed)cargo clippy -p vortex-array --all-targets,cargo +nightly fmt --checkvortex-cuda,vortex-duckdb, or lance-dependent benches locally (CUDA toolkit / DuckDB source download /protocunavailable in the sandbox) — CI covers them.https://claude.ai/code/session_01VPQ7dfZtijfrsjAipwXvEj