fix(mem-wal): reject mismatched shard specs before epoch claim - #7949
fix(mem-wal): reject mismatched shard specs before epoch claim#7949u70b3 wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthrough
ChangesShard claim validation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (1)
rust/lance/src/dataset/mem_wal/manifest.rs-445-447 (1)
445-447: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winDocument sealed-manifest refusal in
# Errors.
claim_epochnow returns an error for sealed manifests, but this public API’s error contract only documents epoch conflicts, shard-spec conflicts, and contention. Document the sealed refusal and its no-claim effect. As per coding guidelines, “Ensure doc comments match actual semantics; distinguish mutates-in-place (&mut self) from returns-new-value behavior.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/lance/src/dataset/mem_wal/manifest.rs` around lines 445 - 447, Update the public `claim_epoch` documentation comment’s `# Errors` section to include refusal for sealed manifests and state that this path makes no claim or mutation. Keep the existing documentation for epoch conflicts, shard-spec conflicts, and contention, and accurately describe the method’s in-place `&mut self` behavior.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Other comments:
In `@rust/lance/src/dataset/mem_wal/manifest.rs`:
- Around line 445-447: Update the public `claim_epoch` documentation comment’s
`# Errors` section to include refusal for sealed manifests and state that this
path makes no claim or mutation. Keep the existing documentation for epoch
conflicts, shard-spec conflicts, and contention, and accurately describe the
method’s in-place `&mut self` behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: QUIET
Plan: Pro Plus
Run ID: eddae87c-eea7-4d35-949b-1203ad196d84
📒 Files selected for processing (1)
rust/lance/src/dataset/mem_wal/manifest.rs
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
hamersaw
left a comment
There was a problem hiding this comment.
I think this change has the right intent, but will not fix underlying issues correctly. It's meant to disallow claiming a table with a different shard_spec_id than the base table. However, Lance currently only uses 0 and 1 as valid values to not manual and automatic sharding configuration. IMO this is part of a larger discussion, we should update the shard spec configuration so that IDs are monotonically increasing. That would make this change valid.
|
Thanks, I think I understand the concern. The manifest-side equality check is only meaningful if every distinct sharding-spec revision has a unique ID. Today the public initialization path assigns It sounds like the prerequisites are:
Would you prefer that I expand this PR to implement the spec-ID lifecycle, or split the monotonic allocation/base-table validation into a prerequisite PR and rebase this change on it? |
6151ec2 to
8a49ce1
Compare
|
Following up on my previous comment: I split the prerequisite work into #8112. #8112 introduces monotonic spec-ID allocation ( The current initializer only creates the first spec, so an empty history produces spec ID Once #8112 lands, I'll rebase #7949 on top of it. #7949 will remain focused on claim-time manifest validation. |
8a49ce1 to
812fe55
Compare
The proto contract promises sharding spec ids are never reused, but the public init path hardcoded id 1 for every automatic sharding configuration, leaving distinct specs indistinguishable at shard-claim time. - add next_spec_id(): greatest id + 1, with 0 reserved as the manual-shard sentinel (MANUAL_SHARD_SPEC_ID) - reject reserved/duplicate spec ids when decoding MemWalIndexDetails - add MemWalIndexDetails::active_sharding_spec() (greatest id) - mem_wal_writer resolves an unset (0) shard_spec_id to the active spec and rejects an explicit mismatch before any shard claim Prerequisite for lance-format#7949.
812fe55 to
0f7bd7f
Compare
The proto contract promises sharding spec ids are never reused, but the public init path hardcoded id 1 for every automatic sharding configuration, leaving distinct specs indistinguishable at shard-claim time. - add next_spec_id(): greatest id + 1, with 0 reserved as the manual-shard sentinel (MANUAL_SHARD_SPEC_ID) - reject reserved/duplicate spec ids when decoding MemWalIndexDetails - add MemWalIndexDetails::active_sharding_spec() (greatest id) - mem_wal_writer resolves an unset (0) shard_spec_id to the active spec and rejects an explicit mismatch before any shard claim Prerequisite for lance-format#7949.
The proto contract promises sharding spec ids are never reused, but the public init path hardcoded id 1 for every automatic sharding configuration, leaving distinct specs indistinguishable at shard-claim time. - add next_spec_id(): greatest id + 1, with 0 reserved as the manual-shard sentinel (MANUAL_SHARD_SPEC_ID) - reject reserved/duplicate spec ids when decoding MemWalIndexDetails - add MemWalIndexDetails::active_sharding_spec() (greatest id) - mem_wal_writer resolves an unset (0) shard_spec_id to the active spec and rejects an explicit mismatch before any shard claim Prerequisite for lance-format#7949.
0f7bd7f to
dc95ea2
Compare
The proto contract promises sharding spec ids are never reused, but the public init path hardcoded id 1 for every automatic sharding configuration, leaving distinct specs indistinguishable at shard-claim time. - add next_spec_id(): greatest id + 1, with 0 reserved as the manual-shard sentinel (MANUAL_SHARD_SPEC_ID) - reject reserved/duplicate spec ids when decoding MemWalIndexDetails - add MemWalIndexDetails::active_sharding_spec() (greatest id) - mem_wal_writer resolves an unset (0) shard_spec_id to the active spec and rejects an explicit mismatch before any shard claim Prerequisite for lance-format#7949.
The proto contract promises sharding spec ids are never reused, but the public init path hardcoded id 1 for every automatic sharding configuration, leaving distinct specs indistinguishable at shard-claim time. - add next_spec_id(): greatest id + 1, with 0 reserved as the manual-shard sentinel (MANUAL_SHARD_SPEC_ID) - reject reserved/duplicate spec ids when decoding MemWalIndexDetails - add MemWalIndexDetails::active_sharding_spec() (greatest id) - mem_wal_writer resolves an unset (0) shard_spec_id to the active spec and rejects an explicit mismatch before any shard claim Prerequisite for lance-format#7949.
The proto contract promises sharding spec ids are never reused, but the public init path hardcoded id 1 for every automatic sharding configuration, leaving distinct specs indistinguishable at shard-claim time. - add next_spec_id(): greatest id + 1, with 0 reserved as the manual-shard sentinel (MANUAL_SHARD_SPEC_ID) - reject reserved/duplicate spec ids when decoding MemWalIndexDetails - add MemWalIndexDetails::active_sharding_spec() (greatest id) - mem_wal_writer resolves an unset (0) shard_spec_id to the active spec and rejects an explicit mismatch before any shard claim Prerequisite for lance-format#7949.
dc95ea2 to
f2ab822
Compare
f2ab822 to
3eaa2e5
Compare
|
Scope and dependency reset completed and force-pushed on latest I narrowed the claim to the identities current Lance code actually emits: manual This PR no longer claims that monotonic spec allocation is a prerequisite or attempts to solve future sharding revisions/activation. #8112 was separately reduced to resolving the writer's default The issue reproducer and tests now use only The existing |
fc60c80 to
27fa780
Compare
27fa780 to
87ea068
Compare
|
@hamersaw PTAL when you have a chance — the open CHANGES_REQUESTED predates the Aug 3 scope reset; the branch is current with |
796c43f to
8e5795f
Compare
|
Rebased onto latest main and resolved the conflict with #8640 (the read_latest split): the claim path now re-validates via refresh_latest() per its uncached-read invariant, and the two observing tests use latest(). All manifest tests and clippy pass locally. @hamersaw your CHANGES_REQUESTED (2026-07-27) was against the pre-2026-08-03 version. Scope has since been narrowed to an independent defensive invariant over the 0/1 identities Lance actually emits today — it no longer depends on monotonic spec-id allocation, which lives in #8112 for independent review. Could you take another look? |
|
@Xuanwo could you help review this when you have a moment? The CHANGES_REQUESTED (2026-07-27) predates the 2026-08-03 scope reset — the PR is now an independent defensive invariant over the 0/1 shard identities Lance actually emits, no longer gated on monotonic spec-id allocation (that lives in #8112). It's rebased onto current main with the #8640 conflict resolved (the claim path re-validates via |
8e5795f to
bcdf203
Compare
There was a problem hiding this comment.
✅ Gate recommendation: approve.
shard_spec_id is already an immutable manifest identity, and this change enforces it at the authoritative claim boundary before any epoch mutation and after write conflicts. It preserves sealed-shard error precedence and existing contention behavior. #8112 remains the complementary creation-side identity resolution rather than a prerequisite for this guard.
Summary
shard_spec_idthat differs from the immutable identity already stored in a shard manifest, before advancing manifest version or writer epoch0/1mismatch directions, sealed manifests, and concurrent first claimsScope
This is an independent defensive invariant over the identities Lance currently emits:
0identifies manually managed shards and1is the sole automatic sharding spec. The check does not require monotonic spec allocation and does not define revisions or activation.#8112 is complementary, not a prerequisite. It resolves a dataset writer's default
0to the current automatic spec before a fresh manifest is created; this PR prevents any caller from changing an identity once the manifest exists. Either change is independently valid and reviewable.shard_spec_id=0is an identity, not a wildcard.Fixes #7945.
Testing
cargo fmt --all -- --checkcargo test -p lance dataset::mem_wal::manifest::tests --lib -- --nocapture(14 passed)cargo clippy --all --tests --benches -- -D warningsBehavior change / rollout
Previously, a writer opening an existing shard with a mismatched
shard_spec_id(e.g. the default0opening an auto-sharded shard stored as1) was silently tolerated pastclaim_epoch. It now fails fast withInvalidInputnaming the shard id and both spec ids — this is the fix intent of #7945. Mixed manual(0)/auto(1) deployments will see the new hard error; resolving the creation-side default-0 identity is tracked in #8112.