Register all database views asynchronously.
This commit is contained in:
parent
96b7dc5163
commit
5cf89a0f3d
4
Podfile
4
Podfile
|
@ -7,8 +7,8 @@ def shared_pods
|
|||
# OWS Pods
|
||||
# pod 'SQLCipher', path: '../sqlcipher2'
|
||||
pod 'SQLCipher', :git => 'https://github.com/sqlcipher/sqlcipher.git', :commit => 'd5c2bec'
|
||||
# pod 'YapDatabase/SQLCipher', path: '../YapDatabase'
|
||||
pod 'YapDatabase/SQLCipher', :git => 'https://github.com/WhisperSystems/YapDatabase.git', branch: 'release/unencryptedHeaders'
|
||||
pod 'YapDatabase/SQLCipher', path: '../YapDatabase'
|
||||
# pod 'YapDatabase/SQLCipher', :git => 'https://github.com/WhisperSystems/YapDatabase.git', branch: 'release/unencryptedHeaders'
|
||||
pod 'SignalServiceKit', path: '.'
|
||||
pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git', branch: 'mkirk/framework-friendly'
|
||||
#pod 'AxolotlKit', path: '../SignalProtocolKit'
|
||||
|
|
10
Podfile.lock
10
Podfile.lock
|
@ -141,7 +141,7 @@ DEPENDENCIES:
|
|||
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
|
||||
- SQLCipher (from `https://github.com/sqlcipher/sqlcipher.git`, commit `d5c2bec`)
|
||||
- SSZipArchive
|
||||
- YapDatabase/SQLCipher (from `https://github.com/WhisperSystems/YapDatabase.git`, branch `release/unencryptedHeaders`)
|
||||
- YapDatabase/SQLCipher (from `../YapDatabase`)
|
||||
- YYImage
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
|
@ -167,8 +167,7 @@ EXTERNAL SOURCES:
|
|||
:commit: d5c2bec
|
||||
:git: https://github.com/sqlcipher/sqlcipher.git
|
||||
YapDatabase:
|
||||
:branch: release/unencryptedHeaders
|
||||
:git: https://github.com/WhisperSystems/YapDatabase.git
|
||||
:path: ../YapDatabase
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
AxolotlKit:
|
||||
|
@ -192,9 +191,6 @@ CHECKOUT OPTIONS:
|
|||
SQLCipher:
|
||||
:commit: d5c2bec
|
||||
:git: https://github.com/sqlcipher/sqlcipher.git
|
||||
YapDatabase:
|
||||
:commit: eaff655ebc774105e83f835ead71f8b7a02e4ac1
|
||||
:git: https://github.com/WhisperSystems/YapDatabase.git
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
|
||||
|
@ -221,6 +217,6 @@ SPEC CHECKSUMS:
|
|||
YapDatabase: 299a32de9d350d37a9ac5b0532609d87d5d2a5de
|
||||
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
|
||||
|
||||
PODFILE CHECKSUM: 0d804514eb2db34b9874b653e543255d8c2f5751
|
||||
PODFILE CHECKSUM: 6da9d13ffba2c3d0ae0a0d376b8881102f41395f
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#import <SignalMessaging/Release.h>
|
||||
#import <SignalMessaging/SignalMessaging.h>
|
||||
#import <SignalMessaging/VersionMigrations.h>
|
||||
#import <SignalServiceKit/AppReadiness.h>
|
||||
#import <SignalServiceKit/NSUserDefaults+OWS.h>
|
||||
#import <SignalServiceKit/OWSBatchMessageProcessor.h>
|
||||
#import <SignalServiceKit/OWSDisappearingMessagesJob.h>
|
||||
|
@ -134,7 +135,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
[self startupLogging];
|
||||
|
||||
|
||||
// If a backup restore is in progress, try to complete it.
|
||||
// Otherwise, cleanup backup state.
|
||||
[OWSBackup applicationDidFinishLaunching];
|
||||
|
@ -197,7 +197,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
return YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The user must unlock the device once after reboot before the database encryption key can be accessed.
|
||||
*/
|
||||
|
@ -394,7 +393,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
DDLogWarn(@"%@ applicationDidBecomeActive.", self.logTag);
|
||||
|
||||
if (CurrentAppContext().isRunningTests) {
|
||||
return;
|
||||
}
|
||||
|
@ -403,6 +401,19 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
[self ensureRootViewController];
|
||||
|
||||
[AppReadiness.sharedManager runNowOrWhenAppIsReady:^{
|
||||
[self handleActivation];
|
||||
}];
|
||||
|
||||
DDLogInfo(@"%@ applicationDidBecomeActive completed.", self.logTag);
|
||||
}
|
||||
|
||||
- (void)handleActivation
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
DDLogWarn(@"%@ handleActivation.", self.logTag);
|
||||
|
||||
// Always check prekeys after app launches, and sometimes check on app activation.
|
||||
[TSPreKeyManager checkPreKeysIfNecessary];
|
||||
|
||||
|
@ -472,10 +483,9 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
preferences:[Environment preferences]];
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
DDLogInfo(@"%@ applicationDidBecomeActive completed.", self.logTag);
|
||||
DDLogInfo(@"%@ handleActivation completed.", self.logTag);
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
|
@ -753,10 +763,13 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
- (void)storageIsReady
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
DDLogInfo(@"%@ storageIsReady", self.logTag);
|
||||
|
||||
[OWSPreferences setIsRegistered:[TSAccountManager isRegistered]];
|
||||
|
||||
[AppReadiness.sharedManager setAppIsReady];
|
||||
|
||||
if ([TSAccountManager isRegistered]) {
|
||||
DDLogInfo(@"localNumber: %@", [TSAccountManager localNumber]);
|
||||
|
||||
|
@ -833,6 +846,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
- (void)ensureRootViewController
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
DDLogInfo(@"%@ ensureRootViewController", self.logTag);
|
||||
|
||||
if (![OWSStorage isStorageReady] || self.hasInitialRootViewController) {
|
||||
|
|
|
@ -338,6 +338,65 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
NSString *_Nullable databaseFilePath = [self createUnconvertedDatabase:databasePassword];
|
||||
XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]);
|
||||
|
||||
__block NSData *_Nullable databaseSalt = nil;
|
||||
YapDatabaseSaltBlock saltBlock = ^(NSData *saltData) {
|
||||
OWSAssert(!databaseSalt);
|
||||
OWSAssert(saltData);
|
||||
|
||||
databaseSalt = saltData;
|
||||
};
|
||||
__block NSData *_Nullable databaseKeySpec = nil;
|
||||
YapDatabaseKeySpecBlock keySpecBlock = ^(NSData *keySpecData) {
|
||||
OWSAssert(!databaseKeySpec);
|
||||
OWSAssert(keySpecData);
|
||||
|
||||
databaseKeySpec = keySpecData;
|
||||
};
|
||||
NSError *_Nullable error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
saltBlock:saltBlock
|
||||
keySpecBlock:keySpecBlock];
|
||||
if (error) {
|
||||
DDLogError(@"%s error: %@", __PRETTY_FUNCTION__, error);
|
||||
}
|
||||
XCTAssertNil(error);
|
||||
XCTAssertFalse([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]);
|
||||
XCTAssertNotNil(databaseSalt);
|
||||
XCTAssertEqual(databaseSalt.length, kSQLCipherSaltLength);
|
||||
XCTAssertNotNil(databaseKeySpec);
|
||||
XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength);
|
||||
|
||||
BOOL isValid = [self verifyTestDatabase:databaseFilePath
|
||||
databasePassword:nil
|
||||
databaseSalt:nil
|
||||
databaseKeySpec:databaseKeySpec];
|
||||
XCTAssertTrue(isValid);
|
||||
}
|
||||
|
||||
// Verifies that legacy users with non-converted databases can convert.
|
||||
- (void)testDatabaseConversionPerformance_WithKeyspec
|
||||
{
|
||||
NSData *databasePassword = [self randomDatabasePassword];
|
||||
NSString *databaseFilePath = [self createTempDatabaseFilePath];
|
||||
|
||||
const int kItemCount = 50 * 1000;
|
||||
|
||||
// Create an populate the unconverted database.
|
||||
[self openYapDatabase:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
databaseSalt:nil
|
||||
databaseKeySpec:nil
|
||||
databaseBlock:^(YapDatabase *database) {
|
||||
YapDatabaseConnection *dbConnection = database.newConnection;
|
||||
[dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
for (int i = 0; i < kItemCount; i++) {
|
||||
[transaction setObject:@(i) forKey:@"test_key_name" inCollection:@"test_collection_name"];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
XCTAssertTrue([YapDatabaseCryptoUtils doesDatabaseNeedToBeConverted:databaseFilePath]);
|
||||
|
||||
__block NSData *_Nullable databaseSalt = nil;
|
||||
YapDatabaseSaltBlock saltBlock = ^(NSData *saltData) {
|
||||
OWSAssert(!databaseSalt);
|
||||
|
@ -366,10 +425,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
XCTAssertNotNil(databaseKeySpec);
|
||||
XCTAssertEqual(databaseKeySpec.length, kSQLCipherKeySpecLength);
|
||||
|
||||
BOOL isValid = [self verifyTestDatabase:databaseFilePath
|
||||
databasePassword:nil
|
||||
databaseSalt:nil
|
||||
databaseKeySpec:databaseKeySpec];
|
||||
// Verify the contents of the unconverted database.
|
||||
__block BOOL isValid = NO;
|
||||
[self openYapDatabase:databaseFilePath
|
||||
databasePassword:databasePassword
|
||||
databaseSalt:nil
|
||||
databaseKeySpec:nil
|
||||
databaseBlock:^(YapDatabase *database) {
|
||||
YapDatabaseConnection *dbConnection = database.newConnection;
|
||||
isValid = [dbConnection numberOfKeysInCollection:@"test_collection_name"] == kItemCount;
|
||||
}];
|
||||
XCTAssertTrue(isValid);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWS104CreateRecipientIdentities.h"
|
||||
|
@ -24,42 +24,36 @@ static NSString *const OWS104CreateRecipientIdentitiesMigrationId = @"104";
|
|||
return OWS104CreateRecipientIdentitiesMigrationId;
|
||||
}
|
||||
|
||||
// Overriding runUp instead of runUpWithTransaction in order to implement a blocking migration.
|
||||
- (void)runUp
|
||||
- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[[OWSRecipientIdentity dbReadWriteConnection] readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
NSMutableDictionary<NSString *, NSData *> *identityKeys = [NSMutableDictionary new];
|
||||
NSMutableDictionary<NSString *, NSData *> *identityKeys = [NSMutableDictionary new];
|
||||
|
||||
[transaction
|
||||
enumerateKeysAndObjectsInCollection:TSStorageManagerTrustedKeysCollection
|
||||
usingBlock:^(
|
||||
NSString *_Nonnull recipientId, id _Nonnull object, BOOL *_Nonnull stop) {
|
||||
if (![object isKindOfClass:[NSData class]]) {
|
||||
OWSFail(
|
||||
@"%@ Unexpected object in trusted keys collection key: %@ object: %@",
|
||||
self.logTag,
|
||||
recipientId,
|
||||
object);
|
||||
return;
|
||||
}
|
||||
NSData *identityKey = (NSData *)object;
|
||||
[identityKeys setObject:identityKey forKey:recipientId];
|
||||
}];
|
||||
[transaction
|
||||
enumerateKeysAndObjectsInCollection:TSStorageManagerTrustedKeysCollection
|
||||
usingBlock:^(NSString *_Nonnull recipientId, id _Nonnull object, BOOL *_Nonnull stop) {
|
||||
if (![object isKindOfClass:[NSData class]]) {
|
||||
OWSFail(@"%@ Unexpected object in trusted keys collection key: %@ object: %@",
|
||||
self.logTag,
|
||||
recipientId,
|
||||
object);
|
||||
return;
|
||||
}
|
||||
NSData *identityKey = (NSData *)object;
|
||||
[identityKeys setObject:identityKey forKey:recipientId];
|
||||
}];
|
||||
|
||||
[identityKeys enumerateKeysAndObjectsUsingBlock:^(
|
||||
NSString *_Nonnull recipientId, NSData *_Nonnull identityKey, BOOL *_Nonnull stop) {
|
||||
DDLogInfo(@"%@ Migrating identity key for recipient: %@", self.logTag, recipientId);
|
||||
[[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId
|
||||
identityKey:identityKey
|
||||
isFirstKnownKey:NO
|
||||
createdAt:[NSDate dateWithTimeIntervalSince1970:0]
|
||||
verificationState:OWSVerificationStateDefault]
|
||||
saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
[identityKeys enumerateKeysAndObjectsUsingBlock:^(
|
||||
NSString *_Nonnull recipientId, NSData *_Nonnull identityKey, BOOL *_Nonnull stop) {
|
||||
DDLogInfo(@"%@ Migrating identity key for recipient: %@", self.logTag, recipientId);
|
||||
[[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId
|
||||
identityKey:identityKey
|
||||
isFirstKnownKey:NO
|
||||
createdAt:[NSDate dateWithTimeIntervalSince1970:0]
|
||||
verificationState:OWSVerificationStateDefault]
|
||||
saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
[self saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -58,6 +58,42 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Database Connections
|
||||
|
||||
#ifdef DEBUG
|
||||
+ (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return self.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
// Database migrations need to occur _before_ storage is ready (by definition),
|
||||
// so we need to use a connection with canWriteBeforeStorageReady set in
|
||||
// debug builds.
|
||||
+ (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
static YapDatabaseConnection *sharedDBConnection;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedDBConnection = [TSStorageManager sharedManager].newDatabaseConnection;
|
||||
|
||||
OWSAssert([sharedDBConnection isKindOfClass:[OWSDatabaseConnection class]]);
|
||||
((OWSDatabaseConnection *)sharedDBConnection).canWriteBeforeStorageReady = YES;
|
||||
});
|
||||
|
||||
return sharedDBConnection;
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return OWSDatabaseMigration.dbReadConnection;
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return OWSDatabaseMigration.dbReadWriteConnection;
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSDatabaseMigrationRunner.h"
|
||||
|
@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[[OWS100RemoveTSRecipientsMigration alloc] initWithStorageManager:storageManager],
|
||||
[[OWS102MoveLoggingPreferenceToUserDefaults alloc] initWithStorageManager:storageManager],
|
||||
[[OWS103EnableVideoCalling alloc] initWithStorageManager:storageManager],
|
||||
// OWS104CreateRecipientIdentities is run separately. See runSafeBlockingMigrations.
|
||||
[[OWS104CreateRecipientIdentities alloc] initWithStorageManager:storageManager],
|
||||
[[OWS105AttachmentFilePaths alloc] initWithStorageManager:storageManager],
|
||||
[[OWS106EnsureProfileComplete alloc] initWithStorageManager:storageManager]
|
||||
];
|
||||
|
@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
TSStorageManager *storageManager = TSStorageManager.sharedManager;
|
||||
return @[
|
||||
[[OWS104CreateRecipientIdentities alloc] initWithStorageManager:storageManager],
|
||||
// [[OWS104CreateRecipientIdentities alloc] initWithStorageManager:storageManager],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface OWSBatchMessageProcessor : NSObject
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
+ (void)syncRegisterDatabaseExtension:(OWSStorage *)storage;
|
||||
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage;
|
||||
|
||||
- (void)enqueueEnvelopeData:(NSData *)envelopeData plaintextData:(NSData *_Nullable)plaintextData;
|
||||
- (void)handleAnyUnprocessedEnvelopesAsync;
|
||||
|
|
|
@ -200,7 +200,7 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
|
|||
}
|
||||
|
||||
|
||||
+ (void)syncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseView *existingView = [storage registeredExtension:OWSMessageContentJobFinderExtensionName];
|
||||
if (existingView) {
|
||||
|
@ -208,7 +208,7 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
|
|||
// already initialized
|
||||
return;
|
||||
}
|
||||
[storage registerExtension:[self databaseExtension] withName:OWSMessageContentJobFinderExtensionName];
|
||||
[storage asyncRegisterExtension:[self databaseExtension] withName:OWSMessageContentJobFinderExtensionName];
|
||||
}
|
||||
|
||||
#pragma mark Logging
|
||||
|
@ -443,9 +443,9 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
|
|||
|
||||
#pragma mark - class methods
|
||||
|
||||
+ (void)syncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
{
|
||||
[OWSMessageContentJobFinder syncRegisterDatabaseExtension:storage];
|
||||
[OWSMessageContentJobFinder asyncRegisterDatabaseExtension:storage];
|
||||
}
|
||||
|
||||
#pragma mark - instance methods
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
extern NSString *const kNSNotificationName_BlockedPhoneNumbersDidChange;
|
||||
|
||||
// This class can be safely accessed and used from any thread.
|
||||
|
|
|
@ -30,10 +30,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
+ (void)asyncRegisterDatabaseExtensions:(OWSStorage *)storage;
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Only use the sync version for testing, generally we'll want to register extensions async
|
||||
*/
|
||||
+ (void)blockingRegisterDatabaseExtensions:(OWSStorage *)storage;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -188,23 +188,17 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
|||
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Useful for tests, don't use in app startup path because it's slow.
|
||||
+ (void)blockingRegisterDatabaseExtensions:(OWSStorage *)storage
|
||||
{
|
||||
[storage registerExtension:[self indexDatabaseExtension] withName:OWSDisappearingMessageFinderExpiresAtIndex];
|
||||
}
|
||||
#endif
|
||||
|
||||
+ (void)asyncRegisterDatabaseExtensions:(OWSStorage *)storage
|
||||
{
|
||||
[storage asyncRegisterExtension:[self indexDatabaseExtension]
|
||||
withName:OWSDisappearingMessageFinderExpiresAtIndex
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (ready) {
|
||||
DDLogDebug(@"%@ completed registering extension async.", self.logTag);
|
||||
} else {
|
||||
DDLogError(@"%@ failed registering extension async.", self.logTag);
|
||||
}
|
||||
}];
|
||||
[storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSDisappearingMessageFinderExpiresAtIndex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -19,10 +19,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
+ (void)asyncRegisterDatabaseExtensionsWithStorageManager:(OWSStorage *)storage;
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Only use the sync version for testing, generally we'll want to register extensions async
|
||||
*/
|
||||
- (void)blockingRegisterDatabaseExtensions;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -117,24 +117,19 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i
|
|||
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Useful for tests, don't use in app startup path because it's slow.
|
||||
- (void)blockingRegisterDatabaseExtensions
|
||||
{
|
||||
[self.storageManager registerExtension:[self.class indexDatabaseExtension]
|
||||
withName:OWSFailedAttachmentDownloadsJobAttachmentStateIndex];
|
||||
}
|
||||
#endif
|
||||
|
||||
+ (void)asyncRegisterDatabaseExtensionsWithStorageManager:(OWSStorage *)storage
|
||||
{
|
||||
[storage asyncRegisterExtension:[self indexDatabaseExtension]
|
||||
withName:OWSFailedAttachmentDownloadsJobAttachmentStateIndex
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (ready) {
|
||||
DDLogDebug(@"%@ completed registering extension async.", self.logTag);
|
||||
} else {
|
||||
DDLogError(@"%@ failed registering extension async.", self.logTag);
|
||||
}
|
||||
}];
|
||||
withName:OWSFailedAttachmentDownloadsJobAttachmentStateIndex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -19,10 +19,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
+ (void)asyncRegisterDatabaseExtensionsWithStorageManager:(OWSStorage *)storage;
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Only use the sync version for testing, generally we'll want to register extensions async
|
||||
*/
|
||||
- (void)blockingRegisterDatabaseExtensions;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -127,24 +127,18 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m
|
|||
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Useful for tests, don't use in app startup path because it's slow.
|
||||
- (void)blockingRegisterDatabaseExtensions
|
||||
{
|
||||
[self.storageManager registerExtension:[self.class indexDatabaseExtension]
|
||||
withName:OWSFailedMessagesJobMessageStateIndex];
|
||||
}
|
||||
#endif
|
||||
|
||||
+ (void)asyncRegisterDatabaseExtensionsWithStorageManager:(OWSStorage *)storage
|
||||
{
|
||||
[storage asyncRegisterExtension:[self indexDatabaseExtension]
|
||||
withName:OWSFailedMessagesJobMessageStateIndex
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (ready) {
|
||||
DDLogDebug(@"%@ completed registering extension async.", self.logTag);
|
||||
} else {
|
||||
DDLogError(@"%@ failed registering extension async.", self.logTag);
|
||||
}
|
||||
}];
|
||||
[storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSFailedMessagesJobMessageStateIndex];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "AppContext.h"
|
||||
#import "AppReadiness.h"
|
||||
#import "NSDate+OWS.h"
|
||||
#import "NSNotificationCenter+OWS.h"
|
||||
#import "NotificationsProtocol.h"
|
||||
|
@ -448,13 +449,13 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (!CurrentAppContext().isMainAppAndActive) {
|
||||
// Only try to sync if the main app is active to avoid interfering with startup.
|
||||
//
|
||||
// applicationDidBecomeActive: will try to sync again when the main app becomes active.
|
||||
return;
|
||||
}
|
||||
[AppReadiness runNowOrWhenAppIsReady:^{
|
||||
[self syncQueuedVerificationStates];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)syncQueuedVerificationStates
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@synchronized(self)
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface OWSMessageReceiver : NSObject
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
+ (void)syncRegisterDatabaseExtension:(OWSStorage *)storage;
|
||||
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage;
|
||||
|
||||
- (void)handleReceivedEnvelope:(OWSSignalServiceProtosEnvelope *)envelope;
|
||||
- (void)handleAnyUnprocessedEnvelopesAsync;
|
||||
|
|
|
@ -190,7 +190,7 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
|
|||
});
|
||||
}
|
||||
|
||||
+ (void)syncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
{
|
||||
[self registerLegacyClasses];
|
||||
|
||||
|
@ -200,7 +200,7 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
|
|||
// already initialized
|
||||
return;
|
||||
}
|
||||
[storage registerExtension:[self databaseExtension] withName:OWSMessageDecryptJobFinderExtensionName];
|
||||
[storage asyncRegisterExtension:[self databaseExtension] withName:OWSMessageDecryptJobFinderExtensionName];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -422,9 +422,9 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
|
|||
|
||||
#pragma mark - class methods
|
||||
|
||||
+ (void)syncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage
|
||||
{
|
||||
[OWSMessageDecryptJobFinder syncRegisterDatabaseExtension:storage];
|
||||
[OWSMessageDecryptJobFinder asyncRegisterDatabaseExtension:storage];
|
||||
}
|
||||
|
||||
#pragma mark - instance methods
|
||||
|
|
|
@ -95,11 +95,7 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess
|
|||
+ (void)asyncRegisterExtensionWithStorageManager:(OWSStorage *)storage
|
||||
{
|
||||
DDLogInfo(@"%@ registering async.", self.logTag);
|
||||
[storage asyncRegisterExtension:self.indexExtension
|
||||
withName:OWSIncomingMessageFinderExtensionName
|
||||
completionBlock:^(BOOL ready) {
|
||||
DDLogInfo(@"%@ finished registering async.", self.logTag);
|
||||
}];
|
||||
[storage asyncRegisterExtension:self.indexExtension withName:OWSIncomingMessageFinderExtensionName];
|
||||
}
|
||||
|
||||
// We should not normally hit this, as we should have prefer registering async, but it is useful for testing.
|
||||
|
|
|
@ -10,6 +10,30 @@ extern NSString *const StorageIsReadyNotification;
|
|||
|
||||
@class YapDatabaseExtension;
|
||||
|
||||
@protocol OWSDatabaseConnectionDelegate <NSObject>
|
||||
|
||||
- (BOOL)areAllRegistrationsComplete;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSDatabaseConnection : YapDatabaseConnection
|
||||
|
||||
@property (atomic, weak) id<OWSDatabaseConnectionDelegate> delegate;
|
||||
|
||||
#ifdef DEBUG
|
||||
@property (atomic) BOOL canWriteBeforeStorageReady;
|
||||
#endif
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithDatabase:(YapDatabase *)database
|
||||
delegate:(id<OWSDatabaseConnectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSStorage : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
@ -37,14 +61,16 @@ extern NSString *const StorageIsReadyNotification;
|
|||
// TODO: Deprecate?
|
||||
- (nullable YapDatabaseConnection *)newDatabaseConnection;
|
||||
|
||||
#ifdef DEBUG
|
||||
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
|
||||
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
|
||||
withName:(NSString *)extensionName
|
||||
completionBlock:(nullable void (^)(BOOL ready))completionBlock;
|
||||
#endif
|
||||
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
|
||||
- (nullable id)registeredExtension:(NSString *)extensionName;
|
||||
|
||||
- (unsigned long long)databaseFileSize;
|
||||
|
||||
- (YapDatabaseConnection *)registrationConnection;
|
||||
|
||||
#pragma mark - Password
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,14 +38,6 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
#pragma mark -
|
||||
|
||||
@protocol OWSDatabaseConnectionDelegate <NSObject>
|
||||
|
||||
- (BOOL)areSyncRegistrationsComplete;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface YapDatabaseConnection ()
|
||||
|
||||
- (id)initWithDatabase:(YapDatabase *)database;
|
||||
|
@ -54,18 +46,6 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSDatabaseConnection : YapDatabaseConnection
|
||||
|
||||
@property (atomic, weak) id<OWSDatabaseConnectionDelegate> delegate;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithDatabase:(YapDatabase *)database
|
||||
delegate:(id<OWSDatabaseConnectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSDatabaseConnection
|
||||
|
||||
- (id)initWithDatabase:(YapDatabase *)database delegate:(id<OWSDatabaseConnectionDelegate>)delegate
|
||||
|
@ -94,28 +74,20 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
{
|
||||
id<OWSDatabaseConnectionDelegate> delegate = self.delegate;
|
||||
OWSAssert(delegate);
|
||||
OWSAssert(delegate.areSyncRegistrationsComplete);
|
||||
OWSAssert(delegate.areAllRegistrationsComplete || self.canWriteBeforeStorageReady);
|
||||
|
||||
[super readWriteWithBlock:block];
|
||||
}
|
||||
|
||||
- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
|
||||
{
|
||||
id<OWSDatabaseConnectionDelegate> delegate = self.delegate;
|
||||
OWSAssert(delegate);
|
||||
OWSAssert(delegate.areSyncRegistrationsComplete);
|
||||
|
||||
[super asyncReadWriteWithBlock:block];
|
||||
[self asyncReadWriteWithBlock:block completionQueue:NULL completionBlock:NULL];
|
||||
}
|
||||
|
||||
- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
|
||||
completionBlock:(nullable dispatch_block_t)completionBlock
|
||||
{
|
||||
id<OWSDatabaseConnectionDelegate> delegate = self.delegate;
|
||||
OWSAssert(delegate);
|
||||
OWSAssert(delegate.areSyncRegistrationsComplete);
|
||||
|
||||
[super asyncReadWriteWithBlock:block completionBlock:completionBlock];
|
||||
[self asyncReadWriteWithBlock:block completionQueue:NULL completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
|
||||
|
@ -124,7 +96,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
{
|
||||
id<OWSDatabaseConnectionDelegate> delegate = self.delegate;
|
||||
OWSAssert(delegate);
|
||||
OWSAssert(delegate.areSyncRegistrationsComplete);
|
||||
OWSAssert(delegate.areAllRegistrationsComplete || self.canWriteBeforeStorageReady);
|
||||
|
||||
[super asyncReadWriteWithBlock:block completionQueue:completionQueue completionBlock:completionBlock];
|
||||
}
|
||||
|
@ -138,6 +110,8 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
- (void)addConnection:(YapDatabaseConnection *)connection;
|
||||
|
||||
- (YapDatabaseConnection *)registrationConnection;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -146,6 +120,8 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
@property (atomic, weak) id<OWSDatabaseConnectionDelegate> delegate;
|
||||
|
||||
@property (atomic, nullable) YapDatabaseConnection *registrationConnectionCached;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (id)initWithPath:(NSString *)inPath
|
||||
serializer:(nullable YapDatabaseSerializer)inSerializer
|
||||
|
@ -192,6 +168,25 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
return connection;
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)registrationConnection
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (!self.registrationConnectionCached) {
|
||||
YapDatabaseConnection *connection = [super registrationConnection];
|
||||
|
||||
#ifdef DEBUG
|
||||
// Flag the registration connection as such.
|
||||
OWSAssert([connection isKindOfClass:[OWSDatabaseConnection class]]);
|
||||
((OWSDatabaseConnection *)connection).canWriteBeforeStorageReady = YES;
|
||||
#endif
|
||||
|
||||
self.registrationConnectionCached = connection;
|
||||
}
|
||||
return self.registrationConnectionCached;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -317,6 +312,16 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)areAllRegistrationsComplete
|
||||
{
|
||||
DDLogInfo(@"%@ areAllRegistrationsComplete: %d %d = %d",
|
||||
self.logTag,
|
||||
self.areSyncRegistrationsComplete,
|
||||
self.areAsyncRegistrationsComplete,
|
||||
self.areSyncRegistrationsComplete && self.areAsyncRegistrationsComplete);
|
||||
return self.areSyncRegistrationsComplete && self.areAsyncRegistrationsComplete;
|
||||
}
|
||||
|
||||
- (void)runSyncRegistrations
|
||||
{
|
||||
OWS_ABSTRACT_METHOD();
|
||||
|
@ -352,11 +357,19 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
|
||||
for (OWSStorage *storage in self.allStorages) {
|
||||
[storage runAsyncRegistrationsWithCompletion:^{
|
||||
|
||||
[self postRegistrationCompleteNotificationIfPossible];
|
||||
}];
|
||||
|
||||
((OWSDatabase *)storage.database).registrationConnectionCached = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)registrationConnection
|
||||
{
|
||||
return self.database.registrationConnection;
|
||||
}
|
||||
|
||||
+ (void)postRegistrationCompleteNotificationIfPossible
|
||||
{
|
||||
if (!self.isStorageReady) {
|
||||
|
@ -374,7 +387,7 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
+ (BOOL)isStorageReady
|
||||
{
|
||||
for (OWSStorage *storage in self.allStorages) {
|
||||
if (!storage.areAsyncRegistrationsComplete) {
|
||||
if (!storage.areAllRegistrationsComplete) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
@ -458,16 +471,25 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
|
|||
return self.database.newConnection;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
|
||||
{
|
||||
return [self.database registerExtension:extension withName:extensionName];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
|
||||
withName:(NSString *)extensionName
|
||||
completionBlock:(nullable void (^)(BOOL ready))completionBlock
|
||||
{
|
||||
[self.database asyncRegisterExtension:extension withName:extensionName completionBlock:completionBlock];
|
||||
[self.database asyncRegisterExtension:extension
|
||||
withName:extensionName
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (!ready) {
|
||||
OWSFail(@"%@ asyncRegisterExtension failed: %@", self.logTag, extensionName);
|
||||
} else {
|
||||
DDLogVerbose(@"%@ asyncRegisterExtension succeeded: %@", self.logTag, extensionName);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (nullable id)registeredExtension:(NSString *)extensionName
|
||||
|
|
|
@ -23,16 +23,16 @@ extern NSString *const TSSecondaryDevicesDatabaseViewExtensionName;
|
|||
|
||||
+ (void)registerCrossProcessNotifier:(OWSStorage *)storage;
|
||||
|
||||
// This method must be called _AFTER_ registerThreadInteractionsDatabaseView.
|
||||
+ (void)registerThreadDatabaseView:(OWSStorage *)storage;
|
||||
// This method must be called _AFTER_ asyncRegisterThreadInteractionsDatabaseView.
|
||||
+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
+ (void)registerThreadInteractionsDatabaseView:(OWSStorage *)storage;
|
||||
+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage;
|
||||
+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
// Instances of OWSReadTracking for wasRead is NO and shouldAffectUnreadCounts is YES.
|
||||
//
|
||||
// Should be used for "unread message counts".
|
||||
+ (void)registerUnreadDatabaseView:(OWSStorage *)storage;
|
||||
+ (void)asyncRegisterUnreadDatabaseView:(OWSStorage *)storage;
|
||||
|
||||
// Should be used for "unread indicator".
|
||||
//
|
||||
|
|
|
@ -72,19 +72,13 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
options:options];
|
||||
|
||||
if (async) {
|
||||
[storage asyncRegisterExtension:view
|
||||
withName:viewName
|
||||
completionBlock:^(BOOL ready) {
|
||||
OWSCAssert(ready);
|
||||
|
||||
DDLogInfo(@"%@ asyncRegisterExtension: %@ -> %d", self.logTag, viewName, ready);
|
||||
}];
|
||||
[storage asyncRegisterExtension:view withName:viewName];
|
||||
} else {
|
||||
[storage registerExtension:view withName:viewName];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)registerUnreadDatabaseView:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterUnreadDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
|
@ -100,7 +94,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
[self registerMessageDatabaseViewWithName:TSUnreadDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
async:NO
|
||||
async:YES
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
|
@ -152,7 +146,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
storage:storage];
|
||||
}
|
||||
|
||||
+ (void)registerThreadInteractionsDatabaseView:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
|
||||
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
|
||||
|
@ -165,7 +159,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
[self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName
|
||||
viewGrouping:viewGrouping
|
||||
version:@"1"
|
||||
async:NO
|
||||
async:YES
|
||||
storage:storage];
|
||||
}
|
||||
|
||||
|
@ -186,7 +180,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
storage:storage];
|
||||
}
|
||||
|
||||
+ (void)registerThreadDatabaseView:(OWSStorage *)storage
|
||||
+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage
|
||||
{
|
||||
YapDatabaseView *threadView = [storage registeredExtension:TSThreadDatabaseViewExtensionName];
|
||||
if (threadView) {
|
||||
|
@ -234,7 +228,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
YapDatabaseView *databaseView =
|
||||
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options];
|
||||
|
||||
[storage registerExtension:databaseView withName:TSThreadDatabaseViewExtensionName];
|
||||
[storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,15 +341,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
|
|||
YapDatabaseView *view =
|
||||
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options];
|
||||
|
||||
[storage asyncRegisterExtension:view
|
||||
withName:TSSecondaryDevicesDatabaseViewExtensionName
|
||||
completionBlock:^(BOOL ready) {
|
||||
if (ready) {
|
||||
DDLogDebug(@"%@ Successfully set up extension: %@", self.logTag, TSSecondaryDevicesGroup);
|
||||
} else {
|
||||
DDLogError(@"%@ Unable to setup extension: %@", self.logTag, TSSecondaryDevicesGroup);
|
||||
}
|
||||
}];
|
||||
[storage asyncRegisterExtension:view withName:TSSecondaryDevicesDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction
|
||||
|
|
|
@ -29,12 +29,6 @@ void runSyncRegistrationsForStorage(OWSStorage *storage)
|
|||
|
||||
// Synchronously register extensions which are essential for views.
|
||||
[TSDatabaseView registerCrossProcessNotifier:storage];
|
||||
[TSDatabaseView registerThreadInteractionsDatabaseView:storage];
|
||||
[TSDatabaseView registerThreadDatabaseView:storage];
|
||||
[TSDatabaseView registerUnreadDatabaseView:storage];
|
||||
[storage registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];
|
||||
[OWSMessageReceiver syncRegisterDatabaseExtension:storage];
|
||||
[OWSBatchMessageProcessor syncRegisterDatabaseExtension:storage];
|
||||
}
|
||||
|
||||
void runAsyncRegistrationsForStorage(OWSStorage *storage)
|
||||
|
@ -45,6 +39,14 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage)
|
|||
//
|
||||
// All sync registrations must be done before all async registrations,
|
||||
// or the sync registrations will block on the async registrations.
|
||||
|
||||
[TSDatabaseView asyncRegisterThreadInteractionsDatabaseView:storage];
|
||||
[TSDatabaseView asyncRegisterThreadDatabaseView:storage];
|
||||
[TSDatabaseView asyncRegisterUnreadDatabaseView:storage];
|
||||
[storage asyncRegisterExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];
|
||||
[OWSMessageReceiver asyncRegisterDatabaseExtension:storage];
|
||||
[OWSBatchMessageProcessor asyncRegisterDatabaseExtension:storage];
|
||||
|
||||
[TSDatabaseView asyncRegisterUnseenDatabaseView:storage];
|
||||
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:storage];
|
||||
[TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView:storage];
|
||||
|
@ -127,12 +129,26 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage)
|
|||
|
||||
runAsyncRegistrationsForStorage(self);
|
||||
|
||||
DDLogVerbose(@"%@ async registrations enqueued.", self.logTag);
|
||||
|
||||
// Block until all async registrations are complete.
|
||||
YapDatabaseConnection *dbConnection = self.newDatabaseConnection;
|
||||
YapDatabaseConnection *dbConnection = self.registrationConnection;
|
||||
OWSAssert(self.registrationConnection);
|
||||
// [dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
|
||||
// OWSAssert(!self.areAsyncRegistrationsComplete);
|
||||
//
|
||||
// DDLogVerbose(@"%@ async registrations flushed.", self.logTag);
|
||||
//
|
||||
// self.areAsyncRegistrationsComplete = YES;
|
||||
//
|
||||
// completion();
|
||||
// }];
|
||||
[dbConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue()
|
||||
completionBlock:^{
|
||||
OWSAssert(!self.areAsyncRegistrationsComplete);
|
||||
|
||||
DDLogVerbose(@"%@ async registrations complete.", self.logTag);
|
||||
|
||||
self.areAsyncRegistrationsComplete = YES;
|
||||
|
||||
completion();
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^AppReadyBlock)(void);
|
||||
|
||||
@interface AppReadiness : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (BOOL)isAppReady;
|
||||
|
||||
+ (void)setAppIsReady;
|
||||
|
||||
+ (void)runNowOrWhenAppIsReady:(AppReadyBlock)block;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppReadiness.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AppReadiness ()
|
||||
|
||||
@property (atomic) BOOL isAppReady;
|
||||
|
||||
@property (nonatomic, nullable) NSMutableArray<AppReadyBlock> *appReadyBlocks;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation AppReadiness
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
static AppReadiness *sharedMyManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedMyManager = [[self alloc] initDefault];
|
||||
});
|
||||
return sharedMyManager;
|
||||
}
|
||||
|
||||
- (instancetype)initDefault
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)isAppReady
|
||||
{
|
||||
return self.sharedManager.isAppReady;
|
||||
}
|
||||
|
||||
+ (void)runNowOrWhenAppIsReady:(AppReadyBlock)block
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
[self.sharedManager runNowOrWhenAppIsReady:block];
|
||||
}
|
||||
|
||||
- (void)runNowOrWhenAppIsReady:(AppReadyBlock)block
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssert(block);
|
||||
|
||||
if (self.isAppReady) {
|
||||
block();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.appReadyBlocks) {
|
||||
self.appReadyBlocks = [NSMutableArray new];
|
||||
}
|
||||
[self.appReadyBlocks addObject:block];
|
||||
}
|
||||
|
||||
+ (void)setAppIsReady
|
||||
{
|
||||
[self.sharedManager setAppIsReady];
|
||||
}
|
||||
|
||||
- (void)setAppIsReady
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssert(!self.isAppReady);
|
||||
|
||||
self.isAppReady = YES;
|
||||
|
||||
[self runAppReadyBlocks];
|
||||
}
|
||||
|
||||
- (void)runAppReadyBlocks
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssert(self.isAppReady);
|
||||
|
||||
for (AppReadyBlock block in self.appReadyBlocks) {
|
||||
block();
|
||||
}
|
||||
self.appReadyBlocks = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -18,12 +18,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
#define kWeekInMs (kDayInMs * 7)
|
||||
#define kMonthInMs (kDayInMs * 30)
|
||||
|
||||
@interface NSDate (millisecondTimeStamp)
|
||||
@interface NSDate (OWS)
|
||||
|
||||
+ (uint64_t)ows_millisecondTimeStamp;
|
||||
+ (NSDate *)ows_dateWithMillisecondsSince1970:(uint64_t)milliseconds;
|
||||
+ (uint64_t)ows_millisecondsSince1970ForDate:(NSDate *)date;
|
||||
|
||||
#pragma mark - Debugging
|
||||
|
||||
+ (NSString *)debugTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDate+OWS.h"
|
||||
|
@ -7,7 +7,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation NSDate (millisecondTimeStamp)
|
||||
@implementation NSDate (OWS)
|
||||
|
||||
+ (uint64_t)ows_millisecondTimeStamp
|
||||
{
|
||||
|
@ -26,6 +26,31 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return (uint64_t)(date.timeIntervalSince1970 * 1000);
|
||||
}
|
||||
|
||||
#pragma mark - Debugging
|
||||
|
||||
+ (NSDateFormatter *)dateFormatterForDebugTimestamps
|
||||
{
|
||||
static NSDateFormatter *formatter;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
formatter = [NSDateFormatter new];
|
||||
[formatter setLocale:[NSLocale currentLocale]];
|
||||
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS"];
|
||||
});
|
||||
return formatter;
|
||||
}
|
||||
|
||||
+ (NSString *)debugTimestamp
|
||||
{
|
||||
// We use ows_millisecondTimeStamp for its higher precision.
|
||||
return [[NSDate ows_dateWithMillisecondsSince1970:[NSDate ows_millisecondTimeStamp]] formattedAsDebugTimestamp];
|
||||
}
|
||||
|
||||
- (NSString *)formattedAsDebugTimestamp
|
||||
{
|
||||
return [[NSDate dateFormatterForDebugTimestamps] stringFromDate:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -58,12 +58,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
sharedDataFilePath:(NSString *)newFilePath
|
||||
exceptionName:(NSString *)exceptionName
|
||||
{
|
||||
DDLogInfo(@"%@ Moving file or directory from: %@ to: %@", self.logTag, oldFilePath, newFilePath);
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if (![fileManager fileExistsAtPath:oldFilePath]) {
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogInfo(@"%@ Moving file or directory from: %@ to: %@", self.logTag, oldFilePath, newFilePath);
|
||||
|
||||
if ([fileManager fileExistsAtPath:newFilePath]) {
|
||||
OWSFail(@"%@ Can't move file or directory from: %@ to: %@; destination already exists.",
|
||||
self.logTag,
|
||||
|
|
Loading…
Reference in New Issue