Implement connection pool in Swift, remove Kotlin framework#130
Draft
Implement connection pool in Swift, remove Kotlin framework#130
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This implements
SqlCursorand connection pools directly in Swift instead of depending on a Kotlin XCFramework. On a high level, this PR:get$Type(name:)functions onSqlCursorare now implemented by delegating toget$Type(index:).SQLiteConnectionPoolProtocolprotocol to be able to actually run statements instead of just exposing asqlite3*pointer. This allows using high-level GRDB APIs to implement that, which lets GRDB track updates and allows us to skip the session hack.SQLiteConnectionPoolProtocolresponsible for opening connections, configuring them and to dispatch queries on a background thread. The actual implementation is close to what we have on JavaScript, with anAsyncSemaphorehelper guarding connections.sqlite3_load_extensionand having to resolve the path manually.For the native SQLite wrapper, the implementation consists of these structs:
NativeSqliteStatementis an owning (~Copyable) struct managing a SQLite statement and exposing raw SQLite methods to step through it.StatementCursorimplements the existingSqlCursorprotocol with a dynamic reference to aNativeSqliteStatement. Ideally, I would have preferred this to be~Copyableas well and change APIs to give users aborrowing SqlCursorin callbacks for safety. That would be breaking though, so we instead have manual checks to verify a cursor isn't used outside of its callback.NativeConnectionPoolmanages a write connection (and an optional collection of readers). These are implemented through the owningRawSqliteConnectionstruct and anAsyncSemaphorewith a design taken from our JS SDK implementation. We use the core extension withpowersync_update_hooksto dispatch update notifications. For simplicity, this class is not responsible for opening connections or dispatching writes to a background thread.AsyncConnectionPoolis responsible for opening connections and supports both in-memory databases and files in the default database directory (the design is so that we can potentially support custom paths in the future as well). It wraps aNativeConnectionPool for concurrency control and invokes callbacks onDispatchQueue.global(qos:)` to avoid blocking the main thread.PowerSyncDatabaseImplimplements high-level PowerSync APIs by opening a pool and running the usual initial statements to resolve the initial sync state.Most of this is covered by existing tests, I've added a simple additional test covering how we bind parameter values.