diff --git a/CHANGELOG.md b/CHANGELOG.md index 80557a58..6f1d1ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 2024-07-10 + +### Changes + +--- + +Packages with breaking changes: + + - There are no breaking changes in this release. + +Packages with other changes: + + - [`powersync` - `v1.3.0-alpha.9`](#powersync---v130-alpha9) + - [`powersync_attachments_helper` - `v0.3.0-alpha.4`](#powersync_attachments_helper---v030-alpha4) + +Packages with dependency updates only: + +> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project. + + - `powersync_attachments_helper` - `v0.3.0-alpha.4` + +--- + +#### `powersync` - `v1.3.0-alpha.9` + + - Updated sqlite_async to use Navigator locks for limiting sync stream implementions in multiple tabs + + ## 2024-07-04 ### Changes diff --git a/demos/supabase-anonymous-auth/pubspec.lock b/demos/supabase-anonymous-auth/pubspec.lock index 3578096b..65f565f4 100644 --- a/demos/supabase-anonymous-auth/pubspec.lock +++ b/demos/supabase-anonymous-auth/pubspec.lock @@ -350,7 +350,7 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.3.0-alpha.7" + version: "1.3.0-alpha.8" realtime_client: dependency: transitive description: @@ -480,10 +480,10 @@ packages: dependency: "direct main" description: name: sqlite_async - sha256: "7c5a9bec86b6f5b7511b9ba30974fa7ea470aee2dc0d5b7021f6321a439a8d63" + sha256: "79e636c857ed43f6cd5e5be72b36967a29f785daa63ff5b078bd34f74f44cb54" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.8.1" stack_trace: dependency: transitive description: diff --git a/demos/supabase-anonymous-auth/pubspec.yaml b/demos/supabase-anonymous-auth/pubspec.yaml index 4dc04e83..9641326c 100644 --- a/demos/supabase-anonymous-auth/pubspec.yaml +++ b/demos/supabase-anonymous-auth/pubspec.yaml @@ -11,12 +11,12 @@ dependencies: flutter: sdk: flutter - powersync: 1.3.0-alpha.8 + powersync: 1.3.0-alpha.9 path_provider: ^2.1.1 supabase_flutter: ^2.0.2 path: ^1.8.3 logging: ^1.2.0 - sqlite_async: ^0.8.0 + sqlite_async: ^0.8.1 universal_io: ^2.2.2 dev_dependencies: diff --git a/demos/supabase-edge-function-auth/pubspec.lock b/demos/supabase-edge-function-auth/pubspec.lock index 3578096b..65f565f4 100644 --- a/demos/supabase-edge-function-auth/pubspec.lock +++ b/demos/supabase-edge-function-auth/pubspec.lock @@ -350,7 +350,7 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.3.0-alpha.7" + version: "1.3.0-alpha.8" realtime_client: dependency: transitive description: @@ -480,10 +480,10 @@ packages: dependency: "direct main" description: name: sqlite_async - sha256: "7c5a9bec86b6f5b7511b9ba30974fa7ea470aee2dc0d5b7021f6321a439a8d63" + sha256: "79e636c857ed43f6cd5e5be72b36967a29f785daa63ff5b078bd34f74f44cb54" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.8.1" stack_trace: dependency: transitive description: diff --git a/demos/supabase-edge-function-auth/pubspec.yaml b/demos/supabase-edge-function-auth/pubspec.yaml index a6d8e5bd..9cc8ba5b 100644 --- a/demos/supabase-edge-function-auth/pubspec.yaml +++ b/demos/supabase-edge-function-auth/pubspec.yaml @@ -11,12 +11,12 @@ dependencies: flutter: sdk: flutter - powersync: 1.3.0-alpha.8 + powersync: 1.3.0-alpha.9 path_provider: ^2.1.1 supabase_flutter: ^2.0.2 path: ^1.8.3 logging: ^1.2.0 - sqlite_async: ^0.8.0 + sqlite_async: ^0.8.1 universal_io: ^2.2.2 dev_dependencies: diff --git a/demos/supabase-simple-chat/pubspec.lock b/demos/supabase-simple-chat/pubspec.lock index 7cb0dc60..45900457 100644 --- a/demos/supabase-simple-chat/pubspec.lock +++ b/demos/supabase-simple-chat/pubspec.lock @@ -382,7 +382,7 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.3.0-alpha.7" + version: "1.3.0-alpha.8" realtime_client: dependency: transitive description: @@ -536,10 +536,10 @@ packages: dependency: transitive description: name: sqlite_async - sha256: "7c5a9bec86b6f5b7511b9ba30974fa7ea470aee2dc0d5b7021f6321a439a8d63" + sha256: "79e636c857ed43f6cd5e5be72b36967a29f785daa63ff5b078bd34f74f44cb54" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.8.1" stack_trace: dependency: transitive description: diff --git a/demos/supabase-simple-chat/pubspec.yaml b/demos/supabase-simple-chat/pubspec.yaml index 70ebaf6c..b1c5a023 100644 --- a/demos/supabase-simple-chat/pubspec.yaml +++ b/demos/supabase-simple-chat/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: supabase_flutter: ^1.10.25 timeago: ^3.6.0 - powersync: 1.3.0-alpha.8 + powersync: 1.3.0-alpha.9 path_provider: ^2.1.1 path: ^1.8.3 logging: ^1.2.0 diff --git a/demos/supabase-todolist/pubspec.lock b/demos/supabase-todolist/pubspec.lock index d494f966..b264a16c 100644 --- a/demos/supabase-todolist/pubspec.lock +++ b/demos/supabase-todolist/pubspec.lock @@ -454,14 +454,14 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.3.0-alpha.7" + version: "1.3.0-alpha.8" powersync_attachments_helper: dependency: "direct main" description: path: "../../packages/powersync_attachments_helper" relative: true source: path - version: "0.3.0-alpha.2" + version: "0.3.0-alpha.3" realtime_client: dependency: transitive description: @@ -591,10 +591,10 @@ packages: dependency: "direct main" description: name: sqlite_async - sha256: "7c5a9bec86b6f5b7511b9ba30974fa7ea470aee2dc0d5b7021f6321a439a8d63" + sha256: "79e636c857ed43f6cd5e5be72b36967a29f785daa63ff5b078bd34f74f44cb54" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.8.1" stack_trace: dependency: transitive description: diff --git a/demos/supabase-todolist/pubspec.yaml b/demos/supabase-todolist/pubspec.yaml index 11e8ae6f..13098a00 100644 --- a/demos/supabase-todolist/pubspec.yaml +++ b/demos/supabase-todolist/pubspec.yaml @@ -10,9 +10,9 @@ environment: dependencies: flutter: sdk: flutter - powersync_attachments_helper: ^0.3.0-alpha.3 + powersync_attachments_helper: ^0.3.0-alpha.4 - powersync: 1.3.0-alpha.8 + powersync: 1.3.0-alpha.9 path_provider: ^2.1.1 supabase_flutter: ^2.0.1 path: ^1.8.3 @@ -20,7 +20,7 @@ dependencies: camera: ^0.10.5+7 image: ^4.1.3 universal_io: ^2.2.2 - sqlite_async: ^0.8.0 + sqlite_async: ^0.8.1 dev_dependencies: flutter_test: diff --git a/packages/powersync/CHANGELOG.md b/packages/powersync/CHANGELOG.md index 087f3c2d..3ad1af70 100644 --- a/packages/powersync/CHANGELOG.md +++ b/packages/powersync/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.0-alpha.9 + +- Updated sqlite_async to use Navigator locks for limiting sync stream implementations in multiple tabs + ## 1.3.0-alpha.8 - **FIX**(powersync-attachements-helper): pubspec file (#29). diff --git a/packages/powersync/lib/src/database/web/web_powersync_database.dart b/packages/powersync/lib/src/database/web/web_powersync_database.dart index 8a8cbc17..60dfcb26 100644 --- a/packages/powersync/lib/src/database/web/web_powersync_database.dart +++ b/packages/powersync/lib/src/database/web/web_powersync_database.dart @@ -134,9 +134,8 @@ class PowerSyncDatabaseImpl await isInitialized; - // TODO multitab support + // TODO better multitab support final storage = BucketStorage(database); - final sync = StreamingSyncImplementation( adapter: storage, credentialsCallback: connector.getCredentialsCached, @@ -144,7 +143,10 @@ class PowerSyncDatabaseImpl uploadCrud: () => connector.uploadData(this), updateStream: updates, retryDelay: Duration(seconds: 3), - client: FetchClient(mode: RequestMode.cors)); + client: FetchClient(mode: RequestMode.cors), + // Only allows 1 sync implementation to run at a time per database + // This should be global (across tabs) when using Navigator locks. + identifier: database.openFactory.path); sync.statusStream.listen((event) { setStatus(event); }); diff --git a/packages/powersync/lib/src/streaming_sync.dart b/packages/powersync/lib/src/streaming_sync.dart index 6830534e..ff925588 100644 --- a/packages/powersync/lib/src/streaming_sync.dart +++ b/packages/powersync/lib/src/streaming_sync.dart @@ -4,6 +4,7 @@ import 'package:http/http.dart' as http; import 'package:powersync/src/abort_controller.dart'; import 'package:powersync/src/exceptions.dart'; import 'package:powersync/src/log_internal.dart'; +import 'package:sqlite_async/mutex.dart'; import 'bucket_storage.dart'; import 'connector.dart'; @@ -37,6 +38,8 @@ class StreamingSyncImplementation { SyncStatus lastStatus = const SyncStatus(); + final Mutex syncMutex, crudMutex; + StreamingSyncImplementation( {required this.adapter, required this.credentialsCallback, @@ -44,7 +47,13 @@ class StreamingSyncImplementation { required this.uploadCrud, required this.updateStream, required this.retryDelay, - required http.Client client}) { + required http.Client client, + + /// A unique identifier for this streaming sync implementation + /// A good value is typically the DB file path which it will mutate when syncing. + String? identifier = "unknown"}) + : syncMutex = Mutex(identifier: "sync-$identifier"), + crudMutex = Mutex(identifier: "crud-$identifier") { _client = client; statusStream = _statusStreamController.stream; } @@ -65,8 +74,10 @@ class StreamingSyncImplementation { await invalidCredentialsCallback!(); invalidCredentials = false; } - await streamingSyncIteration(abortController: abortController); - // Continue immediately + // Protect sync iterations with exclusivity (if a valid Mutex is provided) + await syncMutex.lock( + () => streamingSyncIteration(abortController: abortController), + timeout: retryDelay); } catch (e, stacktrace) { final message = _syncErrorMessage(e); isolateLogger.warning('Sync error: $message', e, stacktrace); @@ -110,21 +121,23 @@ class StreamingSyncImplementation { } Future uploadCrudBatch() async { - if ((await adapter.hasCrud())) { - _updateStatus(uploading: true); - await uploadCrud(); - return false; - } else { - // This isolate is the only one triggering - final updated = await adapter.updateLocalTarget(() async { - return getWriteCheckpoint(); - }); - if (updated) { - _localPingController.add(null); - } + return crudMutex.lock(() async { + if ((await adapter.hasCrud())) { + _updateStatus(uploading: true); + await uploadCrud(); + return false; + } else { + // This isolate is the only one triggering + final updated = await adapter.updateLocalTarget(() async { + return getWriteCheckpoint(); + }); + if (updated) { + _localPingController.add(null); + } - return true; - } + return true; + } + }, timeout: retryDelay); } Future getWriteCheckpoint() async { diff --git a/packages/powersync/pubspec.yaml b/packages/powersync/pubspec.yaml index 25a1a5c3..87a9cb0d 100644 --- a/packages/powersync/pubspec.yaml +++ b/packages/powersync/pubspec.yaml @@ -1,5 +1,5 @@ name: powersync -version: 1.3.0-alpha.8 +version: 1.3.0-alpha.9 homepage: https://powersync.com repository: https://github.com/powersync-ja/powersync.dart description: PowerSync Flutter SDK - keep PostgreSQL databases in sync with on-device SQLite databases. @@ -10,7 +10,8 @@ dependencies: flutter: sdk: flutter - sqlite_async: ^0.8.0 + sqlite_async: ^0.8.1 + universal_io: ^2.0.0 sqlite3_flutter_libs: ^0.5.15 meta: ^1.0.0 diff --git a/packages/powersync_attachments_helper/CHANGELOG.md b/packages/powersync_attachments_helper/CHANGELOG.md index 4e54661b..24a61a35 100644 --- a/packages/powersync_attachments_helper/CHANGELOG.md +++ b/packages/powersync_attachments_helper/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.0-alpha.4 + + - Update a dependency to the latest release. + ## 0.3.0-alpha.3 - Update a dependency to the latest release. diff --git a/packages/powersync_attachments_helper/pubspec.yaml b/packages/powersync_attachments_helper/pubspec.yaml index 1f43e557..bfce3395 100644 --- a/packages/powersync_attachments_helper/pubspec.yaml +++ b/packages/powersync_attachments_helper/pubspec.yaml @@ -1,6 +1,6 @@ name: powersync_attachments_helper description: A helper library for handling attachments when using PowerSync. -version: 0.3.0-alpha.3 +version: 0.3.0-alpha.4 repository: https://github.com/powersync-ja/powersync.dart homepage: https://www.powersync.com/ environment: @@ -10,7 +10,7 @@ dependencies: flutter: sdk: flutter - powersync: 1.3.0-alpha.8 + powersync: 1.3.0-alpha.9 logging: ^1.2.0 sqlite3: "^2.4.4" path_provider: ^2.0.13