feat(transaction): draft action-based transaction wire format (Transaction V2) - #7954
feat(transaction): draft action-based transaction wire format (Transaction V2)#7954wjones127 wants to merge 3 commits into
Conversation
…ction V2)
Draft the full action vocabulary for action-based transactions (Transaction
V2) directly in canonical `transaction.proto`, so it can drive the OSS-1529
squash/merge spike and the OSS-757 PMC vote.
A `UserOperation` (a new `Transaction.operation` oneof arm, field 116) is an
ordered list of `UserAction` steps, each expanding to granular `Action`
deltas. Actions record the *change* to the manifest (not a post-image), which
is what makes compound commits and branch merge fall out uniformly. Minted
identifiers (field/fragment/base ids) carry a `Local` token via a single
`Ref { committed | local }` so they relocate on merge/rebase; reference-stable
changes key off stable coordinates. Computed conflict footprints and large
derivable row-level deltas stay off the wire.
Library support is intentionally READ-side fail-closed only: a transaction
carrying a `UserOperation` is rejected on load with a clear "not supported"
error, and there is no write path, no `apply`, no translation, and no conflict
resolution yet. This keeps older writers safe (a concurrent V2 commit in the
conflict window aborts an in-flight commit rather than being silently skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedIgnore keyword(s) in the title. ⛔ Ignored keywords (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: QUIET Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 |
|
Important This PR touches the Lance format specification. Substantive changes to the format specification — the If this is a meaningful format change:
|
…tory Reorganize the action-based transaction (Transaction V2) wire draft into its own files under protos/transaction/ so the design reads clearly and the shared building blocks have a proper home: - protos/transaction/actions.proto: the V2 vocabulary (Ref, UserOperation, UserAction, Action + action messages), as top-level messages. The design rationale is summarized in an in-tree file header (deltas vs post-images, minting vs reference-stable, Ref/Local resolution, field-level schema, index segments, what stays off the wire) so it stands on its own. - protos/transaction/common.proto: UpdateMap/UpdateMapEntry and KeyExistenceFilter/ExactKeySetFilter/BloomFilter, promoted from nested Transaction messages to top-level so both the legacy operations and the V2 actions can reference them without a circular import. Wire-compatible: field numbers unchanged and none of these types are Any-packed, so the fully-qualified name change is invisible on the wire. - protos/transaction.proto moves to protos/transaction/transaction.proto and keeps only the Transaction envelope, legacy operations, and the user_operation oneof arm. Comments use block style for IDE folding. Rust references to the promoted types are repointed from pb::transaction::X to pb::X (mechanical, compiler-checked); the hand-written dataset::transaction domain types are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refinements to the Transaction V2 wire draft (protos/transaction/actions.proto), no behavior change: - AddFragment / SetDeletionFile: resolve a contradiction. AddFragment's doc implied a freshly-minted (Local) fragment could take a deletion file via SetDeletionFile, but SetDeletionFile.fragment is a committed-only uint64. Clarify that a new fragment has no deletion vector and deletions arrive in a later operation once the id is committed, and document why SetDeletionFile takes no Ref. - data_change: document the marker on every carrier (previously only on AddFragment), cross-referencing the canonical definition. Spell out its non-obvious meaning on AddIndexSegment / RemoveIndexSegment, where it refers to the indexed data rather than table rows. - AssertUniqueKeys: note that key_fields is authoritative and the embedded filter.field_ids (an artifact of the shared KeyExistenceFilter type) is ignored. - AdjustIndexCoverage: rename bare add / remove fields to add_fragments / remove_fragments for self-documentation and consistency with AddIndexSegment.covered_fragments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Drafts the wire format for action-based transactions (Transaction V2): a
UserOperationthat replaces the single legacyOperationwith an ordered list of granular, composableActiondeltas. This is the wire draft only — read-side fail-closed, no write path.Layout
The V2 vocabulary lives in its own files under
protos/transaction/:actions.proto— the V2 vocabulary (Ref,UserOperation,UserAction,Action+ the action messages), with the design rationale summarized in an in-tree file header so it stands on its own.common.proto— shared building blocks (UpdateMap,KeyExistenceFilter, …) referenced by both legacy operations and V2 actions, promoted from nestedTransactionmessages to top-level to avoid a circular import. Wire-compatible: field numbers unchanged and none areAny-packed.transaction.proto— moved into the directory; keeps theTransactionenvelope, legacy operations, and the newuser_operationoneof arm (field 116).What's in the wire format
Design principles (fully documented in
actions.proto):AddDataFile,TombstoneFieldData), so compound commits and branch merge fall out uniformly.Localtoken via a singleRefand relocate on merge/rebase; reference-stable changes key off stable coordinates and keep a post-image with a derivable delta.AddField/DropField/ identity-preservingAlterField(per-facet, so a concurrent cast and nullability change on the same field commute). No wholesaleSetSchema.AddIndexSegment/RemoveIndexSegment/AdjustIndexCoverage(a logical index is the segments sharing aname; per-segment config duplication is a pre-existing limitation this draft doesn't fix).AssertUniqueKeyscarries merge-insert's non-derivable key-existence filter as an explicit precondition.optionalfields.data_changemarkers (Delta-style, for CDC skip of compaction) and index-coverage representation carry in-treeTODOs to finalize.Library changes (minimal, fail-closed)
Read-side rejection only:
TryFrom<pb::Transaction>returnsError::NotSupportedfor aUserOperation, with a comment forbidding lenient parsing (thetry_collectcontract aborts a concurrent V2 commit rather than silently skipping it).test_user_operation_rejected_on_load.No
Operationenum variant, noapply/ translation / conflict resolution, no write path, no Cargo feature gate, no Python/Java changes.Verification
lance-table+lancebuild; new test passes;cargo fmt --allandcargo clippy -p lance-table -p lance --tests -- -D warningsclean.🤖 Generated with Claude Code