Skip to content

Frozen Realms don't reference count correctly #7521

@alecbarber

Description

@alecbarber

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions