Repository navigation
Native: run_in_transaction refuses to replay a block that already committed part of its work (P-03) - #527
Merged
Conversation
…mitted part of its work (P-03) The guard that refuses a retry after a BATCH boundary or a commit() inside the block sat in a try whose own `except ArcadeDBError: pass` swallowed the `raise` it was written to make, so the block was replayed and its durable part applied twice. Only the read of the commit-count witness may fail quietly; the raise now sits outside that try. The JVM core already refused. The new test uses a real conflict (a second thread commits to a record the block also wrote), so it runs on both wheels: red on the native wheel before this change (20 of 25 rows incremented twice after a BATCH boundary, all 25 after a commit() inside the block), green after, green on the JVM wheel. The contract is added to the run_in_transaction API doc. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
tae898
force-pushed
the
fix/p03-native-run-in-tx-partial-commit
branch
from
October 25, 2026 08:32
216bf0a to
514b225
Compare
tae898
changed the base branch from
perf/native-tx-crossings
to
native-preview
October 25, 2026 08:32
tae898
marked this pull request as ready for review
October 25, 2026 09:12
…e text) Co-Authored-By: Claude Opus 5.5 <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.
Backlog row P-03. A correctness fix for the native
run_in_transaction, based onnative-previewand independent of #522. It goes first: #522 (4 -> 3 crossings) rewrites the same lines, so #522 is rebased onto this branch and carries the fix; this PR can merge on its own and does not wait for the performance change.Bug
The native
run_in_transactionhas a guard that refuses a retry when the block already committed part of its work (a statement with aBATCH nboundary, or acommit()inside the block): the rollback cannot take that part back, so a replay applies it twice. The guard was written astry: if <commit count> != commits_at_start: raisefollowed byexcept ArcadeDBError: pass. Theraisere-raises the retryableArcadeDBErrorof the failed attempt, and theexcept ArcadeDBError: passof the sametrycatches it. The guard never fired, and the block was replayed. The JVM core (core.py) has no such handler and refuses.Reproduced
A real conflict (a second thread commits to a record the block also wrote), 25 rows at
v = 0, the block runsUPDATE R SET v = v + 1with a publishing step, then conflicts on its first attempt. Native librarynnext, before this change:v = 2sum(v)(single application: 20 or 25)UPDATE ... BATCH 10commit()+begin()inside the blockFix
Only the read of the commit-count witness may fail quietly (no witness: retry, as the JVM does). The comparison and the
raisenow sit outside thattry, so the original conflict escapes after the rollback, as on the JVM wheel. The contract is added to therun_in_transactionAPI doc.Tests
tests/test_run_in_transaction_partial_commit.pyhas no Java class and no fabricated error, so one file runs on both wheels: the two publishing steps above (single application, one attempt, the conflict raised, no transaction left open) and a block that committed nothing, which is still retried once and succeeds.Local checks
nnextlibrary),native-previewwithout this change: the two partial-commit tests fail (red), the retry-still-works test passesnnextlibrary), this branch: the new file,test_core.py,test_run_in_transaction_retry.pyandtest_interrupt_hygiene.py: 62 passed, 9 skippedwheel-main-78e97b1cff(main): the new file, 3 passed (parity, no change to the JVM side)_native/database.py: no findings🤖 Generated with Claude Code