From 340cc17bb3e32a0fca581b06d3665e4ffe1f8a0f Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Thu, 15 Aug 2024 08:33:15 +0930 Subject: [PATCH 1/2] move all databases to a single isolate --- commet/lib/cache/drift_file_cache.dart | 48 +++----------- .../matrix/database/matrix_database_io.dart | 59 ++++-------------- commet/lib/main.dart | 3 + .../lib/utils/multiple_database_server.dart | 62 +++++++++++++++++++ 4 files changed, 87 insertions(+), 85 deletions(-) create mode 100644 commet/lib/utils/multiple_database_server.dart diff --git a/commet/lib/cache/drift_file_cache.dart b/commet/lib/cache/drift_file_cache.dart index adc66749..d0e5ed4a 100644 --- a/commet/lib/cache/drift_file_cache.dart +++ b/commet/lib/cache/drift_file_cache.dart @@ -1,16 +1,11 @@ import 'dart:io'; -import 'dart:isolate'; -import 'dart:ui'; - import 'package:commet/cache/file_cache.dart'; import 'package:commet/config/app_config.dart'; import 'package:commet/config/build_config.dart'; import 'package:commet/debug/log.dart'; +import 'package:commet/utils/multiple_database_server.dart'; import 'package:commet/utils/rng.dart'; import 'package:drift/drift.dart'; -import 'package:drift/isolate.dart'; -import 'package:drift/native.dart'; -import 'package:flutter/services.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; @@ -147,41 +142,18 @@ class DriftFileCache implements FileCache { isInit = true; - var port = IsolateNameServer.lookupPortByName(DriftFileCache.isolateName); - - var isolate = DriftIsolate.fromConnectPort( - port ?? (await createIsolate()).connectPort); - - db = DriftFileCacheDatabase(await isolate.connect()); - clean(); - } - - Future createIsolate() async { - final token = RootIsolateToken.instance!; - var isolate = await DriftIsolate.spawn(() { - BackgroundIsolateBinaryMessenger.ensureInitialized(token); - - return LazyDatabase(() async { - final dir = p.join(await AppConfig.getDatabasePath(), "app"); - var directory = Directory(dir); - if (!await directory.exists()) { - await directory.create(recursive: true); - } + final dir = p.join(await AppConfig.getDatabasePath(), "app"); + var directory = Directory(dir); + if (!await directory.exists()) { + await directory.create(recursive: true); + } - final file = File(p.join(dir, "app_data.db")); - return NativeDatabase(file); - }); - }, isolateSpawn: DriftFileCache._spawn); + final file = File(p.join(dir, "app_data.db")); - IsolateNameServer.registerPortWithName( - isolate.connectPort, DriftFileCache.isolateName); + var connection = await DatabaseIsolate.connect(file.absolute.path); + db = DriftFileCacheDatabase(connection); - return isolate; - } - - static Future _spawn( - void Function(T message) entryPoint, T message) { - return Isolate.spawn(entryPoint, message, debugName: "File Cache Isolate"); + clean(); } @override diff --git a/commet/lib/client/matrix/database/matrix_database_io.dart b/commet/lib/client/matrix/database/matrix_database_io.dart index 2d79f349..cb869b10 100644 --- a/commet/lib/client/matrix/database/matrix_database_io.dart +++ b/commet/lib/client/matrix/database/matrix_database_io.dart @@ -1,26 +1,26 @@ import 'dart:io'; -import 'dart:isolate'; -import 'dart:ui'; import 'package:commet/config/app_config.dart'; import 'package:commet/diagnostic/diagnostics.dart'; -import 'package:drift/drift.dart'; -import 'package:drift/isolate.dart'; -import 'package:flutter/services.dart'; +import 'package:commet/utils/multiple_database_server.dart'; import 'package:matrix/matrix.dart'; import 'package:matrix_dart_sdk_drift_db/matrix_dart_sdk_drift_db.dart'; import 'package:path/path.dart' as p; -// ignore: depend_on_referenced_packages -import 'package:drift/native.dart'; Future getMatrixDatabaseImplementation(String clientName) async { - var port = - IsolateNameServer.lookupPortByName(_getIsolateNameForClient(clientName)); + var path = await AppConfig.getDriftDatabasePath(); + path = p.join(path, clientName, "data.db"); + var dir = p.dirname(path); - var isolate = DriftIsolate.fromConnectPort( - port ?? (await _createIsolate(clientName)).connectPort); + if (!await Directory(dir).exists()) { + await Directory(dir).create(recursive: true); + } - return MatrixSdkDriftDatabase.init(await isolate.connect(), clientName, + final file = File(path); + + var connection = await DatabaseIsolate.connect(file.absolute.path); + + return MatrixSdkDriftDatabase.init(connection, clientName, benchmark: benchmarkFunc); } @@ -29,41 +29,6 @@ Future benchmarkFunc(String name, Future Function() func, return Diagnostics.databaseDiagnostics.timeAsync(name, func); } -Future _createIsolate(String clientName) async { - final token = RootIsolateToken.instance!; - var isolate = await DriftIsolate.spawn( - () { - BackgroundIsolateBinaryMessenger.ensureInitialized(token); - - return LazyDatabase(() async { - var path = await AppConfig.getDriftDatabasePath(); - path = p.join(path, clientName, "data.db"); - var dir = p.dirname(path); - - if (!await Directory(dir).exists()) { - await Directory(dir).create(recursive: true); - } - - final file = File(path); - return NativeDatabase(file); - }); - }, - isolateSpawn: (Function(T message) entryPoint, T message) { - return Isolate.spawn(entryPoint, message, - debugName: "Client $clientName DB Isolate"); - }, - ); - - IsolateNameServer.registerPortWithName( - isolate.connectPort, _getIsolateNameForClient(clientName)); - - return isolate; -} - -String _getIsolateNameForClient(String clientName) { - return "chat.commet.commetapp.isolate.client_$clientName"; -} - Future getLegacyMatrixDatabaseImplementation( String clientName) async { return null; diff --git a/commet/lib/main.dart b/commet/lib/main.dart index 377fe33b..d6a89f94 100644 --- a/commet/lib/main.dart +++ b/commet/lib/main.dart @@ -20,6 +20,7 @@ import 'package:commet/utils/custom_uri.dart'; import 'package:commet/utils/background_tasks/background_task_manager.dart'; import 'package:commet/utils/emoji/unicode_emoji.dart'; import 'package:commet/utils/event_bus.dart'; +import 'package:commet/utils/multiple_database_server.dart'; import 'package:commet/utils/scaled_app.dart'; import 'package:commet/utils/shortcuts_manager.dart'; import 'package:commet/utils/window_management.dart'; @@ -145,6 +146,8 @@ WidgetsBinding ensureBindingInit() { Future initNecessary() async { sqfliteFfiInit(); await preferences.init(); + await DatabaseIsolate.start(); + fileCache = FileCache.getFileCacheInstance(); await Future.wait([ diff --git a/commet/lib/utils/multiple_database_server.dart b/commet/lib/utils/multiple_database_server.dart new file mode 100644 index 00000000..13279aa2 --- /dev/null +++ b/commet/lib/utils/multiple_database_server.dart @@ -0,0 +1,62 @@ +import 'dart:io'; +import 'dart:isolate'; +import 'dart:ui'; + +import 'package:drift/drift.dart'; +import 'package:drift/isolate.dart'; +import 'package:drift/native.dart'; + +final class MultiDatabaseServer { + final Map _activeIsolates = {}; + final ReceivePort _receiveConnections = ReceivePort(); + + MultiDatabaseServer() { + _receiveConnections.listen((message) { + if (message is (String, SendPort)) { + final name = message.$1; + final isolate = _activeIsolates.putIfAbsent( + name, + () { + return DriftIsolate.inCurrent( + // obviously you can pass a path instead of a name and use that to open the right NativeDatabase + () => NativeDatabase(File(name))); + }, + ); + + message.$2.send(isolate.connectPort); + } + }); + } +} + +class DatabaseIsolate { + static final receiveConnectPort = ReceivePort(); + static SendPort? connectToServer; + static const isolateName = "chat.commet.commetapp.database_isolate"; + + static Future start() async { + connectToServer = IsolateNameServer.lookupPortByName(isolateName); + if (connectToServer == null) { + Isolate.spawn( + (SendPort port) { + final server = MultiDatabaseServer(); + port.send(server._receiveConnections.sendPort); + }, + receiveConnectPort.sendPort, + debugName: "Database Isolate", + ); + + connectToServer = await receiveConnectPort.first as SendPort; + IsolateNameServer.registerPortWithName(connectToServer!, isolateName); + } + } + + static Future connect(String databaseName) async { + final response = ReceivePort(); + connectToServer!.send((databaseName, response.sendPort)); + + final connectPort = await response.first as SendPort; + return DriftIsolate.fromConnectPort(connectPort, serialize: false) + .connect(); + } +} From 698dfa444dd26459189b10a1aaeee5924ad99f0e Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 16 Aug 2024 08:19:29 +0930 Subject: [PATCH 2/2] Fix web builds --- commet/lib/cache/drift_file_cache.dart | 2 +- commet/lib/client/matrix/database/matrix_database_io.dart | 2 +- commet/lib/main.dart | 4 ++-- commet/lib/utils/database/database_server.dart | 6 ++++++ commet/lib/utils/database/database_server_io.dart | 5 +++++ commet/lib/utils/database/database_server_stub.dart | 1 + .../lib/utils/{ => database}/multiple_database_server.dart | 0 7 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 commet/lib/utils/database/database_server.dart create mode 100644 commet/lib/utils/database/database_server_io.dart create mode 100644 commet/lib/utils/database/database_server_stub.dart rename commet/lib/utils/{ => database}/multiple_database_server.dart (100%) diff --git a/commet/lib/cache/drift_file_cache.dart b/commet/lib/cache/drift_file_cache.dart index d0e5ed4a..124666c4 100644 --- a/commet/lib/cache/drift_file_cache.dart +++ b/commet/lib/cache/drift_file_cache.dart @@ -3,7 +3,7 @@ import 'package:commet/cache/file_cache.dart'; import 'package:commet/config/app_config.dart'; import 'package:commet/config/build_config.dart'; import 'package:commet/debug/log.dart'; -import 'package:commet/utils/multiple_database_server.dart'; +import 'package:commet/utils/database/multiple_database_server.dart'; import 'package:commet/utils/rng.dart'; import 'package:drift/drift.dart'; import 'package:path/path.dart' as p; diff --git a/commet/lib/client/matrix/database/matrix_database_io.dart b/commet/lib/client/matrix/database/matrix_database_io.dart index cb869b10..cbb04fca 100644 --- a/commet/lib/client/matrix/database/matrix_database_io.dart +++ b/commet/lib/client/matrix/database/matrix_database_io.dart @@ -2,7 +2,7 @@ import 'dart:io'; import 'package:commet/config/app_config.dart'; import 'package:commet/diagnostic/diagnostics.dart'; -import 'package:commet/utils/multiple_database_server.dart'; +import 'package:commet/utils/database/multiple_database_server.dart'; import 'package:matrix/matrix.dart'; import 'package:matrix_dart_sdk_drift_db/matrix_dart_sdk_drift_db.dart'; import 'package:path/path.dart' as p; diff --git a/commet/lib/main.dart b/commet/lib/main.dart index d6a89f94..f992c8a7 100644 --- a/commet/lib/main.dart +++ b/commet/lib/main.dart @@ -18,9 +18,9 @@ import 'package:commet/ui/pages/main/main_page.dart'; import 'package:commet/utils/android_intent_helper.dart'; import 'package:commet/utils/custom_uri.dart'; import 'package:commet/utils/background_tasks/background_task_manager.dart'; +import 'package:commet/utils/database/database_server.dart'; import 'package:commet/utils/emoji/unicode_emoji.dart'; import 'package:commet/utils/event_bus.dart'; -import 'package:commet/utils/multiple_database_server.dart'; import 'package:commet/utils/scaled_app.dart'; import 'package:commet/utils/shortcuts_manager.dart'; import 'package:commet/utils/window_management.dart'; @@ -146,7 +146,7 @@ WidgetsBinding ensureBindingInit() { Future initNecessary() async { sqfliteFfiInit(); await preferences.init(); - await DatabaseIsolate.start(); + await initDatabaseServer(); fileCache = FileCache.getFileCacheInstance(); diff --git a/commet/lib/utils/database/database_server.dart b/commet/lib/utils/database/database_server.dart new file mode 100644 index 00000000..ef5bc7b3 --- /dev/null +++ b/commet/lib/utils/database/database_server.dart @@ -0,0 +1,6 @@ +import 'database_server_stub.dart' + if (dart.library.io) 'database_server_io.dart'; + +Future initDatabaseServer() async { + await initDatabaseServerImpl(); +} diff --git a/commet/lib/utils/database/database_server_io.dart b/commet/lib/utils/database/database_server_io.dart new file mode 100644 index 00000000..d2e41655 --- /dev/null +++ b/commet/lib/utils/database/database_server_io.dart @@ -0,0 +1,5 @@ +import 'package:commet/utils/database/multiple_database_server.dart'; + +Future? initDatabaseServerImpl() async { + await DatabaseIsolate.start(); +} diff --git a/commet/lib/utils/database/database_server_stub.dart b/commet/lib/utils/database/database_server_stub.dart new file mode 100644 index 00000000..c033cc81 --- /dev/null +++ b/commet/lib/utils/database/database_server_stub.dart @@ -0,0 +1 @@ +Future? initDatabaseServerImpl() => null; diff --git a/commet/lib/utils/multiple_database_server.dart b/commet/lib/utils/database/multiple_database_server.dart similarity index 100% rename from commet/lib/utils/multiple_database_server.dart rename to commet/lib/utils/database/multiple_database_server.dart