-
Notifications
You must be signed in to change notification settings - Fork 96
feat(zero-client): expo-sqlite storage #4669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Branch | 0xcadams/expo |
Testbed | Linux |
Click to view all benchmark results
Benchmark | Throughput | Benchmark 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 | 386.77 ops/s x 1e3(-0.78%)Baseline: 389.83 ops/s x 1e3 | 357.67 ops/s x 1e3 (92.48%) |
src/client/zero.bench.ts > basics > All 1000 rows x 10 columns (numbers) | 📈 view plot 🚷 view threshold | 1.63 ops/s x 1e3(-0.71%)Baseline: 1.64 ops/s x 1e3 | 1.60 ops/s x 1e3 (98.50%) |
src/client/zero.bench.ts > pk compare > pk = N | 📈 view plot 🚷 view threshold | 30.21 ops/s x 1e3(+0.58%)Baseline: 30.04 ops/s x 1e3 | 28.88 ops/s x 1e3 (95.60%) |
src/client/zero.bench.ts > with filter > Lower rows 500 x 10 columns (numbers) | 📈 view plot 🚷 view threshold | 2.55 ops/s x 1e3(-0.93%)Baseline: 2.58 ops/s x 1e3 | 2.51 ops/s x 1e3 (98.24%) |
|
Branch | 0xcadams/expo |
Testbed | Linux |
Click to view all benchmark results
Benchmark | File Size | Benchmark Result kilobytes (KB) (Result Δ%) | Upper Boundary kilobytes (KB) (Limit %) |
---|---|---|---|
zero-package.tgz | 📈 view plot 🚷 view threshold | 1,251.66 KB(+0.53%)Baseline: 1,245.05 KB | 1,269.95 KB (98.56%) |
zero.js | 📈 view plot 🚷 view threshold | 202.56 KB(0.00%)Baseline: 202.56 KB | 206.62 KB (98.04%) |
zero.js.br | 📈 view plot 🚷 view threshold | 56.77 KB(0.00%)Baseline: 56.77 KB | 57.91 KB (98.04%) |
Exciting! I'm on vacation until beginning of August so I will not be able to provide any good feedback on this until then. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for figuring this out
await withWrite(walStore, async wt => { | ||
await wt.put('foo1', 'bar1'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the bench attempting to measure? Just raw transactions per second? Or do you want more information on writes per second?
Writes per second should be roughly on the order of transactions_per_second * writes_per_transaction
so 1 write per transaction will give you the same writes per second as transactions per second.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is a good question. I was using this benchmark to improve performance of the SQLite store w/ better-sqlite3, as a way to test performance of the store as I was making changes to schema/PRAGMAs. I updated this to be simpler and compare WAL modes. Let me know if this doesn't fit into existing benchmarks or any ways you see improving this.
|
||
return Promise.resolve(write); | ||
} catch (e) { | ||
return Promise.reject(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same question as with read.
It does feel weird to be doing locking given the interface we expose to SQLite is technically synchronous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I know Matt is reviewing this already but I was very curious.
I looked at the locking structure and it seems to have the same semantics as the IDBStore.
} | ||
|
||
put(key: string, value: ReadonlyJSONValue): Promise<void> { | ||
this._preparedStatements.put.run([key, JSON.stringify(value)]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason why the type of run takes rest args but the callers always wrap in a single array? Consider removing one array allocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch - moved to rest args
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
new SQLiteDatabaseManager({ | ||
open: name => { | ||
const filename = path.resolve(__dirname, `${name}.db`); | ||
// this cannot be :memory: because multiple read connections must access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's technically doable via memory with some fancy options. But yeah, better to just keep it file based.
OK on more thought I understand the reason for the design here. I was wondering why we cannot rely on RWLock within the context and thereby share a single connection across the context. But the problem is that RWLock wants to allow read tx to overlap. And we cannot represent overlapped, separate read tx with a single connection (at least not cleanly?). LGTM too. |
Unfortunately the tests keep failing and I don't have permissions to override the PR requirements |
Adds a new
@rocicorp/zero/expo
package to add a SQLiteStoreProvider
for Expo/React Native.Builds on @austinm911's work.
SQLiteDatabaseManager
which handles schema setup, PRAGMAs, and connection handling.SQLiteStore
which works with bare SQLite and uses prepared statements withRWLock
.Note:
iOS and Android both had issues with WAL journal mode - they hang on COMMIT indefinitely. According to Expo, this is recommended, but it doesn't seem to work, so it is disabled by default, with a performance hit. Here is the performance difference with
better-sqlite3
:Expo Demo
expo-sqlite.mp4