Skip to content

Commit

Permalink
Keep track of the initial Realm scheduler.
Browse files Browse the repository at this point in the history
  • Loading branch information
clementetb committed Oct 20, 2023
1 parent 5526957 commit 3c8ea7a
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ import io.realm.kotlin.internal.interop.LiveRealmPointer
import io.realm.kotlin.internal.interop.MigrationCallback
import io.realm.kotlin.internal.interop.RealmConfigurationPointer
import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmSchedulerPointer
import io.realm.kotlin.internal.interop.RealmSchemaPointer
import io.realm.kotlin.internal.interop.SchemaMode
import io.realm.kotlin.internal.interop.use
import io.realm.kotlin.internal.platform.appFilesDirectory
import io.realm.kotlin.internal.platform.prepareRealmFilePath
import io.realm.kotlin.internal.platform.realmObjectCompanionOrThrow
Expand Down Expand Up @@ -107,17 +107,14 @@ public open class ConfigurationImpl(
return configInitializer(nativeConfig)
}

override suspend fun openRealm(realm: RealmImpl): Pair<FrozenRealmReference, Boolean> {
override suspend fun openRealm(realm: RealmImpl): Triple<FrozenRealmReference, Boolean, RealmSchedulerPointer> {
val configPtr = realm.configuration.createNativeConfiguration()
return RealmInterop.realm_create_scheduler()
.use { scheduler ->
val (dbPointer, fileCreated) = RealmInterop.realm_open(configPtr, scheduler)
val liveRealmReference = LiveRealmReference(realm, dbPointer)
val frozenReference = liveRealmReference.snapshot(realm)
liveRealmReference.close()
dbPointer.release()
frozenReference to fileCreated
}
val scheduler = RealmInterop.realm_create_scheduler()
val (dbPointer, fileCreated) = RealmInterop.realm_open(configPtr, scheduler)
val liveRealmReference = LiveRealmReference(realm, dbPointer)
val frozenReference = liveRealmReference.snapshot(realm)
liveRealmReference.close()
return Triple(frozenReference, fileCreated, scheduler)
}

override suspend fun initializeRealmData(realm: RealmImpl, realmFileCreated: Boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package io.realm.kotlin.internal

import io.realm.kotlin.Configuration
import io.realm.kotlin.internal.interop.RealmConfigurationPointer
import io.realm.kotlin.internal.interop.RealmSchedulerPointer
import io.realm.kotlin.internal.interop.SchemaMode
import io.realm.kotlin.internal.util.CoroutineDispatcherFactory
import io.realm.kotlin.types.BaseRealmObject
Expand Down Expand Up @@ -59,7 +60,7 @@ public interface InternalConfiguration : Configuration {
* @param realm instance of the Realm that is being created.
* @returns a pair of (LiveRealmPointer, FileCreated)
*/
public suspend fun openRealm(realm: RealmImpl): Pair<FrozenRealmReference, Boolean>
public suspend fun openRealm(realm: RealmImpl): Triple<FrozenRealmReference, Boolean, RealmSchedulerPointer>

/**
* This function is a way `RealmImpl` can defer how the Realm is initialized once opened.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import io.realm.kotlin.Realm
import io.realm.kotlin.dynamic.DynamicRealm
import io.realm.kotlin.internal.dynamic.DynamicRealmImpl
import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmSchedulerPointer
import io.realm.kotlin.internal.interop.SynchronizableObject
import io.realm.kotlin.internal.platform.copyAssetFile
import io.realm.kotlin.internal.platform.fileExists
Expand Down Expand Up @@ -95,6 +96,13 @@ public class RealmImpl private constructor(
override val realmReference: FrozenRealmReference
get() = realmReference()

// TODO We have to keep this scheduler alive while the initial realm is open. We have no notification
// from core when we can release, to be safe we will tie its lifecycle to the user-facing Realm.
// Releasing this scheduler might incur in race-conditions, leading to core crashing.
// For example after a client reset it might try to notify with this scheduler that might have been
// released.
private lateinit var initialScheduler: RealmSchedulerPointer

// TODO Bit of an overkill to have this as we are only catching the initial frozen version.
// Maybe we could just rely on the notifier to issue the initial frozen version, but that
// would require us to sync that up. Didn't address this as we already have a todo on fixing
Expand Down Expand Up @@ -129,7 +137,8 @@ public class RealmImpl private constructor(
}
}
}
val (frozenReference, fileCreated) = configuration.openRealm(this@RealmImpl)
val (frozenReference, fileCreated, scheduler) = configuration.openRealm(this@RealmImpl)
initialScheduler = scheduler
realmFileCreated = assetFileCopied || fileCreated
versionTracker.trackAndCloseExpiredReferences(frozenReference)
_realmReference.value = frozenReference
Expand Down Expand Up @@ -279,7 +288,6 @@ public class RealmImpl private constructor(
if (!realmStateFlow.tryEmit(State.CLOSED)) {
log.warn("Cannot signal internal close")
}

notificationScheduler.close()
writeScheduler.close()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import io.realm.kotlin.internal.interop.RealmAppPointer
import io.realm.kotlin.internal.interop.RealmAsyncOpenTaskPointer
import io.realm.kotlin.internal.interop.RealmConfigurationPointer
import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmSchedulerPointer
import io.realm.kotlin.internal.interop.RealmSyncConfigurationPointer
import io.realm.kotlin.internal.interop.RealmSyncSessionPointer
import io.realm.kotlin.internal.interop.SyncAfterClientResetHandler
Expand Down Expand Up @@ -69,7 +70,7 @@ internal class SyncConfigurationImpl(
override val initialRemoteData: InitialRemoteDataConfiguration?
) : InternalConfiguration by configuration, SyncConfiguration {

override suspend fun openRealm(realm: RealmImpl): Pair<FrozenRealmReference, Boolean> {
override suspend fun openRealm(realm: RealmImpl): Triple<FrozenRealmReference, Boolean, RealmSchedulerPointer> {
// Partition-based Realms with `waitForInitialRemoteData` enabled will use
// async open first do download the server side Realm. This is much faster than
// creating the Realm locally first and then downloading (and integrating) changes into
Expand Down Expand Up @@ -131,8 +132,8 @@ internal class SyncConfigurationImpl(
// So there are two possibilities for the file to be created:
// 1) .waitForInitialRemoteData caused async open to be used, which created the file.
// 2) The synced Realm was opened locally first (without async open), which then created the file.
val result: Pair<FrozenRealmReference, Boolean> = configuration.openRealm(realm)
return Pair(result.first, result.second || asyncOpenCreatedRealmFile.value)
val result: Triple<FrozenRealmReference, Boolean, RealmSchedulerPointer> = configuration.openRealm(realm)
return Triple(result.first, result.second || asyncOpenCreatedRealmFile.value, result.third)
}

override suspend fun initializeRealmData(realm: RealmImpl, realmFileCreated: Boolean) {
Expand Down

0 comments on commit 3c8ea7a

Please sign in to comment.