Skip to content

fix(core): merge WAL generations across schema changes - #175

Merged
beinan merged 3 commits into
mainfrom
fix/wal-schema-backcompat
Jul 23, 2026
Merged

fix(core): merge WAL generations across schema changes#175
beinan merged 3 commits into
mainfrom
fix/wal-schema-backcompat

Conversation

@beinan

@beinan beinan commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • evolve legacy base tables to the latest additive rollout_schema() before WAL merge, adding missing nullable columns as all-null arrays
  • align flushed WAL batches to the evolved base table schema so old generations null-fill missing fields and newer generations preserve populated fields
  • reject missing required columns, type mismatches, and unknown columns instead of silently dropping data
  • preserve the existing base-first scan_one_by_id and lsm_scanner_for_source read path
  • keep legacy WAL point-lookup projections to columns guaranteed across generations; absent post-Add claim-check offloaded message field columns to rollout schema #172 fields decode as None
  • cover old base/old WAL merge, old base/new-schema value preservation, and base/WAL point lookups

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test -p lance-context-core -p lance-context-master --lib
  • cargo test -p lance-context-core --lib claim_check -- --nocapture

@beinan
beinan force-pushed the fix/wal-schema-backcompat branch from 2038efa to d0abbdd Compare July 23, 2026 01:43
@beinan
beinan force-pushed the fix/wal-schema-backcompat branch from d0abbdd to 33f8e77 Compare July 23, 2026 03:18
@beinan
beinan merged commit c8d3740 into main Jul 23, 2026
9 checks passed
beinan added a commit that referenced this pull request Jul 26, 2026
…erate drained generations (#200)

Three fixes the rollout store received but `DatagenStore` never did.
Each is latent today and becomes reachable as soon as datagen sees
concurrent or long-lived use.

## 1. Merge used the compile-time schema, not the live one

`merge_own_shard` built its append batch from `datagen_log_schema()`. A
base table written by an older binary can lack columns the current
schema has, and merging a batch built from the compile-time schema into
it **fails outright**. Now aligned via `align_batch_to_schema` — the
rollout store hit exactly this and was fixed in #175.

## 2. `Drop` swallowed the writer's close error

```rust
let _ = writer.close().await;   // before
```

A failed close leaks the writer's background tasks and, if the memtable
was still buffered, **strands rows that are durable in the WAL but never
sealed** — with no signal anywhere. Now logged, and the no-runtime path
says so too. (Rollout equivalent: #190.)

## 3. A concurrently-drained generation failed the whole lookup

`get_blob` propagated not-found when a merge drained and deleted a
generation between snapshot and open. Those rows are already in the base
table, so it now skips and falls through — as the rollout store does.

## Sharing

`align_batch_to_schema` and `is_not_found_error` become `pub(crate)` so
both stores share one implementation instead of drifting again. This
drift is the actual pattern here: all three bugs are cases where rollout
was fixed and datagen was not.

## Scope note — worth reading

I expected datagen to have the write-lock stall fixed in #199. **It does
not**, and I verified rather than assumed:

- `DatagenStore::append` is already `&mut self` (its writer is a bare
`Option<ShardWriter>`, not behind a mutex), so appends need the
exclusive lock **regardless of merge** — the read/write lock split from
#199 would buy nothing.
- `write_with_resident_writer` already retries on fence, so
`claim_epoch` fencing its own writer is handled. Restoring `claim_epoch`
leaves the new test **green**, confirming this empirically.
- Datagen is not yet wired into any server route or sweeper.

So the epoch change from #199 is deliberately **not** ported. These
three divergences are the real defects.

## Testing

New test asserts a merge does not fence the store's own resident writer,
so an append immediately after a merge still succeeds and both rows stay
readable, and a second merge still converges.

9 datagen tests pass; `clippy --all-targets -D warnings` and `cargo fmt`
clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant