feat(range-tombstone): add structured error context to decode_range_tombstones#37
Conversation
…ombstones - Replace generic Error::Unrecoverable with RangeTombstoneDecode variant carrying field name and byte offset for each decode failure - Add unit test for invalid interval (start >= end) corruption path - Update tampered-block integration test to accept new error variant Closes #26
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughDecode path for on-disk range tombstone blocks now returns structured errors: Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds structured error context for range tombstone block decoding so corruption/debugging can identify which wire-format field failed and at what offset, and updates tests to assert/accept the new error.
Changes:
- Introduce
Error::RangeTombstoneDecode { field, offset }and use it throughoutTable::decode_range_tombstones. - Add a unit test that encodes an invalid interval (
start >= end) via the production wire format and asserts the new error variant. - Update the tampered RT-block recovery integration test to accept the new error variant.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/table/mod.rs |
Replaces generic decode failures with RangeTombstoneDecode { field, offset } during RT block parsing. |
src/error.rs |
Adds the new structured error variant to the public Error enum. |
src/table/tests.rs |
Adds a new unit test covering invalid interval decoding behavior. |
tests/range_tombstone.rs |
Expands the expected error set for tampered RT-block recovery. |
… in test - Snapshot cursor.position() into local `offset` before each read so error reports the field's start byte, not the post-advance position - Replace `buf.len() as u32` with `u32::try_from().expect()` in test to get a checked conversion and drop cast_possible_truncation suppress
…rors - Test truncated start_len, end_len, seqno reads against short buffers - Test start_len and end_len exceeding remaining block data - Test empty block decodes to empty vec - Extract rt_block() and assert_rt_decode_error() test helpers
read_exact on start_buf/end_buf was unreachable after bounds validation — replace with direct slice + set_position to eliminate dead error paths
- Add #[expect(clippy::expect_used)] to rt_block() helper - Replace .expect() with match in empty-block test
…copy - Replace panicking data[pos..pos+len] with data.get().ok_or() - Backtick-escape identifiers in test helper doc strings
|
@coderabbitai re-review |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 23495 🏁 Script executed: Length of output: 8820
Finding 1 —
|
- Use pos (data start) instead of offset (field-length start) in start_buf and end_buf error variants for accurate diagnostics
|
@coderabbitai re-review |
🧩 Analysis chain🏁 Script executed: Length of output: 7845
Finding 1 —
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/table/mod.rs`:
- Around line 723-729: The interval validation error is reporting
cursor.position() (end-of-entry) instead of the entry start, making offsets
inconsistent; fix by recording the entry start offset when beginning to parse
the range tombstone (e.g., let entry_start = cursor.position() at the top of the
tombstone parsing routine) and use that saved entry_start as the offset in the
RangeTombstoneDecode error (replace offset: cursor.position() with offset:
entry_start) in the start >= end branch.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cf7dfaf6-3bae-4347-9f2a-b95836196695
📒 Files selected for processing (4)
src/error.rssrc/table/mod.rssrc/table/tests.rstests/range_tombstone.rs
Use entry_offset (start of tombstone record) instead of cursor.position() (end of record) for consistent diagnostics
…tests - Update offset doc to specify pre-read field-start semantics - Add offset assertions to truncated start_len, end_len, seqno tests
Remove unused assert_rt_decode_error wrapper and Option<u64> indirection. All decode error tests now assert both field and offset directly.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/error.rs:1
- Adding a new variant to a public
Errorenum is a semver-breaking change for downstream crates that exhaustively match onError(unless the enum is#[non_exhaustive]). If this crate has stability/semver guarantees, consider markingErroras#[non_exhaustive](or otherwise documenting this as a breaking change / bumping major version).
// Copyright (c) 2024-present, fjall-rs
…t/end Deduplicate slice extraction logic (checked_add + get + set_position) into a shared helper function called for both start and end keys.
|
@coderabbitai re-review |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 5959 🏁 Script executed: Length of output: 6945
New nit —
|
…checked_slice - Remove redundant data parameter, use cursor.get_ref() instead - Move wire-format doc block back to decode_range_tombstones
…ead_checked_slice Avoid u64→usize→u64 round-trip for error offset by capturing cursor.position() as u64 before the usize cast.
|
@coderabbitai re-review |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 4703
Finding —
|
Summary
Error::UnrecoverablewithRangeTombstoneDecode { field, offset }variant indecode_range_tombstones, preserving which field or validation failed and the pre-read byte offsetentry_offsetfor interval validation errorsread_checked_slicehelper withchecked_addoverflow protection andcursor.get_ref()for data accessstart_buf,end_buf) to wire-format names (start,end); length fields (start_len,end_len) and validation (interval) retain descriptive namesTest plan
cargo test decode_range_tombstones— 7 unit tests pass (invalid interval, truncated start_len/end_len/seqno, oversized start_len/end_len, empty block corruption)cargo test range_tombstone— all range tombstone tests passcargo clippy --lib --tests— no new errors in changed filescargo fmt -- --check— cleanCloses #26