Repository navigation
feat(iceberg): scan Iceberg tables in Ballista - #2638
Open
NoahKusaba wants to merge 11 commits into
Open
NoahKusaba wants to merge 11 commits into
NoahKusaba wants to merge 11 commits into
Conversation
NoahKusaba
force-pushed
the
feat/iceberg-standalone-scans
branch
from
October 21, 2026 23:13
dcb2d25 to
8824ff7
Compare
8 tasks
register_iceberg(state) wraps the session's catalogs so that DataFusion's async table lookup, which runs once per table a query names, loads each catalog-backed Iceberg table and returns it at that version. Every scan of a table in one query reads the same version, and the logical codec no longer loads tables, so it no longer blocks the client or needs a multi-threaded runtime.
Flight SQL clients send SQL that the scheduler plans, so they hold no catalog. iceberg_session_builder builds the scheduler's sessions with configured catalogs mounted and readied with register_iceberg, so their tables are pinned while the scheduler plans. register_iceberg now wraps the codecs itself and leaves an already-ready session unchanged, so register_iceberg_codecs is gone. The docs now say a separately deployed scheduler and executors set the Iceberg codecs as their codec overrides, and that a view keeps the version from when it was created.
NoahKusaba
marked this pull request as ready for review
October 27, 2026 18:52
A metadata table such as t$snapshots reached the inner codec, which failed with an internal error suggesting a DataFusion bug. The logical codec now refuses it as not supported on Ballista yet.
iceberg_session_builder now takes the scheduler's existing session builder and wraps it, so a scheduler that sets up its sessions itself (for example to register object stores) keeps that setup. Also explains the dead_code allow on the shared test helpers.
iceberg_session_builder now takes and returns Arc<dyn Fn>, the shape SchedulerConfig stores, so an existing builder passes straight in and the result goes straight to with_override_session_builder. The Flight SQL docs now link to mounting Iceberg catalogs.
SessionStateBuilder::new_from_existing gives a session a new ID, so register_iceberg now keeps the original, as Ballista's own share_file_statistics_cache does. Also makes the SessionBuilder alias private: ballista-scheduler already exports one.
Contributor
Author
|
PR is ready for those interested, as the description says, we will need to wait for new releases for datafusion-iceberg and iceberg-rust crate. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue does this PR close?
Part of #2174: the first step of its integration foundation, Iceberg scans and codec support, for Rust clients and Flight SQL clients. Split out of #2217 as its smallest reviewable piece: reads only, built on merged upstream code. Related: #1241.
Rationale for this change
datafusion-iceberg plans Iceberg scans, but its tables and scans hold live state (a loaded
Tableand itsFileIO), so Ballista can't send them to the scheduler and executors. This PR adds codecs that can.What changes are included in this PR?
A new crate,
ballista-iceberg(integrations/iceberg), with a logical and a physical extension codec. A client readies its session withregister_iceberg(state); a separately deployed scheduler and executors setIcebergLogicalCodecandIcebergPhysicalCodecas their codec overrides. No changes to Ballista core.FileIO. Metadata files are immutable, so every node rebuilds exactly that version without a catalog. Tables sent from the client also carry the metadata the client already loaded, so the scheduler doesn't read the file. Scans sent to executors carry only the location, keeping each task's plan small.IcebergCatalogTableProvider, including the ones a mountedIcebergCatalogProviderserves) are pinned on the client while the query is planned.register_icebergwraps the session's catalogs so that DataFusion's async table lookup, which runs once per table a query names, loads the table and returns it at that version. Every scan of a table in one query, such as both sides of a self-join, reads the same version; each new query reads the latest one; and the scheduler and executors need no catalog configuration. Encoding does no I/O, so the client can run on any tokio runtime.IcebergStaticTableProvider) send the version they hold, for time travel.iceberg_session_builder(base, catalogs)wraps the scheduler's session builder, passed toSchedulerConfig::with_override_session_builder, to mount Iceberg catalogs on its sessions and pins their tables there the same way. This also gives the scheduler the catalogs that scheduler-side commits ([Iceberg] Run a job's final commit step on the scheduler, not an executor #2622) will need.1) or delegated (0), which also versions the payload format. Everything else goes to the codec the session already had, so other Ballista extensions keep working. A driver for another table format, such as Delta, maintained outside this repo, can wrap these codecs the same way, so one query can join tables from both. It only has to be stacked in the same order on every node.Known limitations, also listed in the docs:
INSERT INTOfails with "isn't supported on Ballista yet".DataFrameor Flight SQL prepared statement run twice likewise reads one version. A test pins this down. Follow-up: re-plan views from their SQL on each query, as Spark does.t$snapshots).Dependencies: iceberg-rust and datafusion-iceberg are pinned to git revisions until they release, with iceberg at the revision datafusion-iceberg pins so the build resolves a single iceberg crate. The crate is
publish = falseand needs Rust 1.95; the rest of the workspace still builds on 1.94. Almost all of theCargo.lockdiff (about 90 new packages) is iceberg's own dependency tree, plus opendal for S3 access.Are these changes tested?
Yes:
INSERTinto it is refused;register_iceberg;iceberg_session_builder, and sees a commit made between two queries.testcontainersfeature, which the existinglinux-testjob already enables.All end-to-end tests run on a single-threaded tokio runtime.
Are there any user-facing changes?
Yes, a new crate and a docs page:
docs/source/user-guide/iceberg.md, covering usage, time travel, SQL clients, how it works and the limitations;cargo run -p ballista-iceberg --example standalone-iceberg-scan.No existing APIs change.