Skip to content

Remote round-trip oracle coverage for schema objects#1667

Merged
timsehn merged 1 commit into
masterfrom
test/remotes-oracle-schema-objects
Jul 17, 2026
Merged

Remote round-trip oracle coverage for schema objects#1667
timsehn merged 1 commit into
masterfrom
test/remotes-oracle-schema-objects

Conversation

@timsehn

@timsehn timsehn commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Continues the schema-objects × VC oracle campaign (#1657 add, #1663 merge, #1665 checkout, #1666 revert/cherry-pick). Fills the remotes gap.

Coverage added (9 scenarios, live Dolt over file remotes)

  • Clone: a repo with a view + index arrives with the view queryable and the index present; a cloned trigger fires on the consumer's first insert.
  • Fast-forward pull: later commits adding a view, an index (usable over pulled data), or a trigger (fires post-pull) all land in the consumer.
  • Pull merge (non-ff): remote view add over a local data commit merges cleanly with both preserved; remote view drop propagates; both sides dropped stays dropped through the pull-merge path (the Merge oracle coverage for schema objects; fix both-drop resurrection #1663 resurrection chokepoint exercised via dolt_pull).
  • Dirty working set: both systems refuse the pull ("cannot pull/merge with uncommitted changes") and deliver nothing.
  • Trigger scenarios run per-dialect scripts via a remote_flow_dual variant of the existing seed→clone→advance→consume harness.

No engine changes

All scenarios pass on master — probing found full parity across clone/push/pull with schema objects (one probe initially looked like a pull bug but was my own dirty-working-set setup error; the refusal itself matches Dolt and is now pinned as a scenario).

Suite total: 29/29. Siblings green: remotes oracle 34/34, push-default-branch 19/19, remotesrv HTTP 28/28.

🤖 Generated with Claude Code

Nine scenarios against live Dolt over file remotes: clone carrying
views, triggers, and indexes (trigger fires on the consumer, index
queries work), fast-forward pulls delivering later view/index/trigger
commits, non-fast-forward pull merges adding and dropping views over
local commits, both-sides-dropped views staying dropped through a pull
merge, and a dirty working set refusing the pull on both systems.
Trigger bodies run per-system scripts via a dual variant of the
remote_flow harness.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Version-Control Performance Ceilings

Runs: median of 3 executions per benchmark, excluding fixture setup. The
working-set fixtures use 800 committed tables with 125 rows each
(100000 rows total); data-dirty cases update 1 row in 40
tables, and schema-dirty cases update 1 row plus add a column in 20 tables.
Branch tests use 300 branches, checkout uses a clean 400-table
branch switch over 100000 rows, and merge
tests use 100000-row tables with 2000 changed or conflicting
rows per side.

Benchmark Median ms Ceiling ms Result
status_clean_many_tables 81 200 PASS
status_dirty_many_tables 84 200 PASS
diff_regular_working_one_table 77 150 PASS
diff_regular_working_many_tables 90 200 PASS
diff_stat_working_many_tables 89 200 PASS
diff_schema_working_many_tables 89 200 PASS
branch_list_many_branches 21 100 PASS
branch_create_delete 24 100 PASS
checkout_branch_clean 54 200 PASS
merge_data_no_conflicts 28 150 PASS
merge_schema_no_conflicts 21 100 PASS
merge_data_conflicts 125 250 PASS
merge_data_conflicts_with_resolve 125 250 PASS

@github-actions

Copy link
Copy Markdown

Sysbench-Style Benchmark: Doltlite vs SQLite

In-Memory

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 22,412 28,581 1.28
oltp_range_select 8,952 12,553 1.40
oltp_sum_range 8,564 12,009 1.40
oltp_order_range 2,363 2,865 1.21
oltp_distinct_range 3,369 3,992 1.18
oltp_index_scan 3,637 5,176 1.42
select_random_points 8,557 10,621 1.24
select_random_ranges 2,704 3,878 1.43
covering_index_scan 4,147 4,091 0.99
groupby_scan 29,017 34,229 1.18
index_join 5,766 7,888 1.37
index_join_scan 3,047 4,362 1.43
types_table_scan 1,056,240 1,252,512 1.19
table_scan 1,174,628 1,345,592 1.15
oltp_read_only 97,036 120,617 1.24
Average 1.27

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 181,768 256,592 1.41
oltp_insert 15,475 28,663 1.85
oltp_update_index 48,200 87,452 1.81
oltp_update_non_index 31,988 57,520 1.80
oltp_delete_insert 42,753 70,526 1.65
oltp_write_only 20,451 43,818 2.14
types_delete_insert 23,314 39,467 1.69
oltp_read_write 63,854 106,555 1.67
Average 1.75

File-Backed

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 91,001 52,705 0.58
oltp_range_select 16,329 15,189 0.93
oltp_sum_range 15,706 14,861 0.95
oltp_order_range 3,315 3,197 0.96
oltp_distinct_range 4,285 4,369 1.02
oltp_index_scan 10,578 7,982 0.75
select_random_points 15,914 13,403 0.84
select_random_ranges 9,560 6,392 0.67
covering_index_scan 11,075 6,780 0.61
groupby_scan 29,654 34,809 1.17
index_join 9,753 9,714 1.00
index_join_scan 4,119 4,826 1.17
types_table_scan 1,055,282 1,264,599 1.20
table_scan 1,175,378 1,347,248 1.15
oltp_read_only 198,002 158,248 0.80
Average 0.92

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 193,438 276,022 1.43
oltp_insert 21,463 35,912 1.67
oltp_update_index 73,002 112,356 1.54
oltp_update_non_index 54,474 79,977 1.47
oltp_delete_insert 62,589 92,217 1.47
oltp_write_only 42,340 62,943 1.49
types_delete_insert 38,004 52,039 1.37
oltp_read_write 86,023 126,202 1.47
Average 1.49

File-Backed (autocommit)

Each statement runs as its own transaction — exposes per-commit
fixed costs that the wrapped-in-BEGIN/COMMIT tests amortize away.
SQLite uses WAL mode with synchronous=FULL in this section so
the comparison uses SQLite's durable WAL autocommit path.

Reads

Reads have no commit cost; these are the same SQL files as the
File-Backed Reads section, included here for symmetry and to
catch any per-statement overhead doltlite pays on the read path.

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 45,479 53,239 1.17
oltp_range_select 11,808 15,207 1.29
oltp_sum_range 11,266 14,764 1.31
oltp_order_range 2,736 3,182 1.16
oltp_distinct_range 3,724 4,401 1.18
oltp_index_scan 6,181 8,015 1.30
select_random_points 11,810 13,684 1.16
select_random_ranges 5,111 6,425 1.26
covering_index_scan 6,524 6,717 1.03
groupby_scan 29,145 34,519 1.18
index_join 7,354 9,574 1.30
index_join_scan 3,667 4,751 1.30
types_table_scan 1,052,239 1,265,787 1.20
table_scan 1,177,451 1,343,687 1.14
oltp_read_only 131,663 156,686 1.19
Average 1.21

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert_ac 20,666 76,935 3.72
oltp_insert_ac 24,851 95,489 3.84
oltp_update_index_ac 25,654 108,392 4.23
oltp_update_non_index_ac 21,950 87,312 3.98
oltp_delete_insert_ac 23,327 101,371 4.35
oltp_write_only_ac 23,962 99,714 4.16
types_delete_insert_ac 21,545 96,987 4.50
oltp_read_write_ac 28,427 104,210 3.67
Average 4.06

100000 rows, median of 5 invocations per test; autocommit writes use 9, workload-only timing via host monotonic clock when available.

Performance Ceiling Check (2.5x individual, 2x average; autocommit writes: 6x / 5x)

All tests within ceilings.

@github-actions

Copy link
Copy Markdown

Sysbench-Style Benchmark (composite PK): Doltlite vs SQLite

Companion to the classic Sysbench-Style Benchmark. Every workload here
runs against tables with a 2-column INTEGER PRIMARY KEY(a, b) WITHOUT ROWID.

Individual ratios gated at 2.5×; section averages gated at 2×. Autocommit writes use 6× / 5×.

In-Memory

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 32,906 40,825 1.24
oltp_range_select 19,172 21,993 1.15
oltp_sum_range 17,924 21,581 1.20
oltp_order_range 3,475 3,901 1.12
oltp_distinct_range 4,577 5,117 1.12
oltp_index_scan 4,569 6,029 1.32
select_random_points 28,153 31,883 1.13
select_random_ranges 7,672 9,047 1.18
covering_index_scan 4,221 4,180 0.99
groupby_scan 35,591 40,774 1.15
index_join 8,173 10,587 1.30
index_join_scan 4,041 5,433 1.34
types_table_scan 1,054,856 1,232,851 1.17
table_scan 1,214,603 1,333,556 1.10
oltp_read_only 146,274 173,243 1.18
Average 1.18

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 248,986 360,739 1.45
oltp_insert 19,176 37,015 1.93
oltp_update_index 67,770 115,780 1.71
oltp_update_non_index 50,899 84,138 1.65
oltp_delete_insert 49,250 96,700 1.96
oltp_write_only 27,793 57,973 2.09
types_delete_insert 33,873 55,236 1.63
oltp_read_write 101,925 158,225 1.55
Average 1.75

File-Backed

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 103,266 64,188 0.62
oltp_range_select 25,956 24,614 0.95
oltp_sum_range 25,679 24,371 0.95
oltp_order_range 4,351 4,258 0.98
oltp_distinct_range 5,484 5,549 1.01
oltp_index_scan 11,897 8,946 0.75
select_random_points 37,046 36,030 0.97
select_random_ranges 15,202 11,918 0.78
covering_index_scan 11,391 7,068 0.62
groupby_scan 37,043 41,460 1.12
index_join 12,409 12,706 1.02
index_join_scan 5,020 5,848 1.16
types_table_scan 1,037,891 1,232,146 1.19
table_scan 1,206,281 1,328,786 1.10
oltp_read_only 255,527 211,249 0.83
Average 0.94

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 261,150 380,606 1.46
oltp_insert 26,322 46,962 1.78
oltp_update_index 98,984 142,371 1.44
oltp_update_non_index 76,702 104,791 1.37
oltp_delete_insert 77,358 119,734 1.55
oltp_write_only 51,830 77,332 1.49
types_delete_insert 50,552 69,385 1.37
oltp_read_write 129,364 175,583 1.36
Average 1.48

File-Backed (autocommit)

Each statement runs as its own transaction — exposes per-commit
fixed costs that the wrapped-in-BEGIN/COMMIT tests amortize away.
SQLite uses WAL mode with synchronous=FULL in this section so
the comparison uses SQLite's durable WAL autocommit path.

Reads

Reads have no commit cost; these are the same SQL files as the
File-Backed Reads section, included here for symmetry and to
catch any per-statement overhead doltlite pays on the read path.

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 57,124 65,138 1.14
oltp_range_select 21,959 24,756 1.13
oltp_sum_range 20,424 24,600 1.20
oltp_order_range 3,887 4,207 1.08
oltp_distinct_range 4,887 5,456 1.12
oltp_index_scan 7,296 8,854 1.21
select_random_points 31,319 35,845 1.14
select_random_ranges 10,264 11,913 1.16
covering_index_scan 6,833 6,982 1.02
groupby_scan 35,777 41,025 1.15
index_join 9,655 12,988 1.35
index_join_scan 4,451 5,880 1.32
types_table_scan 1,046,396 1,233,034 1.18
table_scan 1,201,798 1,328,491 1.11
oltp_read_only 181,925 211,436 1.16
Average 1.16

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert_ac 25,149 84,519 3.36
oltp_insert_ac 24,443 104,706 4.28
oltp_update_index_ac 31,262 115,381 3.69
oltp_update_non_index_ac 25,120 93,885 3.74
oltp_delete_insert_ac 25,541 108,599 4.25
oltp_write_only_ac 26,535 105,415 3.97
types_delete_insert_ac 22,588 96,437 4.27
oltp_read_write_ac 32,117 116,417 3.62
Average 3.90

100000 rows, median of 5 invocations per test; autocommit writes use 9, workload-only timing via host monotonic clock when available.

Performance Ceiling Check (2.5x individual, 2x average; autocommit writes: 6x / 5x)

All tests within ceilings.

@github-actions

Copy link
Copy Markdown

Sysbench-Style Benchmark (BLOB PK): Doltlite vs SQLite

Companion to the classic Sysbench-Style Benchmark. Every workload here
runs against tables with a 16-byte big-endian BLOB PRIMARY KEY.

Individual ratios gated at 2.5×; section averages gated at 2×. Autocommit writes use 6× / 5×.

In-Memory

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 22,318 26,829 1.20
oltp_range_select 10,750 11,111 1.03
oltp_sum_range 10,131 10,232 1.01
oltp_order_range 2,401 2,608 1.09
oltp_distinct_range 3,182 3,470 1.09
oltp_index_scan 3,531 4,607 1.30
select_random_points 14,342 16,941 1.18
select_random_ranges 3,006 4,089 1.36
covering_index_scan 3,103 3,324 1.07
groupby_scan 27,197 27,815 1.02
index_join 5,465 7,196 1.32
index_join_scan 3,302 4,747 1.44
types_table_scan 887,486 990,592 1.12
table_scan 1,047,494 1,087,334 1.04
oltp_read_only 90,740 103,537 1.14
Average 1.16

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 161,045 236,564 1.47
oltp_insert 14,388 27,487 1.91
oltp_update_index 50,831 99,784 1.96
oltp_update_non_index 36,254 62,474 1.72
oltp_delete_insert 36,257 74,254 2.05
oltp_write_only 20,606 43,995 2.14
types_delete_insert 23,500 39,885 1.70
oltp_read_write 59,935 98,937 1.65
Average 1.82

File-Backed

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 47,052 34,938 0.74
oltp_range_select 13,641 12,087 0.89
oltp_sum_range 13,471 11,779 0.87
oltp_order_range 2,843 2,833 1.00
oltp_distinct_range 3,649 3,601 0.99
oltp_index_scan 6,410 5,915 0.92
select_random_points 17,141 18,206 1.06
select_random_ranges 5,749 5,044 0.88
covering_index_scan 6,119 4,585 0.75
groupby_scan 27,705 28,097 1.01
index_join 7,098 8,738 1.23
index_join_scan 3,760 4,987 1.33
types_table_scan 893,602 991,284 1.11
table_scan 1,049,005 1,084,272 1.03
oltp_read_only 125,523 115,787 0.92
Average 0.98

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 221,451 318,984 1.44
oltp_insert 42,811 56,295 1.31
oltp_update_index 168,109 191,284 1.14
oltp_update_non_index 137,188 119,626 0.87
oltp_delete_insert 131,370 139,835 1.06
oltp_write_only 93,212 89,901 0.96
types_delete_insert 89,819 80,282 0.89
oltp_read_write 191,409 178,210 0.93
Average 1.08

File-Backed (autocommit)

Each statement runs as its own transaction — exposes per-commit
fixed costs that the wrapped-in-BEGIN/COMMIT tests amortize away.
SQLite uses WAL mode with synchronous=FULL in this section so
the comparison uses SQLite's durable WAL autocommit path.

Reads

Reads have no commit cost; these are the same SQL files as the
File-Backed Reads section, included here for symmetry and to
catch any per-statement overhead doltlite pays on the read path.

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 30,671 34,828 1.14
oltp_range_select 12,015 12,176 1.01
oltp_sum_range 11,635 11,557 0.99
oltp_order_range 2,694 2,790 1.04
oltp_distinct_range 3,437 3,600 1.05
oltp_index_scan 4,871 5,804 1.19
select_random_points 16,099 18,396 1.14
select_random_ranges 4,141 4,988 1.20
covering_index_scan 4,569 4,626 1.01
groupby_scan 27,341 28,041 1.03
index_join 6,538 8,645 1.32
index_join_scan 3,713 5,020 1.35
types_table_scan 887,327 996,507 1.12
table_scan 1,047,522 1,085,096 1.04
oltp_read_only 102,430 115,696 1.13
Average 1.12

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert_ac 32,951 88,192 2.68
oltp_insert_ac 36,973 108,431 2.93
oltp_update_index_ac 39,188 110,741 2.83
oltp_update_non_index_ac 34,581 109,802 3.18
oltp_delete_insert_ac 37,908 117,107 3.09
oltp_write_only_ac 35,893 110,753 3.09
types_delete_insert_ac 32,577 96,191 2.95
oltp_read_write_ac 44,201 108,405 2.45
Average 2.90

100000 rows, median of 5 invocations per test; autocommit writes use 9, workload-only timing via host monotonic clock when available.

Performance Ceiling Check (2.5x individual, 2x average; autocommit writes: 6x / 5x)

All tests within ceilings.

@github-actions

Copy link
Copy Markdown

Sysbench-Style Benchmark (TEXT PK): Doltlite vs SQLite

Companion to the classic Sysbench-Style Benchmark. Every workload here
runs against tables with a 32-char hex TEXT PRIMARY KEY (UUID-shaped).

Individual ratios gated at 2.5×; section averages gated at 2×. Autocommit writes use 6× / 5×.

In-Memory

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 29,329 34,847 1.19
oltp_range_select 13,663 13,709 1.00
oltp_sum_range 12,126 13,472 1.11
oltp_order_range 3,197 3,238 1.01
oltp_distinct_range 4,205 4,375 1.04
oltp_index_scan 4,445 5,789 1.30
select_random_points 17,524 20,104 1.15
select_random_ranges 4,111 5,328 1.30
covering_index_scan 4,751 4,419 0.93
groupby_scan 33,802 37,073 1.10
index_join 6,807 8,785 1.29
index_join_scan 4,550 5,555 1.22
types_table_scan 1,152,471 1,263,483 1.10
table_scan 1,356,184 1,362,647 1.00
oltp_read_only 119,219 132,638 1.11
Average 1.12

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 230,436 347,409 1.51
oltp_insert 21,950 40,116 1.83
oltp_update_index 72,149 136,922 1.90
oltp_update_non_index 50,870 89,188 1.75
oltp_delete_insert 51,712 107,011 2.07
oltp_write_only 29,950 63,822 2.13
types_delete_insert 33,093 54,596 1.65
oltp_read_write 83,145 136,222 1.64
Average 1.81

File-Backed

Reads

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 112,381 64,055 0.57
oltp_range_select 22,339 16,669 0.75
oltp_sum_range 20,086 16,496 0.82
oltp_order_range 4,178 3,564 0.85
oltp_distinct_range 4,939 4,744 0.96
oltp_index_scan 13,209 9,053 0.69
select_random_points 26,386 23,401 0.89
select_random_ranges 12,246 8,176 0.67
covering_index_scan 13,453 7,776 0.58
groupby_scan 35,112 37,745 1.07
index_join 12,015 11,128 0.93
index_join_scan 5,806 6,215 1.07
types_table_scan 1,155,615 1,255,484 1.09
table_scan 1,376,394 1,371,002 1.00
oltp_read_only 239,497 174,179 0.73
Average 0.84

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert 247,463 381,647 1.54
oltp_insert 55,062 52,668 0.96
oltp_update_index 112,636 172,908 1.54
oltp_update_non_index 101,217 114,842 1.13
oltp_delete_insert 87,535 137,699 1.57
oltp_write_only 96,605 87,769 0.91
types_delete_insert 53,394 74,858 1.40
oltp_read_write 139,301 158,743 1.14
Average 1.27

File-Backed (autocommit)

Each statement runs as its own transaction — exposes per-commit
fixed costs that the wrapped-in-BEGIN/COMMIT tests amortize away.
SQLite uses WAL mode with synchronous=FULL in this section so
the comparison uses SQLite's durable WAL autocommit path.

Reads

Reads have no commit cost; these are the same SQL files as the
File-Backed Reads section, included here for symmetry and to
catch any per-statement overhead doltlite pays on the read path.

Test SQLite (us) Doltlite (us) Multiplier
oltp_point_select 57,130 63,661 1.11
oltp_range_select 17,900 16,734 0.93
oltp_sum_range 15,865 16,528 1.04
oltp_order_range 3,678 3,595 0.98
oltp_distinct_range 4,605 4,732 1.03
oltp_index_scan 7,815 9,066 1.16
select_random_points 21,062 24,295 1.15
select_random_ranges 7,129 8,221 1.15
covering_index_scan 8,919 7,779 0.87
groupby_scan 34,484 37,588 1.09
index_join 9,161 11,368 1.24
index_join_scan 5,162 6,199 1.20
types_table_scan 1,160,800 1,264,034 1.09
table_scan 1,371,918 1,366,068 1.00
oltp_read_only 159,243 174,487 1.10
Average 1.08

Writes

Test SQLite (us) Doltlite (us) Multiplier
oltp_bulk_insert_ac 16,406 60,118 3.66
oltp_insert_ac 18,223 76,218 4.18
oltp_update_index_ac 20,655 93,530 4.53
oltp_update_non_index_ac 16,782 72,730 4.33
oltp_delete_insert_ac 18,021 86,514 4.80
oltp_write_only_ac 18,491 84,797 4.59
types_delete_insert_ac 15,299 73,171 4.78
oltp_read_write_ac 24,689 94,405 3.82
Average 4.34

100000 rows, median of 5 invocations per test; autocommit writes use 9, workload-only timing via host monotonic clock when available.

Performance Ceiling Check (2.5x individual, 2x average; autocommit writes: 6x / 5x)

All tests within ceilings.

@timsehn
timsehn merged commit 1feb9e2 into master Jul 17, 2026
27 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.

1 participant