This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-3406-78f1762aca16cc4745bc913d6e782416b5705299 in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
commit da5cc19a9f7c9e8ea14dc40d4a82974cd26def42 Author: NoahKusaba <[email protected]> AuthorDate: Tue Oct 20 03:46:45 2026 +0000 feat(table): add Table::with_runtime that keeps the manifest cache (#3406) * feat(table): add Table::with_runtime that keeps the manifest cache A table gets its runtime only when it is built, and rebuilding it through Table::builder() starts with an empty ObjectCache. An engine that caches a Table and wants its scans to run on the runtime executing the query has no way to switch runtimes without losing the cached manifests and manifest lists. * docs(table): tighten Table::with_runtime docs Co-authored-by: Copilot App <[email protected]> --------- Co-authored-by: Kevin Liu <[email protected]> Co-authored-by: Copilot App <[email protected]> --- crates/iceberg/public-api.txt | 1 + crates/iceberg/src/table.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/crates/iceberg/public-api.txt b/crates/iceberg/public-api.txt index b86e48c77..9d65474ad 100644 --- a/crates/iceberg/public-api.txt +++ b/crates/iceberg/public-api.txt @@ -3404,6 +3404,7 @@ pub fn iceberg::table::Table::metadata_ref(&self) -> iceberg::spec::TableMetadat pub fn iceberg::table::Table::reader_builder(&self) -> iceberg::arrow::ArrowReaderBuilder pub fn iceberg::table::Table::readonly(&self) -> bool pub fn iceberg::table::Table::scan(&self) -> iceberg::scan::TableScanBuilder<'_> +pub fn iceberg::table::Table::with_runtime(self, runtime: iceberg::Runtime) -> Self impl core::clone::Clone for iceberg::table::Table pub fn iceberg::table::Table::clone(&self) -> iceberg::table::Table impl core::fmt::Debug for iceberg::table::Table diff --git a/crates/iceberg/src/table.rs b/crates/iceberg/src/table.rs index 78c2dff05..f33c246eb 100644 --- a/crates/iceberg/src/table.rs +++ b/crates/iceberg/src/table.rs @@ -219,6 +219,15 @@ impl Table { self } + /// Returns this table bound to `runtime`, sharing its manifest cache. + /// + /// Tasks such as scan planning and reads are spawned on `runtime`. A table rebuilt + /// through [`Table::builder`] starts with an empty cache. + pub fn with_runtime(mut self, runtime: Runtime) -> Self { + self.runtime = runtime; + self + } + /// Returns a TableBuilder to build a table pub fn builder() -> TableBuilder { TableBuilder::new() @@ -497,6 +506,31 @@ mod tests { assert_eq!(table.identifier.name(), "table"); } + #[tokio::test] + async fn test_table_with_runtime_moves_work_and_keeps_object_cache() { + let old = tokio::runtime::Builder::new_current_thread() + .build() + .unwrap(); + let table = Table::builder() + .metadata(load_test_metadata("TableMetadataV2Valid.json")) + .identifier(TableIdent::from_strs(["ns", "table"]).unwrap()) + .file_io(FileIO::new_with_memory()) + .runtime(Runtime::new(&old)) + .build() + .unwrap(); + // With the old runtime shut down, the spawn below succeeds only if + // `rebound` uses the new one. + old.shutdown_background(); + + let rebound = table.clone().with_runtime(Runtime::try_current().unwrap()); + + assert!(Arc::ptr_eq(&table.object_cache(), &rebound.object_cache())); + assert_eq!( + rebound.runtime().io().spawn(async { 42 }).await.unwrap(), + 42 + ); + } + fn make_kms() -> Arc<dyn KeyManagementClient> { let kms = MemoryKeyManagementClient::new(); kms.add_master_key("master-1").unwrap();
