Skip to content

Export decimal Widen arrays to Arrow with one copy - #10994

Merged
connortsui20 merged 3 commits into
developfrom
ct/widen-arrow-export
Nov 3, 2026
Merged

connortsui20 merged 3 commits into
developfrom
ct/widen-arrow-export

Conversation

@connortsui20

@connortsui20 connortsui20 commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Tracking Issue: #10701

Summary

Executing a narrow decimal Widen to its canonical width before Arrow export can copy the values twice. Exporting its child directly avoids the intermediate copy while preserving the logical precision and scale, including in nested arrays.

Changes

Decimal export converts the child's buffer directly to the requested Arrow width. Narrowing skips null payloads, which can contain values too large for that width, and still rejects valid values that do not fit. Tests cover decimal widths, logical precision, nulls, slicing, and nested exports.

API Changes

No public API changes. Decimal export no longer fails solely because a null payload does not fit the Arrow width.

Validation: reviewed the source and confirmed the rebase preserves the Arrow export files. The commit hook ran Rust and TOML formatting checks successfully during the history rewrite. Tests, Clippy, and benchmarks were not run.

@connortsui20 connortsui20 added the changelog/performance A performance improvement label Oct 29, 2026
@connortsui20 connortsui20 changed the title ct/widen arrow export Export decimal Widen arrays to Arrow with one copy Oct 29, 2026
@codspeed

codspeed Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning

⚠️ Walltime results may be unreliable

Some benchmarks used the Walltime instrument outside CodSpeed Macro Runners, which can make the results inconsistent.

Learn more about Macro Runners

See affected benchmarks

✅ 1882 untouched benchmarks
⏩ 469 skipped benchmarks1


Comparing ct/widen-arrow-export (a61ffff) with develop (e59b236)

Open in CodSpeed

Footnotes

  1. 469 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch from 49a4f52 to cab830d Compare October 29, 2026 20:23
@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch from cab830d to dacf961 Compare October 29, 2026 21:33
@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch 2 times, most recently from ce4782e to 6ec069f Compare October 30, 2026 19:28
@connortsui20
connortsui20 force-pushed the ct/decimal-widen branch 3 times, most recently from 06d9f6e to fe95c5d Compare November 2, 2026 16:57
@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch 4 times, most recently from 7f9cd3f to 1f46b5b Compare November 2, 2026 19:52
@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch 2 times, most recently from 773f70c to b63d378 Compare November 2, 2026 21:29
@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch 2 times, most recently from df07a71 to ff9883a Compare November 3, 2026 13:36
Base automatically changed from ct/decimal-widen to develop November 3, 2026 14:22
connortsui20 added a commit that referenced this pull request Nov 3, 2026
Tracking Issue: #10701

Based on `develop`, including the writer work previously in #11002.
#11003 and #10994 build on it. No release gate.

## Summary

Canonical decimal width follows precision, so small values under
`Decimal(38, 2)` still occupy 16 bytes each. A decimal `Widen` keeps
those values in a lower-precision child while retaining the column's
logical dtype.

## Changes

The child precision must hold every valid value and have a narrower
canonical width. Execution restores the logical width. Until the later
kernels land, operations use that canonical fallback.

Serialization writes a concrete decimal leaf through the existing
`vortex.decimal` wire form without executing values or validity. Integer
`Widen` arrays, non-decimal leaves, and nonserializable validity require
explicit preparation by the caller. Its metadata stores the width, while
the containing format supplies the parent precision. This keeps an `i32`
child at four bytes per value, including IPC and writes without a
compressor. A serialized-byte regression test checks that size
independently of the eventual read encoding.

<details>
<summary>Historical local benchmark results</summary>

These retained measurements predate this style pass and rebase. They do
not measure the current head.

`cargo bench -p vortex-array --bench widen_decimal`, Apple M4, medians.
The numbers were measured at the top of this stack before the split, so
they cover the whole stack, not this layer alone. The baseline is the
canonical input, and the candidate is the same values as a `Widen`
(child precision 5 under precision 10, 9 under 18, and 18 under 38).
CodSpeed on this PR measures the layer itself.

| bench | p10 canonical | p10 Widen | p18 canonical | p18 Widen | p38
canonical | p38 Widen |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| `filter` | 22.16 µs | 5.083 µs | 13.66 µs | 4.916 µs | 10.58 µs |
24.74 µs |
| `execute` | 10.59 ns | 2.832 µs | 10.26 ns | 2.926 µs | 10.34 ns |
9.895 µs |

`execute` on a `Widen` is the widening copy, which the canonical input
does not need. The canonical `filter` medians at p10 and p18 were
bimodal across runs, and `filter` at p38 is slower on the `Widen`.

</details>

## API Changes

`WidenArray::try_new` accepts decimal children. Adds
`WidenArray::encode_decimal` and registers a writer-only `WidenPlugin`,
whose only write ID is `vortex.decimal`.

## Validation

Source review and rebase range-diffs only. No local tests, builds,
linting, or documentation checks were run. A commit hook flagged one
formatting wrap, corrected manually without rerunning the check.

---------

Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20
connortsui20 marked this pull request as ready for review November 3, 2026 14:41
Export the narrower decimal child directly with the logical precision and
scale, avoiding the intermediate canonical-width copy. Skip null payloads
when narrowing while still rejecting valid values outside the Arrow width.

Keep decimal export coverage in a separate test module.

Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20
connortsui20 force-pushed the ct/widen-arrow-export branch from ff9883a to e225462 Compare November 3, 2026 18:36
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20
connortsui20 merged commit ff7f582 into develop Nov 3, 2026
73 checks passed
@connortsui20
connortsui20 deleted the ct/widen-arrow-export branch November 3, 2026 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/performance A performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants