Conversation
e952b51 to
f5faf25
Compare
b2491b6 to
e1b6002
Compare
|
Important Format specification voteThis PR modifies the Lance format specification, so it requires 3 binding +1 votes from PMC members (excluding the proposer) and a minimum 72-hour voting period, weekends excluded, before it can merge. Vote by approving this PR (+1) or requesting changes (−1, a veto). See the voting process. Status: ❌ Blocked — 0 of 3 required approvals
Updated automatically by the format-spec vote gate, which re-checks every 15 minutes — just voted? Re-check now (press Run workflow; leave the input blank to re-check every open format PR). A PMC member may apply the |
e1b6002 to
cda87e8
Compare
Reserve every negative field id for system columns and give each of a fragment's three row lineage sequences -- row ids (field -3), created-at versions (-4) and last-updated-at versions (-5) -- a DataFile arm on its DataFragment oneof, so a sequence too large to keep inline can live as a hidden uint64 column of a Lance data file. Placement follows when a value is known: sequences the commit assigns stay inline where a conflict retry can rewrite them; sequences carried over from existing rows may go to a data file. The new feature flag takes bit 11, above FLAG_UNKNOWN like the tagged FRI flag, so every released build refuses such a dataset; this build understands it in debug builds or with LANCE_ENABLE_UNSTABLE_SPILLED_ROW_LINEAGE=1. Readers skip any negative id in a data file's fields so the columns may share the fragment's main data file. Nothing writes the columns yet. Reading one is refused with NotSupported rather than falling back to defaults, which is what the readers and the commit-time lineage paths did for the never-written external arms. Co-authored-by: Will Jones <willjones127@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
cda87e8 to
99bc517
Compare
|
Addressed the three gatekeeper points, here and in the stack:
The rest of the stack (#9336 through #9340, plus the new #9347, which writes compaction's spilled columns into the fragment's own data file) is rebased on this representation. |
There was a problem hiding this comment.
✅ Gate recommendation: approve.
3 fixed. The follow-up is borne out by the current head: DataFragment.files is the single carrier authority, the hidden columns have an executable non-nullable uint64 schema with exact row-count and corruption semantics, and the marker is V2-only while V1 writers remain inline. The feature flag fences unsupported readers and writers.
First of a stack for §5.3 of the Stable Row ID GA design (#8931, tracked as #9250): let a fragment's row lineage sequences -- its row ids and its created-at and last-updated-at versions -- leave the manifest and live as hidden
uint64columns of a Lance data file. This PR defines the format; the stack continues with readers and the spill primitives, then compaction, the commit read-ahead, the update path, and compaction writing the columns into its own output files.Builds on the prototype in #8953 (Will is co-author).
Stack
Problem
Each sequence is stored inline in the fragment's manifest entry. An appended fragment's sequences are single runs and cost a few dozen bytes, but once compaction merges fragments whose rows came from many places the row id sequence degrades to 4-8 bytes per row and the version sequences to a run per row. The manifest then grows with the table's row count and every commit rewrites all of it (#8621).
Format
fields.-1and-2keep their meaning;-3,-4,-5are the hidden_rowid,_row_created_at_versionand_row_last_updated_at_versioncolumns.DataFragmentgains an emptyRowLineageColumnmarker arm on each lineage oneof:column_row_ids = 12,column_last_updated_at_versions = 13,column_created_at_versions = 14. The marker carries no file reference: the column lives in one of the fragment'sfiles, the single entry whosefieldscarry the reserved id, and itscolumn_indiceslocates it like a user column. Zero or several carriers is corruption. The three sequences may share one file with each other or with the fragment's user data.uint64fields, each holding exactlyphysical_rowsvalues in physical row order. A null or a length mismatch is corruption and is rejected, never defaulted.DataFilehas nocolumn_indicesto locate the column, and a fragment cannot mix v1 and v2 files. A writer on a v1 dataset leaves every sequence inline.FLAG_UNSTABLE_SPILLED_ROW_LINEAGE = 1 << 11(bit 9 is reserved, bit 10 is the tagged FRI flag from feat(format): define a unified tagged fragment reuse history #9136), aboveFLAG_UNKNOWNthe way that flag is. Every released build (v11.0.0 boundary 256, v12/v13 pre-releases 512) already refuses such a dataset. Like data overlay files, release builds understand the bit only withLANCE_ENABLE_UNSTABLE_SPILLED_ROW_LINEAGE=1; debug builds always do.external_*arms are untouched.Placement rule, which the writers in later PRs follow: a value the commit assigns -- an appended fragment's row ids, an inserted row's created-at, every row's last-updated-at -- can change when a commit conflict is retried, so it stays inline where the retry can rewrite it. A value carried over from existing rows is fixed before the commit and may go to a data file.
Code
RowIdMeta::ColumnandRowDatasetVersionMeta::Columnunit variants, with proto and JSON round trips and manifest interning.Fragment::row_lineage_file(field_id)finds the carrier amongfilesand reports more than one as corruption. Because the carrier is an ordinary entry offiles, cleanup, shallow-clonebase_idrewriting, file listing and validation already cover it; validation skips the negative ids in a file'sfields.apply_feature_flagssets the flag when any fragment uses a column arm.NotSupportedinstead of falling back to defaults.RowDatasetVersionMeta::load_sequencedoes the same for the external arm instead oftodo!().assign_row_idstreats a spilled sequence as covering every physical row, as it always does.Validation
cargo test -p lance-tablecargo test -p lance --lib -- rowid row_version stable_row optimize::tests dataset_transactions fragment::tests feature_flag update::tests merge_insert::tests dataset_iocargo clippy --all --tests --benches -- -D warnings,cargo fmt --allcargo check --manifest-path python/Cargo.toml,cargo check --manifest-path java/lance-jni/Cargo.tomlRefs #8931, #9250
🤖 Generated with Claude Code