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.
session-ios/SignalServiceKit/src/Storage/TSStorageManager.m

247 lines
7.8 KiB
Matlab

//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
10 years ago
#import "TSStorageManager.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 "SignalRecipient.h"
10 years ago
#import "TSAttachmentStream.h"
#import "TSDatabaseSecondaryIndexes.h"
#import "TSDatabaseView.h"
#import "TSInteraction.h"
#import "TSThread.h"
#import <YapDatabase/YapDatabaseRelationship.h>
10 years ago
NS_ASSUME_NONNULL_BEGIN
NSString *const TSStorageManagerExceptionName_CouldNotMoveDatabaseFile
= @"TSStorageManagerExceptionName_CouldNotMoveDatabaseFile";
NSString *const TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory
= @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory";
#pragma mark -
@interface TSStorageManager ()
@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
@property (nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection;
@end
#pragma mark -
10 years ago
@implementation TSStorageManager
+ (instancetype)sharedManager {
static TSStorageManager *sharedManager = nil;
10 years ago
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[self alloc] initStorage];
10 years ago
#if TARGET_OS_IPHONE
[TSStorageManager protectFiles];
10 years ago
#endif
});
return sharedManager;
10 years ago
}
- (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)setupDatabaseWithSafeBlockingMigrations:(void (^_Nonnull)(void))safeBlockingMigrationsBlock
{
// Synchronously register extensions which are essential for views.
[TSDatabaseView registerCrossProcessNotifier];
[TSDatabaseView registerThreadInteractionsDatabaseView];
[TSDatabaseView registerThreadDatabaseView];
10 years ago
[TSDatabaseView registerUnreadDatabaseView];
[self registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];
[OWSMessageReceiver syncRegisterDatabaseExtension:self];
[OWSBatchMessageProcessor syncRegisterDatabaseExtension: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.
[self setDatabaseInitialized];
// Run the blocking migrations.
//
// These need to run _before_ the async registered database views or
// they will block on them, which (in the upgrade case) can block
// return of appDidFinishLaunching... which in term can cause the
// app to crash on launch.
safeBlockingMigrationsBlock();
// 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];
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView];
[TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView];
// Register extensions which aren't essential for rendering threads async.
[[OWSIncomingMessageFinder new] asyncRegisterExtension];
[TSDatabaseView asyncRegisterSecondaryDevicesDatabaseView];
[OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self];
OWSFailedMessagesJob *failedMessagesJob = [[OWSFailedMessagesJob alloc] initWithStorageManager:self];
[failedMessagesJob asyncRegisterDatabaseExtensions];
OWSFailedAttachmentDownloadsJob *failedAttachmentDownloadsMessagesJob =
[[OWSFailedAttachmentDownloadsJob alloc] initWithStorageManager:self];
[failedAttachmentDownloadsMessagesJob asyncRegisterDatabaseExtensions];
// NOTE: [TSDatabaseView asyncRegistrationCompletion] ensures that
// DatabaseViewRegistrationCompleteNotification is not fired until all
// of the async registrations are complete.
[TSDatabaseView asyncRegistrationCompletion];
10 years ago
}
+ (void)protectFiles
{
// The old database location was in the Document directory,
// so protect the database files individually.
8 years ago
[OWSFileSystem protectFolderAtPath:self.legacyDatabaseFilePath];
[OWSFileSystem protectFolderAtPath:self.legacyDatabaseFilePath_SHM];
[OWSFileSystem protectFolderAtPath:self.legacyDatabaseFilePath_WAL];
// Protect the entire new database directory.
8 years ago
[OWSFileSystem protectFolderAtPath:self.sharedDataDatabaseDirPath];
10 years ago
}
- (BOOL)userSetPassword {
return FALSE;
}
8 years ago
+ (NSString *)legacyDatabaseDirPath
{
return [OWSFileSystem appDocumentDirectoryPath];
10 years ago
}
8 years ago
+ (NSString *)sharedDataDatabaseDirPath
{
NSString *databaseDirPath = [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"];
10 years ago
if (![OWSFileSystem ensureDirectoryExists:databaseDirPath]) {
[NSException raise:TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory
format:@"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"];
}
8 years ago
+ (NSString *)legacyDatabaseFilePath
{
8 years ago
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
}
10 years ago
8 years ago
+ (NSString *)legacyDatabaseFilePath_SHM
{
8 years ago
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
}
8 years ago
+ (NSString *)legacyDatabaseFilePath_WAL
{
8 years ago
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
}
8 years ago
+ (NSString *)sharedDataDatabaseFilePath
{
8 years ago
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
}
8 years ago
+ (NSString *)sharedDataDatabaseFilePath_SHM
{
8 years ago
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
}
10 years ago
8 years ago
+ (NSString *)sharedDataDatabaseFilePath_WAL
{
8 years ago
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
}
10 years ago
+ (void)migrateToSharedData
{
8 years ago
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath
sharedDataFilePath:self.sharedDataDatabaseFilePath
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
8 years ago
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_SHM
sharedDataFilePath:self.sharedDataDatabaseFilePath_SHM
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
8 years ago
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_WAL
sharedDataFilePath:self.sharedDataDatabaseFilePath_WAL
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
}
- (NSString *)dbPath
{
8 years ago
DDLogVerbose(@"databasePath: %@", TSStorageManager.sharedDataDatabaseFilePath);
10 years ago
8 years ago
return TSStorageManager.sharedDataDatabaseFilePath;
10 years ago
}
+ (YapDatabaseConnection *)dbReadConnection
{
return TSStorageManager.dbReadConnection;
10 years ago
}
+ (YapDatabaseConnection *)dbReadWriteConnection
{
return TSStorageManager.dbReadWriteConnection;
}
- (void)deleteDatabaseFile
{
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:[self dbPath] error:&error];
10 years ago
if (error) {
DDLogError(@"Failed to delete database: %@", error.description);
}
}
10 years ago
@end
NS_ASSUME_NONNULL_END