Skip to content

Commit

Permalink
Merge pull request #535 from matrix-org/MXFileStore_async_state
Browse files Browse the repository at this point in the history
Implement the lazy loading of rooms states from MXFileStore
  • Loading branch information
manuroe committed Jul 24, 2018
2 parents e775201 + 89e7626 commit 781e64f
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 56 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Improvements:
* MXRoomSummary: Add a membership property to cache MXRoomState one.
* MXRoomSummary: add isConferenceUserRoom.
* MXStore: Add Obj-C annotations.
* MXFileStore: Add a setting to set which data to preload ([MXFileStore setPreloadOptions:]).

Bug fix:

Expand All @@ -18,6 +19,7 @@ API break:
* MXCall: callee access is now asynchronous.
* MXRoomState: Remove displayName property. Use MXRoomSummary.displayName instead.
* MXRoomState: Create a MXRoomMembers property. All members getter methods has been to the new class.
* MXStore: Make the stateOfRoom method asynchronous.

Changes in Matrix iOS SDK in 0.10.12 (2018-05-31)
===============================================
Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/Data/MXRoom.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ FOUNDATION_EXPORT NSString *const kMXRoomDidFlushDataNotification;
@param store the store to mount data from and to store live data to.
@param roomId the id of the room.
@param mxSession the session to use.
@param matrixSession the session to use.
@return the new instance.
*/
+ (id)loadRoomFromStore:(id<MXStore>)store withRoomId:(NSString *)roomId matrixSession:(MXSession *)matrixSession;
Expand Down
20 changes: 4 additions & 16 deletions MatrixSDK/Data/MXRoom.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ The list of room operations (sending of text, images...) that must be sent
FIFO queue of objects waiting for [self liveTimeline:].
*/
NSMutableArray<void (^)(MXEventTimeline *)> *pendingLiveTimelineRequesters;

// @TODO(async-state): For dev
BOOL __forceAsyncLoad;
}
@end

Expand All @@ -80,7 +77,6 @@ - (instancetype)init
_directUserId = nil;

needToLoadLiveTimeline = NO;
__forceAsyncLoad = YES;
}

return self;
Expand Down Expand Up @@ -180,26 +176,18 @@ - (MXRoomSummary *)summary
- (void)liveTimeline:(void (^)(MXEventTimeline *))onComplete
{
// Is timelime ready?
if (needToLoadLiveTimeline || pendingLiveTimelineRequesters || __forceAsyncLoad)
if (needToLoadLiveTimeline || pendingLiveTimelineRequesters)
{
__forceAsyncLoad = NO;
BOOL __needToLoadLiveTimeline = needToLoadLiveTimeline;

// Queue the requester
if (!pendingLiveTimelineRequesters)
{
pendingLiveTimelineRequesters = [NSMutableArray array];

MXWeakify(self);
// @TODO(async-state): dispatch_async is just for testing that the async access works
dispatch_async(dispatch_get_main_queue(), ^{
[MXRoomState loadRoomStateFromStore:self.mxSession.store withRoomId:self.roomId matrixSession:self.mxSession onComplete:^(MXRoomState *roomState) {
MXStrongifyAndReturnIfNil(self);

if (__needToLoadLiveTimeline)
{
MXRoomState *roomState = [MXRoomState loadRoomStateFromStore:self.mxSession.store withRoomId:self.roomId matrixSession:self.mxSession];
[self->liveTimeline setState:roomState];
}
[self->liveTimeline setState:roomState];

// Provide the timelime to pending requesters
NSArray<void (^)(MXEventTimeline *)> *liveTimelineRequesters = [self->pendingLiveTimelineRequesters copy];
Expand All @@ -210,7 +198,7 @@ - (void)liveTimeline:(void (^)(MXEventTimeline *))onComplete
onRequesterComplete(self->liveTimeline);
}
NSLog(@"[MXRoom] liveTimeline loaded. Pending requesters: %@", @(liveTimelineRequesters.count));
});
}];
}

[pendingLiveTimelineRequesters addObject:onComplete];
Expand Down
7 changes: 4 additions & 3 deletions MatrixSDK/Data/MXRoomState.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,12 @@ Use MXRoomSummary.displayname to get a computed room display name.
@param store the store to mount data from and to store live data to.
@param roomId the id of the room.
@param matrixSession the session to use.
@return the new instance.
@param onComplete the block providing the new instance.
*/
+ (id)loadRoomStateFromStore:(id<MXStore>)store
+ (void)loadRoomStateFromStore:(id<MXStore>)store
withRoomId:(NSString *)roomId
matrixSession:(MXSession *)matrixSession;
matrixSession:(MXSession *)matrixSession
onComplete:(void (^)(MXRoomState *roomState))onComplete;

/**
Create a `MXRoomState` instance used as a back state of a room.
Expand Down
18 changes: 11 additions & 7 deletions MatrixSDK/Data/MXRoomState.m
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,20 @@ - (id)initWithRoomId:(NSString*)roomId
return self;
}

+ (id)loadRoomStateFromStore:(id<MXStore>)store withRoomId:(NSString *)roomId matrixSession:(MXSession *)matrixSession
+ (void)loadRoomStateFromStore:(id<MXStore>)store
withRoomId:(NSString *)roomId
matrixSession:(MXSession *)matrixSession
onComplete:(void (^)(MXRoomState *roomState))onComplete
{
MXRoomState *state = [[MXRoomState alloc] initWithRoomId:roomId andMatrixSession:matrixSession andDirection:YES];
if (state)
MXRoomState *roomState = [[MXRoomState alloc] initWithRoomId:roomId andMatrixSession:matrixSession andDirection:YES];
if (roomState)
{
NSArray *stateEvents = [store stateOfRoom:roomId];
[state handleStateEvents:stateEvents];
}
[store stateOfRoom:roomId success:^(NSArray<MXEvent *> * _Nonnull stateEvents) {
[roomState handleStateEvents:stateEvents];

return state;
onComplete(roomState);
} failure:nil];
}
}

- (id)initBackStateWith:(MXRoomState*)state
Expand Down
35 changes: 25 additions & 10 deletions MatrixSDK/Data/Store/MXFileStore/MXFileStore.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
Copyright 2014 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -19,6 +20,21 @@

NS_ASSUME_NONNULL_BEGIN

/**
Options for preloading data during the `[MXStore openWithCredentials:]` operation.
*/
typedef NS_OPTIONS(NSInteger, MXFileStorePreloadOptions)
{
// Preload rooms summaries
MXFileStorePreloadOptionRoomSummary = 0x1,

// Preload rooms states
MXFileStorePreloadOptionRoomState = 0x2,

// Preload rooms account data
MXFileStorePreloadOptionRoomAccountData = 0x4
};

/**
`MXFileStore` extends MXMemoryStore by adding permanent storage.
Expand Down Expand Up @@ -86,6 +102,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)diskUsageWithBlock:(void(^)(NSUInteger diskUsage))block;

/**
Set the preload options for the file store.
These options are used in the `[MXStore openWithCredentials:]`.
@param preloadOptions bit flags of `MXFileStorePreloadOptions`.
*/
+ (void)setPreloadOptions:(MXFileStorePreloadOptions)preloadOptions;

#pragma mark - Async API

/**
Expand Down Expand Up @@ -126,16 +151,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)asyncRoomsSummaries:(void (^)(NSArray<MXRoomSummary *> *roomsSummaries))success
failure:(nullable void (^)(NSError *error))failure;

/**
Get the stored room state for a specific room.
@param roomId the Id of the room
@param success A block object called when the operation succeeds.
@param failure A block object called when the operation fails.
*/
- (void)asyncStateEventsOfRoom:(NSString *)roomId
success:(void (^)(NSArray<MXEvent *> * _Nonnull stateEvents))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;

/**
Get the stored account data for a specific room.
Expand Down
57 changes: 42 additions & 15 deletions MatrixSDK/Data/Store/MXFileStore/MXFileStore.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
Copyright 2014 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -41,6 +42,8 @@
static NSString *const kMXFileStoreRoomAccountDataFile = @"accountData";
static NSString *const kMXFileStoreRoomReadReceiptsFile = @"readReceipts";

static NSUInteger preloadOptions;

@interface MXFileStore ()
{
// Meta data about the store. It is defined only if the passed MXCredentials contains all information.
Expand Down Expand Up @@ -112,6 +115,16 @@ @interface MXFileStore ()

@implementation MXFileStore

+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{

// By default, we do not need to preload rooms states now
preloadOptions = MXFileStorePreloadOptionRoomSummary | MXFileStorePreloadOptionRoomAccountData;
});
}

- (instancetype)init;
{
self = [super init];
Expand Down Expand Up @@ -211,9 +224,18 @@ - (void)openWithCredentials:(MXCredentials*)someCredentials onComplete:(void (^)
NSLog(@"[MXFileStore] Start data loading from files");

[self loadRoomsMessages];
[self preloadRoomsStates];
[self preloadRoomsSummaries];
[self preloadRoomsAccountData];
if (preloadOptions & MXFileStorePreloadOptionRoomState)
{
[self preloadRoomsStates];
}
if (preloadOptions & MXFileStorePreloadOptionRoomSummary)
{
[self preloadRoomsSummaries];
}
if (preloadOptions & MXFileStorePreloadOptionRoomAccountData)
{
[self preloadRoomsAccountData];
}
[self loadReceipts];
[self loadUsers];
[self loadGroups];
Expand Down Expand Up @@ -276,6 +298,11 @@ - (void)diskUsageWithBlock:(void (^)(NSUInteger))block
}


+ (void)setPreloadOptions:(MXFileStorePreloadOptions)thePreloadOptions
{
preloadOptions = thePreloadOptions;
}

#pragma mark - MXStore
- (void)storeEventForRoom:(NSString*)roomId event:(MXEvent*)event direction:(MXTimelineDirection)direction
{
Expand Down Expand Up @@ -401,6 +428,18 @@ - (void)storeStateForRoom:(NSString*)roomId stateEvents:(NSArray*)stateEvents
roomsToCommitForState[roomId] = stateEvents;
}

- (void)stateOfRoom:(NSString *)roomId success:(void (^)(NSArray<MXEvent *> * _Nonnull))success failure:(void (^)(NSError * _Nonnull))failure
{
dispatch_async(dispatchQueue, ^{

NSArray<MXEvent *> *stateEvents = [self stateOfRoom:roomId];

dispatch_async(dispatch_get_main_queue(), ^{
success(stateEvents);
});
});
}

- (NSArray*)stateOfRoom:(NSString *)roomId
{
// First, try to get the state from the cache
Expand Down Expand Up @@ -1752,18 +1791,6 @@ - (void)asyncRoomsSummaries:(void (^)(NSArray<MXRoomSummary *> * _Nonnull))succe
});
}

- (void)asyncStateEventsOfRoom:(NSString *)roomId success:(void (^)(NSArray<MXEvent *> * _Nonnull))success failure:(nullable void (^)(NSError * _Nonnull))failure
{
dispatch_async(dispatchQueue, ^{

NSArray<MXEvent *> *stateEvents = [self stateOfRoom:roomId];

dispatch_async(dispatch_get_main_queue(), ^{
success(stateEvents);
});
});
}

- (void)asyncAccountDataOfRoom:(NSString *)roomId success:(void (^)(MXRoomAccountData * _Nonnull))success failure:(nullable void (^)(NSError * _Nonnull))failure
{
dispatch_async(dispatchQueue, ^{
Expand Down
8 changes: 5 additions & 3 deletions MatrixSDK/Data/Store/MXStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,12 @@
Note: this method is required in permanent storage implementation.
@param roomId the id of the room.
@return the stored state events that define the room state.
@param success A block object called when the operation succeeds.
@param failure A block object called when the operation fails.
*/
- (NSArray<MXEvent*> * _Nullable)stateOfRoom:(nonnull NSString*)roomId;
- (void)stateOfRoom:(nonnull NSString *)roomId
success:(nonnull void (^)(NSArray<MXEvent *> * _Nonnull stateEvents))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;


#pragma mark - Room summary
Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/MXSession.m
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ -(void)setStore:(id<MXStore>)store success:(void (^)(void))onStoreDataReady fail
// A permanent MXStore must implement these methods:
NSParameterAssert([_store respondsToSelector:@selector(rooms)]);
NSParameterAssert([_store respondsToSelector:@selector(storeStateForRoom:stateEvents:)]);
NSParameterAssert([_store respondsToSelector:@selector(stateOfRoom:)]);
NSParameterAssert([_store respondsToSelector:@selector(stateOfRoom:success:failure:)]);
NSParameterAssert([_store respondsToSelector:@selector(summaryOfRoom:)]);
}

Expand Down

0 comments on commit 781e64f

Please sign in to comment.