123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2014 Realm Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- ////////////////////////////////////////////////////////////////////////////
- #import "RLMTestCase.h"
- #import "RLMRealm_Dynamic.h"
- #import "RLMRealm_Private.h"
- #if !DEBUG && TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
- @interface PerformanceTests : RLMTestCase
- @property (nonatomic) dispatch_queue_t queue;
- @property (nonatomic) dispatch_semaphore_t sema;
- @end
- static RLMRealm *s_smallRealm, *s_mediumRealm, *s_largeRealm;
- @implementation PerformanceTests
- + (void)setUp {
- [super setUp];
- s_smallRealm = [self createStringObjects:1];
- s_mediumRealm = [self createStringObjects:5];
- s_largeRealm = [self createStringObjects:50];
- }
- + (void)tearDown {
- s_smallRealm = s_mediumRealm = s_largeRealm = nil;
- [RLMRealm resetRealmState];
- [super tearDown];
- }
- - (void)resetRealmState {
- // Do nothing, as we need to keep our in-memory realms around between tests
- }
- - (void)measureBlock:(void (^)(void))block {
- [super measureBlock:^{
- @autoreleasepool {
- block();
- }
- }];
- }
- - (void)measureMetrics:(NSArray *)metrics automaticallyStartMeasuring:(BOOL)automaticallyStartMeasuring forBlock:(void (^)(void))block {
- [super measureMetrics:metrics automaticallyStartMeasuring:automaticallyStartMeasuring forBlock:^{
- @autoreleasepool {
- block();
- }
- }];
- }
- + (RLMRealm *)createStringObjects:(int)factor {
- RLMRealmConfiguration *config = [RLMRealmConfiguration new];
- config.inMemoryIdentifier = @(factor).stringValue;
- RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
- [realm beginWriteTransaction];
- for (int i = 0; i < 1000 * factor; ++i) {
- [StringObject createInRealm:realm withValue:@[@"a"]];
- [StringObject createInRealm:realm withValue:@[@"b"]];
- }
- [realm commitWriteTransaction];
- return realm;
- }
- - (RLMRealm *)testRealm {
- RLMRealmConfiguration *config = [RLMRealmConfiguration new];
- config.inMemoryIdentifier = @"test";
- return [RLMRealm realmWithConfiguration:config error:nil];
- }
- - (void)testInsertMultiple {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = self.realmWithTestPath;
- [self startMeasuring];
- [realm beginWriteTransaction];
- for (int i = 0; i < 5000; ++i) {
- StringObject *obj = [[StringObject alloc] init];
- obj.stringCol = @"a";
- [realm addObject:obj];
- }
- [realm commitWriteTransaction];
- [self stopMeasuring];
- [self tearDown];
- }];
- }
- - (void)testInsertSingleLiteral {
- [self measureBlock:^{
- RLMRealm *realm = self.realmWithTestPath;
- for (int i = 0; i < 50; ++i) {
- [realm beginWriteTransaction];
- [StringObject createInRealm:realm withValue:@[@"a"]];
- [realm commitWriteTransaction];
- }
- [self tearDown];
- }];
- }
- - (void)testInsertMultipleLiteral {
- [self measureBlock:^{
- RLMRealm *realm = self.realmWithTestPath;
- [realm beginWriteTransaction];
- for (int i = 0; i < 5000; ++i) {
- [StringObject createInRealm:realm withValue:@[@"a"]];
- }
- [realm commitWriteTransaction];
- [self tearDown];
- }];
- }
- - (RLMRealm *)getStringObjects:(int)factor {
- RLMRealmConfiguration *config = [RLMRealmConfiguration new];
- config.inMemoryIdentifier = @(factor).stringValue;
- RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
- [NSFileManager.defaultManager removeItemAtURL:RLMTestRealmURL() error:nil];
- [realm writeCopyToURL:RLMTestRealmURL() encryptionKey:nil error:nil];
- return [self realmWithTestPath];
- }
- - (void)testCountWhereQuery {
- RLMRealm *realm = [self getStringObjects:50];
- [self measureBlock:^{
- for (int i = 0; i < 50; ++i) {
- RLMResults *array = [StringObject objectsInRealm:realm where:@"stringCol = 'a'"];
- [array count];
- }
- }];
- }
- - (void)testCountWhereTableView {
- RLMRealm *realm = [self getStringObjects:50];
- [self measureBlock:^{
- for (int i = 0; i < 10; ++i) {
- RLMResults *array = [StringObject objectsInRealm:realm where:@"stringCol = 'a'"];
- [array firstObject]; // Force materialization of backing table view
- [array count];
- }
- }];
- }
- - (void)testEnumerateAndAccessQuery {
- RLMRealm *realm = [self getStringObjects:5];
- [self measureBlock:^{
- for (StringObject *so in [StringObject objectsInRealm:realm where:@"stringCol = 'a'"]) {
- (void)[so stringCol];
- }
- }];
- }
- - (void)testEnumerateAndAccessAll {
- RLMRealm *realm = [self getStringObjects:5];
- [self measureBlock:^{
- for (StringObject *so in [StringObject allObjectsInRealm:realm]) {
- (void)[so stringCol];
- }
- }];
- }
- - (void)testEnumerateAndAccessAllSlow {
- RLMRealm *realm = [self getStringObjects:5];
- [self measureBlock:^{
- RLMResults *all = [StringObject allObjectsInRealm:realm];
- for (NSUInteger i = 0; i < all.count; ++i) {
- (void)[all[i] stringCol];
- }
- }];
- }
- - (void)testEnumerateAndAccessArrayProperty {
- RLMRealm *realm = [self getStringObjects:5];
- [realm beginWriteTransaction];
- ArrayPropertyObject *apo = [ArrayPropertyObject createInRealm:realm
- withValue:@[@"name", [StringObject allObjectsInRealm:realm], @[]]];
- [realm commitWriteTransaction];
- [self measureBlock:^{
- for (StringObject *so in apo.array) {
- (void)[so stringCol];
- }
- }];
- }
- - (void)testEnumerateAndAccessArrayPropertySlow {
- RLMRealm *realm = [self getStringObjects:5];
- [realm beginWriteTransaction];
- ArrayPropertyObject *apo = [ArrayPropertyObject createInRealm:realm
- withValue:@[@"name", [StringObject allObjectsInRealm:realm], @[]]];
- [realm commitWriteTransaction];
- [self measureBlock:^{
- RLMArray *array = apo.array;
- for (NSUInteger i = 0; i < array.count; ++i) {
- (void)[array[i] stringCol];
- }
- }];
- }
- - (void)testEnumerateAndMutateAll {
- RLMRealm *realm = [self getStringObjects:5];
- [self measureBlock:^{
- [realm beginWriteTransaction];
- for (StringObject *so in [StringObject allObjectsInRealm:realm]) {
- so.stringCol = @"c";
- }
- [realm commitWriteTransaction];
- }];
- }
- - (void)testEnumerateAndMutateQuery {
- RLMRealm *realm = [self getStringObjects:1];
- [self measureBlock:^{
- [realm beginWriteTransaction];
- for (StringObject *so in [StringObject objectsInRealm:realm where:@"stringCol != 'b'"]) {
- so.stringCol = @"c";
- }
- [realm commitWriteTransaction];
- }];
- }
- - (void)testQueryConstruction {
- RLMRealm *realm = self.realmWithTestPath;
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"boolCol = false and (intCol = 5 or floatCol = 1.0) and objectCol = nil and longCol != 7 and stringCol IN {'a', 'b', 'c'}"];
- [self measureBlock:^{
- for (int i = 0; i < 500; ++i) {
- [AllTypesObject objectsInRealm:realm withPredicate:predicate];
- }
- }];
- }
- - (void)testDeleteAll {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:50];
- [self startMeasuring];
- [realm beginWriteTransaction];
- [realm deleteObjects:[StringObject allObjectsInRealm:realm]];
- [realm commitWriteTransaction];
- [self stopMeasuring];
- }];
- }
- - (void)testQueryDeletion {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:5];
- [self startMeasuring];
- [realm beginWriteTransaction];
- [realm deleteObjects:[StringObject objectsInRealm:realm where:@"stringCol = 'a' OR stringCol = 'b'"]];
- [realm commitWriteTransaction];
- [self stopMeasuring];
- }];
- }
- - (void)testManualDeletion {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:5];
- NSMutableArray *objects = [NSMutableArray arrayWithCapacity:10000];
- for (StringObject *obj in [StringObject allObjectsInRealm:realm]) {
- [objects addObject:obj];
- }
- [self startMeasuring];
- [realm beginWriteTransaction];
- [realm deleteObjects:objects];
- [realm commitWriteTransaction];
- [self stopMeasuring];
- }];
- }
- - (void)testUnIndexedStringLookup {
- RLMRealm *realm = self.realmWithTestPath;
- [realm beginWriteTransaction];
- for (int i = 0; i < 1000; ++i) {
- [StringObject createInRealm:realm withValue:@[@(i).stringValue]];
- }
- [realm commitWriteTransaction];
- [self measureBlock:^{
- for (int i = 0; i < 1000; ++i) {
- [[StringObject objectsInRealm:realm where:@"stringCol = %@", @(i).stringValue] firstObject];
- }
- }];
- }
- - (void)testIndexedStringLookup {
- RLMRealm *realm = self.realmWithTestPath;
- [realm beginWriteTransaction];
- for (int i = 0; i < 1000; ++i) {
- [IndexedStringObject createInRealm:realm withValue:@[@(i).stringValue]];
- }
- [realm commitWriteTransaction];
- [self measureBlock:^{
- for (int i = 0; i < 1000; ++i) {
- [[IndexedStringObject objectsInRealm:realm where:@"stringCol = %@", @(i).stringValue] firstObject];
- }
- }];
- }
- - (void)testLargeINQuery {
- RLMRealm *realm = self.realmWithTestPath;
- [realm beginWriteTransaction];
- NSMutableArray *ids = [NSMutableArray arrayWithCapacity:3000];
- for (int i = 0; i < 3000; ++i) {
- [IntObject createInRealm:realm withValue:@[@(i)]];
- if (i % 2) {
- [ids addObject:@(i)];
- }
- }
- [realm commitWriteTransaction];
- [self measureBlock:^{
- (void)[[IntObject objectsInRealm:realm where:@"intCol IN %@", ids] firstObject];
- }];
- }
- - (void)testSortingAllObjects {
- RLMRealm *realm = self.realmWithTestPath;
- [realm beginWriteTransaction];
- for (int i = 0; i < 3000; ++i) {
- [IntObject createInRealm:realm withValue:@[@(arc4random())]];
- }
- [realm commitWriteTransaction];
- [self measureBlock:^{
- (void)[[IntObject allObjectsInRealm:realm] sortedResultsUsingProperty:@"intCol" ascending:YES].lastObject;
- }];
- }
- - (void)testRealmCreationCached {
- __block RLMRealm *realm;
- [self dispatchAsyncAndWait:^{
- realm = [self realmWithTestPath]; // ensure a cached realm for the path
- }];
- [self measureBlock:^{
- for (int i = 0; i < 250; ++i) {
- @autoreleasepool {
- [self realmWithTestPath];
- }
- }
- }];
- [realm configuration];
- }
- - (void)testRealmCreationUncached {
- [self measureBlock:^{
- for (int i = 0; i < 50; ++i) {
- @autoreleasepool {
- [self realmWithTestPath];
- }
- }
- }];
- }
- - (void)testRealmFileCreation {
- RLMRealmConfiguration *config = [RLMRealmConfiguration new];
- __block int measurement = 0;
- const int iterations = 10;
- [self measureBlock:^{
- for (int i = 0; i < iterations; ++i) {
- @autoreleasepool {
- config.inMemoryIdentifier = @(measurement * iterations + i).stringValue;
- [RLMRealm realmWithConfiguration:config error:nil];
- }
- }
- ++measurement;
- }];
- }
- - (void)testInvalidateRefresh {
- RLMRealm *realm = [self testRealm];
- [self measureBlock:^{
- for (int i = 0; i < 50000; ++i) {
- @autoreleasepool {
- [realm invalidate];
- [realm refresh];
- }
- }
- }];
- }
- - (void)testCommitWriteTransaction {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = self.testRealm;
- [realm beginWriteTransaction];
- IntObject *obj = [IntObject createInRealm:realm withValue:@[@0]];
- [realm commitWriteTransaction];
- [self startMeasuring];
- while (obj.intCol < 100) {
- [realm transactionWithBlock:^{
- obj.intCol++;
- }];
- }
- [self stopMeasuring];
- }];
- }
- - (void)testCommitWriteTransactionWithLocalNotification {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = self.testRealm;
- [realm beginWriteTransaction];
- IntObject *obj = [IntObject createInRealm:realm withValue:@[@0]];
- [realm commitWriteTransaction];
- RLMNotificationToken *token = [realm addNotificationBlock:^(__unused NSString *note, __unused RLMRealm *realm) { }];
- [self startMeasuring];
- while (obj.intCol < 500) {
- [realm transactionWithBlock:^{
- obj.intCol++;
- }];
- }
- [self stopMeasuring];
- [token invalidate];
- }];
- }
- - (void)testCommitWriteTransactionWithCrossThreadNotification {
- const int stopValue = 500;
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = self.testRealm;
- [realm beginWriteTransaction];
- IntObject *obj = [IntObject createInRealm:realm withValue:@[@0]];
- [realm commitWriteTransaction];
- dispatch_semaphore_t sema = dispatch_semaphore_create(0);
- [self dispatchAsync:^{
- RLMRealm *realm = self.testRealm;
- IntObject *obj = [[IntObject allObjectsInRealm:realm] firstObject];
- __block RLMNotificationToken *token;
- CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, ^{
- token = [realm addNotificationBlock:^(__unused NSString *note, __unused RLMRealm *realm) {
- if (obj.intCol == stopValue) {
- CFRunLoopStop(CFRunLoopGetCurrent());
- }
- }];
- dispatch_semaphore_signal(sema);
- });
- CFRunLoopRun();
- [token invalidate];
- }];
- dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
- [self startMeasuring];
- while (obj.intCol < stopValue) {
- [realm transactionWithBlock:^{
- obj.intCol++;
- }];
- }
- [self dispatchAsyncAndWait:^{}];
- [self stopMeasuring];
- }];
- }
- - (void)testCommitWriteTransactionWithResultsNotification {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:5];
- RLMResults *results = [StringObject allObjectsInRealm:realm];
- id token = [results addNotificationBlock:^(__unused RLMResults *results, __unused RLMCollectionChange *change, __unused NSError *error) {
- CFRunLoopStop(CFRunLoopGetCurrent());
- }];
- CFRunLoopRun();
- [realm beginWriteTransaction];
- [realm deleteObjects:[StringObject objectsInRealm:realm where:@"stringCol = 'a'"]];
- [realm commitWriteTransaction];
- [self startMeasuring];
- CFRunLoopRun();
- [token invalidate];
- }];
- }
- - (void)testCommitWriteTransactionWithListNotification {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:5];
- [realm beginWriteTransaction];
- ArrayPropertyObject *arrayObj = [ArrayPropertyObject createInRealm:realm withValue:@[@"", [StringObject allObjectsInRealm:realm], @[]]];
- [realm commitWriteTransaction];
- id token = [arrayObj.array addNotificationBlock:^(__unused RLMArray *results, __unused RLMCollectionChange *change, __unused NSError *error) {
- CFRunLoopStop(CFRunLoopGetCurrent());
- }];
- CFRunLoopRun();
- [realm beginWriteTransaction];
- [realm deleteObjects:[StringObject objectsInRealm:realm where:@"stringCol = 'a'"]];
- [realm commitWriteTransaction];
- [self startMeasuring];
- CFRunLoopRun();
- [token invalidate];
- }];
- }
- - (void)testCrossThreadSyncLatency {
- const int stopValue = 500;
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = self.testRealm;
- [realm beginWriteTransaction];
- [realm deleteAllObjects];
- IntObject *obj = [IntObject createInRealm:realm withValue:@[@0]];
- [realm commitWriteTransaction];
- dispatch_semaphore_t sema = dispatch_semaphore_create(0);
- [self dispatchAsync:^{
- RLMRealm *realm = self.testRealm;
- IntObject *obj = [[IntObject allObjectsInRealm:realm] firstObject];
- __block RLMNotificationToken *token;
- CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, ^{
- token = [realm addNotificationBlock:^(__unused NSString *note, __unused RLMRealm *realm) {
- if (obj.intCol == stopValue) {
- CFRunLoopStop(CFRunLoopGetCurrent());
- }
- else if (obj.intCol % 2 == 0) {
- [realm transactionWithBlock:^{
- obj.intCol++;
- }];
- }
- }];
- dispatch_semaphore_signal(sema);
- });
- CFRunLoopRun();
- [token invalidate];
- }];
- RLMNotificationToken *token = [realm addNotificationBlock:^(__unused NSString *note, __unused RLMRealm *realm) {
- if (obj.intCol % 2 == 1 && obj.intCol < stopValue) {
- [realm transactionWithBlock:^{
- obj.intCol++;
- }];
- }
- }];
- dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
- [self startMeasuring];
- [realm transactionWithBlock:^{
- obj.intCol++;
- }];
- while (obj.intCol < stopValue) {
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
- [self dispatchAsyncAndWait:^{}];
- [self stopMeasuring];
- [token invalidate];
- }];
- }
- - (void)testArrayKVOIndexHandlingRemoveForward {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:50];
- [realm beginWriteTransaction];
- ArrayPropertyObject *obj = [ArrayPropertyObject createInRealm:realm withValue:@[@"", [StringObject allObjectsInRealm:realm], @[]]];
- [realm commitWriteTransaction];
- const NSUInteger initial = obj.array.count;
- [self observeObject:obj keyPath:@"array"
- until:^(id obj) { return [obj array].count < initial; }];
- [self startMeasuring];
- [realm beginWriteTransaction];
- for (NSUInteger i = 0; i < obj.array.count; i += 10) {
- [obj.array removeObjectAtIndex:i];
- }
- [realm commitWriteTransaction];
- dispatch_sync(_queue, ^{});
- }];
- }
- - (void)testArrayKVOIndexHandlingRemoveBackwards {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:50];
- [realm beginWriteTransaction];
- ArrayPropertyObject *obj = [ArrayPropertyObject createInRealm:realm withValue:@[@"", [StringObject allObjectsInRealm:realm], @[]]];
- [realm commitWriteTransaction];
- const NSUInteger initial = obj.array.count;
- [self observeObject:obj keyPath:@"array"
- until:^(id obj) { return [obj array].count < initial; }];
- [self startMeasuring];
- [realm beginWriteTransaction];
- for (NSUInteger i = obj.array.count; i > 0; i -= i > 10 ? 10 : i) {
- [obj.array removeObjectAtIndex:i - 1];
- }
- [realm commitWriteTransaction];
- dispatch_sync(_queue, ^{});
- }];
- }
- - (void)testArrayKVOIndexHandlingInsertCompact {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:50];
- [realm beginWriteTransaction];
- ArrayPropertyObject *obj = [ArrayPropertyObject createInRealm:realm withValue:@[@"", @[], @[]]];
- [realm commitWriteTransaction];
- const NSUInteger count = [StringObject allObjectsInRealm:realm].count / 8;
- const NSUInteger factor = count / 10;
- [self observeObject:obj keyPath:@"array"
- until:^(id obj) { return [obj array].count >= count; }];
- RLMArray *array = obj.array;
- [self startMeasuring];
- [realm beginWriteTransaction];
- for (StringObject *so in [StringObject allObjectsInRealm:realm]) {
- [array addObject:so];
- if (array.count % factor == 0) {
- [realm commitWriteTransaction];
- dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
- [realm beginWriteTransaction];
- }
- if (array.count > count) {
- break;
- }
- }
- [realm commitWriteTransaction];
- dispatch_sync(_queue, ^{});
- }];
- }
- - (void)testArrayKVOIndexHandlingInsertSparse {
- [self measureMetrics:self.class.defaultPerformanceMetrics automaticallyStartMeasuring:NO forBlock:^{
- RLMRealm *realm = [self getStringObjects:50];
- [realm beginWriteTransaction];
- ArrayPropertyObject *obj = [ArrayPropertyObject createInRealm:realm withValue:@[@"", @[], @[]]];
- [realm commitWriteTransaction];
- const NSUInteger count = [StringObject allObjectsInRealm:realm].count / 8;
- const NSUInteger factor = count / 10;
- [self observeObject:obj keyPath:@"array"
- until:^(id obj) { return [obj array].count >= count; }];
- RLMArray *array = obj.array;
- [self startMeasuring];
- [realm beginWriteTransaction];
- for (StringObject *so in [StringObject allObjectsInRealm:realm]) {
- NSUInteger index = array.count;
- if (array.count > factor) {
- index = index * 3 % factor;
- }
- [array insertObject:so atIndex:index];
- if (array.count % factor == 0) {
- [realm commitWriteTransaction];
- dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
- [realm beginWriteTransaction];
- }
- if (array.count > count) {
- break;
- }
- }
- [realm commitWriteTransaction];
- dispatch_sync(_queue, ^{});
- }];
- }
- - (void)observeObject:(RLMObject *)object keyPath:(NSString *)keyPath until:(int (^)(id))block {
- self.sema = dispatch_semaphore_create(0);
- self.queue = dispatch_queue_create("bg", 0);
- RLMRealmConfiguration *config = object.realm.configuration;
- NSString *className = [object.class className];
- dispatch_async(_queue, ^{
- RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
- id obj = [[realm allObjects:className] firstObject];
- [obj addObserver:self forKeyPath:keyPath options:(NSKeyValueObservingOptions)0 context:(__bridge void *)_sema];
- dispatch_semaphore_signal(_sema);
- while (!block(obj)) {
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
- [obj removeObserver:self forKeyPath:keyPath context:(__bridge void *)_sema];
- });
- dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
- }
- - (void)observeValueForKeyPath:(__unused NSString *)keyPath
- ofObject:(__unused id)object
- change:(__unused NSDictionary *)change
- context:(void *)context {
- dispatch_semaphore_signal((__bridge dispatch_semaphore_t)context);
- }
- @end
- #endif
|