From 9960124d3219e2ab72e14443a1a79a1bac6b2cd3 Mon Sep 17 00:00:00 2001 From: Jagandeep Brar Date: Mon, 29 Aug 2022 14:49:50 -0400 Subject: [PATCH] fix(database): prevent deadlock in database deletion actions --- lib/database/database.dart | 31 ++++++++++++++----- lib/system/filesystem/filesystem.dart | 1 + .../filesystem/platform/filesystem_io.dart | 18 +++++++++-- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lib/database/database.dart b/lib/database/database.dart index 0d90beaa..b5ba6fe9 100644 --- a/lib/database/database.dart +++ b/lib/database/database.dart @@ -3,6 +3,8 @@ import 'package:lunasea/database/models/profile.dart'; import 'package:lunasea/database/table.dart'; import 'package:lunasea/database/tables/bios.dart'; import 'package:lunasea/database/tables/lunasea.dart'; +import 'package:lunasea/system/filesystem/filesystem.dart'; +import 'package:lunasea/system/logger.dart'; import 'package:lunasea/system/platform.dart'; import 'package:lunasea/vendor.dart'; @@ -10,13 +12,13 @@ class LunaDatabase { static const String _DATABASE_LEGACY_PATH = 'database'; static const String _DATABASE_PATH = 'LunaSea/database'; - String get _path { + String get path { if (LunaPlatform.isWindows || LunaPlatform.isLinux) return _DATABASE_PATH; return _DATABASE_LEGACY_PATH; } Future initialize() async { - await Hive.initFlutter(_path); + await Hive.initFlutter(path); LunaTable.register(); await open(); } @@ -25,13 +27,28 @@ class LunaDatabase { try { await LunaBox.open(); if (LunaBox.profiles.isEmpty) await bootstrap(); - } catch (error) { - for (final box in LunaBox.values) { - await Hive.deleteBoxFromDisk(box.key); - } - + } catch (error, stack) { + await nuke(); await LunaBox.open(); await bootstrap(databaseCorruption: true); + + LunaLogger().error( + 'Database corruption detected', + error, + stack, + ); + } + } + + Future nuke() async { + await Hive.close(); + + for (final box in LunaBox.values) { + await Hive.deleteBoxFromDisk(box.key, path: path); + } + + if (LunaFileSystem.isSupported) { + await LunaFileSystem().nuke(); } } diff --git a/lib/system/filesystem/filesystem.dart b/lib/system/filesystem/filesystem.dart index 654de64f..011f7c1c 100644 --- a/lib/system/filesystem/filesystem.dart +++ b/lib/system/filesystem/filesystem.dart @@ -17,4 +17,5 @@ abstract class LunaFileSystem { Future save(BuildContext context, String name, List data); Future read(BuildContext context, List extensions); + Future nuke(); } diff --git a/lib/system/filesystem/platform/filesystem_io.dart b/lib/system/filesystem/platform/filesystem_io.dart index b3194c10..f27467d1 100644 --- a/lib/system/filesystem/platform/filesystem_io.dart +++ b/lib/system/filesystem/platform/filesystem_io.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:lunasea/database/database.dart'; import 'package:lunasea/vendor.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; @@ -21,7 +22,20 @@ LunaFileSystem getFileSystem() { throw UnsupportedError('LunaFileSystem unsupported'); } -class _Desktop implements LunaFileSystem { +abstract class _Shared implements LunaFileSystem { + @override + Future nuke() async { + final subpath = LunaDatabase().path; + final appDocDir = await getApplicationDocumentsDirectory(); + final database = Directory('${appDocDir.path}/$subpath'); + + if (database.existsSync()) { + database.deleteSync(recursive: true); + } + } +} + +class _Desktop extends _Shared { @override Future save(BuildContext context, String name, List data) async { try { @@ -69,7 +83,7 @@ class _Desktop implements LunaFileSystem { } } -class _Mobile implements LunaFileSystem { +class _Mobile extends _Shared { @override Future save(BuildContext context, String name, List data) async { try {