Skip to content

Expose callback reads and row-position projections in C FFI - #9965

Draft
mprammer wants to merge 2 commits into
vortex-data:developfrom
mprammer:mp/ffi-reader-at-expressions
Draft

mprammer wants to merge 2 commits into
vortex-data:developfrom
mprammer:mp/ffi-reader-at-expressions

Conversation

@mprammer

Copy link
Copy Markdown
Contributor

Lets a host serve file bytes through its own I/O stack instead of reading the whole file into memory, so a scan fetches only the segments it needs. The C form of dev.vortex.io.NativeReadable.

Changes

vx_readat carries the host's read_at and release callbacks, the source length and an optional name. Reads run on the blocking pool under CoalesceConfig::object_storage(), matching JavaReadable. Ownership is worth a close read: a rejected descriptor never calls release and leaves the context with the caller; an accepted one calls release even if opening the file then fails. concurrency caps reads per source, not across open files, so opening many files multiplies it — no equivalent of the JNI shared limiter yet.

row_idx and pack come with it because the reader alone doesn't get Iceberg onto Vortex: positional deletes and row lineage are defined on physical row positions, which must be projected alongside the data to survive predicate pushdown. pack assembles a projection rather than trimming one, which is also how nested struct fields get pruned.

Tests read a file served entirely through the callbacks, cover both release paths and a failing callback, and check that row_idx under a pushed-down filter returns surviving rows at their original positions.

API Changes

Added:

  • vx_data_source_new_readat(session, reader, err) — data source over caller-supplied read callbacks.
  • vx_expression_row_idx() — row position within the scanned file; only valid inside a scan.
  • vx_expression_pack(names, expressions, len, nullable) — struct-valued expression from named children.

🤖 Generated with Claude Code

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Martin Prammer <martin@spiraldb.com>
@mprammer mprammer added the changelog/feature A new feature label Sep 21, 2026
@codspeed

codspeed Bot commented Sep 21, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 6.02%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 2 improved benchmarks
❌ 6 regressed benchmarks
✅ 2200 untouched benchmarks
⏩ 293 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation decode_primitives[f32, (1000, 512)] 42 µs 59.6 µs -29.52%
WallTime dbp_assemble_kernel_avx512[(I128, 1024)] 463 ns 550 ns -15.82%
WallTime dbp_assemble_kernel_avx2[(I128, 1024)] 464 ns 535 ns -13.27%
Simulation take_fsl_u32_random[128, 100] 208.3 µs 237.2 µs -12.18%
WallTime dbp_assemble_kernel_narrow_msp_avx2[(I128, 1024)] 629 ns 708 ns -11.16%
Simulation take_fsl_f16_random[256, 100] 204.9 µs 230.5 µs -11.11%
Simulation take_fsl_f16_random[16, 100] 179.5 µs 119.4 µs +50.28%
Simulation take_fsl_nullable_random[16, 100] 188 µs 165.7 µs +13.43%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing mprammer:mp/ffi-reader-at-expressions (be7f8d7) with develop (a542cbd)

Open in CodSpeed

Footnotes

  1. 293 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.

@robert3005

Copy link
Copy Markdown
Contributor

@claude review

@github-actions

Copy link
Copy Markdown
Contributor

Claude review automation is disabled for fork pull requests.

Why:

  • fork content is untrusted input
  • this repository does not allow Claude to run against fork content
  • there is no promotion path for forks

If maintainers want Claude to implement a change, restate the task on an issue and use the issue-driven Claude workflow instead.

Addresses review feedback on the C FFI callback reader.

The read callback now returns the number of bytes written rather than a
status code, so a host that reports success without filling the buffer is
rejected instead of handing uninitialized memory to the scan. The Java
bindings already guard this via `remaining()`; the previous C signature made
it undetectable.

A source was owned by the segment source's spawned read driver, which the
FFI's current-thread runtime never polled again once a call returned, so
`release` ran at an unpredictable later point or not at all. Hosts freeing
their context after `vx_data_source_free` could therefore hit a
use-after-free. `CurrentThreadRuntime::drain` runs queued tasks to a stop,
and the FFI drains after dropping a data source and after a failed open, so
`release` now runs before the call that drops the source returns.

Callback concurrency is additionally capped process-wide rather than only
per source, matching how the Java bindings bound upcalls across a
filesystem, and a name view of NULL with a non-zero length is rejected
rather than silently treated as anonymous.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Martin Prammer <martin@spiraldb.com>
Comment thread vortex-ffi/src/read_at.rs
pub name: vx_view,
/// Required. Writes "length" bytes at "offset" into "dst" and returns the
/// count written; a short count or a negative value fails the read.
pub read_at: Option<

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this an option?

@mprammer
mprammer requested a review from 0ax1 September 21, 2026 20:41

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants