Skip to content

feat(rollout): base-table compaction (external-cron driven) - #132

Merged
beinan merged 1 commit into
lance-format:mainfrom
beinan:rollout-compaction
Jul 14, 2026
Merged

beinan merged 1 commit into
lance-format:mainfrom
beinan:rollout-compaction

Conversation

@beinan

@beinan beinan commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds base-table compaction to the rollout store. Every WAL merge (merge_own_shard) appends a fragment to the base table, so a long-lived rollout store accumulates many small fragments that slow scans. This folds them back together via Lance's compact_files, mirroring ContextStore::compact.

Follow-up to #131 (WAL cleanup + concurrency hardening).

Core (RolloutStore)

  • compact(config) — runs compact_files on the base table, reloads the handle, and tracks last_compaction / total_compactions / last_error.
  • should_compact(config) — gates on min_fragments + quiet_hours so an external scheduler can pass the same config.
  • compaction_stats() — fragment count + compaction history.
  • Uses defer_index_remap: true: the rollout base table carries a fieldless MemWAL index, and Lance's inline index remap panics on it ("An index existed with no fields"). Deferring records a fragment-reuse index and remaps lazily instead of touching the MemWAL index during the rewrite.

Server

  • POST /api/v1/rollouts/{name}/compact and GET /api/v1/rollouts/{name}/compact/stats, reusing the existing Compact* DTOs.

Distributed model (important)

Compaction rewrites the shared base table, and two concurrent Rewrite commits conflict in Lance's commit matrix (one wins, the other must redo its work). So this is meant to be driven by a single external scheduler (cron / k8s CronJob), not a per-worker background timer — unlike WAL merge, where each worker only ever touches its own shard. It is safe to run alongside worker appends / WAL merges: Append vs Rewrite is non-conflicting in Lance's matrix, so a concurrent append simply rebases on the compaction (or vice-versa).

Test plan

  • compact_reduces_fragments_and_preserves_reads — fragment count drops; all rows readable exactly once; inline artifact blobs still fetchable; stats updated
  • should_compact_respects_min_fragments
  • compact_composes_with_concurrent_wal_merge — a compaction (Rewrite) and a WAL merge (Append) from another shard run concurrently without failing or losing rows
  • Full lance-context-core (114) and lance-context-server (28) suites, cargo fmt --all --check, cargo clippy --workspace --all-targets all green

🤖 Generated with Claude Code

WAL merges append a fragment to the base table each time, so a long-lived
rollout store accumulates many small fragments. Add compaction to fold
them back together, mirroring ContextStore::compact.

- RolloutStore::compact() runs Lance compact_files on the base table,
  reloads the handle, and tracks last_compaction / total_compactions /
  last_error. should_compact(config) gates on min_fragments + quiet_hours;
  compaction_stats() reports fragment count and history.
- Uses defer_index_remap: the rollout base table carries a fieldless
  MemWAL index, and Lance's inline index remap panics on it ("An index
  existed with no fields"). Deferring records a fragment-reuse index and
  remaps lazily instead of touching the MemWAL index during the rewrite.
- Server: POST /api/v1/rollouts/{name}/compact and
  GET .../compact/stats, reusing the existing Compact* DTOs.

Distributed model: compaction rewrites the SHARED base table, and two
concurrent Rewrite commits conflict in Lance, so this is meant to be
driven by a single external scheduler (cron / k8s CronJob), NOT a
per-worker background timer — unlike WAL merge, which each worker does
only on its own shard. It is safe to run alongside worker appends /
WAL merges: Append vs Rewrite is non-conflicting in Lance's matrix.

Tests: compact reduces fragment count while conserving rows and blobs;
should_compact respects min_fragments; compact composes with a
concurrent WAL merge from another shard without failing or losing rows.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
@beinan
beinan merged commit d537c45 into lance-format:main Jul 14, 2026
9 checks passed
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