Skip to content

Native transactions: no JSON decode for a status the caller does not read - #226

Merged
tae898 merged 1 commit into
mainfrom
perf/native-tx-glue
Nov 4, 2026
Merged

tae898 merged 1 commit into
mainfrom
perf/native-tx-glue

Conversation

@tae898

@tae898 tae898 commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #225

Python only, native build. NativeDatabase.begin(), commit(), rollback() and is_transaction_active() no longer decode the arcadedb_n_tx reply with json.loads. Success, and the active bool, are read from the fixed prefix that ArcadeNative.txState writes ({"ok":true,"active":true,...). The JSON is still decoded for an error reply (so the ArcadeDBError text, .native and .java_chain are the same), for a reply with any other shape, and for the callers that read depth or commits (_transaction_stack_mark, _begin_state, _rollback_state, the unwind in run_in_transaction). begin() and rollback() also skip two wrapper frames (_begin_state and _tx/_call): five frames before, three now.

What is not changed: the crossings (the existing counts in tests/test_native_tx_crossings.py are untouched and lib.call is still the one door), the Java side, the JVM build.

New tests in tests/test_native_tx_crossings.py (native-only file, runs in the native parity run) count json.loads per operation. test_begin_commit_rollback_decode_nothing, test_is_transaction_active_decodes_nothing_and_reports_the_state and test_with_transaction_decodes_only_the_mark are the ones that prove the cut: on main's code they count 4, 5 and 3 decodes and fail (to be shown by the CI run on main, not run locally). test_a_state_reply_still_carries_depth_and_commits, test_an_error_reply_is_decoded_into_the_same_error and test_a_differently_spaced_ok_reply_is_still_read pin what must stay the same and pass on both.

Verification: not run locally (a timed study holds the laptop); the CI runs below are the evidence. Static checks done: compile, pyflakes (only the existing availability-probe imports), bandit==1.9.4 over src and tests files touched, pre-commit (black, isort).

Speed: the numbers in #225 are an untimed discovery pass, directions only. A timed one-library A/B (begin+commit, empty with db.transaction(), a 10-row insert transaction, control: a non-transactional query) is pre-registered and runs on the laptop timed lane before merge, so this stays a draft until its verdict. A further cut (fusing mark and begin, or a packed return value from a new entry) would need a Java change and is not part of this PR.

🤖 Generated with Claude Code

…read

begin(), commit(), rollback() and is_transaction_active() decoded the whole
arcadedb_n_tx reply with json.loads and went through five Python frames. Success
(and the active bool) is now read from the fixed prefix the image writes
(ArcadeNative.txState); an error reply, a reply with another shape, and the
callers that read depth or commits (the marks, run_in_transaction) still decode
it. Crossings, error texts and results are unchanged.

Closes #225

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tae898

tae898 commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator Author

Timed A/B (native wheel; arm A = main's CI native wheel, arm B = the same tree with only this PR's files, A/A control; laptop timed lane, tools/ab.py --noise, ABBA, round 0 dropped). Per-operation time, B/A median with 95% CI (below 1 = this PR is faster):

operation role B/A A/A
empty transaction (begin, commit) gating 0.738 [0.735, 0.739] 0.999 [0.994, 1.008]
begin and commit around one read gating 0.576 [0.570, 0.579] 1.001 [0.990, 1.010]
transaction inserting 10 records gating (no-harm bar 1.03) 0.986 [0.983, 0.990] 1.000 [0.997, 1.006]
query outside a transaction control 1.000 [0.995, 1.007] 1.006 [0.993, 1.015]
rollback info 0.554 [0.548, 0.561] 1.003 [0.996, 1.011]
is_transaction_active info 0.569 [0.566, 0.578] 1.007 [0.997, 1.011]
transaction inserting 1 record info 0.929 [0.926, 0.933] 1.001 [0.999, 1.002]

Clean pairs per figure: 12; every run passed its arm check, and the error-path differential (same values, states, error classes and texts on both arms) passed before the run. By the rule written before the run this is a SHIP: both gating transaction figures are below 0.90, the 10-record transaction is within its no-harm bar, and the control is flat.

The merge waits for the end of the current batch of timed studies that pin main (merging now would move their pins); the PR leaves draft at that point.

@tae898
tae898 marked this pull request as ready for review November 4, 2026 21:42
@tae898
tae898 merged commit 7b7a59d into main Nov 4, 2026
98 checks passed
@tae898
tae898 deleted the perf/native-tx-glue branch November 4, 2026 22:56
@tae898 tae898 added this to the 26.11.1 milestone Nov 5, 2026
@tae898 tae898 added native The arcadedb package (native library build) performance Speed or memory of the bindings, with a measurement labels Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

native The arcadedb package (native library build) performance Speed or memory of the bindings, with a measurement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Native transactions: begin, commit, rollback and is_transaction_active decode a JSON status the caller does not read

1 participant