Improve the robustness of the migration logic.

This commit is contained in:
Matthew Chen 2018-02-20 17:37:14 -05:00
parent e8cbba61f9
commit d91507d897
12 changed files with 139 additions and 52 deletions

View File

@ -230,35 +230,64 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
- (BOOL)ensureIsReadyForAppExtensions
{
// Given how sensitive this migration is, we verbosely
// log the contents of all involved paths before and after.
//
// TODO: Remove this logging once we have high confidence
// in our migration logic.
NSArray<NSString *> *paths = @[
TSStorageManager.legacyDatabaseFilePath,
TSStorageManager.legacyDatabaseFilePath_SHM,
TSStorageManager.legacyDatabaseFilePath_WAL,
TSStorageManager.sharedDataDatabaseFilePath,
TSStorageManager.sharedDataDatabaseFilePath_SHM,
TSStorageManager.sharedDataDatabaseFilePath_WAL,
];
NSFileManager *fileManager = [NSFileManager defaultManager];
for (NSString *path in paths) {
if ([fileManager fileExistsAtPath:path]) {
DDLogInfo(@"%@ storage file: %@, %@", self.logTag, path, [OWSFileSystem fileSizeOfPath:path]);
}
}
if ([OWSPreferences isReadyForAppExtensions]) {
return YES;
}
if ([NSFileManager.defaultManager fileExistsAtPath:TSStorageManager.legacyDatabaseFilePath]) {
DDLogInfo(@"%@ Database file size: %@",
DDLogInfo(@"%@ Legacy Database file size: %@",
self.logTag,
[OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath]);
DDLogInfo(@"%@ \t SHM file size: %@",
DDLogInfo(@"%@ \t Legacy SHM file size: %@",
self.logTag,
[OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath_SHM]);
DDLogInfo(@"%@ \t WAL file size: %@",
DDLogInfo(@"%@ \t Legacy WAL file size: %@",
self.logTag,
[OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath_WAL]);
}
NSError *_Nullable error = [self convertDatabaseIfNecessary];
if (!error) {
[NSUserDefaults migrateToSharedUserDefaults];
}
if (!error) {
error = [TSStorageManager migrateToSharedData];
}
if (!error) {
error = [OWSProfileManager migrateToSharedData];
}
if (!error) {
error = [TSAttachmentStream migrateToSharedData];
}
if (error) {
OWSFail(@"%@ database conversion failed: %@", self.logTag, error);
[self showLaunchFailureUI:error];
return NO;
}
[NSUserDefaults migrateToSharedUserDefaults];
[TSStorageManager migrateToSharedData];
[OWSProfileManager migrateToSharedData];
[TSAttachmentStream migrateToSharedData];
return YES;
}
@ -304,6 +333,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
- (nullable NSError *)convertDatabaseIfNecessary
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSString *databaseFilePath = [TSStorageManager legacyDatabaseFilePath];
if (![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]) {
DDLogVerbose(@"%@ no legacy database file found", self.logTag);

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SignalServiceKit/ProfileManagerProtocol.h>
@ -24,7 +24,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
- (void)resetProfileStorage;
+ (void)migrateToSharedData;
+ (nullable NSError *)migrateToSharedData;
#pragma mark - Local Profile

View File

@ -1113,11 +1113,13 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"];
}
+ (void)migrateToSharedData
+ (nullable NSError *)migrateToSharedData
{
[OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath
sharedDataFilePath:self.sharedDataProfileAvatarsDirPath
exceptionName:@"ProfileManagerCouldNotMigrateProfileDirectory"];
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
return [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath
sharedDataFilePath:self.sharedDataProfileAvatarsDirPath
exceptionName:@"ProfileManagerCouldNotMigrateProfileDirectory"];
}
- (NSString *)profileAvatarsDirPath

View File

@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
- (CGFloat)audioDurationSeconds;
+ (void)migrateToSharedData;
+ (nullable NSError *)migrateToSharedData;
@end

View File

@ -194,11 +194,13 @@ NS_ASSUME_NONNULL_BEGIN
return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"Attachments"];
}
+ (void)migrateToSharedData
+ (nullable NSError *)migrateToSharedData
{
[OWSFileSystem moveAppFilePath:self.legacyAttachmentsDirPath
sharedDataFilePath:self.sharedDataAttachmentsDirPath
exceptionName:@"CouldNotMigrateAttachmentsDirectory"];
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
return [OWSFileSystem moveAppFilePath:self.legacyAttachmentsDirPath
sharedDataFilePath:self.sharedDataAttachmentsDirPath
exceptionName:@"CouldNotMigrateAttachmentsDirectory"];
}
+ (NSString *)attachmentsFolder

View File

@ -21,13 +21,16 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage);
+ (YapDatabaseConnection *)dbReadConnection;
+ (YapDatabaseConnection *)dbReadWriteConnection;
+ (void)migrateToSharedData;
+ (nullable NSError *)migrateToSharedData;
+ (NSString *)databaseFilePath;
+ (NSString *)legacyDatabaseFilePath;
+ (NSString *)legacyDatabaseFilePath_SHM;
+ (NSString *)legacyDatabaseFilePath_WAL;
+ (NSString *)sharedDataDatabaseFilePath;
+ (NSString *)sharedDataDatabaseFilePath_SHM;
+ (NSString *)sharedDataDatabaseFilePath_WAL;
@end

View File

@ -220,8 +220,10 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage)
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
}
+ (void)migrateToSharedData
+ (nullable NSError *)migrateToSharedData
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
// Given how sensitive this migration is, we verbosely
// log the contents of all involved paths before and after.
NSArray<NSString *> *paths = @[
@ -235,7 +237,7 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage)
NSFileManager *fileManager = [NSFileManager defaultManager];
for (NSString *path in paths) {
if ([fileManager fileExistsAtPath:path]) {
DDLogInfo(@"%@ migrateToSharedData before %@: %@", self.logTag, path, [OWSFileSystem fileSizeOfPath:path]);
DDLogInfo(@"%@ before migrateToSharedData: %@, %@", self.logTag, path, [OWSFileSystem fileSizeOfPath:path]);
}
}
@ -252,21 +254,33 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage)
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_SHM];
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_WAL];
[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];
NSError *_Nullable error = nil;
error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath
sharedDataFilePath:self.sharedDataDatabaseFilePath
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
if (error) {
return error;
}
error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_SHM
sharedDataFilePath:self.sharedDataDatabaseFilePath_SHM
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
if (error) {
return error;
}
error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_WAL
sharedDataFilePath:self.sharedDataDatabaseFilePath_WAL
exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile];
if (error) {
return error;
}
for (NSString *path in paths) {
if ([fileManager fileExistsAtPath:path]) {
DDLogInfo(@"%@ migrateToSharedData after %@: %@", self.logTag, path, [OWSFileSystem fileSizeOfPath:path]);
DDLogInfo(@"%@ after migrateToSharedData: %@, %@", self.logTag, path, [OWSFileSystem fileSizeOfPath:path]);
}
}
return nil;
}
+ (NSString *)databaseFilePath

View File

@ -2,8 +2,8 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "AppContext.h"
#import "NSUserDefaults+OWS.h"
#import "AppContext.h"
#import "TSConstants.h"
NS_ASSUME_NONNULL_BEGIN
@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)migrateToSharedUserDefaults
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSUserDefaults *appUserDefaults = self.appUserDefaults;
NSDictionary<NSString *, id> *dictionary = [NSUserDefaults standardUserDefaults].dictionaryRepresentation;

View File

@ -121,6 +121,13 @@ NS_ASSUME_NONNULL_BEGIN
// This macro is intended for use in Objective-C.
#define OWSAssertIsOnMainThread() OWSCAssert([NSThread isMainThread])
#define OWSProdLogAndFail(_messageFormat, ...) \
{ \
DDLogError(_messageFormat, ##__VA_ARGS__); \
[DDLog flushLog]; \
OWSFail(_messageFormat, ##__VA_ARGS__); \
}
// This function is intended for use in Swift.
void AssertIsOnMainThread(void);

View File

@ -27,7 +27,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeContactsUpdaterRateLimit = 777408,
OWSErrorCodeCouldNotWriteAttachmentData = 777409,
OWSErrorCodeMessageDeletedBeforeSent = 777410,
OWSErrorCodeDatabaseConversionFatalError = 777411
OWSErrorCodeDatabaseConversionFatalError = 777411,
OWSErrorCodeMoveFileToSharedDataContainerError = 777412
};
extern NSString *const OWSErrorRecipientIdentifierKey;

View File

@ -17,9 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)cachesDirectoryPath;
+ (void)moveAppFilePath:(NSString *)oldFilePath
sharedDataFilePath:(NSString *)newFilePath
exceptionName:(NSString *)exceptionName;
+ (nullable NSError *)moveAppFilePath:(NSString *)oldFilePath
sharedDataFilePath:(NSString *)newFilePath
exceptionName:(NSString *)exceptionName;
// Returns NO IFF the directory does not exist and could not be created.
+ (BOOL)ensureDirectoryExists:(NSString *)dirPath;

View File

@ -3,6 +3,7 @@
//
#import "OWSFileSystem.h"
#import "OWSError.h"
#import "TSConstants.h"
NS_ASSUME_NONNULL_BEGIN
@ -107,23 +108,47 @@ NS_ASSUME_NONNULL_BEGIN
return paths[0];
}
+ (void)moveAppFilePath:(NSString *)oldFilePath
sharedDataFilePath:(NSString *)newFilePath
exceptionName:(NSString *)exceptionName
+ (nullable NSError *)moveAppFilePath:(NSString *)oldFilePath
sharedDataFilePath:(NSString *)newFilePath
exceptionName:(NSString *)exceptionName
{
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:oldFilePath]) {
return;
return nil;
}
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.",
// If a file/directory already exists at the destination,
// try to move it "aside" by renaming it with an extension.
NSString *legacyFilePath =
[[newFilePath stringByAppendingString:@"."] stringByAppendingString:[NSUUID UUID].UUIDString];
DDLogInfo(@"%@ Trying to rename pre-existing destination file or directory from: %@ to: %@",
self.logTag,
newFilePath,
legacyFilePath);
NSError *_Nullable error;
BOOL success = [fileManager moveItemAtPath:newFilePath toPath:legacyFilePath error:&error];
if (!success || error) {
OWSProdLogAndFail(
@"%@ Could not move pre-existing destination file or directory from: %@ to: %@, error: %@",
self.logTag,
newFilePath,
legacyFilePath,
error);
return error;
}
}
if ([fileManager fileExistsAtPath:newFilePath]) {
OWSProdLogAndFail(@"%@ Can't move file or directory from: %@ to: %@; destination already exists.",
self.logTag,
oldFilePath,
newFilePath);
return;
return OWSErrorWithCodeDescription(
OWSErrorCodeMoveFileToSharedDataContainerError, @"Can't move file; destination already exists.");
}
NSDate *startDate = [NSDate new];
@ -131,14 +156,12 @@ NS_ASSUME_NONNULL_BEGIN
NSError *_Nullable error;
BOOL success = [fileManager moveItemAtPath:oldFilePath toPath:newFilePath error:&error];
if (!success || error) {
NSString *errorDescription =
[NSString stringWithFormat:@"%@ Could not move file or directory from: %@ to: %@, error: %@",
self.logTag,
oldFilePath,
newFilePath,
error];
OWSFail(@"%@", errorDescription);
OWSRaiseException(exceptionName, @"%@", errorDescription);
OWSProdLogAndFail(@"%@ Could not move file or directory from: %@ to: %@, error: %@",
self.logTag,
oldFilePath,
newFilePath,
error);
return error;
}
DDLogInfo(@"%@ Moved file or directory from: %@ to: %@ in: %f",
@ -153,6 +176,8 @@ NS_ASSUME_NONNULL_BEGIN
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self protectRecursiveContentsAtPath:newFilePath];
});
return nil;
}
+ (BOOL)ensureDirectoryExists:(NSString *)dirPath