Home > Software engineering >  Is it safe to perform Realm local migration in background thread?
Is it safe to perform Realm local migration in background thread?

Time:12-12

We in the process of optimizing app startup time and one of the huge slow down come from realm initialization.

We have this code which has been called during didFinishLaunchingWithOptions

RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
config.schemaVersion = kCurrentSchema;
config.migrationBlock = /* migration task */;
config.fileURL = fileUrl;
config.encryptionKey = encryptionKey;
    
return config;

During the initialization we try to create RLMRealm at least once using this configuration to see that we able to open realm or not. If the opening fail then we perform operations to remove Realm folder using NSFileManager and start anew. After everything is done we set

[RLMRealmConfiguration setDefaultConfiguration:config];

My question is

  1. Can we move the whole process of creating RLMRealmConfiguration and initialize RLMRealm in background thread?
  2. Can we dispatch RLMRealmConfiguration create in background thread to main thread to call setDefaultConfiguration on main thread after the migration is done?.
  3. After successful migration and dispatch to call [RLMRealmConfiguration setDefaultConfiguration:config]; on main thread, the migration result from background thread is written to the file or still in memory? If I create another RLMRealm on main thread directly after setDefaultConfiguration. Can I access the migrated version? I know about RLMThreadSafeReference but that only to be used when we know how to access. In my case, we will have too many accesses after the setup.

CodePudding user response:

Creating a new RLMRealmConfiguration and calling setDefaultConfiguration are trivial operations. Neither of them trigger migrations.

Migrations don't run until you open a realm.

There are a couple of ways to cause the migration to run in a background thread. I'll show you the easiest way in Swift. You'll have to translate this code to Objective-C:

enum Migrator {

    static func migrate(completion: @escaping () -> Void) {

        let queue = DispatchQueue(label: "migrator.awesome")

        let configuration = Realm.Configuration(
            schemaVersion: 13,
            migrationBlock: { migration, oldSchemaVersion in
                if oldSchemaVersion < 1 {
                    // ...
                }
                if oldSchemaVersion < 2 {
                    // ...
                }
                if oldSchemaVersion < 3 {
                    // ...
                }
                // ...
            }
        )

        Realm.asyncOpen(configuration: configuration, callbackQueue: queue) { result in

            Realm.Configuration.defaultConfiguration = configuration

            switch result {
            case .failure(let error):
                print("error", error)
            case .success(let realm):
                print("realm", realm)
                break
            }
            completion()
        }
    }
}

asyncOpen will open a realm and run the migration on the specified queue. In your case, you want to pass in a background queue. Once the migration runs asyncOpen will invoke the specified callback on the same queue you specified.

Once the migration is complete you can switch back to the main thread and do whatever you need to do. And yes, the data that was migrated in the background thread will be available to the main thread.

enum RealmInitializer {
    static func initializeRealm() {
        Migrator.migrate {
            DispatchQueue.main.async {
                readAndWriteRealmData()
            }
        }
    }
}
  • Related