Write transactions increase Realm version number on each call
See original GitHub issueHi! This is more of a question of understanding how to keep realm versions low
I’m using the following code to write to the database:
override suspend fun save(e: Entry): Entry = Entry(db.write { upsert(e) })
// equal to, using inline functions:
suspend fun save(e: Entry): Entry = realm.write {
val rid: RealmUUID = e.id
val update: EntryEntity.() -> Unit = {
property = e.property
}
val entity = query<EntryEntity>("id == $0", rid).first().find() ?: EntryEntity().apply { id = rid }
copyToRealm(entity.apply(update), UpdatePolicy.ERROR)
}.mapToEntryDataClass() // maps the object to a domain model immediately outside of the db.write {} block
The save() function is invoked on a background thread (Dispatchers.IO or Dispatchers.Default)
I’m using a global singleton instance provided with Koin to my app
single(createdAtStart = true) { provideDatabase() } // <-- provideDatabase() creates and opens a Realm instance
And a few of the DAO objects, singletons too, accessed on random dispatchers.
But while queries run on Dispatchers.IO using this code:
internal suspend inline fun <T : BaseRealmObject> RealmQuery<T>.findSuspend(
context: CoroutineContext = Dispatchers.IO
) = withContext(context) { find() }
// result is immediately mapped to domain object
all run fine, each write operation produces the following Logcat output:
D Updating Realm version: VersionId(version=50) -> VersionId(version=51)
D Closing unreferenced version: 49
D Updating Realm version: VersionId(version=51) -> VersionId(version=51)
D Updating Realm version: VersionId(version=51) -> VersionId(version=52)
// each write produces 2 version increments
D Updating Realm version: VersionId(version=52) -> VersionId(version=52)
D Updating Realm version: VersionId(version=52) -> VersionId(version=53)
D Updating Realm version: VersionId(version=53) -> VersionId(version=53)
D Updating Realm version: VersionId(version=53) -> VersionId(version=54)
D Updating Realm version: VersionId(version=54) -> VersionId(version=54)
D Updating Realm version: VersionId(version=54) -> VersionId(version=55)
D Updating Realm version: VersionId(version=55) -> VersionId(version=55)
D Updating Realm version: VersionId(version=55) -> VersionId(version=56)
D Updating Realm version: VersionId(version=56) -> VersionId(version=56)
// this is output immediately before crash
D Closing unreferenced version: 55
D Closing unreferenced version: 54
D Closing unreferenced version: 55
D Closing unreferenced version: 53
D Closing unreferenced version: 54
D Closing unreferenced version: 52
D Closing unreferenced version: 53
D Closing unreferenced version: 51
D Closing unreferenced version: 52
D Closing unreferenced version: 51
D Updating Realm version: VersionId(version=56) -> VersionId(version=57)
D Updating Realm version: VersionId(version=57) -> VersionId(version=57)
E Error: java.lang.IllegalStateException: Cannot begin the write transaction: RealmCoreException([5]: Number of active versions (9) in the Realm exceeded the limit of 8)
Could you help me find out where do I leak Entity objects in my code? I don’t really understand where could they be stored as I never return an EntryEntity from my dao, everything is mapped right after it’s returned from the write block or after executing find()
I tried for a long time to find any public method for freezing an object /manually making it unmanaged, couldn’t find any.
Realm version: 1.4.0 Platform: Android Kotlin 1.7.20
My upsert function, which is probably the culprit:
internal inline fun <reified T : RealmObject> MutableRealm.upsert(
id: Uuid,
crossinline create: (RealmUUID) -> T, // verified this is not evaluated unnecessarily
crossinline update: T.() -> Unit,
): T {
val rid = id.toRealmUUID()
val entity = query<T>("id == $0", rid).first().find() ?: create(rid)
return copyToRealm(entity.apply(update), UpdatePolicy.ERROR)
}
Issue Analytics
- State:
- Created a year ago
- Comments:18 (4 by maintainers)
Top GitHub Comments
Thanks @cmelchior for the long answer.
On our side, having the 1. and 3. would cover most of our cases, but 2. and 4. could also be useful in some scenarios.
In our project, we often got the big file-size growth as reported in #1007, we have lots of transactions and active flows in parallel. Hopefully this will fix the issue waiting to have more control over the memory management.
Clearly thats not acceptable, and it’s preventing us to merge our realm-kotlin migration…