[RLC] Case 4b — DML loses to OPTIMIZE (reverse compaction offset remap) - #11
Open
sezruby wants to merge 3 commits into
Open
[RLC] Case 4b — DML loses to OPTIMIZE (reverse compaction offset remap)#11sezruby wants to merge 3 commits into
sezruby wants to merge 3 commits into
Conversation
This was referenced Aug 3, 2026
sezruby
force-pushed
the
optimize-delete-loser
branch
from
August 3, 2026 20:21
9d06444 to
8029aaf
Compare
sezruby
force-pushed
the
optimize-delete-loser
branch
from
August 3, 2026 22:06
8029aaf to
e596626
Compare
sezruby
force-pushed
the
optimize-delete-loser
branch
2 times, most recently
from
August 4, 2026 01:16
7e30378 to
0396ab8
Compare
sezruby
force-pushed
the
optimize-dv-remap
branch
from
August 4, 2026 06:00
e9c24cd to
bf533fc
Compare
sezruby
force-pushed
the
optimize-delete-loser
branch
from
August 4, 2026 06:00
0396ab8 to
312c6b5
Compare
sezruby
force-pushed
the
optimize-dv-remap
branch
from
August 4, 2026 06:43
bf533fc to
b0412f6
Compare
sezruby
force-pushed
the
optimize-delete-loser
branch
from
August 4, 2026 06:43
312c6b5 to
77c5d8a
Compare
sezruby
force-pushed
the
optimize-dv-remap
branch
from
August 4, 2026 19:01
b0412f6 to
1009bfc
Compare
sezruby
force-pushed
the
optimize-delete-loser
branch
from
August 4, 2026 19:01
77c5d8a to
b744f31
Compare
The reverse of the forward reconcile: when a row-level DML (DELETE/UPDATE)
LOSES a commit race to a concurrent compaction OPTIMIZE that removed the
files it touched, remap the DML's deletion vector onto the winner's
compacted output instead of aborting.
- ConflictChecker.resolveReverseOptimizeConflicts reads the winner's
persisted compactedInto / compactionInfo tombstone tags (via the shared
parseOptimizeSourceComposition) and rebases the DML's new deletions onto
each compacted output by contiguous offset + live rank, tombstoning and
re-adding the output with the merged DV.
- Conservative and safe-by-abort: only a pure compaction (every removed
file referenced by an output, every output referenced, dataChange=false);
aborts if any DML-touched source is left un-remapped (e.g. a full-file
delete), if a row falls outside its source's run, or if the output bound
is exceeded.
- Gated by optimize.conflictReconciliation.reverse.enabled (internal,
default off); the flag also drives the write-time capture so the winner
persists its composition.
Stacks on the forward reconcile (optimize.conflictReconciliation.enabled).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sezruby
force-pushed
the
optimize-dv-remap
branch
from
August 4, 2026 20:20
1009bfc to
6a7985d
Compare
sezruby
force-pushed
the
optimize-delete-loser
branch
from
August 4, 2026 20:20
b744f31 to
8cb9d93
Compare
resolveReverseOptimizeConflicts remaps a losing DML's deletion vectors onto the winning OPTIMIZE's compacted output via driver-side object-store DV I/O during conflict detection, mirroring the forward direction. A failure there (unreadable/corrupt DV, transient I/O) would surface an unexpected error out of the conflict checker instead of the retryable Concurrent* exception callers expect. As in the forward direction, reconciliation is a pure optimization over the conservative abort and mutates the transaction only on the success path. Wrap the work in try/catch(NonFatal) so any DV read/merge/write failure leaves the transaction untouched and the standard file-level checks abort cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Part of the row-level-concurrency umbrella (#3) — Case 4b (reverse direction: a concurrent DML that loses to a compaction
OPTIMIZE). Full design: #7. Stacked on PR #9 (Case 4a, forward OPTIMIZE-loser); both consume the composition captured & persisted by PR #12 (write side).What
The mirror of #9's forward reconcile: a row-level DML that loses to a concurrent compaction
OPTIMIZEwhich removed the files it touched. Opt-in viaspark.databricks.delta.optimize.conflictReconciliation.reverse.enabled(internal, default off; must be on for both the OPTIMIZE and the DML sessions — it also arms the write-time capture in PR #12 so the winner persists its composition). Instead of aborting the DML,ConflictChecker.resolveReverseOptimizeConflictsreads the winning OPTIMIZE's persisted per-source composition and remaps the DML's newly-deleted rows onto the compacted output, so the DML commits.Composition it reads (from PR #12)
The winner's
compactedInto/compactionInfotombstone tags, parsed by the sharedConflictChecker.parseOptimizeSourceCompositioninto(outputPath, outputStart, liveCount)per removed source — the same parser and format #9's forward direction uses. This PR adds no write-side or tag code; the capture, the persisted format, and the parser all live in #12 / #9. Multi-run / out-of-commit / unrecognized shapes →None→ abort.Reverse mechanism
The winner
OPTIMIZEcommitsRemoveFile(F1..Fn)+AddFile(C, dataChange=false)— required to be a pure compaction (every removed source carries a composition into one of this commit's outputs, and every added output is a referenced target; otherwise abort). For each newly-deleted physical rowiof the losing DML in a removed sourceF(onlyloserDv \ loserReadDv— rows already deleted at the DML's read time were dropped fromC), computeoutputStart + liveRank(i)whereliveRank(i) = i − |read-time DV below i|, and union it intoC's deletion vector (seeded fromC's existing DV); then re-point the DML'sRemoveFile(F)at the winner's post-image (files keyed by path and DV). All-resolvable-or-abort. A pure compaction is adataChange=falserelocation, so the DML's read stays invariant to it.A DML-touched, winner-removed source that is left un-remapped (e.g. a full-file delete emitting a bare
RemoveFilewith no re-added DV'dAddFile) forces an abort rather than silently dropping the delete.Safety
Opt-in, default off, both directions. No composition tag (repartition shuffle emptied
InputFileBlockHolder, reclustering/ZORDER, a vectorized/native write backend bypassed the capture, multi-run, or an out-of-run row) → falls back to today's abort — never wrong data.Tests —
OptimizeConflictReconciliationSuiteDELETE/UPDATEloser → both commit, read-back correct; correct remap across an OPTIMIZE-time read gap; reverse-off aborts; winner-recorded-no-composition aborts; ZORDER winner aborts; a losing full-file delete that can't be remapped aborts (mixed full/partial).Green:
OptimizeConflictReconciliationSuite(21) +OptimizeConflictSuite(1) +RowLevelConcurrencySuite(9).Dependency
Stacked on #9 (Case 4a, base branch
optimize-dv-remap), which stacks on the capture/persist write side #12 (optimize-dv-remap-capture) and the same-file DV-merge PoC (Case 2 — #5 / PR #2). Combined design: #7.🤖 Generated with Claude Code