Skip to content

feat: add cross-query metadata and snapshot caching - #875

Open
manuzhang wants to merge 5 commits into
apache:mainfrom
manuzhang:agent/add-metadata-snapshot-cache
Open

feat: add cross-query metadata and snapshot caching#875
manuzhang wants to merge 5 commits into
apache:mainfrom
manuzhang:agent/add-metadata-snapshot-cache

Conversation

@manuzhang

@manuzhangmanuzhang commented Aug 6, 2026

Copy link
Copy Markdown
Member

Summary

  • add a shared, bounded FileIO content cache for metadata JSON, manifest lists, and manifests
  • persist parsed manifest-list entries on snapshots for reuse across scans
  • wire Java-compatible cache properties through registry, SQL, and in-memory catalogs
  • add cache behavior and concurrency regression coverage

Why

Repeated table loads and scans currently reread immutable Iceberg metadata files and reparse snapshot manifest lists. This adds cross-query reuse while preserving normal data-file I/O paths.

Co-authored-by: Codex <codex@openai.com>
@manuzhang
manuzhang marked this pull request as ready for review August 6, 2026 09:48
CopilotAI lite review requested due to automatic review settings August 6, 2026 09:48

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces cross-query reuse for immutable Iceberg metadata I/O by adding a bounded metadata-content cache in FileIO and persisting parsed snapshot manifest-list entries on Snapshot instances to avoid repeated parsing across scans.

Changes:

  • Add MetadataCache + MetadataCacheOptions and integrate it into FileIO via ReadFileCached() / NewCachedInputFile(), with Java-compatible property names and defaults.
  • Persist snapshot manifest parsing results via a Snapshot-owned shared cache state and return std::span<const ManifestFile> from SnapshotCache.
  • Wire cache enablement through catalogs/registry and add unit tests + build system registration.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
src/iceberg/update/expire_snapshots.ccAdjust manifest collection to work with the new span<const ManifestFile> cache surface.
src/iceberg/test/metadata_cache_test.ccAdds coverage for cache reuse, eviction, invalidation, and concurrency behavior.
src/iceberg/test/meson.buildRegisters the new metadata cache test with Meson.
src/iceberg/test/CMakeLists.txtRegisters the new metadata cache test with CMake.
src/iceberg/table_metadata.ccSwitches metadata JSON reads to go through the cached read path.
src/iceberg/snapshot.hAdds snapshot-shared cache state and tightens manifest spans to const.
src/iceberg/snapshot.ccImplements snapshot-shared manifest-list parsing/cache coalescing.
src/iceberg/metadata_cache.hIntroduces the public cache/options API and property contract.
src/iceberg/metadata_cache.ccImplements the bounded, expiring, coalescing metadata cache.
src/iceberg/meson.buildAdds metadata_cache.cc and installs metadata_cache.h.
src/iceberg/manifest/manifest_reader.ccEnables metadata-content caching for manifests and manifest lists via reader options.
src/iceberg/file_reader.hAdds ReaderOptions::cache_content to control metadata caching.
src/iceberg/file_io.hAdds cache configuration and cached read/input APIs to FileIO.
src/iceberg/file_io.ccImplements cached reads, cached input wrapping, and cache configuration plumbing.
src/iceberg/file_io_registry.ccConfigures metadata caching during registry-based FileIO creation.
src/iceberg/CMakeLists.txtAdds metadata_cache.cc to the build.
src/iceberg/catalog/sql/sql_catalog.ccWires cache configuration through SQL catalog properties when enabled.
src/iceberg/catalog/memory/in_memory_catalog.ccWires cache configuration through in-memory catalog properties when enabled.
src/iceberg/avro/avro_reader.ccPasses caching intent down to Arrow input opening.
src/iceberg/arrow/arrow_io.ccAdds an opt-in cached-input path when cache is enabled + requested.
src/iceberg/arrow/arrow_io_internal.hExtends Arrow input open helper signature to accept cache intent.

Comment on lines +62 to +65
ICEBERG_ASSIGN_OR_RAISE(auto io, factory(properties));
ICEBERG_PRECHECK(io != nullptr, "FileIO factory returned null for {}", name);
ICEBERG_RETURN_UNEXPECTED(io->ConfigureMetadataCache(properties));
return io;
Comment on lines +47 to +56
template <typename T>
Result<T> ParseNumberProperty(
const std::unordered_map<std::string, std::string>& properties, std::string_view key,
T default_value) {
auto it = properties.find(std::string(key));
if (it == properties.end()) {
return default_value;
}
return StringUtils::ParseNumber<T>(it->second);
}
Co-authored-by: Codex <codex@openai.com>
CopilotAI review requested due to automatic review settings August 6, 2026 11:20

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/iceberg/file_reader.h:104

  • ReaderOptions now exposes cache_content, but not all reader implementations appear to honor it. For example, parquet_reader.cc still calls arrow::OpenArrowInputStream(options.io, options.path, options.length) without passing options.cache_content, so enabling cache_content would have no effect for Parquet reads. If the intent is that this flag controls whether the underlying FileIO uses NewCachedInputFile, it should be forwarded consistently by readers that open Arrow input streams.
 /// \brief FileIO instance to open the file.
std::shared_ptr<class FileIO> io;
/// \brief Cache this immutable metadata file's content when FileIO caching is enabled.
bool cache_content = false;
/// \brief The projection schema to read from the file. This field is required.
std::shared_ptr<class Schema> projection;

Co-authored-by: Codex <codex@openai.com>
CopilotAI review requested due to automatic review settings August 6, 2026 11:31

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/iceberg/metadata_cache.cc:168

  • MetadataCacheOptions::expiration_interval_ms is only validated for non-negativity. Extremely large values can overflow/behave unexpectedly when converted to std::chrono::milliseconds in IsExpired(), leading to incorrect eviction behavior. Consider rejecting values larger than std::chrono::milliseconds::max().count().
 ICEBERG_PRECHECK(options.expiration_interval_ms >= 0,
"Metadata cache expiration interval must not be negative: {}",
options.expiration_interval_ms);

Co-authored-by: Codex <codex@openai.com>
CopilotAI review requested due to automatic review settings August 6, 2026 11:51

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

src/iceberg/snapshot.h:422

  • cache_data is eagerly allocated for every Snapshot instance and the manifest-list parse results appear to be retained for the lifetime of the Snapshot (no bounding/eviction). For tables with many snapshots and large manifest lists, this can cause unbounded memory retention across queries. Consider lazy-initializing the cache state on first use and/or adding a bounded/clearable policy similar to MetadataCache.
 /// Internal lazy state shared by Snapshot copies so manifest lists are parsed once.
mutable std::shared_ptr<internal::SnapshotCacheData> cache_data =
internal::MakeSnapshotCacheData();

Comment threadsrc/iceberg/snapshot.h Outdated
Comment on lines +420 to +422
/// Internal lazy state shared by Snapshot copies so manifest lists are parsed once.
mutable std::shared_ptr<internal::SnapshotCacheData> cache_data =
internal::MakeSnapshotCacheData();
Co-authored-by: Codex <codex@openai.com>
CopilotAI review requested due to automatic review settings August 6, 2026 13:52

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/iceberg/metadata_cache.cc:45

  • ParseBoolean only accepts exact "true"/"false" and rejects common case variants (e.g., "TRUE"), which can break configuration coming from Java-style properties sources. Since this is meant to be Java-compatible, parse booleans case-insensitively.
Result<bool> ParseBoolean(std::string_view key, const std::string& value) {
if (value == "true") {
return true;
}
if (value == "false") {

src/iceberg/file_io.cc:213

  • NewCachedInputFile checks the cache using the caller-provided file_location, but CachedInputFile later uses input_file_->location() as the cache key. If an InputFile implementation normalizes/aliases locations, this inconsistency can cause missed cache hits and duplicate entries; use the InputFile's location consistently.
 if (auto cached = cache->GetIfPresent(file_location)) {
return std::make_unique<CachedInputFile>(std::move(input_file), std::move(cache),
static_cast<int64_t>(cached->size()));
}

src/iceberg/file_io.cc:281

  • ClearMetadataCache currently clears only the byte-content MetadataCache, but it does not reset the per-FileIO SnapshotCacheData (parsed manifest-list entries). That means manifest-list parsing cache can grow without any clear/invalidation path even when callers explicitly clear metadata caches.
void FileIO::ClearMetadataCache() {
auto cache = GetMetadataCache();
if (cache != nullptr) {
cache->Clear();
}

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuzhang