From c542857fb528cb159de67d23cbc590c19e6565e9 Mon Sep 17 00:00:00 2001 From: Krushna Kanta Rout <129386740+krushnarout@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:42:48 +0530 Subject: [PATCH 1/2] fix wal save crash and handle missing directory --- app/lib/services/wals/local_wal_sync.dart | 66 ++++++++++++++--------- app/lib/utils/wal_file_manager.dart | 52 ++++++++++++------ 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/app/lib/services/wals/local_wal_sync.dart b/app/lib/services/wals/local_wal_sync.dart index 7879697a8f..b3b22201df 100644 --- a/app/lib/services/wals/local_wal_sync.dart +++ b/app/lib/services/wals/local_wal_sync.dart @@ -21,6 +21,8 @@ class LocalWalSyncImpl implements LocalWalSync { Timer? _chunkingTimer; Timer? _flushingTimer; + bool _isFlushing = false; + IWalSyncListener listener; int _framesPerSecond = 100; @@ -199,39 +201,51 @@ class LocalWalSyncImpl implements LocalWalSync { } Future _flush() async { - Logger.debug("_flushing"); - for (var i = 0; i < _wals.length; i++) { - final wal = _wals[i]; - - if (wal.storage == WalStorage.mem) { - String? filePath = await Wal.getFilePath(wal.getFileName()); - if (filePath == null) { - throw Exception('Flushing to storage failed. Cannot get file path.'); - } + if (_isFlushing) { + Logger.debug("LocalWalSync: Flush already in progress, skipping"); + return; + } + _isFlushing = true; + + try { + Logger.debug("_flushing"); + for (var i = 0; i < _wals.length; i++) { + final wal = _wals[i]; + + if (wal.storage == WalStorage.mem) { + String? filePath = await Wal.getFilePath(wal.getFileName()); + if (filePath == null) { + throw Exception('Flushing to storage failed. Cannot get file path.'); + } - List data = []; - for (int i = 0; i < wal.data.length; i++) { - var frame = wal.data[i].sublist(3); + List data = []; + for (int i = 0; i < wal.data.length; i++) { + var frame = wal.data[i].sublist(3); - final byteFrame = ByteData(frame.length); - for (int i = 0; i < frame.length; i++) { - byteFrame.setUint8(i, frame[i]); + final byteFrame = ByteData(frame.length); + for (int i = 0; i < frame.length; i++) { + byteFrame.setUint8(i, frame[i]); + } + data.addAll(Uint32List.fromList([frame.length]).buffer.asUint8List()); + data.addAll(byteFrame.buffer.asUint8List()); } - data.addAll(Uint32List.fromList([frame.length]).buffer.asUint8List()); - data.addAll(byteFrame.buffer.asUint8List()); - } - final file = File(filePath); - await file.writeAsBytes(data); - wal.filePath = wal.getFileName(); - wal.storage = WalStorage.disk; + final file = File(filePath); + await file.writeAsBytes(data); + wal.filePath = wal.getFileName(); + wal.storage = WalStorage.disk; - Logger.debug("_flush file ${wal.filePath}"); + Logger.debug("_flush file ${wal.filePath}"); - _wals[i] = wal; + _wals[i] = wal; + } } - } - await _saveWalsToFile(); + await _saveWalsToFile(); + } catch (e) { + Logger.debug("LocalWalSync: Error during flush: $e"); + } finally { + _isFlushing = false; + } } Future _saveWalsToFile() async { diff --git a/app/lib/utils/wal_file_manager.dart b/app/lib/utils/wal_file_manager.dart index b3cfd74121..08179a8942 100644 --- a/app/lib/utils/wal_file_manager.dart +++ b/app/lib/utils/wal_file_manager.dart @@ -53,28 +53,46 @@ class WalFileManager { } static Future saveWals(List wals) async { - if (_walFile == null) { - await init(); - } + final previousFuture = _lastSaveFuture; + final completer = Completer(); + _lastSaveFuture = completer.future; - if (_walFile == null) { - Logger.debug('WAL file is null, cannot save'); - return false; - } + await previousFuture.catchError((_) {}); - await _createBackup(); + try { + if (_walFile == null) { + await init(); + } - final jsonData = { - 'version': 1, - 'timestamp': DateTime.now().millisecondsSinceEpoch, - 'wals': wals.map((wal) => wal.toJson()).toList(), - }; + if (_walFile == null) { + Logger.debug('WAL file is null, cannot save'); + return false; + } - final jsonString = jsonEncode(jsonData); - await _walFile!.writeAsString(jsonString); + if (!_walFile!.parent.existsSync()) { + try { + await _walFile!.parent.create(recursive: true); + } catch (e) { + Logger.debug('Failed to create WAL directory: $e'); + } + } + + await _createBackup(); + + final jsonData = { + 'version': 1, + 'timestamp': DateTime.now().millisecondsSinceEpoch, + 'wals': wals.map((wal) => wal.toJson()).toList(), + }; - Logger.debug('Successfully saved ${wals.length} WALs to file'); - return true; + final jsonString = jsonEncode(jsonData); + await _walFile!.writeAsString(jsonString); + + Logger.debug('Successfully saved ${wals.length} WALs to file'); + return true; + } finally { + completer.complete(); + } } static Future _createBackup() async { From 9f90dc2bb2eeb21d1ba61abc7acd13af593a8a7c Mon Sep 17 00:00:00 2001 From: Krushna Kanta Rout <129386740+krushnarout@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:02:04 +0530 Subject: [PATCH 2/2] fix error handling --- app/lib/services/wals/local_wal_sync.dart | 1 + app/lib/utils/wal_file_manager.dart | 3 +++ 2 files changed, 4 insertions(+) diff --git a/app/lib/services/wals/local_wal_sync.dart b/app/lib/services/wals/local_wal_sync.dart index b3b22201df..7b4746fc27 100644 --- a/app/lib/services/wals/local_wal_sync.dart +++ b/app/lib/services/wals/local_wal_sync.dart @@ -243,6 +243,7 @@ class LocalWalSyncImpl implements LocalWalSync { await _saveWalsToFile(); } catch (e) { Logger.debug("LocalWalSync: Error during flush: $e"); + rethrow; } finally { _isFlushing = false; } diff --git a/app/lib/utils/wal_file_manager.dart b/app/lib/utils/wal_file_manager.dart index 08179a8942..8469b866e5 100644 --- a/app/lib/utils/wal_file_manager.dart +++ b/app/lib/utils/wal_file_manager.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -18,6 +19,7 @@ class WalFileManager { static File? _walFile; static File? _walBackupFile; + static Future _lastSaveFuture = Future.value(); static Future init() async { final directory = @@ -74,6 +76,7 @@ class WalFileManager { await _walFile!.parent.create(recursive: true); } catch (e) { Logger.debug('Failed to create WAL directory: $e'); + return false; } }