-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
openBox/openLazyBox can potentially open a Box twice #345
Comments
openBox is a Future, which means that the compiler will move to the next line before the result of the variable, until the end of the Future, instance1 and instance2 are two different Futures objects. When the result arrives, they will be pointed to the same reference in memory. final instance1 = await Hive.openBox('test'); // instance1.hashCode == instance2.hashCode Thus, I believe that using await there is no possibility to open the box twice. |
There is, I am actually awaiting the Future - I mentioned this is very simplified |
And I believe, it should be prevented on the library level, to open a box twice, since it leads to very unpredictable behavior. |
Well, I guess you didn't quite understand what I meant, so I'll try to explain it better. When you create a variable, it is always a "new" instance. class Foo{}
final a = Foo();
final b = Foo();
print(a==b); // false When you declare a "Future", you are calling the factory of the Future class, and this will always return a new instance. import 'dart:async';
void main() {
final a = asyncFunction();
final b = asyncFunction2();
print(a==b);
//Console: false
}
String global = 'global';
Future<String> asyncFunction() {
return Future.value(global);
}
Future<String> asyncFunction2() {
return Future.value(global);
}
When you declare an instance of a Future, the dart creates an instance of a Future, so that you can get the promised value with an await / then. The delivered object is not the object you are waiting for, it is just a factory, so you can get the instance, function or variable you want with an await/then. import 'dart:async';
void main() async {
final a = await asyncFunction();
final b = await asyncFunction2();
print(a==b);
//Console: true
}
String global = 'global';
Future<String> asyncFunction() {
return Future.value(global);
}
Future<String> asyncFunction2() {
return Future.value(global);
}
Despite always creating a different instance of Future, the created object will always be the same instance when called with an await/then import 'dart:async';
void main() async {
final a = asyncFunction();
final b = asyncFunction2();
print(a==b);
// false
final c = await a;
final d = await b;
print(c ==d);
// true
}
String global = 'global';
Future<String> asyncFunction() {
return Future.value(global);
}
Future<String> asyncFunction2() {
return Future.value(global);
}
So, you are not opening two boxes, you will only open the first, the second will give you the same object as the first. This is standard dart behavior, and the box will only open once on the hive, as hive checks if there is an open box. |
Thank you for the detailed explanation. But it is actually opened twice, I have a working (well broken) example - where I can get two boxes to open and notifications of changes not being delivered. EDIT: |
Awaiting works as expected, the problem is when you don't await them like so (in the synchronous matter), which can easily happen, when you call "openBox" from different parts of the app. Then, you can easily get two different instances. I will try to give you a test scenario which fails. |
But you have to await |
First, I am really disappointed in people replying in this thread (@themisir ) , since all you do is trying to make me the stupid one, who doesn't understand Dart/Flutter. I would appreciate if you tried and instead were open-minded and thought about the problem, instead of fast "bullshit" replies. It's just useless for the open-source community and discourages people like me to contribute and help. I understand my explanations are not perfect, but, well it's not easy to explain complex problems in a few sentences/short samples of code. With that out of way - No, I think you don't understand. I do "await" the opening of box, that's not the problem. I don't await two of them synchronously, in one file one after another. The problem is that having two separate "classes", which both open the same box inside, using them from separate parts of the app. If by chance, you call the "openBox" function at the same time - awaiting results - Dart doesn't guarantee that they will happen one after another and this library doesn't handle this either. Here is a reproduction example: https://github.com/filipproch/hive_bug_synchronization_reproduction Run it and you will get multiple instances of "Box" (in my case for example)
|
Thanks, I understand. Maybe I could cache openBox requests too. I will think about how to fix that issue. Sorry for misunderstanding ): |
Steps to Reproduce
Call
openBox
oropenLazyBox
twice in succession with the same arguments. The result will be two different instances (checked by "hashCode").This causes issues when writing to the database since notifications about changes are tied to a each instance. To obtain new data, one needs to
close
and open again.To solve this, I am using https://pub.dev/packages/synchronized
But I believe this should be handled by the library, as I personally, just to understand where the issue lays, spent a few days of "WTF is happening".
Code sample
EDIT:
Here is a reproduction example: https://github.com/filipproch/hive_bug_synchronization_reproduction
Run it and you will get multiple instances of "Box" (in my case for example)
The following example is simplified, to accent the problem
My solution
Version
The text was updated successfully, but these errors were encountered: