Do not cache session objects

Ensure that any uncommitted session mutation doesn't hang around.

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent 07b54039b2
commit 29e86901e7

@ -4,7 +4,8 @@
#import "TSStorageManager+SessionStore.h" #import "TSStorageManager+SessionStore.h"
#define TSStorageManagerSessionStoreCollection @"TSStorageManagerSessionStoreCollection" NSString *const TSStorageManagerSessionStoreCollection = @"TSStorageManagerSessionStoreCollection";
NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey";
void AssertIsOnSessionStoreQueue() void AssertIsOnSessionStoreQueue()
{ {
@ -17,19 +18,46 @@ void AssertIsOnSessionStoreQueue()
@implementation TSStorageManager (SessionStore) @implementation TSStorageManager (SessionStore)
/**
* Special purpose dbConnection which disables the object cache to better enforce transaction semantics on the store.
* Note that it's still technically possible to access this collection from a different collection,
* but that should be considered a bug.
*/
+ (YapDatabaseConnection *)sessionDBConnection
{
static dispatch_once_t onceToken;
static YapDatabaseConnection *sessionDBConnection;
dispatch_once(&onceToken, ^{
sessionDBConnection = [TSStorageManager sharedManager].newDatabaseConnection;
sessionDBConnection.objectCacheEnabled = NO;
#if DEBUG
sessionDBConnection.permittedTransactions = YDB_AnySyncTransaction;
#endif
});
return sessionDBConnection;
}
- (YapDatabaseConnection *)sessionDBConnection
{
return [[self class] sessionDBConnection];
}
#pragma mark - SessionStore #pragma mark - SessionStore
- (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId - (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId
{ {
AssertIsOnSessionStoreQueue(); AssertIsOnSessionStoreQueue();
NSDictionary *dictionary = __block NSDictionary *dictionary;
[self dictionaryForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
dictionary = [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
}];
SessionRecord *record; SessionRecord *record;
if (dictionary) { if (dictionary) {
record = [dictionary objectForKey:[self keyForInt:deviceId]]; record = [dictionary objectForKey:@(deviceId)];
} }
if (!record) { if (!record) {
@ -46,20 +74,12 @@ void AssertIsOnSessionStoreQueue()
OWSAssert(NO); OWSAssert(NO);
AssertIsOnSessionStoreQueue(); AssertIsOnSessionStoreQueue();
NSDictionary *dictionary = __block NSDictionary *dictionary;
[self objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
dictionary = [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
NSMutableArray *subDevicesSessions = [NSMutableArray array]; }];
if (dictionary) {
for (NSString *key in [dictionary allKeys]) {
NSNumber *number = @([key doubleValue]);
[subDevicesSessions addObject:number];
}
}
return subDevicesSessions; return dictionary ? dictionary.allKeys : @[];
} }
- (void)storeSession:(NSString *)contactIdentifier deviceId:(int)deviceId session:(SessionRecord *)session - (void)storeSession:(NSString *)contactIdentifier deviceId:(int)deviceId session:(SessionRecord *)session
@ -71,18 +91,27 @@ void AssertIsOnSessionStoreQueue()
// YapDB (initWithCoder:). However, because YapDB has an object cache, rather than fetching/deserializing, it's // YapDB (initWithCoder:). However, because YapDB has an object cache, rather than fetching/deserializing, it's
// possible we'd get back *this* exact instance of the object (which, at this point, is still potentially "fresh"), // possible we'd get back *this* exact instance of the object (which, at this point, is still potentially "fresh"),
// thus we explicitly mark this instance as "unfresh", any time we save. // thus we explicitly mark this instance as "unfresh", any time we save.
// NOTE: this may no longer be necessary now that we have a non-caching session db connection.
[session markAsUnFresh]; [session markAsUnFresh];
NSMutableDictionary *dictionary = __block NSDictionary *immutableDictionary;
[[self dictionaryForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection] mutableCopy]; [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
immutableDictionary =
[transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
}];
NSMutableDictionary *dictionary = [immutableDictionary mutableCopy];
if (!dictionary) { if (!dictionary) {
dictionary = [NSMutableDictionary dictionary]; dictionary = [NSMutableDictionary dictionary];
} }
[dictionary setObject:session forKey:[self keyForInt:deviceId]]; [dictionary setObject:session forKey:@(deviceId)];
[self setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; // TODO copy dictionary back to Immutable
[self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
}];
} }
- (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId - (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId
@ -97,16 +126,24 @@ void AssertIsOnSessionStoreQueue()
AssertIsOnSessionStoreQueue(); AssertIsOnSessionStoreQueue();
DDLogInfo( DDLogInfo(
@"[TSStorageManager (SessionStore)] deleting session for contact: %@ device: %d", contactIdentifier, deviceId); @"[TSStorageManager (SessionStore)] deleting session for contact: %@ device: %d", contactIdentifier, deviceId);
NSMutableDictionary *dictionary =
[[self dictionaryForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection] mutableCopy]; __block NSDictionary *immutableDictionary;
[self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
immutableDictionary =
[transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
}];
NSMutableDictionary *dictionary = [immutableDictionary mutableCopy];
if (!dictionary) { if (!dictionary) {
dictionary = [NSMutableDictionary dictionary]; dictionary = [NSMutableDictionary dictionary];
} }
[dictionary removeObjectForKey:[self keyForInt:deviceId]]; [dictionary removeObjectForKey:@(deviceId)];
[self setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; // TODO copy dictionary back to Immutable
[self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
}];
} }
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier - (void)deleteAllSessionsForContact:(NSString *)contactIdentifier
@ -114,13 +151,9 @@ void AssertIsOnSessionStoreQueue()
AssertIsOnSessionStoreQueue(); AssertIsOnSessionStoreQueue();
DDLogInfo(@"[TSStorageManager (SessionStore)] deleting all sessions for contact:%@", contactIdentifier); DDLogInfo(@"[TSStorageManager (SessionStore)] deleting all sessions for contact:%@", contactIdentifier);
[self removeObjectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; [self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
} [transaction removeObjectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
}];
#pragma mark - util
- (NSNumber *)keyForInt:(int)number {
return [NSNumber numberWithInt:number];
} }
#pragma mark - debug #pragma mark - debug
@ -130,7 +163,7 @@ void AssertIsOnSessionStoreQueue()
AssertIsOnSessionStoreQueue(); AssertIsOnSessionStoreQueue();
NSString *tag = @"[TSStorageManager (SessionStore)]"; NSString *tag = @"[TSStorageManager (SessionStore)]";
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
DDLogDebug(@"%@ All Sessions:", tag); DDLogDebug(@"%@ All Sessions:", tag);
[transaction [transaction
enumerateKeysAndObjectsInCollection:TSStorageManagerSessionStoreCollection enumerateKeysAndObjectsInCollection:TSStorageManagerSessionStoreCollection

Loading…
Cancel
Save