Improve the robustness of the migration logic.
This commit is contained in:
parent
e8cbba61f9
commit
d91507d897
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (CGFloat)audioDurationSeconds;
|
||||
|
||||
+ (void)migrateToSharedData;
|
||||
+ (nullable NSError *)migrateToSharedData;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue