[da-vinci][server] Add bounded hot transient record cache for large records during ingestion#2700
[da-vinci][server] Add bounded hot transient record cache for large records during ingestion#2700sixpluszero wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a bounded “hot” transient record cache (Caffeine) to retain frequently-accessed large records across consumer poll boundaries during ingestion (primarily for A/A replication and write-compute), reducing expensive RocksDB lookups after the per-partition transient map entry is drained.
Changes:
- Add a version-level flag (
transientRecordCacheEnabled) to the store metadata schema and bump the meta system store protocol to v42. - Add server-side configs (enable switch, max weight, min admission size) and instantiate a per-
StoreIngestionTaskshared Caffeine cache passed intoPartitionConsumptionState. - Add unit tests covering cache retention, admission gating, invalidation behavior, and cross-partition key isolation; add a host-level metric hook for cache hits.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/venice-common/src/main/resources/avro/StoreMetaValue/v42/StoreMetaValue.avsc | Adds transientRecordCacheEnabled to StoreVersion with default false. |
| internal/venice-common/src/main/java/com/linkedin/venice/serialization/avro/AvroProtocolDefinition.java | Bumps meta system store value schema protocol version to 42. |
| internal/venice-common/src/main/java/com/linkedin/venice/meta/VersionImpl.java | Implements getter/setter for the new version-level flag. |
| internal/venice-common/src/main/java/com/linkedin/venice/meta/Version.java | Adds new Version interface methods for transient record cache enablement. |
| internal/venice-common/src/main/java/com/linkedin/venice/ConfigKeys.java | Introduces server config keys for cache enablement, max weight, and min value size. |
| clients/da-vinci-client/src/test/java/com/linkedin/davinci/kafka/consumer/PartitionConsumptionStateTest.java | Adds unit tests validating hot-cache behavior and invalidation rules. |
| clients/da-vinci-client/src/main/java/com/linkedin/davinci/stats/HostLevelIngestionStats.java | Adds a sensor + recording method for hot-cache hit counts. |
| clients/da-vinci-client/src/main/java/com/linkedin/davinci/kafka/consumer/StoreIngestionTask.java | Creates/configures the shared Caffeine cache and passes it into PCS instances. |
| clients/da-vinci-client/src/main/java/com/linkedin/davinci/kafka/consumer/PartitionConsumptionState.java | Adds hot-cache admission/invalidation and fallback lookup logic; tracks hit count. |
| clients/da-vinci-client/src/main/java/com/linkedin/davinci/config/VeniceServerConfig.java | Wires server properties into new config getters. |
| build.gradle | Updates schema compatibility override pin from StoreMetaValue v40 to v42. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Two upcoming features need new version-level configs to be added to the Avro protocol schemas: 1. Transient Record Cache (PR #2700): A bounded hot transient record cache for large records during A/A ingestion. 2. Merged Value-RMD Column Family (PR #2528): Merging value and RMD into a single column family to reduce read amplification during A/A ingestion. These features require protocol schema changes to be landed first, before the implementation PRs can use them.
|
Hi there. This pull request has been inactive for 30 days. To keep our review queue healthy, we plan to close it in 7 days unless there is new activity. If you are still working on this, please push a commit, leave a comment, or convert it to draft to signal intent. Thank you for your time and contributions. |
|
Closing this pull request due to 37 days of inactivity. This is not a judgment on the value of the work. If you would like to continue, please reopen or open a new PR and we will be happy to take another look. Thank you again for contributing. |
…ecords during ingestion Adds a shared, bounded Caffeine cache per StoreIngestionTask as a second-level lookup behind the per-partition transient record map. Targets bursty hot large keys: when the drainer has already evicted a key's transient entry, the first access of a later burst would otherwise pay an expensive chunked RocksDB old-value lookup. The cache retains large records across that gap. - Version-level transientRecordCacheEnabled (default false) + host-level kill switch server.ingestion.transient.record.cache.enabled (default true) - Weight-based eviction (max.weight, default 32MB) + size admission (min.value.size, default 100KB); stale entries invalidated on smaller/null overwrite - Hot-cache hits recorded to the hot_record_cache_hit_count metric - Cache key combines partition+key without copying (no per-lookup allocation) The StoreMetaValue field backing the flag is already present on main, so this carries no schema/protocol change.
31fedf6 to
b3a605e
Compare
|
Hi there. This pull request has been inactive for 30 days. To keep our review queue healthy, we plan to close it in 7 days unless there is new activity. If you are still working on this, please push a commit, leave a comment, or convert it to draft to signal intent. Thank you for your time and contributions. |
Problem Statement
During Active-Active replication and Write Compute ingestion, the transient record map in
PartitionConsumptionStateholds records only until the drainer processes them. For large/chunked values, once evicted from the transient map, the ingestion pipeline must perform expensive RocksDB lookups to re-fetch the record. This is especially costly when the same key is accessed repeatedly across consumer poll boundaries.Solution
Introduce a shared, bounded Caffeine cache per
StoreIngestionTaskthat retains large transient records across consumer poll boundaries, acting as a second-level lookup after the per-partition transient record map.Key design:
transientRecordCacheEnabled) controls whether the cache is active for a given store versionserver.ingestion.transient.record.cache.enabled, defaulttrue) allows operators to disable the cache on a node immediately without requiring a new pushserver.ingestion.transient.record.cache.max.weight, default 32MB)server.ingestion.transient.record.cache.min.value.size, default 100KB)Code changes
transientRecordCacheEnabled(version-level, defaultfalse)server.ingestion.transient.record.cache.enabled(server-level, defaulttrue)server.ingestion.transient.record.cache.max.weight(server-level, default33554432/ 32MB)server.ingestion.transient.record.cache.min.value.size(server-level, default102400/ 100KB)Concurrency-Specific Checks
Both reviewer and PR author to verify
AtomicLong.synchronized,RWLock) are used where needed.ConcurrentHashMap,CopyOnWriteArrayList).How was this PR tested?
Does this PR introduce any user-facing or breaking changes?