-
Notifications
You must be signed in to change notification settings - Fork 19
Concurrent Connections #145
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
Link SQLite statically on native platforms
core/src/commonMain/kotlin/com/powersync/db/internal/ConnectionPool.kt
Outdated
Show resolved
Hide resolved
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.
This generally looks really nice, it's awesome to see how much custom native code we can throw out with this.
I have a bunch of comments, but they're all pretty minor.
core/src/commonMain/kotlin/com/powersync/db/PowerSyncDatabaseImpl.kt
Outdated
Show resolved
Hide resolved
core/src/commonMain/kotlin/com/powersync/db/internal/PowerSyncTransaction.kt
Outdated
Show resolved
Hide resolved
core/src/iosSimulatorArm64Test/kotlin/com/powersync/testutils/TestUtils.iosSimulatorArm64.kt
Show resolved
Hide resolved
Co-authored-by: Simon Binder <[email protected]>
…Transaction.kt Co-authored-by: Simon Binder <[email protected]>
…cripts. Use lateinit for PowersyncVersion. Add comment for ios tempdir. Update SQLite version to 3.49.1.
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 🚀
Overview
This PR introduces minor improvements to the SQLite driver functionality.
Unified Concurrency
The PowerSync client now supports readLock and writeLock APIs, aligning with the functionality in other SDKs.
Previously, concurrency was implemented differently across the various platform SQLite drivers. The Android and iOS drivers had their own concurrency models. The iOS driver opened a single read and write connection, while the Android driver’s read connections were dependent on available system memory ("The maximum number of connections used for parallel queries depends on the device’s memory and possibly other factors.").
The JVM driver only created a single connection, preventing concurrent reads.
The current driver interface required substantial work on the driver implementation to route queries to the appropriate internal connection. Implementing concurrency for the JVM driver would have been complex. Instead, we unified the concurrency model across all platforms by modifying the implementation to use multiple SQLite drivers.
Now, a single write connection driver is used for write operations, while a pool of read connection drivers is maintained.
SQLite Driver Improvements
Android
The current Android SQLite driver uses Requery, which does not support SQLite table update hooks in its API. Although PRs for adding SQLite hooks were introduced recently, they have not been released yet.
We currently use custom native C interops to access SQLite hooks via C APIs. However, these interops are limited and only function properly with a single SQLite connection/driver.
Implementing update hooks for multiple connections in native C interops is complex. As a result, this PR switches the Android driver to use the Xerial JDBC SQLite library (which is also used in the JVM build). This library supports SQLite hooks as part of its API.
Although the Xerial library requires shipping JNI binaries with our SDK, the Gradle build scripts have been updated to include the necessary JNI libraries during the build process.
The JDBC driver code is now shared between the Android and JVM targets, simplifying the implementation.
Removing the Requery dependency also streamlines installation, as users no longer need to add the Jitpack Maven repository to their build scripts.
TODOs:
iOS
The iOS driver currently uses SQLiteR, which interfaces closely with the SQLite C APIs. However, SQLiteR does not expose SQLite hooks in its API, requiring us to use a native C interop for hook functionality.
The current hook implementation only works with the last driver created by the DatabaseDriverFactory. This implementation has been updated to support multiple connections.
Previously, the iOS driver loaded the PowerSync SQLite core extension statically by calling sqlite3_auto_extension through a native C interop. This PR now dynamically loads the extension and throws exceptions if the PowerSync core framework cannot be located.
Full-text search is now enabled by default for iOS.
Native Interops
Much of the native interop code has been removed, as it is no longer necessary.
Database Options
The Android and JVM drivers now support opening a database using a dbDirectory parameter. This feature is not supported on iOS.
SQLDelight Queries
We currently use SQLDelight's dialect for internal PowerSync queries. These operations use the driver directly. Which easily can cause synchronous code execution to block the main thread (some examples of this have been removed). Using the driver directly also has some slight chance of interfering with connection locks.
The use of SQLDelight dialect internally has mostly been removed and replaced with raw SQLite queries.