Improve the robustness of the migration logic.

pull/1/head
Matthew Chen 7 years ago
parent e8cbba61f9
commit d91507d897

@ -230,35 +230,64 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
- (BOOL)ensureIsReadyForAppExtensions - (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]) { if ([OWSPreferences isReadyForAppExtensions]) {
return YES; return YES;
} }
if ([NSFileManager.defaultManager fileExistsAtPath:TSStorageManager.legacyDatabaseFilePath]) { if ([NSFileManager.defaultManager fileExistsAtPath:TSStorageManager.legacyDatabaseFilePath]) {
DDLogInfo(@"%@ Database file size: %@", DDLogInfo(@"%@ Legacy Database file size: %@",
self.logTag, self.logTag,
[OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath]); [OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath]);
DDLogInfo(@"%@ \t SHM file size: %@", DDLogInfo(@"%@ \t Legacy SHM file size: %@",
self.logTag, self.logTag,
[OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath_SHM]); [OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath_SHM]);
DDLogInfo(@"%@ \t WAL file size: %@", DDLogInfo(@"%@ \t Legacy WAL file size: %@",
self.logTag, self.logTag,
[OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath_WAL]); [OWSFileSystem fileSizeOfPath:TSStorageManager.legacyDatabaseFilePath_WAL]);
} }
NSError *_Nullable error = [self convertDatabaseIfNecessary]; 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) { if (error) {
OWSFail(@"%@ database conversion failed: %@", self.logTag, error); OWSFail(@"%@ database conversion failed: %@", self.logTag, error);
[self showLaunchFailureUI:error]; [self showLaunchFailureUI:error];
return NO; return NO;
} }
[NSUserDefaults migrateToSharedUserDefaults];
[TSStorageManager migrateToSharedData];
[OWSProfileManager migrateToSharedData];
[TSAttachmentStream migrateToSharedData];
return YES; return YES;
} }
@ -304,6 +333,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
- (nullable NSError *)convertDatabaseIfNecessary - (nullable NSError *)convertDatabaseIfNecessary
{ {
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSString *databaseFilePath = [TSStorageManager legacyDatabaseFilePath]; NSString *databaseFilePath = [TSStorageManager legacyDatabaseFilePath];
if (![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]) { if (![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]) {
DDLogVerbose(@"%@ no legacy database file found", self.logTag); DDLogVerbose(@"%@ no legacy database file found", self.logTag);

@ -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> #import <SignalServiceKit/ProfileManagerProtocol.h>
@ -24,7 +24,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
- (void)resetProfileStorage; - (void)resetProfileStorage;
+ (void)migrateToSharedData; + (nullable NSError *)migrateToSharedData;
#pragma mark - Local Profile #pragma mark - Local Profile

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

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

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

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

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

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

@ -121,6 +121,13 @@ NS_ASSUME_NONNULL_BEGIN
// This macro is intended for use in Objective-C. // This macro is intended for use in Objective-C.
#define OWSAssertIsOnMainThread() OWSCAssert([NSThread isMainThread]) #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. // This function is intended for use in Swift.
void AssertIsOnMainThread(void); void AssertIsOnMainThread(void);

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

@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)cachesDirectoryPath; + (NSString *)cachesDirectoryPath;
+ (void)moveAppFilePath:(NSString *)oldFilePath + (nullable NSError *)moveAppFilePath:(NSString *)oldFilePath
sharedDataFilePath:(NSString *)newFilePath sharedDataFilePath:(NSString *)newFilePath
exceptionName:(NSString *)exceptionName; exceptionName:(NSString *)exceptionName;

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

Loading…
Cancel
Save