-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Goal
I would like the following code not to crash.
val realm = Realm.getDefaultInstance()
// Freeze the Realm
val realm1 = realm.freeze()
// Freeze a second time first, then write to the live Realm
val realm2 = realm.freeze()
realm.executeTransaction { ... }
// Close the first frozen instance.
realm1.close()
// Make a query on the second frozen instance
// Throws IllegalStateException, saying that realm2 is closed.
realm2.where<...>().findAll().doSomething()
// Clean up
realm2.close()
realm.close()Actual Results
The code crashes on querying realm2, saying that realm2 is closed.
Steps & Code to Reproduce
Run the above code.
Version of Realm and tooling
Realm version(s): 10.6.0
Realm Sync feature enabled: No
Android Studio version: 4.2
Android Build Tools version: 4.0.1
Gradle version: 6.7.1
Which Android version and device(s): Android Emulator running 7.1.1 and 9.0
Other comments
The cause of the issue is the reference counting associated with the following code:
val realm1 = Realm.getDefaultInstance().freeze()
val realm2 = Realm.getDefaultInstance().freeze()
// The count of frozen instances at this version of the Realm is 1, not 2
// Now when we close one of our frozen instances, the reference count goes to 0. The shared frozen instance is deallocated.
realm1.close()
// So when we try to do a query on the other instance, an IllegalStateException is thrown.
realm2.where<...>().findAll()If we insert a write transaction (to an unfrozen instance) between the two freeze() calls, then an exception is no longer thrown because realm1 and realm2 now point at different database versions, rather than sharing a frozen instance. The main issue for me is that this can lead to a race condition between modifying the database and taking a frozen snapshot, with different results depending on who wins.
I submitted a PR (#7504) which I think fixes this – not sure what your guys' workflow is so sorry if that was a bit forward of me :D