diff --git a/CHANGELOG.md b/CHANGELOG.md index 17d4deaa184..f6593d2f106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ x.y.z Release notes (yyyy-MM-dd) ============================================================= ### Enhancements -* None. +* Greatly improve the performance of obtaining cached Realm instances in Swift + when using a sync configuration. ### Fixed * ([#????](https://github.com/realm/realm-swift/issues/????), since v?.?.?) diff --git a/Realm/ObjectServerTests/SwiftObjectServerTests.swift b/Realm/ObjectServerTests/SwiftObjectServerTests.swift index c52c1c5deca..dba1cae2009 100644 --- a/Realm/ObjectServerTests/SwiftObjectServerTests.swift +++ b/Realm/ObjectServerTests/SwiftObjectServerTests.swift @@ -354,7 +354,7 @@ class SwiftObjectServerTests: SwiftSyncTestCase { waitForSyncDisabled(appServerId: appServerId, syncServiceId: syncServiceId) - try block() + try autoreleasepool(invoking: block) waitForSyncEnabled(appServerId: appServerId, syncServiceId: syncServiceId, syncServiceConfig: syncServiceConfig) try waitForDevModeEnabled(appServerId: appServerId, syncServiceId: syncServiceId, syncServiceConfig: syncServiceConfig) @@ -436,16 +436,15 @@ class SwiftObjectServerTests: SwiftSyncTestCase { // Sync is disabled, block executed, sync re-enabled try executeBlockOffline { - try autoreleasepool { - var configuration = user.configuration(partitionValue: partition) - configuration.objectTypes = [SwiftPerson.self] - let realm = try Realm(configuration: configuration) - // Add an object to the local realm that will not be in the server realm (because sync is disabled). - try realm.write { - realm.add(SwiftPerson(firstName: "John", lastName: "L")) - } - XCTAssertEqual(realm.objects(SwiftPerson.self).count, 1) + var configuration = user.configuration(partitionValue: partition) + configuration.objectTypes = [SwiftPerson.self] + let realm = try Realm(configuration: configuration) + realm.syncSession!.suspend() + // Add an object to the local realm that will not be in the server realm (because sync is disabled). + try realm.write { + realm.add(SwiftPerson(firstName: "John", lastName: "L")) } + XCTAssertEqual(realm.objects(SwiftPerson.self).count, 1) } // After restarting sync, the sync history translator service needs time @@ -498,7 +497,8 @@ class SwiftObjectServerTests: SwiftSyncTestCase { afterCallbackEx.fulfill() } - var configuration = user.configuration(partitionValue: #function, clientResetMode: .discardLocal(beforeClientResetBlock, afterClientResetBlock)) + var configuration = user.configuration(partitionValue: #function, + clientResetMode: .discardLocal(beforeClientResetBlock, afterClientResetBlock)) configuration.objectTypes = [SwiftPerson.self] guard let syncConfig = configuration.syncConfiguration else { fatalError("Test condition failure. SyncConfiguration not set.") } diff --git a/Realm/RLMApp.h b/Realm/RLMApp.h index 825cac68eb2..34a3d57156d 100644 --- a/Realm/RLMApp.h +++ b/Realm/RLMApp.h @@ -76,7 +76,7 @@ Create a new Realm App configuration. */ - (instancetype)initWithBaseURL:(nullable NSString *) baseURL transport:(nullable id)transport - localAppName:(nullable NSString *) localAppName + localAppName:(nullable NSString *)localAppName localAppVersion:(nullable NSString *)localAppVersion defaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS; diff --git a/Realm/RLMApp.mm b/Realm/RLMApp.mm index 30a3d65be10..ee32444a2fe 100644 --- a/Realm/RLMApp.mm +++ b/Realm/RLMApp.mm @@ -98,6 +98,13 @@ - (instancetype)initWithConfig:(const realm::app::App::Config &)config { return nil; } +- (instancetype)init { + return [self initWithBaseURL:nil + transport:nil + localAppName:nil + localAppVersion:nil]; +} + - (instancetype)initWithBaseURL:(nullable NSString *)baseURL transport:(nullable id)transport localAppName:(nullable NSString *)localAppName @@ -111,7 +118,7 @@ - (instancetype)initWithBaseURL:(nullable NSString *)baseURL - (instancetype)initWithBaseURL:(nullable NSString *)baseURL transport:(nullable id)transport - localAppName:(NSString *)localAppName + localAppName:(nullable NSString *)localAppName localAppVersion:(nullable NSString *)localAppVersion defaultRequestTimeoutMS:(NSUInteger)defaultRequestTimeoutMS { if (self = [super init]) { diff --git a/Realm/RLMRealmConfiguration.mm b/Realm/RLMRealmConfiguration.mm index 2a10b13b5d2..5ec72e89e14 100644 --- a/Realm/RLMRealmConfiguration.mm +++ b/Realm/RLMRealmConfiguration.mm @@ -177,7 +177,9 @@ - (void)setInMemoryIdentifier:(NSString *)inMemoryIdentifier { - (void)setSeedFilePath:(NSURL *)seedFilePath { _seedFilePath = seedFilePath; - _config.in_memory = false; + if (_seedFilePath) { + _config.in_memory = false; + } } - (NSData *)encryptionKey { @@ -354,15 +356,8 @@ - (void)setSyncConfiguration:(RLMSyncConfiguration *)syncConfiguration { NSAssert(user.identifier, @"Cannot call this method on a user that doesn't have an identifier."); _config.in_memory = false; - _config.sync_config = std::make_shared([syncConfiguration rawConfiguration]); - - if (syncConfiguration.customFileURL) { - _config.path = syncConfiguration.customFileURL.path.UTF8String; - } else if (_config.sync_config->flx_sync_requested) { - _config.path = [user pathForFlexibleSync]; - } else { - _config.path = [user pathForPartitionValue:_config.sync_config->partition_value]; - } + _config.sync_config = std::make_shared(syncConfiguration.rawConfiguration); + _config.path = syncConfiguration.path; [self updateSchemaMode]; } @@ -371,7 +366,7 @@ - (RLMSyncConfiguration *)syncConfiguration { if (!_config.sync_config) { return nil; } - return [[RLMSyncConfiguration alloc] initWithRawConfig:*_config.sync_config]; + return [[RLMSyncConfiguration alloc] initWithRawConfig:*_config.sync_config path:_config.path]; } #else // REALM_ENABLE_SYNC diff --git a/Realm/RLMSyncConfiguration.h b/Realm/RLMSyncConfiguration.h index a31330d5dba..86d34e3c5e0 100644 --- a/Realm/RLMSyncConfiguration.h +++ b/Realm/RLMSyncConfiguration.h @@ -112,16 +112,6 @@ typedef void(^RLMClientResetAfterBlock)(RLMRealm * _Nonnull beforeFrozen, RLMRea */ @property (nonatomic) bool cancelAsyncOpenOnNonFatalErrors; -/// :nodoc: -- (instancetype)initWithUser:(RLMUser *)user - partitionValue:(nullable id)partitionValue __attribute__((unavailable("Use [RLMUser configurationWithPartitionValue:] instead"))); - -/// :nodoc: -+ (RLMRealmConfiguration *)automaticConfiguration __attribute__((unavailable("Use [RLMUser configuration] instead"))); - -/// :nodoc: -+ (RLMRealmConfiguration *)automaticConfigurationForUser:(RLMUser *)user __attribute__((unavailable("Use [RLMUser configuration] instead"))); - /// :nodoc: - (instancetype)init __attribute__((unavailable("This type cannot be created directly"))); diff --git a/Realm/RLMSyncConfiguration.mm b/Realm/RLMSyncConfiguration.mm index 28f67e92ce4..b864e6ec0f1 100644 --- a/Realm/RLMSyncConfiguration.mm +++ b/Realm/RLMSyncConfiguration.mm @@ -113,9 +113,10 @@ @implementation RLMSyncConfiguration @dynamic stopPolicy; -- (instancetype)initWithRawConfig:(realm::SyncConfig)config { +- (instancetype)initWithRawConfig:(realm::SyncConfig)config path:(std::string const&)path { if (self = [super init]) { _config = std::make_unique(std::move(config)); + _path = path; } return self; } @@ -126,8 +127,8 @@ - (BOOL)isEqual:(id)object { } RLMSyncConfiguration *that = (RLMSyncConfiguration *)object; return [self.partitionValue isEqual:that.partitionValue] - && [self.user isEqual:that.user] - && self.stopPolicy == that.stopPolicy; + && [self.user isEqual:that.user] + && self.stopPolicy == that.stopPolicy; } - (realm::SyncConfig&)rawConfiguration { @@ -151,6 +152,10 @@ - (RLMClientResetMode)clientResetMode { return RLMClientResetMode(_config->client_resync_mode); } +- (void)setClientResetMode:(RLMClientResetMode)clientResetMode { + _config->client_resync_mode = realm::ClientResyncMode(clientResetMode); +} + - (RLMClientResetBeforeBlock)beforeClientReset { if (_config->notify_before_client_reset) { auto wrapper = _config->notify_before_client_reset.target(); @@ -223,79 +228,6 @@ - (BOOL)enableFlexibleSync { return _config->flx_sync_requested; } -- (instancetype)initWithUser:(RLMUser *)user - partitionValue:(nullable id)partitionValue { - return [self initWithUser:user - partitionValue:partitionValue - customFileURL:nil - stopPolicy:RLMSyncStopPolicyAfterChangesUploaded - enableFlexibleSync:false - clientResetMode:RLMClientResetModeManual - notifyBeforeReset:nil - notifyAfterReset:nil]; -} - -- (instancetype)initWithUser:(RLMUser *)user - partitionValue:(nullable id)partitionValue - stopPolicy:(RLMSyncStopPolicy)stopPolicy - clientResetMode:(RLMClientResetMode)clientResetMode - notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock - notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { - auto config = [self initWithUser:user - partitionValue:partitionValue - customFileURL:nil - stopPolicy:stopPolicy - enableFlexibleSync:false - clientResetMode:clientResetMode - notifyBeforeReset:beforeResetBlock - notifyAfterReset:afterResetBlock]; - return config; -} - -- (instancetype)initWithUser:(RLMUser *)user - stopPolicy:(RLMSyncStopPolicy)stopPolicy - enableFlexibleSync:(BOOL)enableFlexibleSync { - auto config = [self initWithUser:user - partitionValue:nil - customFileURL:nil - stopPolicy:stopPolicy - enableFlexibleSync:enableFlexibleSync - clientResetMode:RLMClientResetModeManual - notifyBeforeReset:nil - notifyAfterReset:nil]; - return config; -} - - - -- (instancetype)initWithUser:(RLMUser *)user - partitionValue:(nullable id)partitionValue - clientResetMode:(RLMClientResetMode)clientResetMode { - auto config = [self initWithUser:user - partitionValue:partitionValue - customFileURL:nil - stopPolicy:RLMSyncStopPolicyAfterChangesUploaded - enableFlexibleSync:false - clientResetMode:clientResetMode - notifyBeforeReset:nil - notifyAfterReset:nil]; - return config; -} - -- (instancetype)initWithUser:(RLMUser *)user - enableFlexibleSync:(BOOL)enableFlexibleSync - clientResetMode:(RLMClientResetMode)clientResetMode { - auto config = [self initWithUser:user - partitionValue:nil - customFileURL:nil - stopPolicy:RLMSyncStopPolicyAfterChangesUploaded - enableFlexibleSync:enableFlexibleSync - clientResetMode:clientResetMode - notifyBeforeReset:nil - notifyAfterReset:nil]; - return config; -} - NSError *RLMTranslateSyncError(SyncError error) { NSString *recoveryPath; RLMSyncErrorActionToken *token; @@ -338,61 +270,59 @@ - (instancetype)initWithUser:(RLMUser *)user return make_sync_error(errorClass, @(error.message.c_str()), error.error_code.value(), custom); } -- (instancetype)initWithUser:(RLMUser *)user - partitionValue:(nullable id)partitionValue - customFileURL:(nullable NSURL *)customFileURL - stopPolicy:(RLMSyncStopPolicy)stopPolicy - enableFlexibleSync:(BOOL)enableFlexibleSync - clientResetMode:(RLMClientResetMode)clientResetMode - notifyBeforeReset:(RLMClientResetBeforeBlock)beforeResetBlock - notifyAfterReset:(RLMClientResetAfterBlock)afterResetBlock { - if (self = [super init]) { - if (enableFlexibleSync) { - _config = std::make_unique([user _syncUser], SyncConfig::FLXSyncEnabled{}); - } else { - std::stringstream s; - s << RLMConvertRLMBSONToBson(partitionValue); - _config = std::make_unique([user _syncUser], - s.str()); +static void setDefaults(SyncConfig& config, RLMUser *user) { + config.client_resync_mode = ClientResyncMode::Manual; + config.stop_policy = SyncSessionStopPolicy::AfterChangesUploaded; + + RLMSyncManager *manager = [user.app syncManager]; + __weak RLMSyncManager *weakManager = manager; + config.error_handler = [weakManager](std::shared_ptr errored_session, SyncError error) { + RLMSyncErrorReportingBlock errorHandler; + @autoreleasepool { + errorHandler = weakManager.errorHandler; } - _config->stop_policy = translateStopPolicy(stopPolicy); - RLMSyncManager *manager = [user.app syncManager]; - __weak RLMSyncManager *weakManager = manager; - _config->error_handler = [weakManager](std::shared_ptr errored_session, SyncError error) { - RLMSyncErrorReportingBlock errorHandler; - @autoreleasepool { - errorHandler = weakManager.errorHandler; - } - if (!errorHandler) { - return; - } - NSError *nsError = RLMTranslateSyncError(std::move(error)); - if (!nsError) { - return; - } - RLMSyncSession *session = [[RLMSyncSession alloc] initWithSyncSession:errored_session]; - dispatch_async(dispatch_get_main_queue(), ^{ - errorHandler(nsError, session); - }); - }; - // Default to manual mode - _config->client_resync_mode = realm::ClientResyncMode(clientResetMode); - self.beforeClientReset = beforeResetBlock; - self.afterClientReset = afterResetBlock; - - if (NSString *authorizationHeaderName = manager.authorizationHeaderName) { - _config->authorization_header_name.emplace(authorizationHeaderName.UTF8String); + if (!errorHandler) { + return; } - if (NSDictionary *customRequestHeaders = manager.customRequestHeaders) { - for (NSString *key in customRequestHeaders) { - _config->custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String); - } + NSError *nsError = RLMTranslateSyncError(std::move(error)); + if (!nsError) { + return; + } + RLMSyncSession *session = [[RLMSyncSession alloc] initWithSyncSession:errored_session]; + dispatch_async(dispatch_get_main_queue(), ^{ + errorHandler(nsError, session); + }); + }; + + if (NSString *authorizationHeaderName = manager.authorizationHeaderName) { + config.authorization_header_name.emplace(authorizationHeaderName.UTF8String); + } + if (NSDictionary *customRequestHeaders = manager.customRequestHeaders) { + for (NSString *key in customRequestHeaders) { + config.custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String); } + } +} - self.customFileURL = customFileURL; - return self; +- (instancetype)initWithUser:(RLMUser *)user + partitionValue:(nullable id)partitionValue { + if (self = [super init]) { + std::stringstream s; + s << RLMConvertRLMBSONToBson(partitionValue); + _config = std::make_unique([user _syncUser], s.str()); + _path = [user pathForPartitionValue:_config->partition_value]; + setDefaults(*_config, user); } - return nil; + return self; +} + +- (instancetype)initWithUser:(RLMUser *)user { + if (self = [super init]) { + _config = std::make_unique([user _syncUser], SyncConfig::FLXSyncEnabled{}); + _path = [user pathForFlexibleSync]; + setDefaults(*_config, user); + } + return self; } @end diff --git a/Realm/RLMSyncConfiguration_Private.h b/Realm/RLMSyncConfiguration_Private.h index 66cc4a52032..b951952fc45 100644 --- a/Realm/RLMSyncConfiguration_Private.h +++ b/Realm/RLMSyncConfiguration_Private.h @@ -33,22 +33,14 @@ typedef RLM_CLOSED_ENUM(NSUInteger, RLMSyncStopPolicy) { @interface RLMSyncConfiguration () +// Flexible sync +- (instancetype)initWithUser:(RLMUser *)user; +// Partition-based sync - (instancetype)initWithUser:(RLMUser *)user - partitionValue:(nullable id)partitionValue - stopPolicy:(RLMSyncStopPolicy)stopPolicy - clientResetMode:(RLMClientResetMode)clientResetMode - notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock - notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock; - -- (instancetype)initWithUser:(RLMUser *)user - stopPolicy:(RLMSyncStopPolicy)stopPolicy - enableFlexibleSync:(BOOL)enableFlexibleSync; - -@property (nonatomic, readwrite) RLMSyncStopPolicy stopPolicy; + partitionValue:(nullable id)partitionValue; // Internal-only APIs -@property (nullable, nonatomic) NSURL *customFileURL; - +@property (nonatomic, readwrite) RLMSyncStopPolicy stopPolicy; @property (nonatomic, readonly) BOOL enableFlexibleSync; @end diff --git a/Realm/RLMSyncConfiguration_Private.hpp b/Realm/RLMSyncConfiguration_Private.hpp index 28cedd64b67..ef9dbdb4820 100644 --- a/Realm/RLMSyncConfiguration_Private.hpp +++ b/Realm/RLMSyncConfiguration_Private.hpp @@ -32,14 +32,15 @@ NS_ASSUME_NONNULL_BEGIN @interface RLMSyncConfiguration () -- (instancetype)initWithRawConfig:(realm::SyncConfig)config; - +- (instancetype)initWithRawConfig:(realm::SyncConfig)config path:(std::string const&)path; - (realm::SyncConfig&)rawConfiguration; // Pass the RLMRealmConfiguration to it's sync configuration so client reset callbacks // can access schema, dynamic, and path properties. void RLMSetConfigInfoForClientResetCallbacks(realm::SyncConfig& syncConfig, RLMRealmConfiguration *config); +@property (nonatomic) std::string path; + @end NSError *_Nullable RLMTranslateSyncError(realm::SyncError); diff --git a/Realm/RLMSyncSession.mm b/Realm/RLMSyncSession.mm index fe44ff2ab5e..9447861f06a 100644 --- a/Realm/RLMSyncSession.mm +++ b/Realm/RLMSyncSession.mm @@ -125,7 +125,7 @@ - (instancetype)initWithSyncSession:(std::shared_ptr const&)session - (RLMSyncConfiguration *)configuration { if (auto session = _session.lock()) { - return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config()]; + return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config() path:session->path()]; } return nil; } diff --git a/Realm/RLMUser.mm b/Realm/RLMUser.mm index 763e414ed4b..878bdf9cf7a 100644 --- a/Realm/RLMUser.mm +++ b/Realm/RLMUser.mm @@ -87,10 +87,12 @@ - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue clientResetMode:(RLMClientResetMode)clientResetMode { - return [self configurationWithPartitionValue:partitionValue - clientResetMode:clientResetMode - notifyBeforeReset:nil - notifyAfterReset:nil]; + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; + config.syncConfiguration = syncConfig; + return config; } - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id)partitionValue @@ -98,30 +100,24 @@ - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock { auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self - partitionValue:partitionValue - stopPolicy:RLMSyncStopPolicyImmediately - clientResetMode:clientResetMode - notifyBeforeReset:beforeResetBlock - notifyAfterReset:afterResetBlock]; + partitionValue:partitionValue]; + syncConfig.clientResetMode = clientResetMode; + syncConfig.beforeClientReset = beforeResetBlock; + syncConfig.afterClientReset = afterResetBlock; RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; config.syncConfiguration = syncConfig; return config; } - (RLMRealmConfiguration *)flexibleSyncConfiguration { - auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self - stopPolicy:RLMSyncStopPolicyAfterChangesUploaded - enableFlexibleSync:true]; RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; - config.syncConfiguration = syncConfig; + config.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:self]; return config; } - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions rerunOnOpen:(BOOL)rerunOnOpen { - auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self - stopPolicy:RLMSyncStopPolicyAfterChangesUploaded - enableFlexibleSync:true]; + auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self]; RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init]; config.initialSubscriptions = initialSubscriptions; config.rerunOnOpen = rerunOnOpen; diff --git a/Realm/TestUtils/TestUtils.mm b/Realm/TestUtils/TestUtils.mm index 496392947a5..153ef1138f0 100644 --- a/Realm/TestUtils/TestUtils.mm +++ b/Realm/TestUtils/TestUtils.mm @@ -194,6 +194,19 @@ bool RLMHasCachedRealmForPath(NSString *path) { return encoded_prefix + "." + encoded_body + "." + suffix; } +// A network transport which doesn't actually do anything +@interface NoOpTransport : NSObject +@end +@implementation NoOpTransport +- (void)sendRequestToServer:(RLMRequest *)request + completion:(RLMNetworkTransportCompletionBlock)completionBlock { +} +- (NSURLSession *)doStreamRequest:(RLMRequest *)request + eventSubscriber:(id)subscriber { + return nil; +} +@end + RLMUser *RLMDummyUser() { // Add a fake user to the metadata Realm @autoreleasepool { @@ -213,7 +226,9 @@ bool RLMHasCachedRealmForPath(NSString *path) { } // Creating an app reads the fake cached user - RLMApp *app = [RLMApp appWithId:@"dummy"]; + RLMAppConfiguration *config = [RLMAppConfiguration new]; + config.transport = [NoOpTransport new]; + RLMApp *app = [RLMApp appWithId:@"dummy" configuration:config]; return app.allUsers.allValues.firstObject; } diff --git a/RealmSwift/ObjectiveCSupport+Sync.swift b/RealmSwift/ObjectiveCSupport+Sync.swift index b06ce690498..558294e04f4 100644 --- a/RealmSwift/ObjectiveCSupport+Sync.swift +++ b/RealmSwift/ObjectiveCSupport+Sync.swift @@ -24,7 +24,7 @@ import Realm public extension ObjectiveCSupport { /// Convert a `SyncConfiguration` to a `RLMSyncConfiguration`. static func convert(object: SyncConfiguration) -> RLMSyncConfiguration { - return object.asConfig() + return object.config } /// Convert a `RLMSyncConfiguration` to a `SyncConfiguration`. diff --git a/RealmSwift/RealmConfiguration.swift b/RealmSwift/RealmConfiguration.swift index b21a6170f09..34a183724f1 100644 --- a/RealmSwift/RealmConfiguration.swift +++ b/RealmSwift/RealmConfiguration.swift @@ -289,7 +289,7 @@ extension Realm { internal var rlmConfiguration: RLMRealmConfiguration { let configuration = RLMRealmConfiguration() if let syncConfiguration = syncConfiguration { - configuration.syncConfiguration = syncConfiguration.asConfig() + configuration.syncConfiguration = syncConfiguration.config } if let fileURL = fileURL { configuration.fileURL = fileURL @@ -298,21 +298,13 @@ extension Realm { } else if syncConfiguration == nil { fatalError("A Realm Configuration must specify a path or an in-memory identifier.") } - if let seedFilePath = seedFilePath { - configuration.seedFilePath = seedFilePath - } else if let inMemoryIdentifier = inMemoryIdentifier { - configuration.inMemoryIdentifier = inMemoryIdentifier - } + configuration.seedFilePath = self.seedFilePath configuration.encryptionKey = self.encryptionKey configuration.readOnly = self.readOnly configuration.schemaVersion = self.schemaVersion configuration.migrationBlock = self.migrationBlock.map { accessorMigrationBlock($0) } configuration.deleteRealmIfMigrationNeeded = self.deleteRealmIfMigrationNeeded - if let shouldCompactOnLaunch = self.shouldCompactOnLaunch { - configuration.shouldCompactOnLaunch = ObjectiveCSupport.convert(object: shouldCompactOnLaunch) - } else { - configuration.shouldCompactOnLaunch = nil - } + configuration.shouldCompactOnLaunch = self.shouldCompactOnLaunch.map(ObjectiveCSupport.convert(object:)) configuration.setCustomSchemaWithoutCopying(self.customSchema) configuration.disableFormatUpgrade = self.disableFormatUpgrade configuration.maximumNumberOfActiveVersions = self.maximumNumberOfActiveVersions ?? 0 @@ -337,11 +329,7 @@ extension Realm { var configuration = Configuration() configuration._path = rlmConfiguration.fileURL?.path configuration._inMemoryIdentifier = rlmConfiguration.inMemoryIdentifier - if let objcSyncConfig = rlmConfiguration.syncConfiguration { - configuration._syncConfiguration = SyncConfiguration(config: objcSyncConfig) - } else { - configuration._syncConfiguration = nil - } + configuration._syncConfiguration = rlmConfiguration.syncConfiguration.map(SyncConfiguration.init(config:)) configuration.encryptionKey = rlmConfiguration.encryptionKey configuration.readOnly = rlmConfiguration.readOnly configuration.schemaVersion = rlmConfiguration.schemaVersion diff --git a/RealmSwift/Sync.swift b/RealmSwift/Sync.swift index ef3ff30c9b3..b5725ba038a 100644 --- a/RealmSwift/Sync.swift +++ b/RealmSwift/Sync.swift @@ -262,20 +262,18 @@ public enum ClientResetMode { */ @frozen public struct SyncConfiguration { /// The `SyncUser` who owns the Realm that this configuration should open. - public let user: User + public var user: User { + config.user + } /** The value this Realm is partitioned on. The partition key is a property defined in Atlas App Services. All classes with a property with this value will be synchronized to the Realm. */ - public let partitionValue: AnyBSON? - - /** - A policy that determines what should happen when all references to Realms opened by this - configuration go out of scope. - */ - internal let stopPolicy: RLMSyncStopPolicy + public var partitionValue: AnyBSON? { + ObjectiveCSupport.convert(object: config.partitionValue) + } /** An enum which determines file recovery behvaior in the event of a client reset. @@ -284,12 +282,16 @@ public enum ClientResetMode { - see: `ClientResetMode` and `RLMClientResetMode` - see: https://docs.mongodb.com/realm/sync/error-handling/client-resets/ */ - public let clientResetMode: ClientResetMode - - /** - Determines if the sync configuration is flexible sync or not - */ - internal let isFlexibleSync: Bool + public var clientResetMode: ClientResetMode { + switch config.clientResetMode { + case .manual: + return .manual + case .discardLocal: + return .discardLocal(ObjectiveCSupport.convert(object: config.beforeClientReset), ObjectiveCSupport.convert(object: config.afterClientReset)) + @unknown default: + fatalError() + } + } /** By default, Realm.asyncOpen() swallows non-fatal connection errors such as @@ -297,49 +299,13 @@ public enum ClientResetMode { this is set to `true`, instead the error will be reported to the callback and the async open will be cancelled. */ - public let cancelAsyncOpenOnNonFatalErrors: Bool - - internal init(config: RLMSyncConfiguration) { - self.user = config.user - self.stopPolicy = config.stopPolicy - self.partitionValue = ObjectiveCSupport.convert(object: config.partitionValue) - self.cancelAsyncOpenOnNonFatalErrors = config.cancelAsyncOpenOnNonFatalErrors - self.isFlexibleSync = config.enableFlexibleSync - switch config.clientResetMode { - case .manual: - self.clientResetMode = .manual - case .discardLocal: - self.clientResetMode = .discardLocal(ObjectiveCSupport.convert(object: config.beforeClientReset), ObjectiveCSupport.convert(object: config.afterClientReset)) - @unknown default: - fatalError("what's best in this case?") - } + public var cancelAsyncOpenOnNonFatalErrors: Bool { + config.cancelAsyncOpenOnNonFatalErrors } - func asConfig() -> RLMSyncConfiguration { - let syncConfiguration: RLMSyncConfiguration - if isFlexibleSync { - syncConfiguration = RLMSyncConfiguration(user: user, stopPolicy: stopPolicy, enableFlexibleSync: isFlexibleSync) - } else { - switch clientResetMode { - case .manual: - syncConfiguration = RLMSyncConfiguration(user: user, - partitionValue: partitionValue.map(ObjectiveCSupport.convertBson), - stopPolicy: stopPolicy, - clientResetMode: .manual, - notifyBeforeReset: nil, - notifyAfterReset: nil) - case .discardLocal(let before, let after): - syncConfiguration = RLMSyncConfiguration(user: user, - partitionValue: partitionValue.map(ObjectiveCSupport.convertBson), - stopPolicy: stopPolicy, - clientResetMode: .discardLocal, - notifyBeforeReset: ObjectiveCSupport.convert(object: before), - notifyAfterReset: ObjectiveCSupport.convert(object: after)) - } - - } - syncConfiguration.cancelAsyncOpenOnNonFatalErrors = cancelAsyncOpenOnNonFatalErrors - return syncConfiguration + internal let config: RLMSyncConfiguration + internal init(config: RLMSyncConfiguration) { + self.config = config } } diff --git a/RealmSwift/Tests/PerformanceTests.swift b/RealmSwift/Tests/PerformanceTests.swift index 3324d3d31f8..ef62f4beeb0 100644 --- a/RealmSwift/Tests/PerformanceTests.swift +++ b/RealmSwift/Tests/PerformanceTests.swift @@ -19,6 +19,10 @@ import XCTest import RealmSwift +#if canImport(RealmTestSupport) +import RealmTestSupport +#endif + private func createStringObjects(_ factor: Int) -> Realm { let realm = inMemoryRealm(factor.description) try! realm.write { @@ -435,6 +439,92 @@ class SwiftPerformanceTests: TestCase { } } + func deleteServerFiles() { + try! FileManager.default.removeItem(at: URL(fileURLWithPath: testDir, isDirectory: true).deletingLastPathComponent().appendingPathComponent("mongodb-realm")) + App.resetAppCache() + } + + func testSyncRealmCacheLookup() { + var config = RLMDummyUser().configuration(partitionValue: "") + config.objectTypes = [] + let realm = try! Realm(configuration: config) + + measure { + for _ in 0..<1250 { + autoreleasepool { + _ = try! Realm(configuration: config) + } + } + } + realm.invalidate() + deleteServerFiles() + } + + func testSyncRealmCreationCached() { + var config = RLMDummyUser().configuration(partitionValue: "") + config.objectTypes = [] + var realm: Realm! + dispatchSyncNewThread { + realm = try! Realm(configuration: config) + } + + measure { + for _ in 0..<1250 { + autoreleasepool { + _ = try! Realm(configuration: config) + } + } + } + _ = realm.configuration + deleteServerFiles() + } + + func testSyncRealmMultithreadedCacheLookup() { + var config = RLMDummyUser().configuration(partitionValue: "") + config.objectTypes = [] + var realm: Realm! + dispatchSyncNewThread { + realm = try! Realm(configuration: config) + } + + measure { + DispatchQueue.concurrentPerform(iterations: 50) { _ in + autoreleasepool { + let realm = try! Realm(configuration: config) + for _ in 0..<25 { + autoreleasepool { + _ = try! Realm(configuration: config) + } + } + realm.invalidate() + } + } + } + _ = realm.configuration + deleteServerFiles() + } + + func testSyncRealmMultithreadedCreationCached() { + var config = RLMDummyUser().configuration(partitionValue: "") + config.objectTypes = [] + var realm: Realm! + dispatchSyncNewThread { + realm = try! Realm(configuration: config) + } + + measure { + DispatchQueue.concurrentPerform(iterations: 50) { _ in + for _ in 0..<25 { + autoreleasepool { + _ = try! Realm(configuration: config) + } + } + } + } + _ = realm.configuration + deleteServerFiles() + } + func testCommitWriteTransaction() { inMeasureBlock { let realm = inMemoryRealm("test")