Manifest Entry Cache#
Overview#
Large tables may contain many manifest entries, while a scan may only need a small subset after bucket, partition, and statistics pruning. The snapshot live manifest entry cache reduces repeated manifest decoding cost for successive full scans that target the same bucket.
The cache stores decoded and merged live manifest entries by table path, branch,
and bucket for ScanMode::ALL. Each cache value can retain several snapshot
results for that bucket. Exact snapshot hits are served from the cache; cache
misses rebuild the target snapshot bucket from the target snapshot’s data
manifests and store the rebuilt live entries.
Request-specific filters are not stored in the cache. Partition, level, and predicate filters are still evaluated for each scan, so cached entries can be reused safely across different scan predicates for the same bucket.
Configuration#
Manifest entry caching reuses the cache instance provided by
ScanContextBuilder::WithCache() and stores bucket-scoped snapshot entries
under
CacheKind::SNAPSHOT_LIVE_MANIFEST:
auto cache = std::make_shared<LruCache>(128 * 1024 * 1024);
ScanContextBuilder context_builder(table_path);
PAIMON_ASSIGN_OR_RAISE(
std::unique_ptr<ScanContext> scan_context,
context_builder
.WithCache(cache)
.AddOption(Options::SCAN_MANIFEST_ENTRY_CACHE_MAX_SNAPSHOTS, "3")
.Finish());
Cache entries are scoped by table path, branch, and bucket, so they can be
reused across newly created TableScan and FileStoreScan instances as
long as they share the same cache object and scan the same bucket.
Options::SCAN_MANIFEST_ENTRY_CACHE_MAX_SNAPSHOTS controls how many snapshot
results are retained in each table/branch/bucket cache value. Older snapshots in
the same bucket are evicted first. The default value is 0, which disables
the cache path. Set it to a positive value to enable the cache when
ScanContextBuilder::WithCache() is also configured. Physical cache eviction
is still controlled by the configured Cache implementation, for example the
capacity of LruCache.
If no cache is provided through ScanContextBuilder::WithCache(), this
optimization is skipped. The snapshot manifest entry cache shares the same
Cache interface with raw manifest and data-file footer caches, but it uses a
dedicated CacheKind and a table/branch/bucket key instead of file byte
ranges.
Limitations#
The cache is currently used only for ScanMode::ALL scans that can determine
a single target bucket. It is skipped for scans without a bucket filter because
reading or deserializing all buckets would be too expensive for selective
queries. It is also skipped for row-range scans because row-range pruning is
applied at manifest-meta level.
Metrics#
The scan metrics expose existing counters for the last scan:
lastScannedManifests: how many manifest files were loaded during this scan before manifest entry decoding.