Release 2.6.0 — secondary index blobs: non-key lookups prune#24
Merged
Conversation
An index is one immutable blob per (table, column) mapping chunkId -> sorted distinct values, referenced from the manifest's table entry and re-staged copy-on-write in the same atomic commit that changes the table's chunks (plans, transactions, group-commit batches, tier-A folds all route through one maintenance hook). Queries with =/IN/range predicates on an indexed column keep only chunks whose entry can satisfy the predicate. Keying entries by immutable chunk id means an entry can only be wrong by ABSENCE, and absent chunks are always fetched — so a pre-index writer, a rebase-lost update, or a vacuumed blob degrade pruning, never results. No format bump needed; verified by an offline chaos suite comparing indexed lookups against full scans under contention, plus a planted proto-level 'old client' write. - .index() in defineSchema (auto-synced both ways at connect; create backfills from existing chunks in one commit) - CREATE INDEX [IF NOT EXISTS] [name] ON t (col) / DROP INDEX ON t (col) (one index per column, addressed by column; UNIQUE/composite rejected by name) - vacuum retains index blobs by the same reachability rule as chunks - 296 checks (group-commit 75 -> 87, sql-smoke 134 -> 143) - design doc §5/§8/§14 (roadmap complete) + all agent-facing docs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gpt-5.5 finding: the MAX sentinel string was compared as a value, so an open-ended range (WHERE col > 'z') could wrongly prune a chunk whose values sort above the sentinel — in both the new index pruning and the pre-existing zone-map check. The marker is now identity-checked (===) as 'no upper bound'; a real value equal to it merely over-fetches. +1 regression check (297 total). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last SQL-dialect roadmap item (LARVA-DESIGN.md §14) — the roadmap is now complete.
What an index is
Exactly what §14 promised: just another immutable blob committed in the same atomic swap. Per indexed column, one ULID-named blob maps
chunkId → sorted distinct non-NULL values. The manifest's table entry carries the current ref; every commit that changes the table's chunk set re-stages the blob copy-on-write (drop retired ids, add entries for new chunks) and re-points the ref in the same commit. Plans, transactions, group-commit batches, ordered-intent leader batching, and tier-A folds all route through one maintenance hook. Queries with=,IN, or range predicates on an indexed column then keep only the chunks whose entry can satisfy the predicate (binary search over the sorted values).Why no format bump
The load-bearing decision: entries are keyed by immutable chunk id, so an index entry can only ever be wrong by absence — and a chunk id missing from the map is simply always fetched. Absence is exactly what every failure mode produces:
readIndextreats 404 as "no index").Each degrades pruning; none can change results. Verified offline: a chaos suite compares indexed lookups against full scans under two-writer contention, and a planted proto-level "old client" write proves the stale-safety path.
Using it
t.text().index()— flags sync both ways at connect (performance metadata, never drift); creating one backfills from existing chunks in a single commit that re-executes if the chunk set moves underneath it.CREATE INDEX [IF NOT EXISTS] [name] ON t (col)/DROP INDEX ON t (col)— one index per column, addressed by column (a name parses and is ignored).CREATE UNIQUE INDEXand composite indexes rejected by name with the reason.Measured in the smoke suite:
WHERE total = 220on a 5-chunk table fetches 1 chunk; the offline suite shows equality/IN/range each pruning to exactly the matching chunks.Tests — 297 checks (was 275)
Docs synced: design doc §5/§8/§14 (roadmap marked complete), content/sql.mdx + api.mdx, docs/larva-for-agents.md (→ /llms.txt), quickstart agent prompt, READMEs, CLAUDE.md.
Self-review plus an independent gpt-5.5 (codex) pass focused on the absence-only safety argument. The review confirmed no path makes a present index entry wrong for its chunk id, and found one real bug, fixed with a regression test: the internal MAX sentinel for open-ended ranges was compared as a value, so
WHERE indexed_col > 'z'could wrongly prune a chunk whose values sort above the sentinel (the pre-existing zone-map check had the same latent hole). The marker is now identity-checked as "no upper bound".🤖 Generated with Claude Code