Skip to content

Commit

Permalink
Merge pull request #341 from Simperium/develop
Browse files Browse the repository at this point in the history
Simperium Mk 0.6.8
  • Loading branch information
jleandroperez committed Aug 27, 2014
2 parents 2ad6ba5 + 833279e commit 7f2b0e4
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Simperium.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Simperium"
s.version = "0.6.6"
s.version = "0.6.8"
s.summary = "Simperium libraries."
s.description = "Simperium is a simple way for developers to move data as it changes, instantly and automatically."
s.homepage = "https://github.com/Simperium/simperium-ios"
Expand Down
6 changes: 3 additions & 3 deletions Simperium/DiffMatchPatch+Simperium.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ - (NSArray *)patch_apply:(NSArray *)sourcePatches toString:(NSString *)text erro
}

if (!success && error) {
*error = [NSError errorWithDomain:NSStringFromClass([self class])
code:DiffMatchPatchApplyError
description:@"Error while applying patch"];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class])
code:DiffMatchPatchApplyError
description:@"Error while applying patch"];
}

return patched;
Expand Down
2 changes: 1 addition & 1 deletion Simperium/NSError+Simperium.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@

@interface NSError ()

+ (NSError*)errorWithDomain:(NSString*)errorDomain code:(NSInteger)errorCode description:(NSString*)description;
+ (NSError*)sp_errorWithDomain:(NSString*)errorDomain code:(NSInteger)errorCode description:(NSString*)description;

@end
2 changes: 1 addition & 1 deletion Simperium/NSError+Simperium.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@implementation NSError (Simperium)

+ (NSError*)errorWithDomain:(NSString*)errorDomain code:(NSInteger)errorCode description:(NSString*)description
+ (NSError*)sp_errorWithDomain:(NSString*)errorDomain code:(NSInteger)errorCode description:(NSString*)description
{
if (!description) {
return [NSError errorWithDomain:errorDomain code:errorCode userInfo:nil];
Expand Down
1 change: 0 additions & 1 deletion Simperium/NSMutableDictionary+Simperium.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,4 @@ - (void)associateSimperiumKey:(NSString *)key {
objc_setAssociatedObject(self, SimperiumKey, key, OBJC_ASSOCIATION_COPY);
}


@end
5 changes: 0 additions & 5 deletions Simperium/SPBucket.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ - (instancetype)initWithSchema:(SPSchema *)aSchema storage:(id<SPStorageProvider
[nc addObserver:self selector:@selector(objectsAcknowledged:) name:ProcessorDidAcknowledgeObjectsNotification object:self];
[nc addObserver:self selector:@selector(objectsWillChange:) name:ProcessorWillChangeObjectsNotification object:self];
[nc addObserver:self selector:@selector(acknowledgedObjectDeletion:) name:ProcessorDidAcknowledgeDeleteNotification object:self];
[nc addObserver:self selector:@selector(requestLatestVersions) name:ProcessorRequestsReindexingNotification object:self];
}

return self;
Expand Down Expand Up @@ -242,10 +241,6 @@ - (void)acknowledgedObjectDeletion:(NSNotification *)notification {
}
}

- (void)requestLatestVersions {
[self.network requestLatestVersionsForBucket:self];
}

- (SPSchema *)schema {
return self.differ.schema;
}
Expand Down
5 changes: 3 additions & 2 deletions Simperium/SPChangeProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ typedef NS_ENUM(NSInteger, SPProcessorErrors) {
SPProcessorErrorsReceivedZombieChange, // No need to handle: The backend sent a change for a locally nuked entity
SPProcessorErrorsReceivedUnknownChange, // No need to handle: We've received a change for an unknown entity
SPProcessorErrorsReceivedInvalidChange, // Should Redownload the Entity: We couldn't apply a remote diff
SPProcessorErrorsServerError, // Should Retry: Catch-all server errors
SPProcessorErrorsClientError // Should Nuke PendingChange: Catch-all client errors
SPProcessorErrorsClientOutOfSync, // We received a change with an SV != local version: Reindex is required
SPProcessorErrorsClientError, // Should Nuke PendingChange: Catch-all client errors
SPProcessorErrorsServerError // Should Retry: Catch-all server errors
};


Expand Down
27 changes: 14 additions & 13 deletions Simperium/SPChangeProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ - (BOOL)processRemoteError:(NSDictionary *)change bucket:(SPBucket *)bucket erro

if (error) {
NSString *wrappedDescription = [NSString stringWithFormat:@"%@ : %d", description, (int)errorCode];
*error = [NSError errorWithDomain:NSStringFromClass([self class]) code:wrappedCode description:wrappedDescription];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:wrappedCode description:wrappedDescription];
}

return YES;
Expand Down Expand Up @@ -196,7 +196,6 @@ - (BOOL)processRemoteDeleteWithKey:(NSString*)simperiumKey bucket:(SPBucket *)bu
// - Split this method into processRemoteModify and processRemoteInsertion
// - This method should receive the coreData context + object, so we prevent double fetching
// - Once the above are implemented, move the 'begin/finish'SafeSection calls to the caller, and nuke duplicated code, PLEASE!
// - Nuke ProcessorRequestsReindexingNotification. That should be handled by the processRemoteChanges error handler block
//
- (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)bucket change:(NSDictionary *)change
acknowledged:(BOOL)acknowledged clientMatches:(BOOL)clientMatches error:(NSError **)error {
Expand All @@ -214,7 +213,7 @@ - (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)b
// It Must have been locally deleted before the confirmation got through!
if (clientMatches) {
if (error) {
*error = [NSError errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedZombieChange description:nil];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedZombieChange description:nil];
}
[storage finishSafeSection];
return NO;
Expand Down Expand Up @@ -257,7 +256,7 @@ - (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)b
if (!object.ghost) {
SPLogWarn(@"Simperium warning: received change for unknown entity (%@): %@", bucket.name, simperiumKey);
if (error) {
*error = [NSError errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedUnknownChange description:nil];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedUnknownChange description:nil];
}
[storage finishSafeSection];
return NO;
Expand All @@ -282,7 +281,7 @@ - (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)b
if (![bucket.differ applyGhostDiffFromDictionary:diff toObject:object error:&theError]) {
SPLogError(@"Simperium error during applyGhostDiff: %@", theError.localizedDescription);
if (error) {
*error = [NSError errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedInvalidChange description:theError.description];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedInvalidChange description:theError.description];
}
[storage finishSafeSection];
return NO;
Expand All @@ -307,7 +306,7 @@ - (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)b
if (theError) {
SPLogError(@"Simperium error during diff transform: %@", theError.localizedDescription);
if (error) {
*error = [NSError errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedInvalidChange description:theError.description];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedInvalidChange description:theError.description];
}
[storage finishSafeSection];
return NO;
Expand All @@ -331,14 +330,15 @@ - (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)b
if (![bucket.differ applyDiffFromDictionary:diff toObject:object error:&theError]) {
SPLogError(@"Simperium error during applyDiff: %@", theError.localizedDescription);
if (error) {
*error = [NSError errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedInvalidChange description:theError.description];
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsReceivedInvalidChange description:theError.description];
}
[storage finishSafeSection];
return NO;
}
}

[storage save];
[storage finishSafeSection];

dispatch_async(dispatch_get_main_queue(), ^{
NSMutableDictionary *userInfo = [@{
Expand All @@ -359,16 +359,17 @@ - (BOOL)processRemoteModifyWithKey:(NSString *)simperiumKey bucket:(SPBucket *)b
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:bucket userInfo:userInfo];
});

} else {
SPLogWarn(@"Simperium warning: couldn't apply change due to version mismatch (duplicate? start %@, old %@): change %@", startVersion, oldVersion, change);
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:ProcessorRequestsReindexingNotification object:bucket];
});
return YES;
}

SPLogWarn(@"Simperium warning: couldn't apply change due to version mismatch (duplicate? start %@, old %@): change %@", startVersion, oldVersion, change);
if (error) {
*error = [NSError sp_errorWithDomain:NSStringFromClass([self class]) code:SPProcessorErrorsClientOutOfSync description:nil];
}

[storage finishSafeSection];

return YES;
return NO;
}

- (BOOL)processRemoteChange:(NSDictionary *)change bucket:(SPBucket *)bucket error:(NSError **)error {
Expand Down
2 changes: 1 addition & 1 deletion Simperium/SPEnvironment.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#endif

// TODO: Update this automatically via a script that looks at current git tag
NSString* const SPLibraryVersion = @"0.6.7";
NSString* const SPLibraryVersion = @"0.6.8";

// SSL Certificate Expiration: '2016-09-07 02:36:04 +0000' expressed as seconds since 1970
NSTimeInterval const SPCertificateExpiration = 1473215764;
Expand Down
54 changes: 34 additions & 20 deletions Simperium/SPIndexProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ - (void)processVersions:(NSArray *)versions bucket:(SPBucket *)bucket changeHand
NSString *key = versionData[SPVersionKey];
NSString *version = versionData[SPVersionNumber];
NSDictionary *data = versionData[SPVersionData];
NSMutableDictionary *ghostData = nil;

// Process the Object's Member Data
id<SPDiffable> object = objects[key];
Expand All @@ -214,70 +215,83 @@ - (void)processVersions:(NSArray *)versions bucket:(SPBucket *)bucket changeHand
object.bucket = bucket; // set it manually since it won't be set automatically yet
[object loadMemberData:data];

ghostData = [[object dictionary] mutableCopy];

[addedKeys addObject:key];
SPLogVerbose(@"Simperium added object from index (%@): %@", bucket.name, object.simperiumKey);

// The object exists. Let's attempt to rebase local pending changes
} else {

// 1. Calculate Delta: LocalGhost > LocalMembers
SPGhost *localGhost = [object.ghost copy];
NSDictionary *localDiff = [bucket.differ diffFromDictionary:localGhost.memberData toObject:object];
// 1. Failsafe: Make sure that the object is in memory
[object willBeRead];

// 2. Calculate Delta: LocalGhost > LocalMembers
SPGhost *localGhost = [object.ghost copy];
NSDictionary *localDiff = [bucket.differ diffFromDictionary:localGhost.memberData toObject:object];

// 2. Load the full Remote Member Data
// 3. Load the full Remote Member Data
[object loadMemberData:data];
SPLogWarn(@"Simperium successfully reloaded local entity (%@): %@", bucket.name, key);
SPLogWarn(@"Simperium successfully reloaded local entity (%@): %@.%@", bucket.name, key, version);

// 3. Rebase + apply localDiff
// 4. Be sure to load all members into ghost (since the version results might only contain a subset of members that were changed)
ghostData = [[object dictionary] mutableCopy];

// 5. Rebase + apply localDiff
BOOL isRebaseDisabled = [self.keysForObjectsWithRebaseDisabled containsObject:key];

if (localDiff.count && !isRebaseDisabled) {

// 3.1. Calculate Delta: LocalGhost > RemoteMembers
// 5.1. Calculate Delta: LocalGhost > RemoteMembers
NSDictionary *remoteDiff = [bucket.differ diffFromDictionary:localGhost.memberData toObject:object];

// 3.2. Transform localDiff: LocalGhost >> RemoteMembers >> LocalDiff (equivalent to git rebase)
// 5.2. Transform localDiff: LocalGhost >> RemoteMembers >> LocalDiff (equivalent to git rebase)
NSError *error = nil;
NSDictionary *rebaseDiff = nil;

if (remoteDiff.count) {
// Note: if remoteDiff is empty, there is just no need to rebase!.
SPLogWarn(@"Simperium rebasing local changes for object (%@): %@.%@", bucket.name, key, version);
rebaseDiff = [bucket.differ transform:object diff:localDiff oldDiff:remoteDiff oldGhost:localGhost error:&error];
} else {
SPLogWarn(@"Simperium rebasing local changes for object (%@): %@.%@", bucket.name, key, version);
rebaseDiff = localDiff;
}

// 3.3. Attempt to apply the Local Transformed Diff
// 5.3. Attempt to apply the Local Transformed Diff
if (!error && rebaseDiff.count) {
[bucket.differ applyDiffFromDictionary:rebaseDiff toObject:object error:&error];
}

// 3.4. Some debugging
// 5.4. Some debugging
if (error) {
SPLogWarn(@"Simperium error: could not apply local transformed diff for entity (%@): %@", bucket.name, key);
SPLogWarn(@"Simperium error: could not apply local transformed diff for entity (%@): %@.%@", bucket.name, key, version);
} else {
SPLogWarn(@"Simperium successfully updated local entity (%@): %@", bucket.name, key);
SPLogWarn(@"Simperium successfully updated local entity (%@): %@.%@", bucket.name, key, version);
}

// 3.5. Signal the changeHandler that the object has untracked changes. Do this after saving the storage!
// 5.5. Signal the changeHandler that the object has untracked changes. Do this after saving the storage!
[rebasedKeys addObject:key];
}

// 4. Keep track of changed Keys
// 6. Keep track of changed Keys
[changedKeys addObject:key];

// 5. Cleanup
// 7. Cleanup
if (isRebaseDisabled) {
[self.keysForObjectsWithRebaseDisabled removeObject:key];
}
}

// 4. Update the ghost with the remote member data + version
SPGhost *ghost = [[SPGhost alloc] initWithKey:object.simperiumKey memberData:[data mutableCopy]];
ghost.version = version;
object.ghost = ghost;
// Update the ghost with the remote member data + version
SPGhost *ghost = [[SPGhost alloc] initWithKey:object.simperiumKey memberData:ghostData];
ghost.version = version;
object.ghost = ghost;

// Slight hack to ensure Core Data realizes the object has changed and needs a save
object.ghostData = [[object.ghost.dictionary sp_JSONString] copy];

SPLogVerbose(@"Simperium updating ghost data for object %@ (%@)", object.simperiumKey, bucket.name);
SPLogVerbose(@"Simperium updating ghost data for object %@.%@ (%@)", object.simperiumKey, version, bucket.name);
}

// Store after processing the batch for efficiency
Expand Down
1 change: 0 additions & 1 deletion Simperium/SPProcessorConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ extern NSString * const ProcessorDidDeleteObjectKeysNotification;
extern NSString * const ProcessorDidAcknowledgeObjectsNotification;
extern NSString * const ProcessorWillChangeObjectsNotification;
extern NSString * const ProcessorDidAcknowledgeDeleteNotification;
extern NSString * const ProcessorRequestsReindexingNotification;


#pragma mark ====================================================================================
Expand Down
1 change: 0 additions & 1 deletion Simperium/SPProcessorConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
NSString * const ProcessorDidAcknowledgeObjectsNotification = @"ProcessorDidAcknowledgeObjectsNotification";
NSString * const ProcessorWillChangeObjectsNotification = @"ProcessorWillChangeObjectsNotification";
NSString * const ProcessorDidAcknowledgeDeleteNotification = @"ProcessorDidAcknowledgeDeleteNotification";
NSString * const ProcessorRequestsReindexingNotification = @"ProcessorRequestsReindexingNotification";


#pragma mark ====================================================================================
Expand Down
10 changes: 8 additions & 2 deletions Simperium/SPWebSocketChannel.m
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,12 @@ - (void)processBatchChanges:(NSArray *)changes bucket:(SPBucket *)bucket {

SPLogError(@"Simperium Received Error [%@] for object with key [%@]", error.localizedDescription, simperiumKey);

if (error.code == SPProcessorErrorsSentDuplicateChange) {
if (error.code == SPProcessorErrorsClientOutOfSync) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf requestLatestVersionsForBucket:bucket];
});

} else if (error.code == SPProcessorErrorsSentDuplicateChange) {
[changeProcessor discardPendingChanges:simperiumKey bucket:bucket];

} else if (error.code == SPProcessorErrorsSentInvalidChange) {
Expand Down Expand Up @@ -603,7 +608,8 @@ - (void)processVersionsBatchForBucket:(SPBucket *)bucket {
}

[bucket.indexProcessor processVersions:batch bucket:bucket changeHandler:^(NSString *key) {
// Local version was different, so process it as a local change
// Local version was different, so nuke old changes, and recalculate the delta
[bucket.changeProcessor discardPendingChanges:key bucket:bucket];
[bucket.changeProcessor enqueueObjectForMoreChanges:key bucket:bucket];
}];

Expand Down

0 comments on commit 7f2b0e4

Please sign in to comment.