Skip to content

Unwedge dolt_commit after a refused merge in --no-commit state - #2549

Merged
timsehn merged 2 commits into
masterfrom
fix/2539-merge-refuse-wedges-commit
Sep 2, 2026
Merged

Unwedge dolt_commit after a refused merge in --no-commit state#2549
timsehn merged 2 commits into
masterfrom
fix/2539-merge-refuse-wedges-commit

Conversation

@timsehn

@timsehn timsehn commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Fixes #2539.

A session that reopens a --no-commit merge correctly refuses a second dolt_merge (uncommitted changes — commit or reset before merging). That refusal left a btree write transaction open: doltliteEnsureWriteTxnAndSavepoints starts a write from a read-only SELECT VM, and halt then skips RollbackAll. The next dolt_commit in the same session saw sqlite3_txn_state != NONE with autoCommit still 1, issued COMMIT, and failed with cannot commit - no transaction is active. A retry worked.

On autocommit, every doltliteMergeRef error after EnsureWriteTxnAndSavepoints now sqlite3RollbackAll + sqlite3CloseSavepoints. User BEGIN sessions are left alone.

test/doltlite_merge.sh covers the issue repro: refuse, then a first-try commit that is a 2-parent merge.

Co-Authored-By: Grok 4.6 noreply@x.ai

A second dolt_merge in a session that hydrated persisted --no-commit
merge state correctly refuses with uncommitted changes, but
EnsureWriteTxnAndSavepoints had already started a btree write from the
read-only SELECT VM. Halt skips RollbackAll in that case, so the
connection stays TXN_WRITE with autoCommit still 1. The next
dolt_commit then issues COMMIT and gets "cannot commit - no
transaction is active".

Rollback the autocommit write on every post-EnsureWriteTxn refusal.
The following dolt_commit then records the 2-parent merge on the first
try, matching Dolt.

Fixes #2539

Co-Authored-By: Grok 4.6 <noreply@x.ai>
@itoqa

itoqa Bot commented Sep 1, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: 549dfb4: 14 test cases ran, 14 passed ✅.

Summary

Coverage spans normal and failed merge flows, branch-history and working-data preservation, transaction and connection recovery, explicit rollback behavior, and remote update failures. It includes both happy-path business behavior and adversarial edge cases around retries, missing sources, refusals, and pending changes.

Safe to merge — all exercised behaviors passed, and the apparent pending-merge loss findings were independently determined not to reflect an actual defect or a promise of the code. No PR-attributable regressions or unresolved failures remain.

Tests run by Ito

View full run

Result Severity Type Description
General Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The finding assumes that sqlite3RollbackAll rolls the connection back past the previously sealed --no-commit merge. That is not how this backend's transaction path works: the first merge durably persists and seals its working set, the retry's write begin adopts the current catalog and VC merge metadata as its committed baseline, and rollback restores that exact baseline. The retry is reachable and…
General Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The finding's decisive premise is that the newly added RollbackAll erases the already persisted no-commit merge. The repository implements the opposite: reopen loads that working catalog and merge marker, write startup snapshots them as the rollback baseline, and rollback restores that snapshot; the subsequent commit then uses the restored merge marker for its second parent. The scenario is reacha…
General A missing-source merge showed the expected error without leaving stale merge details behind. After reopening, a valid merge completed and restored all three rows.
General A merge with a missing source showed the expected error. The same session stayed usable, showed no pending merge, and completed a later valid merge.
General A failed remote update kept the expected error message. The connection stayed usable in autocommit mode, and work made inside an explicit transaction remained until the caller rolled it back.
General Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The scenario is reachable and preserving a pending no-commit merge is an explicit PR requirement, but the finding's decisive causal premise is wrong. The refused retry starts a write transaction only after the persisted merged working set is loaded; that catalog and its merge metadata become the rollback baseline, so RollbackAll restores the merged rows and second-parent state rather than discardi…
General The missing-branch error was shown, the next query returned 99, and a valid merge completed with rows 1, 2, and 3 still present.
Merge The missing branch showed the expected error, and the next query on the same connection returned 42.
Merge Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The finding assumes that rolling back the write transaction opened by the second dolt_merge also rolls back the earlier --no-commit merge. The source establishes the opposite: the first merge is persisted and sealed, the next write transaction adopts that state as its committed baseline, and rollback restores the catalog plus merge metadata from that baseline. Therefore the claimed loss mechanism …
Merge Merging the feature branch without the no-commit option succeeded. The new head was a merge commit, and the table kept rows from both branches.
Merge A failed merge kept the unrelated row available inside the open transaction. The row disappeared only after the explicit rollback, as expected.
Rev The missing branch returned the expected error, and the next commit succeeded immediately. The new row was still present after reopening the database.
Rev A merge refused because of uncommitted changes, and the user's rollback kept the database consistent. The uncommitted row was gone after reopening, while the existing branch history stayed unchanged.
Rev A failed merge kept the new row and the modified status intact. The next commit succeeded on the first try, and both rows were still present after reopening the database.

Tip

Reply with @itoqa to send us feedback on this test run.

RollbackAll on an early dolt_merge refusal restored the still-open
write snapshot and persisted it. That wiped earlier autocommit merges
in the same connection: merge A, merge bogus, merge B left only the
pre-A working set. Error-recovery oracles then reported 1 row where
Dolt had 3 or 4.

These refusals have not mutated. sqlite3BtreeCommit ends the write so
halt is not stuck on TXN_WRITE (the #2539 wedge) without rewinding
HEAD. The fan-in bogus-name sequence keeps every successful merge.

Co-Authored-By: Grok 4.6 <noreply@x.ai>
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

DoltLite performance vs PR base

  • Baseline: 18c8964d3602366d7a544cdc590ed2970421e2fc
  • Candidate: 8be82284cf3408c54e95b921331996303b89efeb
  • Overall ratio: 0.992x
  • Gate result: PASS
  • Gates: individual > 1.50x with more than 10.00ms regression; section, suite, or overall > 1.25x with the same minimum delta
  • vc individual gate: > 2.00x with more than 50.00ms regression
  • Confirmed failed gates: none
  • Automatic retries: compositepk cleared after 2 attempts; no gate failed every time
Suite Workloads Baseline total Candidate total Ratio Result
blobpk 69 10.51s 10.47s 0.996x PASS
compositepk 69 10.65s 10.36s 0.973x PASS
int 69 9.87s 9.81s 0.993x PASS
textpk 69 10.40s 10.45s 1.005x PASS
vc 13 748.59ms 745.39ms 0.996x PASS
blobpk details
Section Test Baseline Candidate Delta Ratio Result
mem_reads oltp_point_select 32.98ms 33.07ms +83us 1.003x PASS
mem_reads oltp_range_select 12.66ms 12.56ms -98us 0.992x PASS
mem_reads oltp_sum_range 12.53ms 12.52ms -17us 0.999x PASS
mem_reads oltp_order_range 2.88ms 2.89ms +9us 1.003x PASS
mem_reads oltp_distinct_range 3.98ms 3.99ms +12us 1.003x PASS
mem_reads oltp_index_scan 5.41ms 5.44ms +27us 1.005x PASS
mem_reads select_random_points 20.13ms 20.31ms +179us 1.009x PASS
mem_reads select_random_ranges 4.55ms 4.59ms +40us 1.009x PASS
mem_reads covering_index_scan 4.23ms 4.13ms -107us 0.975x PASS
mem_reads groupby_scan 33.05ms 32.94ms -119us 0.996x PASS
mem_reads index_join 8.89ms 8.82ms -73us 0.992x PASS
mem_reads index_join_scan 5.09ms 5.04ms -47us 0.991x PASS
mem_reads types_table_scan 1.17s 1.16s -10.29ms 0.991x PASS
mem_reads table_scan 1.29s 1.28s -5.91ms 0.995x PASS
mem_reads oltp_read_only 125.67ms 126.44ms +772us 1.006x PASS
mem_writes oltp_bulk_insert 300.56ms 301.56ms +999us 1.003x PASS
mem_writes oltp_insert 33.38ms 33.12ms -257us 0.992x PASS
mem_writes oltp_update_index 121.77ms 122.32ms +552us 1.005x PASS
mem_writes oltp_update_non_index 67.35ms 66.92ms -429us 0.994x PASS
mem_writes oltp_delete_insert 91.86ms 92.35ms +497us 1.005x PASS
mem_writes oltp_write_only 51.96ms 52.24ms +279us 1.005x PASS
mem_writes types_delete_insert 45.20ms 45.44ms +242us 1.005x PASS
mem_writes oltp_read_write 127.10ms 127.37ms +267us 1.002x PASS
file_reads oltp_point_select 42.00ms 42.38ms +376us 1.009x PASS
file_reads oltp_range_select 13.66ms 13.78ms +120us 1.009x PASS
file_reads oltp_sum_range 13.99ms 14.14ms +147us 1.011x PASS
file_reads oltp_order_range 3.08ms 3.12ms +34us 1.011x PASS
file_reads oltp_distinct_range 5.02ms 4.25ms -773us 0.846x PASS
file_reads oltp_index_scan 6.46ms 6.68ms +222us 1.034x PASS
file_reads select_random_points 21.68ms 21.65ms -37us 0.998x PASS
file_reads select_random_ranges 5.67ms 5.59ms -81us 0.986x PASS
file_reads covering_index_scan 5.20ms 5.09ms -110us 0.979x PASS
file_reads groupby_scan 33.20ms 33.12ms -85us 0.997x PASS
file_reads index_join 9.33ms 9.32ms -11us 0.999x PASS
file_reads index_join_scan 5.25ms 5.19ms -60us 0.989x PASS
file_reads types_table_scan 1.15s 1.15s +940us 1.001x PASS
file_reads table_scan 1.27s 1.25s -17.73ms 0.986x PASS
file_reads oltp_read_only 138.33ms 140.81ms +2.48ms 1.018x PASS
file_writes oltp_bulk_insert 310.85ms 311.75ms +898us 1.003x PASS
file_writes oltp_insert 38.65ms 39.46ms +811us 1.021x PASS
file_writes oltp_update_index 129.54ms 131.39ms +1.86ms 1.014x PASS
file_writes oltp_update_non_index 78.03ms 77.36ms -673us 0.991x PASS
file_writes oltp_delete_insert 100.84ms 101.01ms +169us 1.002x PASS
file_writes oltp_write_only 60.05ms 60.35ms +301us 1.005x PASS
file_writes types_delete_insert 51.49ms 52.02ms +528us 1.010x PASS
file_writes oltp_read_write 131.91ms 132.59ms +688us 1.005x PASS
ac_reads oltp_point_select 40.23ms 41.29ms +1.06ms 1.026x PASS
ac_reads oltp_range_select 14.87ms 13.53ms -1.33ms 0.910x PASS
ac_reads oltp_sum_range 13.62ms 13.63ms +11us 1.001x PASS
ac_reads oltp_order_range 3.03ms 3.31ms +284us 1.094x PASS
ac_reads oltp_distinct_range 4.15ms 4.22ms +66us 1.016x PASS
ac_reads oltp_index_scan 6.28ms 6.48ms +201us 1.032x PASS
ac_reads select_random_points 21.33ms 21.10ms -238us 0.989x PASS
ac_reads select_random_ranges 5.54ms 5.56ms +23us 1.004x PASS
ac_reads covering_index_scan 5.13ms 5.04ms -95us 0.981x PASS
ac_reads groupby_scan 33.29ms 32.95ms -339us 0.990x PASS
ac_reads index_join 9.42ms 9.47ms +57us 1.006x PASS
ac_reads index_join_scan 5.26ms 5.15ms -113us 0.979x PASS
ac_reads types_table_scan 1.15s 1.15s -3.43ms 0.997x PASS
ac_reads table_scan 1.29s 1.28s -7.14ms 0.994x PASS
ac_reads oltp_read_only 141.61ms 140.64ms -973us 0.993x PASS
ac_writes oltp_bulk_insert_ac 55.67ms 55.56ms -108us 0.998x PASS
ac_writes oltp_insert_ac 73.52ms 71.78ms -1.73ms 0.976x PASS
ac_writes oltp_update_index_ac 81.38ms 83.50ms +2.11ms 1.026x PASS
ac_writes oltp_update_non_index_ac 66.75ms 65.06ms -1.69ms 0.975x PASS
ac_writes oltp_delete_insert_ac 75.79ms 74.54ms -1.24ms 0.984x PASS
ac_writes oltp_write_only_ac 72.90ms 71.73ms -1.17ms 0.984x PASS
ac_writes types_delete_insert_ac 65.98ms 65.67ms -315us 0.995x PASS
ac_writes oltp_read_write_ac 80.09ms 80.25ms +157us 1.002x PASS
compositepk details
Section Test Baseline Candidate Delta Ratio Result
mem_reads oltp_point_select 29.14ms 29.24ms +106us 1.004x PASS
mem_reads oltp_range_select 16.06ms 15.83ms -236us 0.985x PASS
mem_reads oltp_sum_range 15.05ms 15.08ms +26us 1.002x PASS
mem_reads oltp_order_range 3.02ms 3.00ms -16us 0.995x PASS
mem_reads oltp_distinct_range 3.91ms 3.91ms +3us 1.001x PASS
mem_reads oltp_index_scan 4.43ms 4.39ms -38us 0.991x PASS
mem_reads select_random_points 23.77ms 24.13ms +369us 1.016x PASS
mem_reads select_random_ranges 6.51ms 6.52ms +8us 1.001x PASS
mem_reads covering_index_scan 3.26ms 3.25ms -13us 0.996x PASS
mem_reads groupby_scan 31.91ms 31.66ms -249us 0.992x PASS
mem_reads index_join 7.85ms 7.91ms +62us 1.008x PASS
mem_reads index_join_scan 4.54ms 4.61ms +77us 1.017x PASS
mem_reads types_table_scan 955.64ms 950.54ms -5.10ms 0.995x PASS
mem_reads table_scan 1.06s 1.05s -4.78ms 0.995x PASS
mem_reads oltp_read_only 125.50ms 126.09ms +589us 1.005x PASS
mem_writes oltp_bulk_insert 255.68ms 259.82ms +4.14ms 1.016x PASS
mem_writes oltp_insert 25.90ms 25.77ms -131us 0.995x PASS
mem_writes oltp_update_index 89.16ms 89.15ms -14us 1.000x PASS
mem_writes oltp_update_non_index 55.46ms 55.95ms +491us 1.009x PASS
mem_writes oltp_delete_insert 70.33ms 70.27ms -55us 0.999x PASS
mem_writes oltp_write_only 41.52ms 41.82ms +303us 1.007x PASS
mem_writes types_delete_insert 37.25ms 37.83ms +584us 1.016x PASS
mem_writes oltp_read_write 113.35ms 114.12ms +774us 1.007x PASS
file_reads oltp_point_select 46.16ms 46.29ms +129us 1.003x PASS
file_reads oltp_range_select 17.70ms 17.66ms -39us 0.998x PASS
file_reads oltp_sum_range 16.92ms 17.08ms +161us 1.010x PASS
file_reads oltp_order_range 3.26ms 3.28ms +23us 1.007x PASS
file_reads oltp_distinct_range 4.19ms 4.17ms -19us 0.995x PASS
file_reads oltp_index_scan 6.59ms 6.61ms +14us 1.002x PASS
file_reads select_random_points 25.85ms 26.18ms +334us 1.013x PASS
file_reads select_random_ranges 8.33ms 8.29ms -36us 0.996x PASS
file_reads covering_index_scan 5.42ms 5.42ms -7us 0.999x PASS
file_reads groupby_scan 32.13ms 32.01ms -120us 0.996x PASS
file_reads index_join 9.67ms 9.67ms -1us 1.000x PASS
file_reads index_join_scan 4.93ms 5.02ms +90us 1.018x PASS
file_reads types_table_scan 952.77ms 948.04ms -4.73ms 0.995x PASS
file_reads table_scan 1.06s 1.05s -8.08ms 0.992x PASS
file_reads oltp_read_only 150.71ms 150.95ms +242us 1.002x PASS
file_writes oltp_bulk_insert 299.55ms 355.40ms +55.85ms 1.186x PASS
file_writes oltp_insert 81.90ms 39.13ms -42.77ms 0.478x PASS
file_writes oltp_update_index 190.59ms 202.92ms +12.32ms 1.065x PASS
file_writes oltp_update_non_index 102.43ms 102.33ms -106us 0.999x PASS
file_writes oltp_delete_insert 146.70ms 119.72ms -26.98ms 0.816x PASS
file_writes oltp_write_only 88.10ms 88.06ms -40us 1.000x PASS
file_writes types_delete_insert 150.44ms 116.51ms -33.93ms 0.774x PASS
file_writes oltp_read_write 203.92ms 171.49ms -32.43ms 0.841x PASS
ac_reads oltp_point_select 46.02ms 46.32ms +306us 1.007x PASS
ac_reads oltp_range_select 17.80ms 17.79ms -9us 0.999x PASS
ac_reads oltp_sum_range 16.92ms 16.97ms +49us 1.003x PASS
ac_reads oltp_order_range 3.26ms 3.28ms +20us 1.006x PASS
ac_reads oltp_distinct_range 4.18ms 4.16ms -20us 0.995x PASS
ac_reads oltp_index_scan 6.59ms 6.56ms -37us 0.994x PASS
ac_reads select_random_points 25.73ms 26.23ms +503us 1.020x PASS
ac_reads select_random_ranges 8.34ms 8.38ms +43us 1.005x PASS
ac_reads covering_index_scan 5.42ms 5.41ms -15us 0.997x PASS
ac_reads groupby_scan 32.13ms 31.89ms -240us 0.993x PASS
ac_reads index_join 9.48ms 9.71ms +224us 1.024x PASS
ac_reads index_join_scan 4.87ms 4.92ms +46us 1.009x PASS
ac_reads types_table_scan 954.79ms 949.13ms -5.66ms 0.994x PASS
ac_reads table_scan 1.06s 1.05s -5.23ms 0.995x PASS
ac_reads oltp_read_only 149.68ms 149.85ms +165us 1.001x PASS
ac_writes oltp_bulk_insert_ac 127.30ms 164.48ms +37.19ms 1.292x PASS
ac_writes oltp_insert_ac 361.82ms 294.04ms -67.78ms 0.813x PASS
ac_writes oltp_update_index_ac 159.18ms 267.91ms +108.73ms 1.683x TRANSIENT
ac_writes oltp_update_non_index_ac 214.90ms 168.49ms -46.41ms 0.784x PASS
ac_writes oltp_delete_insert_ac 248.17ms 182.50ms -65.68ms 0.735x PASS
ac_writes oltp_write_only_ac 206.42ms 153.94ms -52.48ms 0.746x PASS
ac_writes types_delete_insert_ac 238.01ms 143.97ms -94.04ms 0.605x PASS
ac_writes oltp_read_write_ac 168.49ms 154.45ms -14.04ms 0.917x PASS
int details
Section Test Baseline Candidate Delta Ratio Result
mem_reads oltp_point_select 23.96ms 24.29ms +326us 1.014x PASS
mem_reads oltp_range_select 9.73ms 9.55ms -178us 0.982x PASS
mem_reads oltp_sum_range 9.68ms 9.56ms -120us 0.988x PASS
mem_reads oltp_order_range 2.58ms 2.57ms -8us 0.997x PASS
mem_reads oltp_distinct_range 3.64ms 3.66ms +20us 1.006x PASS
mem_reads oltp_index_scan 4.33ms 4.30ms -32us 0.993x PASS
mem_reads select_random_points 10.57ms 10.75ms +185us 1.018x PASS
mem_reads select_random_ranges 3.36ms 3.35ms -16us 0.995x PASS
mem_reads covering_index_scan 3.63ms 3.60ms -24us 0.993x PASS
mem_reads groupby_scan 31.37ms 31.28ms -90us 0.997x PASS
mem_reads index_join 7.29ms 7.28ms -19us 0.997x PASS
mem_reads index_join_scan 4.08ms 4.07ms -5us 0.999x PASS
mem_reads types_table_scan 1.08s 1.07s -10.28ms 0.990x PASS
mem_reads table_scan 1.22s 1.21s -6.67ms 0.995x PASS
mem_reads oltp_read_only 102.98ms 102.06ms -919us 0.991x PASS
mem_writes oltp_bulk_insert 190.98ms 193.21ms +2.23ms 1.012x PASS
mem_writes oltp_insert 21.66ms 21.61ms -53us 0.998x PASS
mem_writes oltp_update_index 77.50ms 78.53ms +1.02ms 1.013x PASS
mem_writes oltp_update_non_index 43.79ms 44.59ms +802us 1.018x PASS
mem_writes oltp_delete_insert 59.14ms 58.77ms -375us 0.994x PASS
mem_writes oltp_write_only 35.81ms 36.00ms +185us 1.005x PASS
mem_writes types_delete_insert 29.38ms 29.12ms -262us 0.991x PASS
mem_writes oltp_read_write 89.75ms 88.71ms -1.04ms 0.988x PASS
file_reads oltp_point_select 30.71ms 30.80ms +96us 1.003x PASS
file_reads oltp_range_select 10.61ms 10.49ms -117us 0.989x PASS
file_reads oltp_sum_range 10.49ms 10.56ms +71us 1.007x PASS
file_reads oltp_order_range 2.71ms 2.71ms +0us 1.000x PASS
file_reads oltp_distinct_range 3.70ms 3.72ms +22us 1.006x PASS
file_reads oltp_index_scan 5.32ms 5.38ms +65us 1.012x PASS
file_reads select_random_points 11.61ms 11.55ms -52us 0.996x PASS
file_reads select_random_ranges 4.18ms 4.13ms -41us 0.990x PASS
file_reads covering_index_scan 4.56ms 4.54ms -19us 0.996x PASS
file_reads groupby_scan 30.84ms 30.82ms -19us 0.999x PASS
file_reads index_join 8.05ms 8.08ms +36us 1.004x PASS
file_reads index_join_scan 4.24ms 4.24ms -5us 0.999x PASS
file_reads types_table_scan 1.07s 1.07s -1.87ms 0.998x PASS
file_reads table_scan 1.20s 1.18s -11.36ms 0.990x PASS
file_reads oltp_read_only 112.18ms 111.32ms -859us 0.992x PASS
file_writes oltp_bulk_insert 243.67ms 245.74ms +2.06ms 1.008x PASS
file_writes oltp_insert 37.17ms 37.26ms +93us 1.003x PASS
file_writes oltp_update_index 140.56ms 139.50ms -1.06ms 0.992x PASS
file_writes oltp_update_non_index 97.92ms 97.03ms -890us 0.991x PASS
file_writes oltp_delete_insert 113.81ms 114.74ms +928us 1.008x PASS
file_writes oltp_write_only 83.03ms 82.25ms -778us 0.991x PASS
file_writes types_delete_insert 63.90ms 63.86ms -39us 0.999x PASS
file_writes oltp_read_write 136.21ms 136.18ms -32us 1.000x PASS
ac_reads oltp_point_select 30.62ms 30.77ms +154us 1.005x PASS
ac_reads oltp_range_select 10.67ms 10.54ms -139us 0.987x PASS
ac_reads oltp_sum_range 10.52ms 10.59ms +74us 1.007x PASS
ac_reads oltp_order_range 2.70ms 2.69ms -14us 0.995x PASS
ac_reads oltp_distinct_range 3.69ms 3.72ms +38us 1.010x PASS
ac_reads oltp_index_scan 5.38ms 5.33ms -55us 0.990x PASS
ac_reads select_random_points 11.75ms 11.64ms -107us 0.991x PASS
ac_reads select_random_ranges 4.11ms 4.10ms -10us 0.998x PASS
ac_reads covering_index_scan 4.57ms 4.49ms -82us 0.982x PASS
ac_reads groupby_scan 31.07ms 31.07ms +2us 1.000x PASS
ac_reads index_join 8.11ms 8.17ms +64us 1.008x PASS
ac_reads index_join_scan 4.26ms 4.27ms +6us 1.001x PASS
ac_reads types_table_scan 1.07s 1.05s -12.84ms 0.988x PASS
ac_reads table_scan 1.21s 1.19s -16.20ms 0.987x PASS
ac_reads oltp_read_only 113.58ms 112.73ms -850us 0.993x PASS
ac_writes oltp_bulk_insert_ac 100.66ms 93.16ms -7.51ms 0.925x PASS
ac_writes oltp_insert_ac 106.25ms 112.08ms +5.83ms 1.055x PASS
ac_writes oltp_update_index_ac 127.14ms 139.99ms +12.85ms 1.101x PASS
ac_writes oltp_update_non_index_ac 99.69ms 99.18ms -509us 0.995x PASS
ac_writes oltp_delete_insert_ac 113.37ms 99.72ms -13.66ms 0.880x PASS
ac_writes oltp_write_only_ac 100.54ms 104.12ms +3.59ms 1.036x PASS
ac_writes types_delete_insert_ac 109.58ms 101.74ms -7.84ms 0.928x PASS
ac_writes oltp_read_write_ac 119.23ms 118.17ms -1.05ms 0.991x PASS
textpk details
Section Test Baseline Candidate Delta Ratio Result
mem_reads oltp_point_select 26.92ms 26.96ms +39us 1.001x PASS
mem_reads oltp_range_select 10.74ms 10.53ms -211us 0.980x PASS
mem_reads oltp_sum_range 10.51ms 10.83ms +323us 1.031x PASS
mem_reads oltp_order_range 2.57ms 2.53ms -39us 0.985x PASS
mem_reads oltp_distinct_range 3.57ms 3.52ms -49us 0.986x PASS
mem_reads oltp_index_scan 4.50ms 4.49ms -7us 0.998x PASS
mem_reads select_random_points 17.33ms 17.25ms -74us 0.996x PASS
mem_reads select_random_ranges 4.06ms 4.10ms +38us 1.009x PASS
mem_reads covering_index_scan 3.44ms 3.46ms +16us 1.005x PASS
mem_reads groupby_scan 29.22ms 28.95ms -273us 0.991x PASS
mem_reads index_join 7.27ms 7.35ms +87us 1.012x PASS
mem_reads index_join_scan 4.78ms 4.70ms -85us 0.982x PASS
mem_reads types_table_scan 995.06ms 986.61ms -8.46ms 0.992x PASS
mem_reads table_scan 1.12s 1.10s -18.95ms 0.983x PASS
mem_reads oltp_read_only 107.12ms 106.02ms -1.10ms 0.990x PASS
mem_writes oltp_bulk_insert 253.88ms 255.52ms +1.64ms 1.006x PASS
mem_writes oltp_insert 27.82ms 28.63ms +814us 1.029x PASS
mem_writes oltp_update_index 103.48ms 107.20ms +3.72ms 1.036x PASS
mem_writes oltp_update_non_index 60.21ms 58.41ms -1.80ms 0.970x PASS
mem_writes oltp_delete_insert 76.38ms 77.63ms +1.25ms 1.016x PASS
mem_writes oltp_write_only 43.55ms 43.92ms +375us 1.009x PASS
mem_writes types_delete_insert 38.29ms 38.03ms -260us 0.993x PASS
mem_writes oltp_read_write 105.41ms 104.97ms -440us 0.996x PASS
file_reads oltp_point_select 34.22ms 33.88ms -345us 0.990x PASS
file_reads oltp_range_select 11.56ms 11.58ms +20us 1.002x PASS
file_reads oltp_sum_range 11.49ms 11.54ms +51us 1.004x PASS
file_reads oltp_order_range 2.70ms 2.67ms -27us 0.990x PASS
file_reads oltp_distinct_range 3.58ms 3.66ms +76us 1.021x PASS
file_reads oltp_index_scan 5.61ms 5.52ms -91us 0.984x PASS
file_reads select_random_points 19.43ms 18.73ms -701us 0.964x PASS
file_reads select_random_ranges 4.86ms 4.99ms +122us 1.025x PASS
file_reads covering_index_scan 4.36ms 4.44ms +76us 1.017x PASS
file_reads groupby_scan 29.98ms 29.38ms -603us 0.980x PASS
file_reads index_join 8.85ms 8.76ms -86us 0.990x PASS
file_reads index_join_scan 5.11ms 5.01ms -94us 0.982x PASS
file_reads types_table_scan 1.00s 994.10ms -8.55ms 0.991x PASS
file_reads table_scan 1.10s 1.09s -9.01ms 0.992x PASS
file_reads oltp_read_only 114.15ms 114.40ms +244us 1.002x PASS
file_writes oltp_bulk_insert 318.66ms 320.20ms +1.54ms 1.005x PASS
file_writes oltp_insert 53.17ms 53.54ms +369us 1.007x PASS
file_writes oltp_update_index 185.81ms 188.05ms +2.23ms 1.012x PASS
file_writes oltp_update_non_index 118.56ms 118.78ms +222us 1.002x PASS
file_writes oltp_delete_insert 141.49ms 148.06ms +6.58ms 1.046x PASS
file_writes oltp_write_only 102.50ms 103.27ms +768us 1.007x PASS
file_writes types_delete_insert 70.43ms 71.27ms +844us 1.012x PASS
file_writes oltp_read_write 159.17ms 191.45ms +32.28ms 1.203x PASS
ac_reads oltp_point_select 33.84ms 33.97ms +126us 1.004x PASS
ac_reads oltp_range_select 11.50ms 11.50ms +1us 1.000x PASS
ac_reads oltp_sum_range 11.37ms 11.37ms -1us 1.000x PASS
ac_reads oltp_order_range 2.72ms 2.72ms +4us 1.001x PASS
ac_reads oltp_distinct_range 3.61ms 3.61ms -1us 1.000x PASS
ac_reads oltp_index_scan 5.61ms 5.57ms -43us 0.992x PASS
ac_reads select_random_points 18.48ms 18.43ms -50us 0.997x PASS
ac_reads select_random_ranges 4.89ms 4.82ms -68us 0.986x PASS
ac_reads covering_index_scan 4.46ms 4.44ms -16us 0.996x PASS
ac_reads groupby_scan 29.61ms 29.23ms -383us 0.987x PASS
ac_reads index_join 8.71ms 8.73ms +18us 1.002x PASS
ac_reads index_join_scan 5.20ms 4.95ms -253us 0.951x PASS
ac_reads types_table_scan 987.07ms 977.53ms -9.54ms 0.990x PASS
ac_reads table_scan 1.09s 1.09s -3.44ms 0.997x PASS
ac_reads oltp_read_only 113.39ms 112.84ms -550us 0.995x PASS
ac_writes oltp_bulk_insert_ac 112.63ms 147.84ms +35.21ms 1.313x PASS
ac_writes oltp_insert_ac 321.27ms 282.08ms -39.19ms 0.878x PASS
ac_writes oltp_update_index_ac 183.08ms 151.24ms -31.84ms 0.826x PASS
ac_writes oltp_update_non_index_ac 113.37ms 161.62ms +48.25ms 1.426x PASS
ac_writes oltp_delete_insert_ac 144.24ms 136.83ms -7.41ms 0.949x PASS
ac_writes oltp_write_only_ac 177.97ms 197.52ms +19.56ms 1.110x PASS
ac_writes types_delete_insert_ac 207.71ms 273.33ms +65.62ms 1.316x PASS
ac_writes oltp_read_write_ac 243.65ms 215.44ms -28.21ms 0.884x PASS
vc details
Section Test Baseline Candidate Delta Ratio Result
vc status_clean_many_tables 83.50ms 83.41ms -89us 0.999x PASS
vc status_dirty_many_tables 87.56ms 86.37ms -1.19ms 0.986x PASS
vc diff_regular_working_one_table 78.50ms 78.60ms +102us 1.001x PASS
vc diff_regular_working_many_tables 92.06ms 91.92ms -148us 0.998x PASS
vc diff_stat_working_many_tables 92.26ms 91.65ms -609us 0.993x PASS
vc diff_schema_working_many_tables 91.62ms 91.69ms +69us 1.001x PASS
vc branch_list_many_branches 23.48ms 23.17ms -314us 0.987x PASS
vc branch_create_delete 25.57ms 25.59ms +19us 1.001x PASS
vc checkout_branch_clean 56.59ms 56.76ms +162us 1.003x PASS
vc merge_data_no_conflicts 29.48ms 29.18ms -302us 0.990x PASS
vc merge_schema_no_conflicts 22.42ms 22.50ms +82us 1.004x PASS
vc merge_data_conflicts 32.88ms 32.32ms -559us 0.983x PASS
vc merge_data_conflicts_with_resolve 32.67ms 32.23ms -434us 0.987x PASS

All relative performance gates passed.

@itoqa

itoqa Bot commented Sep 1, 2026

Copy link
Copy Markdown

Ito QA test results
Ito Diff Report549dfb46107206: 14 test cases ran, 14 passing ✅.

Diff Summary

Coverage focused on database merge and transaction behavior, including successful merges, missing or refused sources, dirty working data, rollback and savepoints, repeated recovery attempts, persistence after reopening, and concurrent access. These scenarios exercise normal workflows as well as adversarial and edge-case handling around data safety, transaction ownership, and recovery.

Safe to merge — the exercised behaviors are healthy, with no PR-attributable regressions, new failures, or previously flagged failures still failing. The untested previously passing cases are coverage gaps rather than merge blockers, so they are flag-for-later observations.

Tests run by Ito

View full run

Result State Severity Type Description
Passing General After a valid branch merge and a missing-source refusal, the table still showed rows 0 and 1 before commit and after reopening the database.
Passing General After the merge was refused, rolling back to the caller's savepoint removed the later unwanted row and kept the intended row. The commit and reopen checks matched the expected data.
Passing General A merge refused the dirty working state, then a clean retry succeeded. Reopening the database showed only the intended rows 0 and 1, with no extra row left behind.
Passing General After the merge was refused, the caller rolled back its pending row and then committed a later row successfully.
Passing General After a refused merge was rolled back, a later merge completed and its rows were saved successfully. The saved rows were still present after the database was reopened.
Passing General Two connections handled the concurrent merge safely: one reported the expected database lock, while the other committed successfully. After reopening, both connections showed rows 1, 2, and 3, with no false transaction error.
Passing Commit The merge was refused because the working changes were not committed, as expected. The next commit succeeded on the first try and kept all three rows intact.
Passing Merge Two invalid merge requests were refused, but the earlier merge stayed in place and the later merge succeeded. The table still contained rows 0, 1, and 2.
Passing Merge The first branch merge succeeded, the missing branch was refused, and the next merge still succeeded. The table kept rows 0, 1, and 2.
Passing Rev The missing branch returned the expected error. The next merge succeeded immediately, and both rows were still present after the database was reopened.
Passing Rev A merge refused because of unsaved changes left the new row and its pending-change status intact. Reopening the database showed no merge in progress and no extra commit.
Passing Rev The database recovered from missing and refused merges, then completed both valid merges on the first try. All three rows and the two-parent merge history were still present after reopening the database.
Passing Transaction After the merge was refused, the caller could abort the merge and complete COMMIT itself. The existing MAIN value stayed intact.
Passing Transaction After the merge was refused, the caller could roll back to its savepoint, release it, and commit successfully. The main value remained unchanged.
⏸️ Skipped General Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The finding assumes that sqlite3RollbackAll rolls the connection back past the previously sealed --no-commit merge. That is not how this backend's transaction path works: the first merge durably persists and seals its working set, the retry's write begin adopts the current catalog and VC merge metadata as its committed baseline, and rollback restores that exact baseline. The retry is reachable and…
⏸️ Skipped General Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The finding's decisive premise is that the newly added RollbackAll erases the already persisted no-commit merge. The repository implements the opposite: reopen loads that working catalog and merge marker, write startup snapshots them as the rollback baseline, and rollback restores that snapshot; the subsequent commit then uses the restored merge marker for its second parent. The scenario is reacha…
⏸️ Skipped General A missing-source merge showed the expected error without leaving stale merge details behind. After reopening, a valid merge completed and restored all three rows.
⏸️ Skipped General A merge with a missing source showed the expected error. The same session stayed usable, showed no pending merge, and completed a later valid merge.
⏸️ Skipped General A failed remote update kept the expected error message. The connection stayed usable in autocommit mode, and work made inside an explicit transaction remained until the caller rolled it back.
⏸️ Skipped General Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The scenario is reachable and preserving a pending no-commit merge is an explicit PR requirement, but the finding's decisive causal premise is wrong. The refused retry starts a write transaction only after the persisted merged working set is loaded; that catalog and its merge metadata become the rollback baseline, so RollbackAll restores the merged rows and second-parent state rather than discardi…
⏸️ Skipped General The missing-branch error was shown, the next query returned 99, and a valid merge completed with rows 1, 2, and 3 still present.
⏸️ Skipped Merge The missing branch showed the expected error, and the next query on the same connection returned 42.
⏸️ Skipped Merge Verified acceptable by independent adversarial review: the reported expectation does not match what the code actually promises. Review notes: The finding assumes that rolling back the write transaction opened by the second dolt_merge also rolls back the earlier --no-commit merge. The source establishes the opposite: the first merge is persisted and sealed, the next write transaction adopts that state as its committed baseline, and rollback restores the catalog plus merge metadata from that baseline. Therefore the claimed loss mechanism …
⏸️ Skipped Merge Merging the feature branch without the no-commit option succeeded. The new head was a merge commit, and the table kept rows from both branches.
⏸️ Skipped Merge A failed merge kept the unrelated row available inside the open transaction. The row disappeared only after the explicit rollback, as expected.
⏸️ Skipped Rev The missing branch returned the expected error, and the next commit succeeded immediately. The new row was still present after reopening the database.
⏸️ Skipped Rev A merge refused because of uncommitted changes, and the user's rollback kept the database consistent. The uncommitted row was gone after reopening, while the existing branch history stayed unchanged.
⏸️ Skipped Rev A failed merge kept the new row and the modified status intact. The next commit succeeded on the first try, and both rows were still present after reopening the database.

Tip

Reply with @itoqa to send us feedback on this test run.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

DoltLite source coverage

Metric Covered Total Coverage
Lines 53598 62995 85.08%
Branches 24801 36576 67.81%
Functions 2509 2721 92.21%

Merged 202 pooled raw profiles from the distributed Linux correctness jobs.

Per-file coverage (98 files)
File Lines Branches Functions
src/btree_orig_api.c 87.91% 77.27% 89.53%
src/chunk_file.c 100.00% 100.00% 100.00%
src/chunk_index.c 84.27% 66.78% 100.00%
src/chunk_refs.c 84.99% 69.17% 79.37%
src/chunk_staging.c 93.75% 81.15% 100.00%
src/chunk_store.c 91.11% 75.34% 100.00%
src/chunk_store_commit.c 86.75% 67.23% 100.00%
src/chunk_store_lock.c 88.69% 71.00% 100.00%
src/chunk_store_refs_api.c 91.17% 76.75% 100.00%
src/chunk_wal.c 82.48% 58.70% 87.50%
src/doltlite.c 100.00% 100.00% 100.00%
src/doltlite_add.c 85.95% 69.53% 100.00%
src/doltlite_ancestor.c 89.19% 68.92% 100.00%
src/doltlite_at.c 83.39% 64.20% 100.00%
src/doltlite_blame.c 80.86% 61.14% 96.43%
src/doltlite_branch.c 88.30% 80.66% 100.00%
src/doltlite_branches.c 93.75% 75.93% 93.75%
src/doltlite_checkout.c 77.57% 63.06% 96.43%
src/doltlite_cherry_pick.c 79.00% 59.57% 71.43%
src/doltlite_chunk_walk.c 92.23% 66.22% 100.00%
src/doltlite_clean.c 94.23% 68.10% 100.00%
src/doltlite_cmd.c 81.09% 75.19% 100.00%
src/doltlite_commit.c 94.41% 76.87% 100.00%
src/doltlite_commit_ancestors.c 92.09% 72.83% 92.31%
src/doltlite_commit_cmd.c 78.08% 67.50% 100.00%
src/doltlite_config.c 80.47% 71.74% 100.00%
src/doltlite_conflicts.c 84.27% 62.50% 93.75%
src/doltlite_constraint_violations.c 82.46% 57.54% 91.11%
src/doltlite_core.c 91.34% 70.81% 100.00%
src/doltlite_creds.c 84.09% 53.78% 92.00%
src/doltlite_dbpage.c 93.45% 78.33% 91.67%
src/doltlite_diff.c 88.56% 68.99% 96.55%
src/doltlite_diff_stat.c 94.17% 76.01% 95.65%
src/doltlite_diff_table.c 94.18% 70.74% 97.06%
src/doltlite_docs.c 83.94% 71.43% 94.74%
src/doltlite_gc.c 78.48% 58.10% 96.55%
src/doltlite_hashof.c 79.79% 70.05% 100.00%
src/doltlite_history.c 86.93% 76.40% 100.00%
src/doltlite_http_remote.c 82.22% 57.34% 92.31%
src/doltlite_ignore.c 77.57% 62.25% 82.14%
src/doltlite_log.c 96.81% 73.24% 92.86%
src/doltlite_merge.c 95.93% 70.46% 100.00%
src/doltlite_merge_cmd.c 87.39% 72.36% 100.00%
src/doltlite_merge_constraints.c 86.15% 63.64% 95.00%
src/doltlite_merge_constraints_check.c 86.81% 67.79% 100.00%
src/doltlite_merge_constraints_fk.c 78.00% 56.64% 100.00%
src/doltlite_merge_constraints_notnull.c 80.45% 67.92% 100.00%
src/doltlite_merge_constraints_strict.c 77.35% 63.04% 100.00%
src/doltlite_merge_constraints_unique.c 85.99% 62.82% 100.00%
src/doltlite_merge_pass1.c 92.94% 74.16% 100.00%
src/doltlite_merge_pass2.c 83.59% 67.46% 100.00%
src/doltlite_merge_predetect.c 86.38% 71.15% 95.45%
src/doltlite_merge_rebuild.c 99.15% 78.91% 100.00%
src/doltlite_merge_rows.c 82.93% 64.74% 100.00%
src/doltlite_merge_schema.c 90.95% 71.94% 97.06%
src/doltlite_merge_status.c 91.98% 73.53% 92.31%
src/doltlite_patch.c 94.36% 70.71% 98.15%
src/doltlite_rebase.c 85.42% 59.55% 100.00%
src/doltlite_record.c 78.67% 59.36% 95.24%
src/doltlite_ref.c 95.52% 75.36% 100.00%
src/doltlite_remote.c 85.61% 66.89% 96.00%
src/doltlite_remote_sql.c 66.60% 60.73% 93.55%
src/doltlite_remotesrv.c 75.76% 64.75% 90.77%
src/doltlite_reset.c 87.48% 72.76% 100.00%
src/doltlite_revert.c 80.51% 69.44% 100.00%
src/doltlite_schema_diff.c 94.42% 71.13% 96.97%
src/doltlite_schemas.c 70.86% 48.75% 90.91%
src/doltlite_status.c 91.49% 72.78% 97.56%
src/doltlite_tag.c 86.84% 70.31% 94.12%
src/doltlite_tests.c 84.22% 69.61% 91.11%
src/doltlite_tls.c 85.04% 61.82% 92.31%
src/doltlite_verify_constraints.c 79.15% 66.44% 100.00%
src/doltlite_workspace.c 91.84% 70.27% 100.00%
src/pager_shim.c 58.87% 67.46% 34.29%
src/prolly_btree.c 86.00% 66.45% 90.70%
src/prolly_btree_catalog.c 83.10% 69.11% 97.22%
src/prolly_btree_cursor.c 84.15% 62.09% 96.00%
src/prolly_btree_cursor_count.c 80.05% 56.74% 100.00%
src/prolly_btree_cursor_payload.c 75.69% 54.48% 95.65%
src/prolly_btree_cursor_seek.c 76.68% 66.20% 82.35%
src/prolly_btree_mutation.c 87.89% 68.20% 97.83%
src/prolly_btree_orig.c 93.75% 71.43% 93.15%
src/prolly_btree_state.c 93.51% 66.38% 100.00%
src/prolly_btree_txn.c 81.84% 69.30% 98.08%
src/prolly_cache.c 93.27% 69.12% 100.00%
src/prolly_check.c 60.36% 62.96% 100.00%
src/prolly_chunker.c 94.04% 78.38% 100.00%
src/prolly_cursor.c 89.67% 80.47% 100.00%
src/prolly_diff.c 59.59% 46.05% 71.43%
src/prolly_hash.c 93.33% 80.00% 100.00%
src/prolly_hashset.c 90.48% 80.56% 100.00%
src/prolly_mutate.c 80.78% 69.11% 100.00%
src/prolly_mutmap.c 93.87% 80.34% 100.00%
src/prolly_node.c 88.91% 73.81% 100.00%
src/prolly_three_way_diff.c 95.79% 85.37% 100.00%
src/prolly_three_way_merge.c 81.92% 67.41% 91.67%
src/prolly_xxhash.c 100.00% 100.00% 100.00%
src/sortkey.c 93.16% 81.51% 100.00%

Download HTML and LCOV artifacts from this workflow run.

@timsehn
timsehn merged commit 32a9a13 into master Sep 2, 2026
68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refused dolt_merge in a session with persisted --no-commit merge state wedges the next dolt_commit

1 participant