Tracking issue of RFC-6297: Cache Layer
- Dominant language
- Rust
- Stars
- 5.4k
- Forks
- 825
- Avg merge
- 1d 14m
- Merged PRs (30d)
- 127
Description
# Summary
Track the implementation work for the general `CacheLayer` design proposed by RFC #6297.
RFC #6297 has been merged. The accepted direction is to keep `CacheLayer` as a thin composition layer over:
- a source `Operator` for the underlying storage,
- a cache `Operator` for cached data,
- a user-provided `CachePolicy` that decides whether to use cache, whether to fill on miss, and how to shape cache entries.
Path-based dispatch is handled by `RouteLayer` instead of `CacheLayer`. Users that need different caching behavior for different paths should build separate operator stacks and combine them with `RouteLayer`.
# Scope
- Add a general `CacheLayer` that accepts an OpenDAL `Operator` as the cache backend.
- Add a public `CachePolicy` surface for read/stat/write/delete decisions.
- Support whole-object caching as the first baseline policy.
- Define cache key namespacing so cache entries cannot collide with user-visible paths in the cache operator.
- Apply best-effort invalidation after successful writes and deletes.
- Respect OpenDAL operation lifecycle semantics; for example, delete invalidation happens after the underlying `Deleter` commits successfully.
- Keep cache backend eviction, TTL, and capacity control owned by the selected cache operator or its own layers.
# Implementation plan
## Phase 1: API skeleton and whole-object cache
- Add `CacheLayer::new(cache: Operator, policy: impl CachePolicy)`.
- Add request and decision types for read/stat/write/delete policy evaluation.
- Implement `WholeCachePolicy` for read-through caching with optional fill-on-miss.
- Add best-effort invalidation for successful write/delete operations.
- Add tests with `Memory` as the cache operator.
## Phase 2: RouteLayer composition examples
- Document how to combine `RouteLayer` with `CacheLayer` for path-specific policies.
- Keep route matching out of `CacheLayer` itself.
- Add examples for different policies such as JSON whole-object caching and Parquet chunked caching.
## Phase 3: Chunked/range-aware caching
- Add `ChunkedCachePolicy` or equivalent range-aware policy support.
- Define range-to-cache-entry mapping and partial-hit behavior.
- Encode version and range information into cache keys where relevant.
- Add tests for aligned and unaligned range reads.
## Phase 4: Metadata cache boundary
- Decide which metadata fields are safe to serve from cache.
- Avoid returning placeholder metadata for `stat` cache hits.
- Fall back to source `stat` when cached metadata is incomplete or not trusted.
## Phase 5: Integration with specialized cache layers
- Keep `FoyerLayer` usable as a specialized integration that can leverage foyer-specific features such as `fetch()` and request deduplication.
- Revisit whether parts of `FoyerLayer` can share policy or key-shaping logic with the general `CacheLayer` after the baseline design is implemented.
# Out of scope
- Strong consistency across external writers.
- Caching `list` results.
- Replacing `RouteLayer` path dispatch.
- Replacing specialized integrations such as `FoyerLayer`.
- Mandating a specific eviction, TTL, or capacity policy.
# References
- RFC PR: #6297
- RouteLayer RFC: #7130
- FoyerLayer RFC: #6370
Contributor guide
Research direction
Start by reading RFC #6297 and the Phase 1 plan, then review the existing FoyerLayer and RouteLayer designs for composition boundaries. Implementing the baseline requires defining the CacheLayer, CachePolicy, whole-object caching, invalidation semantics, and Memory-backed tests; done means the Phase 1 API and behavior are covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100