Track newer snapshot versions in RocksDB metadata reads (#15086) - #15086
Track newer snapshot versions in RocksDB metadata reads (#15086)#15086xingbowang wants to merge 1 commit into
Conversation
|
@xingbowang has exported this pull request. If you are a Meta employee, you can view the originating Diff in D104182397. |
|
| Check | Count |
|---|---|
clang-analyzer-core.NullDereference |
8 |
| Total | 8 |
Details
db/c.cc (8 warning(s))
db/c.cc:2652:22: warning: Dereference of null pointer (loaded from variable 'timestamp_len') [clang-analyzer-core.NullDereference]
db/c.cc:2653:18: warning: Dereference of null pointer (loaded from variable 'timestamp') [clang-analyzer-core.NullDereference]
db/c.cc:2658:18: warning: Dereference of null pointer (loaded from variable 'timestamp') [clang-analyzer-core.NullDereference]
db/c.cc:2659:22: warning: Dereference of null pointer (loaded from variable 'timestamp_len') [clang-analyzer-core.NullDereference]
db/c.cc:2836:27: warning: Array access (from variable 'timestamp_list') results in a null pointer dereference [clang-analyzer-core.NullDereference]
db/c.cc:2837:33: warning: Array access (from variable 'timestamp_list_sizes') results in a null pointer dereference [clang-analyzer-core.NullDereference]
db/c.cc:2844:27: warning: Array access (from variable 'timestamp_list') results in a null pointer dereference [clang-analyzer-core.NullDereference]
db/c.cc:2845:33: warning: Array access (from variable 'timestamp_list_sizes') results in a null pointer dereference [clang-analyzer-core.NullDereference]
a390fd0 to
8801143
Compare
Claude Code Review - OBSOLETESuperseded by a newer AI review. Expand to see the original review.✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit 8801143 SummaryLarge, well-structured PR adding experimental High-severity findings (3):
Full review (click to expand)Findings🔴 HIGHH1. Range tombstone dual-iterator complexity —
|
| Context | Handled? | Notes |
|---|---|---|
| WritePreparedTxnDB | Yes | Rejected when callback != nullptr |
| ReadOnly DB | Yes | Returns false metadata |
| Secondary DB | Yes | Returns NotSupported with snapshot |
| CompactedDB | Yes | Returns false metadata |
| User-defined timestamps | Yes | Tested |
| Row cache | Yes | Bypassed during tracking |
| MemPurge | Unknown | MetadataReadCtx passes through imm path; needs verification |
| BlobDB (integrated) | Likely OK | Direct-write resolution after metadata tracking |
Positive Observations
- Clean opt-in design via
OutputMetadata::Want*()methods — extensible and zero-overhead when not used. - Correct snapshot isolation — widened lookup + ReadCallback filtering preserves the invariant that returned values match regular
Get(). - Comprehensive tests — 15+ test cases covering diverse scenarios including row cache, range deletes, merges, cross-CF, error handling, and special DB modes.
- Proper rejection of incompatible modes (kPersistedTier, transaction callbacks).
UNLIKELYannotation on the hot-path metadata check inSaveValue.
ℹ️ About this response
Generated by Claude Code.
Review methodology: claude_md/ci_review_prompt.md
Limitations:
- Claude may miss context from files not in the diff
- Large PRs may be truncated
- Always apply human judgment to AI suggestions
Commands:
/claude-review [context]— Request a code review/claude-query <question>— Ask about the PR or codebase
8801143 to
0be18d4
Compare
Summary: Pull Request resolved: facebook#15086 Add experimental GetWithMetadata and MultiGetWithMetadata APIs that can report whether an explicit-snapshot read observed a newer committed write for the same key while still returning the snapshot-visible result. The implementation widens metadata reads only when the opt-in newer-version field is requested, preserves snapshot visibility with the existing read callback machinery, and forwards the API through the C/C++/Java wrapper surfaces. This update addresses the latest review feedback by documenting and asserting the range-tombstone lookup-sequence versus snapshot-sequence relationship, avoiding heap allocation for small metadata MultiGet forwarding batches while preserving a contiguous large-batch fallback, and adding coverage for newer point writes and range tombstones in immutable memtables. Differential Revision: D104182397
0be18d4 to
c1dd050
Compare
✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit c1dd050 SummaryA well-structured PR adding experimental High-severity findings (0): No high-severity findings. Full review (click to expand)Findings🔴 HIGHNone. 🟡 MEDIUMM1.
|
| Context | Behavior | Assessment |
|---|---|---|
| WritePreparedTxnDB | Delegates to DB::GetWithMetadata base → falls back to Get() without tracking when snapshot is set |
Correct: custom read callbacks are unsupported, so tracking is skipped |
| ReadOnly DB | Sets newer_version_present = nullptr in GetImpl, returns false for MultiGet |
Correct: no writes possible, so no newer versions |
| Secondary DB | Returns NotSupported for snapshot reads |
Correct: secondary has limited write visibility guarantees |
| CompactedDB | Always returns false | Correct: no new writes can occur |
| BlobDB | Forwards newer_version_present through GetImpl |
Correct: blob index resolution happens after metadata tracking |
| TTL DB | Delegates to base class, strips TTL timestamp | Correct: metadata tracking is independent of TTL value format |
| Row cache | Bypassed when tracking active | Correct: cached rows don't expose sequence numbers |
| User-defined timestamps | GetWithTimestampReadCallback::IsNewerVisibleForMetadataRead handles correctly |
Correct: checks snapshot < seq <= max_visible_seq |
| kPersistedTier | Returns NotSupported |
Correct: cannot guarantee seeing all relevant sequences |
Assumption stress test:
-
Claim: "snapshot visibility is preserved" — Verified. The
LookupKeyuseslookup_snapshot(wider) to scan more entries, butReadCallback::IsVisible(seq)still filters atsnapshot(original). Range tombstone masking usesrange_del_read_seq(= original snapshot). Themax_covering_tombstone_seqis set by the original-snapshot iterator. Entry selection and merge context accumulation respect the original snapshot. -
Claim: "false negatives are possible" — Verified. The window between SV pin and
GetLastPublishedSequence()call can miss concurrent writes. Additionally, ifconsistent_seqnum == newer_version_upper_bound_seq, tracking is skipped entirely (track_newer_versions = false), so writes published exactly at the snapshot boundary are missed. -
Claim: "row cache bypass is necessary" — Verified. Cached rows store values without sequence numbers. A row cache hit would skip the memtable/SST scan where metadata tracking occurs. After a newer version is observed, subsequent lookups CAN use the row cache (the
NeedToTrackNewerVersions()check is false whenHasNewerVersion()returns true).
Positive Observations
- The opt-in
OutputMetadatadesign withstd::optionalfields ensures zero overhead for callers that don't request metadata. - The
MetadataReadCtxdesign cleanly separates metadata tracking state from the main read path, using const pointers and a reference to the output bool. - The test suite is thorough, covering immutable memtables, range tombstones with
ignore_range_deletions, row cache bypass, read-only DB, compacted DB, cross-CF MultiGet, kPersistedTier rejection, and null-value validation. - The db_stress integration validates consistency of newer-version metadata across batched operations.
- The db_bench integration with
--read_with_metadataenables performance benchmarking. - The assertion
assert(range_del_read_seq <= lookup_seq)inmemtable.ccprovides a safety net for the two-iterator design. - The single shared
latest_range_del_iterper MultiGet batch (rather than per-key) is a good optimization.
ℹ️ About this response
Generated by Claude Code.
Review methodology: claude_md/ci_review_prompt.md
Limitations:
- Claude may miss context from files not in the diff
- Large PRs may be truncated
- Always apply human judgment to AI suggestions
Commands:
/claude-review [context]— Request a code review/claude-query <question>— Ask about the PR or codebase
Summary:
Add experimental GetWithMetadata and MultiGetWithMetadata APIs that can report whether an explicit-snapshot read observed a newer committed write for the same key while still returning the snapshot-visible result. The implementation widens metadata reads only when the opt-in newer-version field is requested, preserves snapshot visibility with the existing read callback machinery, and forwards the API through the C/C++/Java wrapper surfaces.
This update addresses the latest review feedback by documenting and asserting the range-tombstone lookup-sequence versus snapshot-sequence relationship, avoiding heap allocation for small metadata MultiGet forwarding batches while preserving a contiguous large-batch fallback, and adding coverage for newer point writes and range tombstones in immutable memtables.
Differential Revision: D104182397