Repository navigation
Conversation
|
@rban1 has exported this pull request. If you are a Meta employee, you can view the originating Diff in D119743760. |
|
| Check | Count |
|---|---|
cppcoreguidelines-avoid-non-const-global-variables |
1 |
cppcoreguidelines-special-member-functions |
1 |
modernize-use-emplace |
1 |
| Total | 3 |
Details
db/lsm_edit_test.cc (2 warning(s))
db/lsm_edit_test.cc:109:14: warning: use emplace_back instead of push_back [modernize-use-emplace]
db/lsm_edit_test.cc:176:7: warning: class 'LsmEditTest' defines a non-default destructor but does not define a move constructor or a move assignment operator [cppcoreguidelines-special-member-functions]
file/file_util.cc (1 warning(s))
file/file_util.cc:38:41: warning: variable 'current_io_callback' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]
Claude Code Review - OBSOLETESuperseded by a newer AI review. Expand to see the original review.✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit 6b49c53 SummaryWell-structured addition of High-severity findings (1):
Full review (click to expand)Findings🔴 HIGHH1.
|
| Context | Executes? | Assumptions hold? | Notes |
|---|---|---|---|
| WritePreparedTxnDB | Yes (StackableDB delegates) | Yes | Foreign seqnos not in prepare map, so visible |
| ReadOnly DB | No (ModelDB returns NotSupported) | N/A | Safe |
| User-defined timestamps | No (RecordDeclaredLevels rejects) | N/A | Correctly blocked |
| FIFO compaction | Yes | Partially | Multi-level placement accepted but may not compact (M5) |
| Universal compaction | Yes | Yes | Level semantics still apply |
| BlobDB | Yes (StackableDB) | Yes | External files are standard SSTs |
| Concurrent writes | Yes | Yes | NeedsFlush + allow_blocking_flush handle memtable overlap |
| MemPurge | Yes | Yes | MemPurge is a flush variant; NeedsFlush still works |
| Snapshots | Yes | Mostly | See M4 about foreign seqno visibility |
Positive Observations
- Clean reuse of existing infrastructure: The
ExternalSstFileIngestionJobreuse avoids duplicating the complex prepare/commit/flush/rollback logic. TheLsmEditJobSpecoptional cleanly separates the new behavior. - Thorough validation:
RecordDeclaredLevelschecks level bounds, UDT incompatibility, and same-level overlap.ProbeStraddlingFileschecks both point keys and range tombstones. - Good test coverage: 15 tests covering multi-level, multi-CF, rollback, persistence, and various rejection cases.
- Correct sequence number handling: The
allow_db_generated_files = true+allow_global_seqno = falsecombination correctly preserves original seqnos without modifying the files. - DeclaredFileFitsInLevel correctly accounts for doomed files: The edit's deleted files are excluded from overlap checking, allowing a declared level to reuse space freed by the edit.
- Range tombstone detection in ProbeStraddlingFiles: The
ReadRangeDelAggregator+IsRangeOverlappedcheck correctly catches range tombstones that would shadow grafted data.
ℹ️ 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:
`IngestExternalFile()` is a policy engine that *derives* a `VersionEdit` from
files: you hand it paths, it probes the LSM level by level and decides where
each file lands and what sequence number it gets. That works well when the
caller has no opinion about shape, and badly when it does. Two things fall out
of it that keep costing us real I/O:
- **Placement is emergent, not stated.** A caller that already has a valid LSM
-- because it built one in a scratch instance -- cannot transplant it. It has
to flatten that LSM into a single non-overlapping sorted run first, purely so
the placement heuristic will accept it. That flattening is a full rewrite of
data that was already correct.
- **Ranges must be file-aligned.** `atomic_replace_range` refuses a range that
any existing file only partly overlaps, even when that file holds no key
inside the range. The fix available today is to compact the range so a file
boundary lands on it -- again, rewriting correct data to move a boundary.
This diff adds the primitive that expresses the operation directly instead:
Status DB::ApplyLsmEdit(const LsmEditOptions&, const std::vector<LsmEdit>&);
An `LsmEdit` names a column family, a half-open key range, and the files that
will occupy it, each carrying the level it goes to. RocksDB validates that
arrangement rather than deriving one, and commits every edit in the call as a
single atomic MANIFEST write. Files keep the sequence numbers they were written
with; no global seqno is assigned.
Two capabilities are new, and they are what the callers above are missing:
**Declared placement.** `LsmEditFile::level` is an input. A multi-level set of
files installs with its layering intact, level 0 included -- overlapping level 0
runs are ordered by their position in `add_files`, oldest first. RocksDB checks
that the level has room (no surviving file's key range overlaps there) and
rejects the edit otherwise.
**Straddler probing.** Installing files with their own sequence numbers is only
sound if nothing already live sits in the range, so the edit removes every file
contained in it and *probes* every file that merely crosses its boundary. The
probe is one seek per straddling file, plus a range-tombstone check, and it
either proves the file holds nothing in the range -- in which case the file is
retained untouched -- or fails the edit. Where the alternative was compacting
live data to move a file boundary, this is a handful of block reads.
Implementation reuses `ExternalSstFileIngestionJob` rather than adding a
parallel path: the job gains an optional `LsmEditJobSpec` carrying the declared
levels, `AssignLevelAndSeqnoForIngestedFile()` validates the declared level
instead of searching when one is present, and the existing
`atomic_replace_range` machinery supplies range containment, memtable overlap,
pending-compaction conflict detection and the delete side of the edit.
The API is EXPERIMENTAL and has no C or Java binding yet, matching
`PrepareFileIngestion()`.
Differential Revision: D119743760
6b49c53 to
1b42be3
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 1b42be3 SummaryWell-structured PR that adds a useful declarative LSM edit primitive by reusing the existing file ingestion infrastructure. The design is sound and the implementation follows existing RocksDB patterns. Most validation paths are well-covered by tests. High-severity findings (1):
Full review (click to expand)Findings🔴 HIGHH1.
|
| Context | Executes? | Assumptions hold? | Notes |
|---|---|---|---|
| WritePreparedTxnDB | Yes (StackableDB passthrough) | Yes | Range verified empty, no conflict with prepared txns |
| User-defined timestamps | Rejected in RecordDeclaredLevels | N/A | Correctly guarded |
| Old snapshots | Yes | Yes | Range is empty pre-edit; edit is atomic MANIFEST write |
| Concurrent compaction | Yes | Yes | Range overlap with compaction checked in Run() |
| Concurrent writes | Protected | Yes | Write thread entered during commit |
| FIFO compaction | Yes | Yes | Level 0 only; declared levels validated |
Positive Observations
- Clean reuse of existing infrastructure: Extends
ExternalSstFileIngestionJobwith minimal mode-switch code rather than a parallel path. - Comprehensive test suite: 13 test cases covering the main use case, error paths, multi-CF atomicity, rollback, L0 ordering, reopen persistence, and cross-DB grafting.
- Elegant straddler probing: One seek per straddling file is an excellent design — avoids requiring file-boundary-aligned ranges.
- Good error messages: Specific, actionable error strings throughout.
- Clean API: Well-separated
LsmEditOptions/LsmEdit/LsmEditFilestructs are extensible and consistent with existing RocksDB patterns.
ℹ️ 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:
`IngestExternalFile()` is a policy engine that *derives* a `VersionEdit` from
files: you hand it paths, it probes the LSM level by level and decides where
each file lands and what sequence number it gets. That works well when the
caller has no opinion about shape, and badly when it does. Two things fall out
of it that keep costing us real I/O:
- **Placement is emergent, not stated.** A caller that already has a valid LSM
-- because it built one in a scratch instance -- cannot transplant it. It has
to flatten that LSM into a single non-overlapping sorted run first, purely so
the placement heuristic will accept it. That flattening is a full rewrite of
data that was already correct.
- **Ranges must be file-aligned.** `atomic_replace_range` refuses a range that
any existing file only partly overlaps, even when that file holds no key
inside the range. The fix available today is to compact the range so a file
boundary lands on it -- again, rewriting correct data to move a boundary.
This diff adds the primitive that expresses the operation directly instead:
Status DB::ApplyLsmEdit(const LsmEditOptions&, const std::vector<LsmEdit>&);
An `LsmEdit` names a column family, a half-open key range, and the files that
will occupy it, each carrying the level it goes to. RocksDB validates that
arrangement rather than deriving one, and commits every edit in the call as a
single atomic MANIFEST write. Files keep the sequence numbers they were written
with; no global seqno is assigned.
Two capabilities are new, and they are what the callers above are missing:
**Declared placement.** `LsmEditFile::level` is an input. A multi-level set of
files installs with its layering intact, level 0 included -- overlapping level 0
runs are ordered by their position in `add_files`, oldest first. RocksDB checks
that the level has room (no surviving file's key range overlaps there) and
rejects the edit otherwise.
**Straddler probing.** Installing files with their own sequence numbers is only
sound if nothing already live sits in the range, so the edit removes every file
contained in it and *probes* every file that merely crosses its boundary. The
probe is one seek per straddling file, plus a range-tombstone check, and it
either proves the file holds nothing in the range -- in which case the file is
retained untouched -- or fails the edit. Where the alternative was compacting
live data to move a file boundary, this is a handful of block reads.
Implementation reuses `ExternalSstFileIngestionJob` rather than adding a
parallel path: the job gains an optional `LsmEditJobSpec` carrying the declared
levels, `AssignLevelAndSeqnoForIngestedFile()` validates the declared level
instead of searching when one is present, and the existing
`atomic_replace_range` machinery supplies range containment, memtable overlap,
pending-compaction conflict detection and the delete side of the edit.
The API is EXPERIMENTAL and has no C or Java binding yet, matching
`PrepareFileIngestion()`.
Differential Revision: D119743760
1b42be3 to
1666032
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 1666032 SummaryWell-designed API that cleanly reuses the existing High-severity findings (1):
Full review (click to expand)Findings🔴 HIGHH1. Missing
|
| Context | Applicable? | Safe? | Notes |
|---|---|---|---|
| ReadOnly DB | YES | NO | Missing override -- H1 |
| Secondary Instance | YES | NO | Missing override -- H1 |
| WritePreparedTxnDB | YES | YES | Inherits from DBImpl, uses allow_db_generated_files path which preserves original seqnos. read_callback_ is not involved since there's no write/read during ingestion. |
| User-defined timestamps | Blocked | YES | RecordDeclaredLevels explicitly returns NotSupported for timestamp_size > 0. |
| MemPurge | NO | N/A | ApplyLsmEdit triggers a flush if needed, doesn't interact with MemPurge. |
| BlobDB | Not tested | Unknown | No validation that ingested files don't reference blob files. Likely safe since external SSTs don't use blob references, but not tested. |
| FIFO compaction | YES | YES | Declaring a level >= num_levels fails with "outside [0, N)". FIFO typically has num_levels=1, so only L0 is valid. |
| Universal compaction | YES | YES | Works correctly; the range tombstone fallback is correctly disabled. |
| Level compaction | YES | YES | Primary tested configuration. |
Positive Observations
-
Clean reuse of existing infrastructure: Rather than creating a parallel code path, the PR adds an optional
LsmEditJobSpectoExternalSstFileIngestionJob. This minimizes code duplication and ensures that the existing validation, file management, and commit logic is shared. -
Thorough sequence number validation: The
LsmEditSequenceOrderValidatorchecks point entries, range tombstones against points (both directions), and range tombstones against each other. This is comprehensive. -
Well-designed straddler probing: The
ProbeStraddlingFilesmethod elegantly handles the case where a file straddles the edit range boundary. By seeking into the file and checking for live keys, it avoids unnecessary compaction while maintaining correctness. -
Good test coverage: 20 test cases covering the happy path, various rejection scenarios, multi-CF atomicity, persistence, and the full LSM transplant use case.
-
Clean API design: The
LsmEditOptions/LsmEdit/LsmEditFilestructs are well-documented and follow existing RocksDB conventions. The EXPERIMENTAL marking is clear and consistent withPrepareFileIngestion(). -
Correct epoch number ordering: Each L0 file gets a
NewEpochNumber()in the order they appear in the ingestion loop, which processes files inadd_filesorder (oldest first). This ensures the newest file gets the highest epoch number, preserving the intended read ordering.
ℹ️ 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:
`IngestExternalFile()` is a policy engine that *derives* a `VersionEdit` from
files: you hand it paths, it probes the LSM level by level and decides where
each file lands and what sequence number it gets. That works well when the
caller has no opinion about shape, and badly when it does. Two things fall out
of it that keep costing us real I/O:
- **Placement is emergent, not stated.** A caller that already has a valid LSM
-- because it built one in a scratch instance -- cannot transplant it. It has
to flatten that LSM into a single non-overlapping sorted run first, purely so
the placement heuristic will accept it. That flattening is a full rewrite of
data that was already correct.
- **Ranges must be file-aligned.** `atomic_replace_range` refuses a range that
any existing file only partly overlaps, even when that file holds no key
inside the range. The fix available today is to compact the range so a file
boundary lands on it -- again, rewriting correct data to move a boundary.
This diff adds the primitive that expresses the operation directly instead:
Status DB::ApplyLsmEdit(const LsmEditOptions&, const std::vector<LsmEdit>&);
An `LsmEdit` names a column family, a half-open key range, and the files that
will occupy it, each carrying the level it goes to. RocksDB validates that
arrangement rather than deriving one, and commits every edit in the call as a
single atomic MANIFEST write. Files keep the sequence numbers they were written
with; no global seqno is assigned.
Two capabilities are new, and they are what the callers above are missing:
**Declared placement.** `LsmEditFile::level` is an input. A multi-level set of
files installs with its layering intact, level 0 included -- overlapping level 0
runs are ordered by their position in `add_files`, oldest first. RocksDB checks
that the level has room (no surviving file's key range overlaps there) and
rejects the edit otherwise.
**Straddler probing.** Installing files with their own sequence numbers is only
sound if nothing already live sits in the range, so the edit removes every file
contained in it and *probes* every file that merely crosses its boundary. The
probe is one seek per straddling file, plus a range-tombstone check, and it
either proves the file holds nothing in the range -- in which case the file is
retained untouched -- or fails the edit. Where the alternative was compacting
live data to move a file boundary, this is a handful of block reads.
Implementation reuses `ExternalSstFileIngestionJob` rather than adding a
parallel path: the job gains an optional `LsmEditJobSpec` carrying the declared
levels, `AssignLevelAndSeqnoForIngestedFile()` validates the declared level
instead of searching when one is present, and the existing
`atomic_replace_range` machinery supplies range containment, memtable overlap,
pending-compaction conflict detection and the delete side of the edit.
The API is EXPERIMENTAL and has no C or Java binding yet, matching
`PrepareFileIngestion()`.
Differential Revision: D119743760
1666032 to
0f0c5ad
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 0f0c5ad SummaryWell-designed API that reuses the existing ingestion pipeline rather than duplicating it. The approach of adding an optional High-severity findings (1):
Full review (click to expand)Findings🔴 HIGHH1. FIFO compaction style bypass —
|
| Context | Does code execute? | Assumptions hold? | Action needed? |
|---|---|---|---|
| WritePreparedTxnDB | YES (via DB virtual) | YES — files keep own seqnos, read_callback handles visibility | Safe |
| ReadOnly DB | Returns NotSupported | N/A | Handled |
| Secondary DB | Returns NotSupported | N/A | Handled |
| User-defined timestamps | Rejected in RecordDeclaredLevels | N/A | Handled |
| FIFO compaction | YES — NOT GUARDED | NO — FIFO expects L0 only | See H1 |
| Universal compaction | YES | YES — atomic_replace_range machinery reused | Safe |
| Level compaction | YES | YES | Safe |
| BlobDB (via StackableDB) | Forwarded to inner DB | YES | Safe |
| Concurrent memtable writes | Handled by flush + write-thread stall | YES | Safe |
| Old snapshots | Safe — files keep own seqnos, snapshot reads use normal seqno visibility | YES | Safe |
Assumption stress-test results:
-
"Edit range holds no live keys": Protected by (a) memtable flush check + write-thread stall, (b) straddler probing, (c) contained-file deletion. Concurrent compaction output is guarded by
RangeOverlapWithCompactioncheck. -
"Sequence numbers correctly ordered": Validated by
LsmEditSequenceOrderValidatorwhich checks point-vs-point, tombstone-vs-point, and tombstone-vs-tombstone. The pairwise check is correct for transitive ordering because: if A > B and B > C at every overlapping key, then A > C holds. The validator checks all overlapping pairs. -
"L0 ordering is correct": L0 files are ordered by epoch number (
cfd_->NewEpochNumber()), which is assigned inAssignLevelsForOneBatchat line ~908. Files inadd_filesorder get ascending epoch numbers because they're processed sequentially and each callsNewEpochNumber(). The "later = newer" claim holds.
Positive Observations
- Clean API design:
LsmEditOptions/LsmEdit/LsmEditFileare well-structured and follow existing RocksDB patterns. - Thorough sequence validation: The
LsmEditSequenceOrderValidatoris more rigorous than what normal ingestion performs, checking all combinations of point entries and range tombstones. - Elegant straddler probing: A single seek + range tombstone check avoids the need to compact just to move a file boundary.
- Good code reuse: Building on
ExternalSstFileIngestionJobrather than creating a parallel path avoids duplicating complex flush, compaction-conflict, and MANIFEST-commit logic. - Comprehensive test suite: 21 test cases covering positive paths, error paths, multi-CF atomicity, cross-level sequence ordering, reopening, and read-only/secondary rejection.
- All DB subclasses updated: StackableDB, DBImplReadOnly, DBImplSecondary, and ModelDB all have the new virtual method override.
ℹ️ 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:
`IngestExternalFile()` is a policy engine that *derives* a `VersionEdit` from
files: you hand it paths, it probes the LSM level by level and decides where
each file lands and what sequence number it gets. That works well when the
caller has no opinion about shape, and badly when it does. Two things fall out
of it that keep costing us real I/O:
- **Placement is emergent, not stated.** A caller that already has a valid LSM
-- because it built one in a scratch instance -- cannot transplant it. It has
to flatten that LSM into a single non-overlapping sorted run first, purely so
the placement heuristic will accept it. That flattening is a full rewrite of
data that was already correct.
- **Ranges must be file-aligned.** `atomic_replace_range` refuses a range that
any existing file only partly overlaps, even when that file holds no key
inside the range. The fix available today is to compact the range so a file
boundary lands on it -- again, rewriting correct data to move a boundary.
This diff adds the primitive that expresses the operation directly instead:
Status DB::ApplyLsmEdit(const LsmEditOptions&, const std::vector<LsmEdit>&);
An `LsmEdit` names a column family, a half-open key range, and the files that
will occupy it, each carrying the level it goes to. RocksDB validates that
arrangement rather than deriving one, and commits every edit in the call as a
single atomic MANIFEST write. Files keep the sequence numbers they were written
with; no global seqno is assigned.
Two capabilities are new, and they are what the callers above are missing:
**Declared placement.** `LsmEditFile::level` is an input. A multi-level set of
files installs with its layering intact, level 0 included -- overlapping level 0
runs are ordered by their position in `add_files`, oldest first. RocksDB checks
that the level has room (no surviving file's key range overlaps there) and
rejects the edit otherwise.
**Straddler probing.** Installing files with their own sequence numbers is only
sound if nothing already live sits in the range, so the edit removes every file
contained in it and *probes* every file that merely crosses its boundary. The
probe is one seek per straddling file, plus a range-tombstone check, and it
either proves the file holds nothing in the range -- in which case the file is
retained untouched -- or fails the edit. Where the alternative was compacting
live data to move a file boundary, this is a handful of block reads.
Implementation reuses `ExternalSstFileIngestionJob` rather than adding a
parallel path: the job gains an optional `LsmEditJobSpec` carrying the declared
levels, `AssignLevelAndSeqnoForIngestedFile()` validates the declared level
instead of searching when one is present, and the existing
`atomic_replace_range` machinery supplies range containment, memtable overlap,
pending-compaction conflict detection and the delete side of the edit.
The API is EXPERIMENTAL and has no C or Java binding yet, matching
`PrepareFileIngestion()`.
Differential Revision: D119743760
0f0c5ad to
c2b2b9a
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 c2b2b9a SummaryWell-designed new API that fills a real gap in the file ingestion surface. The implementation cleanly reuses High-severity findings (0): No high-severity findings. Full review (click to expand)Findings🔴 HIGHNone. 🟡 MEDIUMM1.
|
| Context | Does code execute? | Assumptions hold? | Action needed? |
|---|---|---|---|
| WritePreparedTxnDB | YES (via StackableDB) | YES - no read_callback interaction | Safe |
| ReadOnly DB | Returns NotSupported | N/A | None |
| SecondaryInstance | Returns NotSupported | N/A | None |
| User-defined timestamps | Rejected in RecordDeclaredLevels | N/A | None |
| BlobDB | SST files installed, blob files missing | Potentially unsafe | See M4 |
| FIFO compaction | Correctly requires level 0 | YES | None |
| Universal compaction | Works via probe path | YES | Add test (L2) |
| Snapshots | Range verified empty; seqnos preserved | YES | Safe |
| Concurrent writers | Flush check + mutex in Run() | YES | Safe |
Positive Observations
-
Clean reuse of existing infrastructure. The PR adds a small mode flag (
LsmEditJobSpec) toExternalSstFileIngestionJobrather than building a parallel pipeline. All existing safeguards (memtable overlap, compaction conflict, file copy/link, checksum, MANIFEST write) are inherited. -
Thorough sequence-number validation.
LsmEditSequenceOrderValidatorchecks all four combinations (point-vs-point, tombstone-vs-point, point-vs-tombstone, tombstone-vs-tombstone) with a merge-like scan. The fast path skipping table scans when seqno ranges are disjoint is a good optimization. -
Good API design. The
LsmEdit/LsmEditFile/LsmEditOptionsstructs are well-documented and consistent with existing RocksDB patterns. The separation between per-call options and per-edit parameters is clean. -
Straddler probing is elegant. One seek per file + range-tombstone check avoids rewriting data that is already correct.
-
Comprehensive test coverage. 18 test cases covering: basic grafting, rejection of non-empty ranges, range tombstones, straddler probe disable, level occupancy, removed-file reuse, whole-CF replace, cross-CF atomicity, rollback on failure, L0 ordering, overlapping files, sequence number validation (3 variants), bad arguments, FIFO, incomplete checksums, full LSM transplant, reopen durability, and read-only/secondary rejection.
-
Build system updates are complete. Makefile, CMakeLists.txt, BUCK, and src.mk all updated.
ℹ️ 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:
`IngestExternalFile()` is a policy engine that *derives* a `VersionEdit` from
files: you hand it paths, it probes the LSM level by level and decides where
each file lands and what sequence number it gets. That works well when the
caller has no opinion about shape, and badly when it does. Two things fall out
of it that keep costing us real I/O:
- **Placement is emergent, not stated.** A caller that already has a valid LSM
-- because it built one in a scratch instance -- cannot transplant it. It has
to flatten that LSM into a single non-overlapping sorted run first, purely so
the placement heuristic will accept it. That flattening is a full rewrite of
data that was already correct.
- **Ranges must be file-aligned.** `atomic_replace_range` refuses a range that
any existing file only partly overlaps, even when that file holds no key
inside the range. The fix available today is to compact the range so a file
boundary lands on it -- again, rewriting correct data to move a boundary.
This diff adds the primitive that expresses the operation directly instead:
Status DB::ApplyLsmEdit(const LsmEditOptions&, const std::vector<LsmEdit>&);
An `LsmEdit` names a column family, a half-open key range, and the files that
will occupy it, each carrying the level it goes to. RocksDB validates that
arrangement rather than deriving one, and commits every edit in the call as a
single atomic MANIFEST write. Files keep the sequence numbers they were written
with; no global seqno is assigned.
Two capabilities are new, and they are what the callers above are missing:
**Declared placement.** `LsmEditFile::level` is an input. A multi-level set of
files installs with its layering intact, level 0 included -- overlapping level 0
runs are ordered by their position in `add_files`, oldest first. RocksDB checks
that the level has room (no surviving file's key range overlaps there) and
rejects the edit otherwise.
**Straddler probing.** Installing files with their own sequence numbers is only
sound if nothing already live sits in the range, so the edit removes every file
contained in it and *probes* every file that merely crosses its boundary. The
probe is one seek per straddling file, plus a range-tombstone check, and it
either proves the file holds nothing in the range -- in which case the file is
retained untouched -- or fails the edit. Where the alternative was compacting
live data to move a file boundary, this is a handful of block reads.
Implementation reuses `ExternalSstFileIngestionJob` rather than adding a
parallel path: the job gains an optional `LsmEditJobSpec` carrying the declared
levels, `AssignLevelAndSeqnoForIngestedFile()` validates the declared level
instead of searching when one is present, and the existing
`atomic_replace_range` machinery supplies range containment, memtable overlap,
pending-compaction conflict detection and the delete side of the edit.
The API is EXPERIMENTAL and has no C or Java binding yet, matching
`PrepareFileIngestion()`.
Differential Revision: D119743760
c2b2b9a to
aa8e208
Compare
Summary: Add experimental `DB::ApplyLsmEdit()` for atomic, caller-declared SST additions/deletions across column families. The caller supplies levels; RocksDB validates the resulting layout instead of deriving placement. `kFilesInRange` replaces a bounded range, deleting contained files and probing preserved-sequence straddlers. Eligible external-V2 sequence-zero replacements can receive fresh global sequences and a covering tombstone; optional relocation makes room while preserving relative run order. `kExplicitFiles` deletes only listed files and supports additive edits without asserting range emptiness. Surviving same-level boundaries must remain disjoint above L0, and overlapping point/range entries are checked for valid sequence order. Sequence-zero point files are accepted under the declared level ordering. The destination watermark advances for retained nonzero input sequences so later writes remain newer. `merge_incoming_files` is opt-in: merge only incoming files into one compact SST per declared level using destination table/compression settings. Existing destination files are not merged unless `merge_existing_files` is also enabled. Later inputs resolve equal-sequence point overwrites; deletes, merge operands and range tombstones keep normal semantics. Embedded scalar/wide-column blobs are materialized before rewriting. Incoming validation within a merged level becomes a multiway merge, approximately O(K log F), rather than pairwise file scans. Remaining overlap validation seeks to the common key interval. Merge bytes are included in compaction counters. `zero_sequence_numbers` normalizes point snapshot inputs built in a different DB while preserving non-reset online-event sequences. Active snapshots are rejected by default. Add-only explicit edits may opt out, as may bounded `kFilesInRange` edits with incoming merging and straddler probing enabled. The latter fail if any destination file would be deleted or a retained straddler contains point entries or covering range tombstones in the range. Unflushed destination entries also block installation when blocking flushes are disabled. This permits a verified-empty-range import with active snapshots, not deletion of old data. The normal compaction snapshot context retains imported versions needed by already-active readers. This does not make foreign/old sequence imports generally snapshot-consistent. Read-only/secondary instances reject the API; FIFO rejects non-L0 placement; incomplete/mixed checksums and conflicting move/link options fail early. Mutable ingestion options are captured under the DB mutex. User-defined timestamps remain unsupported. No C/Java binding is added. `merge_existing_files` includes live same-level destination SSTs in the merged output, following the transitive boundary-overlap closure (including gaps between incoming runs). It requires add-only explicit edits; original incoming files obey the range contract, while merged output may extend outside it and preserves those existing keys/sequences. Pinned preparation versions and normal compaction snapshot context protect readers. Final commit checks every selected file identity/level and rejects stale or busy inputs with `TryAgain`, then atomically deletes originals and installs outputs. Existing source files are never removed through incoming-file cleanup. Both incoming and destination rewrite bytes are counted; this mode does not promise rewrite avoidance. Live merge readers preserve effective MANIFEST-assigned global sequences, not just serialized SST keys. A targeted snapshot regression reproduced and fixed loss of that override. Selected SSTs with separate blob-file references remain unsupported; self-contained/embedded blobs are supported. Previously the snapshot opt-out rejected every range-mode edit before probing, forcing MyRocks to choose an unchecked additive edit or reject concurrent snapshots. The narrow extension keeps defaults, nonempty-range deletion restrictions, explicit edits and generic destination merging unchanged; the final no-deletion check runs against the installation version under the existing write fence. Tests exercise successful L6-straddler retention with older snapshots and rejection of contained, straddling, tombstone and memtable data. Differential Revision: D119743760
aa8e208 to
0f7589e
Compare
Summary: X-link: meta#15203 Add experimental `DB::ApplyLsmEdit()` for atomic, caller-declared SST additions/deletions across column families. The caller supplies levels; RocksDB validates the resulting layout instead of deriving placement. `kFilesInRange` replaces a bounded range, deleting contained files and probing preserved-sequence straddlers. Eligible external-V2 sequence-zero replacements can receive fresh global sequences and a covering tombstone; optional relocation makes room while preserving relative run order. `kExplicitFiles` deletes only listed files and supports additive edits without asserting range emptiness. Surviving same-level boundaries must remain disjoint above L0, and overlapping point/range entries are checked for valid sequence order. Sequence-zero point files are accepted under the declared level ordering. The destination watermark advances for retained nonzero input sequences so later writes remain newer. `merge_incoming_files` is opt-in: merge only incoming files into one compact SST per declared level using destination table/compression settings. Existing destination files are not merged unless `merge_existing_files` is also enabled. Later inputs resolve equal-sequence point overwrites; deletes, merge operands and range tombstones keep normal semantics. Embedded scalar/wide-column blobs are materialized before rewriting. Incoming validation within a merged level becomes a multiway merge, approximately O(K log F), rather than pairwise file scans. Remaining overlap validation seeks to the common key interval. Merge bytes are included in compaction counters. `zero_sequence_numbers` normalizes point snapshot inputs built in a different DB while preserving non-reset online-event sequences. Active snapshots are rejected by default. Add-only explicit edits may opt out, as may bounded `kFilesInRange` edits with incoming merging and straddler probing enabled. The latter fail if any destination file would be deleted or a retained straddler contains point entries or covering range tombstones in the range. Unflushed destination entries also block installation when blocking flushes are disabled. This permits a verified-empty-range import with active snapshots, not deletion of old data. The normal compaction snapshot context retains imported versions needed by already-active readers. This does not make foreign/old sequence imports generally snapshot-consistent. Read-only/secondary instances reject the API; FIFO rejects non-L0 placement; incomplete/mixed checksums and conflicting move/link options fail early. Mutable ingestion options are captured under the DB mutex. User-defined timestamps remain unsupported. No C/Java binding is added. `merge_existing_files` includes live same-level destination SSTs in the merged output, following the transitive boundary-overlap closure (including gaps between incoming runs). It requires add-only explicit edits; original incoming files obey the range contract, while merged output may extend outside it and preserves those existing keys/sequences. Pinned preparation versions and normal compaction snapshot context protect readers. Final commit checks every selected file identity/level and rejects stale or busy inputs with `TryAgain`, then atomically deletes originals and installs outputs. Existing source files are never removed through incoming-file cleanup. Both incoming and destination rewrite bytes are counted; this mode does not promise rewrite avoidance. Live merge readers preserve effective MANIFEST-assigned global sequences, not just serialized SST keys. A targeted snapshot regression reproduced and fixed loss of that override. Selected SSTs with separate blob-file references remain unsupported; self-contained/embedded blobs are supported. Previously the snapshot opt-out rejected every range-mode edit before probing, forcing MyRocks to choose an unchecked additive edit or reject concurrent snapshots. The narrow extension keeps defaults, nonempty-range deletion restrictions, explicit edits and generic destination merging unchanged; the final no-deletion check runs against the installation version under the existing write fence. Tests exercise successful L6-straddler retention with older snapshots and rejection of contained, straddling, tombstone and memtable data. October 28 review corrections: `autovector` iterators now satisfy the default-construction requirement used by libc++ `stable_sort`. The LSM snapshot fence is raised after required blocking flushes, avoiding the WritePrepared internal-snapshot deadlock while retaining the final installation fence. Ordinary read and compaction merging preserve source priority for equal-sequence point entries, and user iterators suppress duplicate sequence-zero keys; the declared priority is therefore honored by scans as well as `Get`. Equal-bound validation requires known entry statistics and never bypasses strict newer-range-tombstone checks. Lazy live-file counts are treated as unknown. Declared-level fit retains exclusive range-end sentinel semantics. Merged outputs persist consistent key/creation/ancestor ages, with conservative import-time fallback for unknown input ages. Generated merged/tombstone SSTs are registered with `SstFileManager`, enforce the space limit during preparation and again before commit, and are untracked on rollback only after physical deletion. Existing destination inputs remain tracked until ordinary obsolete-file cleanup. These fixes add no SST or MANIFEST format fields. The October 27 Merlin measurements predate them; no new performance measurement is claimed for this revision. Differential Revision: D119743760
0f7589e to
baa2565
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 baa2565 SummaryThis is a large and complex PR (~4500 insertions across 28 files) adding High-severity findings (3):
Full review (click to expand)Findings🔴 HIGHH1. Global merging iterator comparator change drops value-type tiebreaking --
|
| Context | Affected? | Assessment |
|---|---|---|
| WritePreparedTxnDB | YES - snapshot creation waits | The bg_cv_.Wait() in GetSnapshotImpl adds latency when LSM edits are running. WritePreparedTxnDB creates snapshots on its read path. If an LSM edit is running concurrently, reads may stall. The PR description mentions "avoiding the WritePrepared internal-snapshot deadlock." |
| ReadOnly DB | NO | Returns NotSupported |
| Secondary Instance | NO | Returns NotSupported |
| FIFO compaction | Partially - L0 only | Non-L0 placement rejected; L0 edits allowed |
| BlobDB | Partially | External blob references rejected; inline/same-file blobs supported via SameFileBlobReader |
| User-defined timestamps | NO | Rejected by RecordDeclaredLevels |
| CompactedDB | NO | Returns NotSupported |
| Concurrent compactions | YES | RangeOverlapWithCompaction check + RegisterCompaction blocking. But per-file being_compacted check for deleted files is only done late (M1). |
| Concurrent snapshots | YES | Double-blocked during commit. Wait loop in GetSnapshotImpl under mutex. |
Positive Observations
-
Thorough validation: The sequence ordering validation (
LsmEditSequenceOrderValidator) is comprehensive, checking point entries, tombstones-vs-points, and tombstone-vs-tombstone orderings. -
Lifecycle safety: Changing
mutable_db_options_andenv_options_from references to values prevents dangling reference bugs when the job outlives the caller's scope. -
SstFileManager integration: Generated files (merged outputs, tombstones) are properly registered and unregistered with SstFileManager, including space limit checks.
-
Preparation SuperVersion pinning: SuperVersions are pinned during preparation with
shared_ptr+ custom deleter, preventing use-after-free if a flush replaces the SuperVersion during preparation. -
Comprehensive error handling: The code validates inputs extensively before doing expensive I/O, and rolls back cleanly on failure.
-
Test coverage: The 2191-line test file exercises a wide range of scenarios including sequence ordering, snapshot consistency, merge modes, straddler probing, and error cases.
ℹ️ 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
baa2565 to
0d73ba0
Compare
Summary: Pull Request resolved: meta#15203 X-link: meta#15203 Add experimental `DB::ApplyLsmEdit()` for atomic, caller-declared SST additions/deletions across column families. The caller supplies levels; RocksDB validates the resulting layout instead of deriving placement. `kFilesInRange` replaces a bounded range, deleting contained files and probing preserved-sequence straddlers. Eligible external-V2 sequence-zero replacements can receive fresh global sequences and a covering tombstone; optional relocation makes room while preserving relative run order. `kExplicitFiles` deletes only listed files and supports additive edits without asserting range emptiness. Surviving same-level boundaries must remain disjoint above L0, and overlapping point/range entries are checked for valid sequence order. Sequence-zero point files are accepted under the declared level ordering. The destination watermark advances for retained nonzero input sequences so later writes remain newer. `merge_incoming_files` is opt-in: merge only incoming files into one compact SST per declared level using destination table/compression settings. Existing destination files are not merged unless `merge_existing_files` is also enabled. Later inputs resolve equal-sequence point overwrites; deletes, merge operands and range tombstones keep normal semantics. Embedded scalar/wide-column blobs are materialized before rewriting. Incoming validation within a merged level becomes a multiway merge, approximately O(K log F), rather than pairwise file scans. Remaining overlap validation seeks to the common key interval. Merge bytes are included in compaction counters. `zero_sequence_numbers` normalizes point snapshot inputs built in a different DB while preserving non-reset online-event sequences. Active snapshots are rejected by default. Add-only explicit edits may opt out, as may bounded `kFilesInRange` edits with incoming merging and straddler probing enabled. The latter fail if any destination file would be deleted or a retained straddler contains point entries or covering range tombstones in the range. Unflushed destination entries also block installation when blocking flushes are disabled. This permits a verified-empty-range import with active snapshots, not deletion of old data. The normal compaction snapshot context retains imported versions needed by already-active readers. This does not make foreign/old sequence imports generally snapshot-consistent. Read-only/secondary instances reject the API; FIFO rejects non-L0 placement; incomplete/mixed checksums and conflicting move/link options fail early. Mutable ingestion options are captured under the DB mutex. User-defined timestamps remain unsupported. No C/Java binding is added. `merge_existing_files` includes live same-level destination SSTs in the merged output, following the transitive boundary-overlap closure (including gaps between incoming runs). It requires add-only explicit edits; original incoming files obey the range contract, while merged output may extend outside it and preserves those existing keys/sequences. Pinned preparation versions and normal compaction snapshot context protect readers. Final commit checks every selected file identity/level and rejects stale or busy inputs with `TryAgain`, then atomically deletes originals and installs outputs. Existing source files are never removed through incoming-file cleanup. Both incoming and destination rewrite bytes are counted; this mode does not promise rewrite avoidance. Live merge readers preserve effective MANIFEST-assigned global sequences, not just serialized SST keys. A targeted snapshot regression reproduced and fixed loss of that override. Selected SSTs with separate blob-file references remain unsupported; self-contained/embedded blobs are supported. Previously the snapshot opt-out rejected every range-mode edit before probing, forcing MyRocks to choose an unchecked additive edit or reject concurrent snapshots. The narrow extension keeps defaults, nonempty-range deletion restrictions, explicit edits and generic destination merging unchanged; the final no-deletion check runs against the installation version under the existing write fence. Tests exercise successful L6-straddler retention with older snapshots and rejection of contained, straddling, tombstone and memtable data. October 28 review corrections: `autovector` iterators now satisfy the default-construction requirement used by libc++ `stable_sort`. The LSM snapshot fence is raised after required blocking flushes, avoiding the WritePrepared internal-snapshot deadlock while retaining the final installation fence. Ordinary read and compaction merging preserve source priority for equal-sequence point entries, and user iterators suppress duplicate sequence-zero keys; the declared priority is therefore honored by scans as well as `Get`. Equal-bound validation requires known entry statistics and never bypasses strict newer-range-tombstone checks. Lazy live-file counts are treated as unknown. Declared-level fit retains exclusive range-end sentinel semantics. Merged outputs persist consistent key/creation/ancestor ages, with conservative import-time fallback for unknown input ages. Generated merged/tombstone SSTs are registered with `SstFileManager`, enforce the space limit during preparation and again before commit, and are untracked on rollback only after physical deletion. Existing destination inputs remain tracked until ordinary obsolete-file cleanup. These fixes add no SST or MANIFEST format fields. The October 27 Merlin measurements predate them; no new performance measurement is claimed for this revision. Follow-up fixes from the October 28 22:49 UTC review: - Fix durable stale-value retention: compaction now uses a transitive key/sequence/source ordering for points, range starts and file boundaries. Range starts precede equal-key/sequence points independently of point type. Read-side range-start checks and reverse transitions use compatible key/sequence comparisons. A native three-run wide-column/tombstone regression reproduces loss of the newest value when the compaction fix is disabled. - Fix unresolved merge collisions: incoming output validation rejects duplicate internal keys before calling the SST builder. When no available base or valid partial merge can consolidate equal-sequence operands, return `NotSupported`, retaining the inputs and destination state. Duplicate equal-key/sequence merge operands cannot remain in separate runs either; validation rejects those incoming/surviving and cross-level histories before installation. Sequence-zero puts/deletes and ordinary distinct-sequence merge history remain supported. - Fix callback self-deadlock: a scoped file-I/O notification dispatcher finishes already-running callbacks before taking DB/write locks, queues new notifications for the configured listeners across foreground and worker threads, and delivers them with owned path/timestamp/status metadata after installation releases its locks and snapshot fence, before `OnExternalFileIngested`. Public snapshot creation remains fenced through installation. Normal non-LSM ingestion keeps synchronous notification behavior; I/O notifications remain opt-in. - Fix live-file reservation bookkeeping: external-ingestion reservations distinguish real L0 deletion inputs from incoming placeholders, enroll real inputs in L0 exclusion, and refresh current compaction scores/candidate lists after reserving and releasing live inputs, including rollback. This covers deletion-only edits and destination merging; the verified-empty-range MyRocks path removes no destination files and avoids these full picker refreshes. Safety and compatibility: no SST/MANIFEST format changes or new public options. `ApplyLsmEdit` file-I/O callback timing/threading is explicitly documented. Queued notifications consume memory proportional to the notification count; a minimal same-binary microbenchmark with one configured callback measured about 24 ns additional dispatch overhead per event. The dispatcher is not invoked at notification sites without I/O listeners. This is not a DB/DDL performance measurement. The MyRocks caller/default-OFF gate, supported level placement and historical Merlin measurements are unchanged. Differential Revision: D119743760
Summary: Pull Request resolved: meta#15203 X-link: meta#15203 Adds experimental DB::ApplyLsmEdit() for installing caller-declared SST additions, deletions and levels atomically across column families. Unlike IngestExternalFile(), which chooses placement, this API validates the requested LSM layout. It lets callers transplant a prepared layout or replace data without first compacting destination files merely to move their boundaries. ## File changes and placement - Explicit mode — kExplicitFiles: removes only the listed live files. Unlisted files remain, even inside the edit’s range. Supports additive imports, deletion-only edits and file replacement. - Range mode — kFilesInRange: removes files wholly contained in [start, limit). Boundary-straddling files must retain their out-of-range data. Preserved-sequence imports probe them across all levels and reject the edit if they contain points or covering tombstones inside the range. Eligible external-V2 sequence-zero replacements can instead receive fresh sequences and a covering tombstone. - Levels are normally exact: L1+ file boundaries must remain non-overlapping, including against surviving files. Probing does not relax this structural rule. Optional relocation applies only to eligible sequence-zero range replacements and preserves relative run order. - Optional merging: merge_incoming_files rewrites incoming files into one SST per declared level using destination settings. merge_existing_files additionally incorporates overlapping same-level destination files, preserving their out-of-range contents. It requires an add-only explicit edit and can rewrite substantially more data than the incoming files. Unset range endpoints mean the whole CF; otherwise both endpoints are required. The range bounds incoming and explicitly deleted files, but destination-merge output may extend beyond it. ## Sequences, snapshots and safety - Preserved-sequence imports retain their entry sequences. The destination sequence watermark advances when necessary so subsequent writes are newer. - Overlapping histories are validated against added and surviving files. Supported sequence-zero point ties follow declared level/L0 run priority consistently through reads and compaction; range tombstones must still be strictly newer than covered points. - zero_sequence_numbers explicitly normalizes point snapshot inputs during merging, while non-reset online changes retain their sequences. Equal-key/sequence merge operands must be consolidated; unsupported collisions return NotSupported. - Active snapshots are rejected by default. Opt-out permits additive explicit edits or bounded, merged, probed range imports that delete no destination files and verify an empty destination range. It does not generally make foreign-sequence imports snapshot-consistent. - Installation revalidates current state, prevents conflicting compactions, flushes overlapping memtables or fails when blocking flushes are disabled, and commits atomically. Cleanup preserves source ownership and generated-file accounting. Recent fixes also protect picker bookkeeping, TTL metadata and snapshot-taking I/O callbacks. Read-only/secondary DBs and timestamp-enabled CFs reject the API; FIFO permits only L0. No SST/MANIFEST format changes are introduced. October 29 static-analysis cleanup: explicitly delete move construction/assignment for `ScopedDeferredFileIOListeners`, `FileIOCallbackGuard` and `OwnedFileOperationInfo`, and default the owned-event destructor. These types remain noncopyable/nonmovable, preserving registered object identity and borrowed references into owned event data. Reserve the exact input-level vector capacity before appending. This addresses all four clang-tidy comments without suppressions or API/format/sequence changes. October 29 third-review concurrency fixes (F001-F003): deletion reservation cleanup clears its bookkeeping after the protected picker refresh, so later job destruction does not access current-Version or mutable-CF state. LSM edit callback scopes sharing configured listeners now hold an exclusive lease through I/O callback delivery, before another matching edit can enter DB/write locks. Non-overlapping listener sets may proceed independently. Matching reentrant LSM edits return `NotSupported` before preparation or commit; this also prevents recursive MANIFEST writes during file-number reservation. Direct and deferred callbacks are tracked with a thread-local callback stack. File contents, level/sequence rules and SST/MANIFEST formats are unchanged. This update is confined to the base draft; downstream release refresh and MyRocks testing are deferred at the user's request. Strict checked-status validation also exposed two existing experimental paths that could abort: a default `Status` was unused in an empty deletion-only batch, and `BuildMergedFile()` left `BuildTable()`'s secondary I/O status unread on an early iterator failure. Scope the per-file status inside its loop, and consume the I/O status while preserving the primary error (propagating an I/O error if the primary status is OK). No checks are suppressed. Differential Revision: D119743760
0d73ba0 to
9501529
Compare
✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit 9501529 SummaryLarge, well-structured PR adding an experimental declarative LSM edit API. The core LSM edit logic is generally sound, but the PR makes several changes to shared infrastructure (MergingIterator, CompactionMergingIterator, DBIter) that affect all code paths, not just LSM edits. Two of these changes carry behavioral risk for existing workloads. High-severity findings (2):
Full review (click to expand)Findings🔴 HIGHH1. MergingIterator comparator change affects ALL read paths --
|
| Context | Affected? | Assessment |
|---|---|---|
| WritePreparedTxnDB | No (LSM edit does not use read_callback) | Safe |
| ReadOnly DB | Explicitly rejected | Safe |
| SecondaryInstance | Explicitly rejected | Safe |
| CompactedDB | Explicitly rejected | Safe |
| User-defined timestamps | Explicitly rejected in RecordDeclaredLevels | Safe |
| FIFO compaction | Only L0 permitted | Safe |
| MergingIterator change | ALL reads and compactions | Risk (H1, H2) |
| DBIter change | ALL forward iteration | Performance risk (M1) |
| Snapshot blocking | All snapshot creation | Safe (properly paired BlockNew/UnblockNew) |
| StackableDB | Passthrough override added | Safe |
Positive Observations
- The API design is clean and well-documented, with clear separation between LsmEditOptions (per-call) and LsmEdit (per-CF).
- Extensive input validation: sequence order between overlapping files, level-fit checking, straddling file probing, external blob reference rejection, checksum consistency.
- Proper rejection for unsupported configurations (read-only, secondary, timestamps, compacted DB).
- The
ScopedDeferredFileIOListenersmechanism for preventing I/O callback re-entrancy and deadlock is a thoughtful solution. The thread-local callback stack and IsInCallback check are well-designed. - Build system properly updated across all four systems (Makefile, CMakeLists.txt, src.mk, BUCK).
- The
entry_stats_initializedflag correctly distinguishes "zero entries" from "entry count unknown." - The snapshot blocking with
num_running_lsm_edits_counter is correctly paired (two BlockNew + two UnblockNew when LSM edits are active, matching the ShardedSnapshotList counter semantics). - The deletion reservation cleanup fix (MarkFilesBeingCompacted(false) before UnregisterCompaction, plus ComputeCompactionScore refresh) correctly addresses the picker bookkeeping issue.
- The LsmEditMergeIterator properly handles blob resolution via GetSameFileBlobReader, zero_sequence_numbers reset, and equal-sequence point deduplication.
ℹ️ 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:
X-link: #15203
Adds experimental DB::ApplyLsmEdit() for installing caller-declared SST additions, deletions and levels atomically across column families. Unlike IngestExternalFile(), which chooses placement, this API validates the requested LSM layout. It lets callers transplant a prepared layout or replace data without first compacting destination files merely to move their boundaries.
File changes and placement
Unset range endpoints mean the whole CF; otherwise both endpoints are required. The range bounds incoming and explicitly deleted files, but destination-merge output may extend beyond it.
Sequences, snapshots and safety
Read-only/secondary DBs and timestamp-enabled CFs reject the API; FIFO permits only L0. No SST/MANIFEST format changes are introduced.
October 29 static-analysis cleanup: explicitly delete move construction/assignment for
ScopedDeferredFileIOListeners,FileIOCallbackGuardandOwnedFileOperationInfo, and default the owned-event destructor. These types remain noncopyable/nonmovable, preserving registered object identity and borrowed references into owned event data. Reserve the exact input-level vector capacity before appending. This addresses all four clang-tidy comments without suppressions or API/format/sequence changes.October 29 third-review concurrency fixes (F001-F003): deletion reservation cleanup clears its bookkeeping after the protected picker refresh, so later job destruction does not access current-Version or mutable-CF state. LSM edit callback scopes sharing configured listeners now hold an exclusive lease through I/O callback delivery, before another matching edit can enter DB/write locks. Non-overlapping listener sets may proceed independently. Matching reentrant LSM edits return
NotSupportedbefore preparation or commit; this also prevents recursive MANIFEST writes during file-number reservation. Direct and deferred callbacks are tracked with a thread-local callback stack. File contents, level/sequence rules and SST/MANIFEST formats are unchanged. This update is confined to the base draft; downstream release refresh and MyRocks testing are deferred at the user's request.Strict checked-status validation also exposed two existing experimental paths that could abort: a default
Statuswas unused in an empty deletion-only batch, andBuildMergedFile()leftBuildTable()'s secondary I/O status unread on an early iterator failure. Scope the per-file status inside its loop, and consume the I/O status while preserving the primary error (propagating an I/O error if the primary status is OK). No checks are suppressed.Differential Revision: D119743760