From b4546730cbf36871c89cf90776a603ce9fd2991f Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 12 Aug 2016 15:39:35 +0200 Subject: [PATCH] MXFileStore: Be more robust on commit interruption: Introduce the commit backup https://github.com/vector-im/vector-ios/issues/376 --- .../Data/Store/MXFileStore/MXFileStore.h | 12 +++- .../Data/Store/MXFileStore/MXFileStore.m | 68 +++++++++++-------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.h b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.h index b8f6093662..5d8bcb59df 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.h +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.h @@ -27,17 +27,25 @@ + MXFileStore + Matrix user id (one folder per account) + rooms - + roomId1 + + {roomId1} L messages: The room messages L state: The room state events L accountData: The account data for this room L receipts: The read receipts for this room - + roomId2 + + {roomId2} L messages L state L accountData L receipts + ... + + roomsBackup: This folder contains backup of room files that are modified + during the commit process. It is flushed when the commit completes. + This allows to rollback to previous data if the commit process was + interrupted. + + {syncToken} : the token that corresponds to the backup data + + {roomIdA} + + {roomIdB} + + ... L MXFileStore : Information about the stored data */ @interface MXFileStore : MXMemoryStore diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 2a1df9e693..8558817263 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -28,6 +28,7 @@ NSString *const kMXFileStoreSavingMarker = @"savingMarker"; NSString *const kMXFileStoreRoomsFolder = @"rooms"; +NSString *const kMXFileStoreRoomsBackupFolder = @"roomsBackup"; NSString *const kMXFileStoreRoomMessagesFile = @"messages"; NSString *const kMXFileStoreRoomStateFile = @"state"; NSString *const kMXFileStoreRoomAccountDataFile = @"accountData"; @@ -57,6 +58,9 @@ @interface MXFileStore () // The path of the rooms folder NSString *storeRoomsPath; + // The path of the rooms backup folder + NSString *storeRoomsBackupPath; + // Flag to indicate metaData needs to be store BOOL metaDataHasChanged; @@ -107,6 +111,7 @@ - (void)openWithCredentials:(MXCredentials*)someCredentials onComplete:(void (^) storePath = [[cachePath stringByAppendingPathComponent:kMXFileStoreFolder] stringByAppendingPathComponent:credentials.userId]; savingMarkerFile = [storePath stringByAppendingPathComponent:kMXFileStoreSavingMarker]; storeRoomsPath = [storePath stringByAppendingPathComponent:kMXFileStoreRoomsFolder]; + storeRoomsBackupPath = [storePath stringByAppendingPathComponent:kMXFileStoreRoomsBackupFolder]; /* Mount data corresponding to the account credentials. @@ -233,10 +238,10 @@ - (void)deleteAllMessagesInRoom:(NSString *)roomId NSError *error; // Remove room messages and read receipts from file system. Keep room state - [[NSFileManager defaultManager] removeItemAtPath:[self messagesFileForRoom:roomId] error:&error]; + [[NSFileManager defaultManager] removeItemAtPath:[self messagesFileForRoom:roomId forBackup:NO] error:&error]; // Remove Read receipts - [[NSFileManager defaultManager] removeItemAtPath:[self readReceiptsFileForRoom:roomId] error:&error]; + [[NSFileManager defaultManager] removeItemAtPath:[self readReceiptsFileForRoom:roomId forBackup:NO] error:&error]; if (NSNotFound == [roomsToCommitForMessages indexOfObject:roomId]) { @@ -248,10 +253,8 @@ - (void)deleteRoom:(NSString *)roomId { [super deleteRoom:roomId]; - NSError *error; - // Remove the room folder from file system - [[NSFileManager defaultManager] removeItemAtPath:[self folderForRoom:roomId] error:&error]; + [[NSFileManager defaultManager] removeItemAtPath:[self folderForRoom:roomId forBackup:NO] error:nil]; } - (void)deleteAllData @@ -356,7 +359,7 @@ - (NSArray*)stateOfRoom:(NSString *)roomId if (!stateEvents) { - stateEvents =[NSKeyedUnarchiver unarchiveObjectWithFile:[self stateFileForRoom:roomId]]; + stateEvents =[NSKeyedUnarchiver unarchiveObjectWithFile:[self stateFileForRoom:roomId forBackup:NO]]; if (NO == [NSThread isMainThread]) { @@ -386,7 +389,7 @@ - (MXRoomAccountData *)accountDataOfRoom:(NSString *)roomId if (!roomUserdData) { - roomUserdData =[NSKeyedUnarchiver unarchiveObjectWithFile:[self accountDataFileForRoom:roomId]]; + roomUserdData =[NSKeyedUnarchiver unarchiveObjectWithFile:[self accountDataFileForRoom:roomId forBackup:NO]]; if (NO == [NSThread isMainThread]) { @@ -497,38 +500,45 @@ - (MXMemoryRoomStore*)getOrCreateRoomStore:(NSString*)roomId #pragma mark - Private methods -- (NSString*)folderForRoom:(NSString*)roomId +- (NSString*)folderForRoom:(NSString*)roomId forBackup:(BOOL)backup { - return [storeRoomsPath stringByAppendingPathComponent:roomId]; + if (!backup) + { + return [storeRoomsPath stringByAppendingPathComponent:roomId]; + } + else + { + return [[storeRoomsBackupPath stringByAppendingPathComponent:self.eventStreamToken] stringByAppendingPathComponent:roomId]; + } } -- (void)checkFolderExistenceForRoom:(NSString*)roomId +- (void)checkFolderExistenceForRoom:(NSString*)roomId forBackup:(BOOL)backup { - NSString *roomFolder = [self folderForRoom:roomId]; + NSString *roomFolder = [self folderForRoom:roomId forBackup:backup]; if (![NSFileManager.defaultManager fileExistsAtPath:roomFolder]) { [[NSFileManager defaultManager] createDirectoryAtPath:roomFolder withIntermediateDirectories:YES attributes:nil error:nil]; } } -- (NSString*)messagesFileForRoom:(NSString*)roomId +- (NSString*)messagesFileForRoom:(NSString*)roomId forBackup:(BOOL)backup { - return [[storeRoomsPath stringByAppendingPathComponent:roomId] stringByAppendingPathComponent:kMXFileStoreRoomMessagesFile]; + return [[self folderForRoom:roomId forBackup:backup] stringByAppendingPathComponent:kMXFileStoreRoomMessagesFile]; } -- (NSString*)stateFileForRoom:(NSString*)roomId +- (NSString*)stateFileForRoom:(NSString*)roomId forBackup:(BOOL)backup { - return [[storeRoomsPath stringByAppendingPathComponent:roomId] stringByAppendingPathComponent:kMXFileStoreRoomStateFile]; + return [[self folderForRoom:roomId forBackup:backup] stringByAppendingPathComponent:kMXFileStoreRoomStateFile]; } -- (NSString*)accountDataFileForRoom:(NSString*)roomId +- (NSString*)accountDataFileForRoom:(NSString*)roomId forBackup:(BOOL)backup { - return [[storeRoomsPath stringByAppendingPathComponent:roomId] stringByAppendingPathComponent:kMXFileStoreRoomAccountDataFile]; + return [[self folderForRoom:roomId forBackup:backup] stringByAppendingPathComponent:kMXFileStoreRoomAccountDataFile]; } -- (NSString*)readReceiptsFileForRoom:(NSString*)roomId +- (NSString*)readReceiptsFileForRoom:(NSString*)roomId forBackup:(BOOL)backup { - return [[storeRoomsPath stringByAppendingPathComponent:roomId] stringByAppendingPathComponent:kMXFileStoreRoomReadReceiptsFile]; + return [[self folderForRoom:roomId forBackup:backup] stringByAppendingPathComponent:kMXFileStoreRoomReadReceiptsFile]; } @@ -558,7 +568,7 @@ - (void)loadRoomsMessages for (NSString *roomId in roomIDArray) { - NSString *roomFile = [self messagesFileForRoom:roomId]; + NSString *roomFile = [self messagesFileForRoom:roomId forBackup:NO]; MXFileRoomStore *roomStore; @try @@ -605,8 +615,8 @@ - (void)saveRoomsMessages MXFileRoomStore *roomStore = roomStores[roomId]; if (roomStore) { - [self checkFolderExistenceForRoom:roomId]; - [NSKeyedArchiver archiveRootObject:roomStore toFile:[self messagesFileForRoom:roomId]]; + [self checkFolderExistenceForRoom:roomId forBackup:NO]; + [NSKeyedArchiver archiveRootObject:roomStore toFile:[self messagesFileForRoom:roomId forBackup:NO]]; } } @@ -648,8 +658,8 @@ - (void)saveRoomsState { NSArray *stateEvents = roomsToCommit[roomId]; - [self checkFolderExistenceForRoom:roomId]; - [NSKeyedArchiver archiveRootObject:stateEvents toFile:[self stateFileForRoom:roomId]]; + [self checkFolderExistenceForRoom:roomId forBackup:NO]; + [NSKeyedArchiver archiveRootObject:stateEvents toFile:[self stateFileForRoom:roomId forBackup:NO]]; } }); } @@ -688,8 +698,8 @@ - (void)saveRoomsAccountData { MXRoomAccountData *roomAccountData = roomsToCommit[roomId]; - [self checkFolderExistenceForRoom:roomId]; - [NSKeyedArchiver archiveRootObject:roomAccountData toFile:[self accountDataFileForRoom:roomId]]; + [self checkFolderExistenceForRoom:roomId forBackup:NO]; + [NSKeyedArchiver archiveRootObject:roomAccountData toFile:[self accountDataFileForRoom:roomId forBackup:NO]]; } }); } @@ -821,7 +831,7 @@ - (void)loadReceipts { for (NSString *roomId in roomIDArray) { - NSString *roomFile = [self readReceiptsFileForRoom:roomId]; + NSString *roomFile = [self readReceiptsFileForRoom:roomId forBackup:NO]; NSMutableDictionary *receiptsDict = NULL; @try @@ -868,8 +878,8 @@ - (void)saveReceipts { @synchronized (receiptsByUserId) { - [self checkFolderExistenceForRoom:roomId]; - BOOL success = [NSKeyedArchiver archiveRootObject:receiptsByUserId toFile:[self readReceiptsFileForRoom:roomId]]; + [self checkFolderExistenceForRoom:roomId forBackup:NO]; + BOOL success = [NSKeyedArchiver archiveRootObject:receiptsByUserId toFile:[self readReceiptsFileForRoom:roomId forBackup:NO]]; if (!success) { NSLog(@"[MXFileStore] Error: Failed to store read receipts for room %@", roomId);