Skip to content

Conversation

darkgnotic
Copy link
Contributor

@darkgnotic darkgnotic commented Oct 2, 2025

Change the schema of the replica's changeLog table such that changes are ordered (and traversed) chronologically, i.e. in the order in which they were received from upstream.

This addresses a previous possible constraint violation whereby changing the columns of a unique key might violate the unique constraint of a disjoint key in the same row, as the delete + set of the rows could have happened in the wrong order.

User report:

The changeLog still maintains a unique index on the <table, rowKey> columns such that only the last change to a row is kept, maintaining the O(num-rows) bound on the size of the log and performance benefit of removing redundant ivm pushes.

Copy link

vercel bot commented Oct 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
replicache-docs Ready Ready Preview Comment Oct 2, 2025 1:12am
zbugs Ready Ready Preview Comment Oct 2, 2025 1:12am

Copy link

github-actions bot commented Oct 2, 2025

🐰 Bencher Report

Branchdarkgnotic/order-change-entries
TestbedLinux
Click to view all benchmark results
BenchmarkFile SizeBenchmark Result
kilobytes (KB)
(Result Δ%)
Upper Boundary
kilobytes (KB)
(Limit %)
zero-package.tgz📈 view plot
🚷 view threshold
1,361.62 KB
(+0.00%)Baseline: 1,361.57 KB
1,388.80 KB
(98.04%)
zero.js📈 view plot
🚷 view threshold
225.48 KB
(0.00%)Baseline: 225.48 KB
229.99 KB
(98.04%)
zero.js.br📈 view plot
🚷 view threshold
63.08 KB
(0.00%)Baseline: 63.08 KB
64.35 KB
(98.04%)
🐰 View full continuous benchmarking report in Bencher

Copy link

github-actions bot commented Oct 2, 2025

🐰 Bencher Report

Branchdarkgnotic/order-change-entries
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
zpg: (pk lookup) select * from track where id = 3163📈 view plot
🚷 view threshold
926.49 ops/s
(-7.16%)Baseline: 997.94 ops/s
827.25 ops/s
(89.29%)
zpg: (secondary index lookup) select * from track where album_id = 248📈 view plot
🚷 view threshold
1,013.53 ops/s
(-1.74%)Baseline: 1,031.50 ops/s
871.57 ops/s
(85.99%)
zpg: (table scan) select * from album📈 view plot
🚷 view threshold
682.28 ops/s
(-2.98%)Baseline: 703.25 ops/s
653.97 ops/s
(95.85%)
zpg: OR with empty branch and limit📈 view plot
🚷 view threshold
880.25 ops/s
(-3.17%)Baseline: 909.02 ops/s
824.07 ops/s
(93.62%)
zpg: OR with empty branch and limit with exists📈 view plot
🚷 view threshold
749.16 ops/s
(+5.04%)Baseline: 713.22 ops/s
590.85 ops/s
(78.87%)
zpg: all playlists📈 view plot
🚷 view threshold
5.40 ops/s
(+0.19%)Baseline: 5.39 ops/s
5.18 ops/s
(95.90%)
zpg: scan with one depth related📈 view plot
🚷 view threshold
409.57 ops/s
(-0.26%)Baseline: 410.66 ops/s
382.34 ops/s
(93.35%)
zql: (pk lookup) select * from track where id = 3163📈 view plot
🚷 view threshold
125,077.60 ops/s
(+0.58%)Baseline: 124,353.48 ops/s
113,608.07 ops/s
(90.83%)
zql: (secondary index lookup) select * from track where album_id = 248📈 view plot
🚷 view threshold
2,174.86 ops/s
(+2.81%)Baseline: 2,115.41 ops/s
1,924.83 ops/s
(88.50%)
zql: (table scan) select * from album📈 view plot
🚷 view threshold
6,738.05 ops/s
(+4.26%)Baseline: 6,462.64 ops/s
5,978.69 ops/s
(88.73%)
zql: OR with empty branch and limit📈 view plot
🚷 view threshold
59,168.46 ops/s
(+9.83%)Baseline: 53,874.02 ops/s
44,172.92 ops/s
(74.66%)
zql: OR with empty branch and limit with exists📈 view plot
🚷 view threshold
11,939.94 ops/s
(+0.85%)Baseline: 11,839.27 ops/s
10,372.39 ops/s
(86.87%)
zql: all playlists📈 view plot
🚷 view threshold
4.34 ops/s
(+5.44%)Baseline: 4.12 ops/s
3.66 ops/s
(84.30%)
zql: edit for limited query, inside the bound📈 view plot
🚷 view threshold
211,290.50 ops/s
(-1.56%)Baseline: 214,632.26 ops/s
199,083.16 ops/s
(94.22%)
zql: edit for limited query, outside the bound📈 view plot
🚷 view threshold
217,412.94 ops/s
(-0.42%)Baseline: 218,340.10 ops/s
197,095.13 ops/s
(90.65%)
zql: push into limited query, inside the bound📈 view plot
🚷 view threshold
105,212.79 ops/s
(-1.59%)Baseline: 106,908.24 ops/s
100,978.37 ops/s
(95.98%)
zql: push into limited query, outside the bound📈 view plot
🚷 view threshold
406,446.61 ops/s
(+1.72%)Baseline: 399,573.75 ops/s
369,565.27 ops/s
(90.93%)
zql: push into unlimited query📈 view plot
🚷 view threshold
315,625.08 ops/s
(-3.00%)Baseline: 325,386.48 ops/s
308,304.31 ops/s
(97.68%)
zql: scan with one depth related📈 view plot
🚷 view threshold
477.20 ops/s
(+2.98%)Baseline: 463.38 ops/s
420.63 ops/s
(88.15%)
zqlite: (pk lookup) select * from track where id = 3163📈 view plot
🚷 view threshold
41,981.76 ops/s
(-0.24%)Baseline: 42,082.69 ops/s
38,036.35 ops/s
(90.60%)
zqlite: (secondary index lookup) select * from track where album_id = 248📈 view plot
🚷 view threshold
10,090.56 ops/s
(+1.38%)Baseline: 9,953.30 ops/s
9,554.14 ops/s
(94.68%)
zqlite: (table scan) select * from album📈 view plot
🚷 view threshold
1,342.51 ops/s
(+1.34%)Baseline: 1,324.77 ops/s
1,244.13 ops/s
(92.67%)
zqlite: OR with empty branch and limit📈 view plot
🚷 view threshold
17,761.11 ops/s
(+3.19%)Baseline: 17,211.44 ops/s
15,890.75 ops/s
(89.47%)
zqlite: OR with empty branch and limit with exists📈 view plot
🚷 view threshold
5,405.37 ops/s
(+0.77%)Baseline: 5,363.96 ops/s
4,898.13 ops/s
(90.62%)
zqlite: all playlists📈 view plot
🚷 view threshold
1.42 ops/s
(+3.75%)Baseline: 1.37 ops/s
1.23 ops/s
(86.73%)
zqlite: edit for limited query, inside the bound📈 view plot
🚷 view threshold
114,728.97 ops/s
(-1.84%)Baseline: 116,876.06 ops/s
108,817.21 ops/s
(94.85%)
zqlite: edit for limited query, outside the bound📈 view plot
🚷 view threshold
125,364.85 ops/s
(+4.15%)Baseline: 120,374.90 ops/s
109,630.78 ops/s
(87.45%)
zqlite: push into limited query, inside the bound📈 view plot
🚷 view threshold
3,966.69 ops/s
(-2.62%)Baseline: 4,073.55 ops/s
3,828.04 ops/s
(96.50%)
zqlite: push into limited query, outside the bound📈 view plot
🚷 view threshold
147,760.88 ops/s
(+2.92%)Baseline: 143,570.94 ops/s
128,541.16 ops/s
(86.99%)
zqlite: push into unlimited query📈 view plot
🚷 view threshold
125,799.28 ops/s
(+0.28%)Baseline: 125,449.19 ops/s
115,889.06 ops/s
(92.12%)
zqlite: scan with one depth related📈 view plot
🚷 view threshold
159.20 ops/s
(+0.30%)Baseline: 158.72 ops/s
147.50 ops/s
(92.65%)
🐰 View full continuous benchmarking report in Bencher

Copy link

github-actions bot commented Oct 2, 2025

🐰 Bencher Report

Branchdarkgnotic/order-change-entries
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s) x 1e3
(Result Δ%)
Lower Boundary
operations / second (ops/s) x 1e3
(Limit %)
src/size-of-value.bench.ts > getSizeOfValue performance > arrays > large array (100 items)📈 view plot
🚷 view threshold
1,682.59 ops/s x 1e3
(+1.23%)Baseline: 1,662.10 ops/s x 1e3
1,619.19 ops/s x 1e3
(96.23%)
src/size-of-value.bench.ts > getSizeOfValue performance > arrays > small array (10 items)📈 view plot
🚷 view threshold
5,067.94 ops/s x 1e3
(-1.05%)Baseline: 5,121.63 ops/s x 1e3
4,824.83 ops/s x 1e3
(95.20%)
src/size-of-value.bench.ts > getSizeOfValue performance > datasets > large dataset (100x512B)📈 view plot
🚷 view threshold
66.15 ops/s x 1e3
(-9.47%)Baseline: 73.07 ops/s x 1e3
57.93 ops/s x 1e3
(87.58%)
src/size-of-value.bench.ts > getSizeOfValue performance > datasets > small dataset (10x256B)📈 view plot
🚷 view threshold
590.37 ops/s x 1e3
(-8.17%)Baseline: 642.92 ops/s x 1e3
502.52 ops/s x 1e3
(85.12%)
src/size-of-value.bench.ts > getSizeOfValue performance > objects > nested object📈 view plot
🚷 view threshold
2,944.10 ops/s x 1e3
(-3.63%)Baseline: 3,054.96 ops/s x 1e3
2,681.53 ops/s x 1e3
(91.08%)
src/size-of-value.bench.ts > getSizeOfValue performance > objects > structured object (1KB)📈 view plot
🚷 view threshold
3,402.45 ops/s x 1e3
(-4.98%)Baseline: 3,580.73 ops/s x 1e3
3,068.51 ops/s x 1e3
(90.19%)
src/size-of-value.bench.ts > getSizeOfValue performance > objects > structured object (256B)📈 view plot
🚷 view threshold
3,274.61 ops/s x 1e3
(-7.78%)Baseline: 3,550.93 ops/s x 1e3
3,005.65 ops/s x 1e3
(91.79%)
src/size-of-value.bench.ts > getSizeOfValue performance > primitives > boolean📈 view plot
🚷 view threshold
7,264.25 ops/s x 1e3
(-0.48%)Baseline: 7,299.58 ops/s x 1e3
6,728.61 ops/s x 1e3
(92.63%)
src/size-of-value.bench.ts > getSizeOfValue performance > primitives > integer📈 view plot
🚷 view threshold
7,276.88 ops/s x 1e3
(-0.18%)Baseline: 7,289.78 ops/s x 1e3
6,801.21 ops/s x 1e3
(93.46%)
src/size-of-value.bench.ts > getSizeOfValue performance > primitives > null📈 view plot
🚷 view threshold
7,193.33 ops/s x 1e3
(-1.65%)Baseline: 7,313.96 ops/s x 1e3
6,847.58 ops/s x 1e3
(95.19%)
src/size-of-value.bench.ts > getSizeOfValue performance > primitives > string (100 chars)📈 view plot
🚷 view threshold
1,083.15 ops/s x 1e3
(+0.66%)Baseline: 1,076.02 ops/s x 1e3
1,009.50 ops/s x 1e3
(93.20%)
🐰 View full continuous benchmarking report in Bencher

Copy link

github-actions bot commented Oct 2, 2025

🐰 Bencher Report

Branchdarkgnotic/order-change-entries
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s) x 1e3
(Result Δ%)
Lower Boundary
operations / second (ops/s) x 1e3
(Limit %)
src/client/custom.bench.ts > big schema📈 view plot
🚷 view threshold
549.11 ops/s x 1e3
(-9.86%)Baseline: 609.16 ops/s x 1e3
287.19 ops/s x 1e3
(52.30%)
src/client/zero.bench.ts > basics > All 1000 rows x 10 columns (numbers)📈 view plot
🚷 view threshold
2.72 ops/s x 1e3
(-0.83%)Baseline: 2.74 ops/s x 1e3
2.60 ops/s x 1e3
(95.60%)
src/client/zero.bench.ts > pk compare > pk = N📈 view plot
🚷 view threshold
41.40 ops/s x 1e3
(-1.54%)Baseline: 42.05 ops/s x 1e3
39.70 ops/s x 1e3
(95.89%)
src/client/zero.bench.ts > with filter > Lower rows 500 x 10 columns (numbers)📈 view plot
🚷 view threshold
3.90 ops/s x 1e3
(-2.84%)Baseline: 4.01 ops/s x 1e3
3.81 ops/s x 1e3
(97.84%)
🐰 View full continuous benchmarking report in Bencher

changesSince(prevVersion: string) {
const cached = this.db.statementCache.get(
'SELECT * FROM "_zero.changeLog" WHERE stateVersion > ?',
'SELECT * FROM "_zero.changeLog" WHERE stateVersion > ? ORDER BY stateVersion ASC, pos ASC',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I believe this ordering was already the case, but I feel better about specifying it explicitly.

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