mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
8.3 KiB
Objective-C
257 lines
8.3 KiB
Objective-C
//
|
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
#import "TSStorageManager.h"
|
|
#import "AppContext.h"
|
|
#import "OWSAnalytics.h"
|
|
#import "OWSBatchMessageProcessor.h"
|
|
#import "OWSDisappearingMessagesFinder.h"
|
|
#import "OWSFailedAttachmentDownloadsJob.h"
|
|
#import "OWSFailedMessagesJob.h"
|
|
#import "OWSFileSystem.h"
|
|
#import "OWSIncomingMessageFinder.h"
|
|
#import "OWSMessageReceiver.h"
|
|
#import "OWSStorage+Subclass.h"
|
|
#import "TSDatabaseSecondaryIndexes.h"
|
|
#import "TSDatabaseView.h"
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
NSString *const TSStorageManagerExceptionName_CouldNotMoveDatabaseFile
|
|
= @"TSStorageManagerExceptionName_CouldNotMoveDatabaseFile";
|
|
NSString *const TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory
|
|
= @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory";
|
|
|
|
void runSyncRegistrationsForStorage(OWSStorage *storage)
|
|
{
|
|
OWSCAssert(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)
|
|
{
|
|
OWSCAssert(storage);
|
|
|
|
// Asynchronously register other extensions.
|
|
//
|
|
// All sync registrations must be done before all async registrations,
|
|
// or the sync registrations will block on the async registrations.
|
|
[TSDatabaseView asyncRegisterUnseenDatabaseView:storage];
|
|
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:storage];
|
|
[TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView:storage];
|
|
|
|
// Register extensions which aren't essential for rendering threads async.
|
|
[OWSIncomingMessageFinder asyncRegisterExtensionWithStorageManager:storage];
|
|
[TSDatabaseView asyncRegisterSecondaryDevicesDatabaseView:storage];
|
|
[OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:storage];
|
|
[OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithStorageManager:storage];
|
|
[OWSFailedAttachmentDownloadsJob asyncRegisterDatabaseExtensionsWithStorageManager:storage];
|
|
}
|
|
|
|
#pragma mark -
|
|
@interface TSStorageManager ()
|
|
|
|
@property (nonatomic, readonly, nullable) YapDatabaseConnection *dbReadConnection;
|
|
@property (nonatomic, readonly, nullable) YapDatabaseConnection *dbReadWriteConnection;
|
|
|
|
@property (atomic) BOOL areAsyncRegistrationsComplete;
|
|
@property (atomic) BOOL areSyncRegistrationsComplete;
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@implementation TSStorageManager
|
|
|
|
+ (instancetype)sharedManager {
|
|
static TSStorageManager *sharedManager = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
sharedManager = [[self alloc] initStorage];
|
|
|
|
#if TARGET_OS_IPHONE
|
|
[TSStorageManager protectFiles];
|
|
#endif
|
|
});
|
|
return sharedManager;
|
|
}
|
|
|
|
- (instancetype)initStorage
|
|
{
|
|
self = [super initStorage];
|
|
|
|
if (self) {
|
|
_dbReadConnection = self.newDatabaseConnection;
|
|
_dbReadWriteConnection = self.newDatabaseConnection;
|
|
|
|
OWSSingletonAssert();
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)resetStorage
|
|
{
|
|
_dbReadConnection = nil;
|
|
_dbReadWriteConnection = nil;
|
|
|
|
[super resetStorage];
|
|
}
|
|
|
|
- (void)runSyncRegistrations
|
|
{
|
|
runSyncRegistrationsForStorage(self);
|
|
|
|
// See comments on OWSDatabaseConnection.
|
|
//
|
|
// In the absence of finding documentation that can shed light on the issue we've been
|
|
// seeing, this issue only seems to affect sync and not async registrations. We've always
|
|
// been opening write transactions before the async registrations complete without negative
|
|
// consequences.
|
|
OWSAssert(!self.areSyncRegistrationsComplete);
|
|
self.areSyncRegistrationsComplete = YES;
|
|
}
|
|
|
|
- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion
|
|
{
|
|
OWSAssert(completion);
|
|
|
|
runAsyncRegistrationsForStorage(self);
|
|
|
|
// Block until all async registrations are complete.
|
|
YapDatabaseConnection *dbConnection = self.newDatabaseConnection;
|
|
[dbConnection flushTransactionsWithCompletionQueue:dispatch_get_main_queue()
|
|
completionBlock:^{
|
|
OWSAssert(!self.areAsyncRegistrationsComplete);
|
|
|
|
self.areAsyncRegistrationsComplete = YES;
|
|
|
|
completion();
|
|
}];
|
|
}
|
|
|
|
+ (void)protectFiles
|
|
{
|
|
DDLogInfo(@"%@ Database file size: %@", self.logTag, [OWSFileSystem fileSizeOfPath:self.legacyDatabaseFilePath]);
|
|
DDLogInfo(@"%@ \t SHM file size: %@", self.logTag, [OWSFileSystem fileSizeOfPath:self.legacyDatabaseFilePath_SHM]);
|
|
DDLogInfo(@"%@ \t WAL file size: %@", self.logTag, [OWSFileSystem fileSizeOfPath:self.legacyDatabaseFilePath_WAL]);
|
|
|
|
// The old database location was in the Document directory,
|
|
// so protect the database files individually.
|
|
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath];
|
|
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_SHM];
|
|
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_WAL];
|
|
|
|
// Protect the entire new database directory.
|
|
[OWSFileSystem protectFileOrFolderAtPath:self.sharedDataDatabaseDirPath];
|
|
}
|
|
|
|
+ (NSString *)legacyDatabaseDirPath
|
|
{
|
|
return [OWSFileSystem appDocumentDirectoryPath];
|
|
}
|
|
|
|
+ (NSString *)sharedDataDatabaseDirPath
|
|
{
|
|
NSString *databaseDirPath = [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"];
|
|
|
|
if (![OWSFileSystem ensureDirectoryExists:databaseDirPath]) {
|
|
OWSRaiseException(
|
|
TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory, @"Could not create new database directory");
|
|
}
|
|
return databaseDirPath;
|
|
}
|
|
|
|
+ (NSString *)databaseFilename
|
|
{
|
|
return @"Signal.sqlite";
|
|
}
|
|
|
|
+ (NSString *)databaseFilename_SHM
|
|
{
|
|
return [self.databaseFilename stringByAppendingString:@"-shm"];
|
|
}
|
|
|
|
+ (NSString *)databaseFilename_WAL
|
|
{
|
|
return [self.databaseFilename stringByAppendingString:@"-wal"];
|
|
}
|
|
|
|
+ (NSString *)legacyDatabaseFilePath
|
|
{
|
|
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
|
|
}
|
|
|
|
+ (NSString *)legacyDatabaseFilePath_SHM
|
|
{
|
|
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
|
|
}
|
|
|
|
+ (NSString *)legacyDatabaseFilePath_WAL
|
|
{
|
|
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
|
|
}
|
|
|
|
+ (NSString *)sharedDataDatabaseFilePath
|
|
{
|
|
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
|
|
}
|
|
|
|
+ (NSString *)sharedDataDatabaseFilePath_SHM
|
|
{
|
|
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
|
|
}
|
|
|
|
+ (NSString *)sharedDataDatabaseFilePath_WAL
|
|
{
|
|
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
|
|
}
|
|
|
|
+ (void)migrateToSharedData
|
|
{
|
|
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath
|
|
sharedDataFilePath:self.sharedDataDatabaseFilePath
|
|
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
|
|
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_SHM
|
|
sharedDataFilePath:self.sharedDataDatabaseFilePath_SHM
|
|
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
|
|
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_WAL
|
|
sharedDataFilePath:self.sharedDataDatabaseFilePath_WAL
|
|
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
|
|
}
|
|
|
|
+ (NSString *)databaseFilePath
|
|
{
|
|
DDLogVerbose(@"databasePath: %@", TSStorageManager.sharedDataDatabaseFilePath);
|
|
|
|
return self.sharedDataDatabaseFilePath;
|
|
}
|
|
|
|
- (NSString *)databaseFilePath
|
|
{
|
|
return TSStorageManager.databaseFilePath;
|
|
}
|
|
|
|
+ (YapDatabaseConnection *)dbReadConnection
|
|
{
|
|
return TSStorageManager.sharedManager.dbReadConnection;
|
|
}
|
|
|
|
+ (YapDatabaseConnection *)dbReadWriteConnection
|
|
{
|
|
return TSStorageManager.sharedManager.dbReadWriteConnection;
|
|
}
|
|
|
|
@end
|
|
|
|
NS_ASSUME_NONNULL_END
|