isar / isar/hive

Is it possible to catch correctly FileSystemException when openBox fails?

Open
#1,149 1 comment 0 reactions 0 assignees View on GitHub
question
Dominant language
Dart
Stars
4.4k
Forks
449
PR merge metrics
No merged PRs in 30d

Description

In my Linux server there are two users allowed to execute a Hive based program. It works okay for both users unless program is executed at the same time. One gets hive.lock file correctly, the other gets FileSystemException.

The trouble came when I tried to implement a 3 attemps logic. I catch this exception, then I wait for 1500 ms and retry again (with 3 maximum attemps). I catch the Exception successfully, but then it came another exception (exactly the same stackTrace). I have been fighting for 2 hours with this issue, asking myself what I was doing bad, even recreating that logic in a test program.

Finally I decided to look at the source code (version 2.2.3). At HiveImpl._openBox method, I can see the catch clause at 116 line and I can see now the trouble:

```
Future> _openBox(
String name,
bool lazy,
HiveCipher? cipher,
KeyComparator comparator,
CompactionStrategy compaction,
bool recovery,
String? path,
Uint8List? bytes,
String? collection,
) async {
assert(path == null || bytes == null);
assert(name.length <= 255 && name.isAscii,
'Box names need to be ASCII Strings with a max length of 255.');
name = name.toLowerCase();
if (isBoxOpen(name)) {
if (lazy) {
return lazyBox(name);
} else {
return box(name);
}
} else {
if (_openingBoxes.containsKey(name)) {
await _openingBoxes[name];
if (lazy) {
return lazyBox(name);
} else {
return box(name);
}
}

var completer = Completer();
_openingBoxes[name] = completer.future;

BoxBaseImpl? newBox;
try {
StorageBackend backend;
if (bytes != null) {
backend = StorageBackendMemory(bytes, cipher);
} else {
backend = await _manager.open(
name, path ?? homePath, recovery, cipher, collection);
}

if (lazy) {
newBox = LazyBoxImpl(this, name, comparator, compaction, backend);
} else {
newBox = BoxImpl(this, name, comparator, compaction, backend);
}

await newBox.initialize();
_boxes[name] = newBox;

completer.complete();
return newBox;
} catch (error, stackTrace) {
newBox?.close();
completer.completeError(error, stackTrace);
rethrow;
} finally {
// ignore: unawaited_futures
_openingBoxes.remove(name);
}
}
}
```

Exception is getting rethrowed again (okay). The thing is the completer getting complete with that error, but this time I don't see a way to catch it and an UnhandledException is crashing my app/logic.

Any idea/workaround?

Thank you

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at HiveImpl._openBox, especially the _openingBoxes completer path shown in the issue, and reproduce two simultaneous openBox calls followed by retries. Done means the FileSystemException can be handled by the caller without an additional unhandled error during concurrent opens.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.