(fix) last fixes for cache coherency
parent
74085ed96b
commit
114622fee0
|
@ -112,10 +112,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
@implementation SOGoActiveSyncDispatcher (Sync)
|
@implementation SOGoActiveSyncDispatcher (Sync)
|
||||||
|
|
||||||
- (void) _setOrUnsetSyncInProgress: (BOOL) set
|
- (void) _setOrUnsetSyncRequest: (BOOL) set
|
||||||
invalidate: (BOOL) invalidate
|
collections: (NSArray *) collections
|
||||||
{
|
{
|
||||||
SOGoCacheGCSObject *o;
|
SOGoCacheGCSObject *o;
|
||||||
|
NSNumber *processIdentifier;
|
||||||
|
NSString *key;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
processIdentifier = [NSNumber numberWithInt: [[NSProcessInfo processInfo] processIdentifier]];
|
||||||
|
|
||||||
o = [SOGoCacheGCSObject objectWithName: [context objectForKey: @"DeviceId"] inContainer: nil useCache: NO];
|
o = [SOGoCacheGCSObject objectWithName: [context objectForKey: @"DeviceId"] inContainer: nil useCache: NO];
|
||||||
[o setObjectType: ActiveSyncGlobalCacheObject];
|
[o setObjectType: ActiveSyncGlobalCacheObject];
|
||||||
|
@ -123,14 +128,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
[o reloadIfNeeded];
|
[o reloadIfNeeded];
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
if (invalidate)
|
{
|
||||||
[[o properties] setObject: [NSCalendarDate date] forKey: @"InvalidateSyncInProgress"];
|
RELEASE(syncRequest);
|
||||||
else
|
syncRequest = [NSNumber numberWithUnsignedInt: [[NSCalendarDate date] timeIntervalSince1970]];
|
||||||
[[o properties] setObject: [NSCalendarDate date] forKey: @"SyncInProgress"];
|
RETAIN(syncRequest);
|
||||||
|
|
||||||
|
[[o properties] setObject: syncRequest forKey: @"SyncRequest"];
|
||||||
|
|
||||||
|
for (i = 0; i < [collections count]; i++)
|
||||||
|
{
|
||||||
|
key = [NSString stringWithFormat: @"SyncRequest+%@", [[[(id)[[collections objectAtIndex: i] getElementsByTagName: @"CollectionId"] lastObject] textValue] stringByUnescapingURL]];
|
||||||
|
[[o properties] setObject: processIdentifier forKey: key];
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[[o properties] removeObjectForKey: @"SyncInProgress"];
|
[[o properties] removeObjectForKey: @"SyncRequest"];
|
||||||
[[o properties] removeObjectForKey: @"InvalidateSyncInProgress"];
|
for (i = 0; i < [collections count]; i++)
|
||||||
|
{
|
||||||
|
key = [NSString stringWithFormat: @"SyncRequest+%@", [[[(id)[[collections objectAtIndex: i] getElementsByTagName: @"CollectionId"] lastObject] textValue] stringByUnescapingURL]];
|
||||||
|
[[o properties] removeObjectForKey: key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[o save];
|
[o save];
|
||||||
|
@ -139,10 +157,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
- (void) _setFolderMetadata: (NSDictionary *) theFolderMetadata
|
- (void) _setFolderMetadata: (NSDictionary *) theFolderMetadata
|
||||||
forKey: (NSString *) theFolderKey
|
forKey: (NSString *) theFolderKey
|
||||||
{
|
{
|
||||||
|
NSNumber *processIdentifier, *processIdentifierInCache;
|
||||||
SOGoCacheGCSObject *o;
|
SOGoCacheGCSObject *o;
|
||||||
NSDictionary *values;
|
NSDictionary *values;
|
||||||
NSString *key;
|
NSString *key;
|
||||||
|
|
||||||
|
if ([theFolderKey hasPrefix: @"folder"])
|
||||||
|
key = [NSString stringWithFormat: @"SyncRequest+mail/%@", [theFolderKey substringFromIndex: 6]];
|
||||||
|
else
|
||||||
|
key = [NSString stringWithFormat: @"SyncRequest+%@", theFolderKey];
|
||||||
|
|
||||||
|
processIdentifier = [NSNumber numberWithInt: [[NSProcessInfo processInfo] processIdentifier]];
|
||||||
|
processIdentifierInCache = [[self globalMetadataForDevice] objectForKey: key];
|
||||||
|
|
||||||
|
// Don't update the cache if another request is processing the same collection.
|
||||||
|
if (!([processIdentifierInCache isEqual: processIdentifier]))
|
||||||
|
{
|
||||||
|
if (debugOn)
|
||||||
|
[self logWithFormat: @"EAS - We lost our lock - discard folder cache update %@ %@ <> %@", key, processIdentifierInCache, processIdentifier];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
|
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
|
||||||
values = [theFolderMetadata copy];
|
values = [theFolderMetadata copy];
|
||||||
|
|
||||||
|
@ -428,7 +464,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
[o takeActiveSyncValues: allChanges inContext: context];
|
[o takeActiveSyncValues: allChanges inContext: context];
|
||||||
[sogoObject saveComponent: o];
|
[sogoObject saveComponent: o];
|
||||||
|
|
||||||
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
if ([syncCache objectForKey: serverId])
|
||||||
|
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ActiveSyncEventFolder:
|
case ActiveSyncEventFolder:
|
||||||
|
@ -438,7 +475,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
[o takeActiveSyncValues: allChanges inContext: context];
|
[o takeActiveSyncValues: allChanges inContext: context];
|
||||||
[sogoObject saveComponent: o];
|
[sogoObject saveComponent: o];
|
||||||
|
|
||||||
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
if ([syncCache objectForKey: serverId])
|
||||||
|
[syncCache setObject: [NSString stringWithFormat:@"%f", [[sogoObject lastModified] timeIntervalSince1970]] forKey: serverId];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ActiveSyncMailFolder:
|
case ActiveSyncMailFolder:
|
||||||
|
@ -452,7 +490,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
result = [sogoObject fetchParts: [NSArray arrayWithObject: @"MODSEQ"]];
|
result = [sogoObject fetchParts: [NSArray arrayWithObject: @"MODSEQ"]];
|
||||||
modseq = [[[result objectForKey: @"RawResponse"] objectForKey: @"fetch"] objectForKey: @"modseq"];
|
modseq = [[[result objectForKey: @"RawResponse"] objectForKey: @"fetch"] objectForKey: @"modseq"];
|
||||||
|
|
||||||
if (modseq)
|
if (modseq && [syncCache objectForKey: serverId])
|
||||||
[syncCache setObject: [modseq stringValue] forKey: serverId];
|
[syncCache setObject: [modseq stringValue] forKey: serverId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,6 +638,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
withFilterType: (NSCalendarDate *) theFilterType
|
withFilterType: (NSCalendarDate *) theFilterType
|
||||||
inBuffer: (NSMutableString *) theBuffer
|
inBuffer: (NSMutableString *) theBuffer
|
||||||
lastServerKey: (NSString **) theLastServerKey
|
lastServerKey: (NSString **) theLastServerKey
|
||||||
|
defaultInterval: (unsigned int) theDefaultInterval
|
||||||
{
|
{
|
||||||
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
|
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
|
||||||
NSString *davCollectionTagToStore;
|
NSString *davCollectionTagToStore;
|
||||||
|
@ -624,7 +663,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
{
|
{
|
||||||
// The syncKey received from the client doesn't match the syncKey we have in cache - client might have missed a response.
|
// The syncKey received from the client doesn't match the syncKey we have in cache - client might have missed a response.
|
||||||
// We need to cleanup this mess.
|
// We need to cleanup this mess.
|
||||||
[self logWithFormat: @"Cache cleanup needed for device %@ - user: %@", [context objectForKey: @"DeviceId"], [[context activeUser] login]];
|
[self logWithFormat: @"Cache cleanup needed for device %@ - user: %@ syncKey: %@ cache: %@", [context objectForKey: @"DeviceId"], [[context activeUser] login], theSyncKey, [folderMetadata objectForKey: @"SyncKey"]];
|
||||||
cleanup_needed = YES;
|
cleanup_needed = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,6 +795,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// Check for the WindowSize
|
// Check for the WindowSize
|
||||||
max = [allComponents count];
|
max = [allComponents count];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cleanup the mess
|
||||||
|
//
|
||||||
|
if (cleanup_needed)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
component = [allComponents objectAtIndex: i];
|
||||||
|
deleted = [[component objectForKey: @"c_deleted"] intValue];
|
||||||
|
|
||||||
|
if (!deleted && ![[component objectForKey: @"c_component"] isEqualToString: component_name])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uid = [[component objectForKey: @"c_name"] sanitizedServerIdWithType: theFolderType];
|
||||||
|
|
||||||
|
if (deleted)
|
||||||
|
{
|
||||||
|
if (debugOn)
|
||||||
|
[self logWithFormat: @"EAS - Cache cleanup: DELETE %@", uid];
|
||||||
|
|
||||||
|
// For deletes we have to recreate a cache entry to make sure the delete is sent again.
|
||||||
|
[syncCache setObject: @"0" forKey: uid];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ([syncCache objectForKey: uid] && [[component objectForKey: @"c_creationdate"] intValue] > [theSyncKey intValue])
|
||||||
|
{
|
||||||
|
if (debugOn)
|
||||||
|
[self logWithFormat: @"EAS - Cache cleanup: ADD %@", uid];
|
||||||
|
|
||||||
|
// Cleanup the cache to make sure the add is sent again.
|
||||||
|
[syncCache removeObjectForKey: uid];
|
||||||
|
[dateCache removeObjectForKey: uid];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (debugOn)
|
||||||
|
[self logWithFormat: @"EAS - Cache cleanup: CHANGE %@", uid];
|
||||||
|
|
||||||
|
// Update cache entry to make sure the change is sent again.
|
||||||
|
[syncCache setObject: @"0" forKey: uid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return_count = 0;
|
return_count = 0;
|
||||||
|
|
||||||
for (i = 0; i < max; i++)
|
for (i = 0; i < max; i++)
|
||||||
|
@ -914,15 +1000,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
SOGoMailObject *mailObject;
|
SOGoMailObject *mailObject;
|
||||||
NSArray *allMessages, *a;
|
NSArray *allMessages, *a;
|
||||||
NSString *lastSequence, *firstUidAdded;
|
NSString *firstUIDAdded;
|
||||||
|
|
||||||
int j, k, return_count, highestmodseq;
|
int j, k, return_count, highestmodseq;
|
||||||
BOOL found_in_cache, initialLoadInProgress;
|
BOOL found_in_cache, initialLoadInProgress;
|
||||||
|
|
||||||
initialLoadInProgress = NO;
|
initialLoadInProgress = NO;
|
||||||
found_in_cache = NO;
|
found_in_cache = NO;
|
||||||
lastSequence = nil;
|
firstUIDAdded = nil;
|
||||||
firstUidAdded = nil;
|
|
||||||
|
|
||||||
if ([theSyncKey isEqualToString: @"-1"])
|
if ([theSyncKey isEqualToString: @"-1"])
|
||||||
{
|
{
|
||||||
|
@ -1030,7 +1115,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
for (j = 0; j < [allCacheObjects count]; j++)
|
for (j = 0; j < [allCacheObjects count]; j++)
|
||||||
{
|
{
|
||||||
if (([[[allCacheObjects objectAtIndex: j] sequence] isEqual: [NSNull null]] && [syncCache objectForKey: [[allCacheObjects objectAtIndex: j] uid]]) ||
|
if (([[[allCacheObjects objectAtIndex: j] sequence] isEqual: [NSNull null]] && [syncCache objectForKey: [[allCacheObjects objectAtIndex: j] uid]]) ||
|
||||||
([[allCacheObjects objectAtIndex: j] sequence] && ![syncCache objectForKey: [[allCacheObjects objectAtIndex: j] uid]]))
|
(![[[allCacheObjects objectAtIndex: j] sequence] isEqual: [NSNull null]] && ![syncCache objectForKey: [[allCacheObjects objectAtIndex: j] uid]]))
|
||||||
{
|
{
|
||||||
// We need to continue with adds or deletes from here.
|
// We need to continue with adds or deletes from here.
|
||||||
found_in_cache = YES;
|
found_in_cache = YES;
|
||||||
|
@ -1066,17 +1151,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// Check for the WindowSize and slice accordingly
|
// Check for the WindowSize and slice accordingly
|
||||||
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
|
if (return_count >= theWindowSize || (theMaxSyncResponseSize > 0 && [s length] >= theMaxSyncResponseSize))
|
||||||
{
|
{
|
||||||
|
NSString *lastSequence;
|
||||||
more_available = YES;
|
more_available = YES;
|
||||||
|
|
||||||
if (!firstUidAdded)
|
if (!firstUIDAdded)
|
||||||
{
|
{
|
||||||
a = [davCollectionTagToStore componentsSeparatedByString: @"-"];
|
a = [davCollectionTagToStore componentsSeparatedByString: @"-"];
|
||||||
firstUidAdded = [a objectAtIndex: 0];
|
firstUIDAdded = [a objectAtIndex: 0];
|
||||||
RETAIN(firstUidAdded);
|
RETAIN(firstUIDAdded);
|
||||||
}
|
}
|
||||||
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? [NSString stringWithFormat:@"%d", highestmodseq] : [aCacheObject sequence]);
|
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? [NSString stringWithFormat:@"%d", highestmodseq] : [aCacheObject sequence]);
|
||||||
//RETAIN(lastSequence);
|
*theLastServerKey = [[NSString alloc] initWithFormat: @"%@-%@", firstUIDAdded, lastSequence];
|
||||||
*theLastServerKey = [[NSString alloc] initWithFormat: @"%@-%@", firstUidAdded, lastSequence];
|
|
||||||
|
|
||||||
if (debugOn)
|
if (debugOn)
|
||||||
[self logWithFormat: @"EAS - Reached windowSize - lastUID will be: %@", *theLastServerKey];
|
[self logWithFormat: @"EAS - Reached windowSize - lastUID will be: %@", *theLastServerKey];
|
||||||
|
@ -1173,12 +1258,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
[dateCache setObject: [NSCalendarDate date] forKey: [aCacheObject uid]];
|
[dateCache setObject: [NSCalendarDate date] forKey: [aCacheObject uid]];
|
||||||
|
|
||||||
// Save the frist UID we add. We will use it for the synckey late.
|
// Save the frist UID we add. We will use it for the synckey late.
|
||||||
if (!firstUidAdded)
|
if (!firstUIDAdded)
|
||||||
{
|
{
|
||||||
firstUidAdded = [aCacheObject uid];
|
firstUIDAdded = [aCacheObject uid];
|
||||||
RETAIN(firstUidAdded);
|
RETAIN(firstUIDAdded);
|
||||||
if (debugOn)
|
if (debugOn)
|
||||||
[self logWithFormat: @"EAS - first uid added %@", firstUidAdded];
|
[self logWithFormat: @"EAS - first uid added %@", firstUIDAdded];
|
||||||
}
|
}
|
||||||
|
|
||||||
return_count++;
|
return_count++;
|
||||||
|
@ -1195,19 +1280,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
if (more_available)
|
if (more_available)
|
||||||
{
|
{
|
||||||
//[folderMetadata setObject: lastSequence forKey: @"MoreAvailable"];
|
|
||||||
[folderMetadata setObject: [NSNumber numberWithInt: YES] forKey: @"MoreAvailable"];
|
[folderMetadata setObject: [NSNumber numberWithInt: YES] forKey: @"MoreAvailable"];
|
||||||
[folderMetadata setObject: *theLastServerKey forKey: @"SyncKey"];
|
[folderMetadata setObject: *theLastServerKey forKey: @"SyncKey"];
|
||||||
//RELEASE(lastSequence);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[folderMetadata removeObjectForKey: @"MoreAvailable"];
|
[folderMetadata removeObjectForKey: @"MoreAvailable"];
|
||||||
|
|
||||||
if (firstUidAdded)
|
if (firstUIDAdded)
|
||||||
{
|
{
|
||||||
a = [davCollectionTagToStore componentsSeparatedByString: @"-"];
|
a = [davCollectionTagToStore componentsSeparatedByString: @"-"];
|
||||||
[folderMetadata setObject: [[NSString alloc] initWithFormat: @"%@-%@", firstUidAdded, [a objectAtIndex: 1]] forKey: @"SyncKey"];
|
[folderMetadata setObject: [[NSString alloc] initWithFormat: @"%@-%@", firstUIDAdded, [a objectAtIndex: 1]] forKey: @"SyncKey"];
|
||||||
|
RELEASE(firstUIDAdded);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
|
[folderMetadata setObject: davCollectionTagToStore forKey: @"SyncKey"];
|
||||||
|
@ -1215,7 +1299,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||||
|
|
||||||
RELEASE(firstUidAdded);
|
|
||||||
RELEASE(*theLastServerKey);
|
RELEASE(*theLastServerKey);
|
||||||
|
|
||||||
} // default:
|
} // default:
|
||||||
|
@ -1481,7 +1564,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
withFolderType: folderType
|
withFolderType: folderType
|
||||||
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
|
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
|
||||||
inBuffer: changeBuffer
|
inBuffer: changeBuffer
|
||||||
lastServerKey: &lastServerKey];
|
lastServerKey: &lastServerKey
|
||||||
|
defaultInterval: [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncInterval]];
|
||||||
}
|
}
|
||||||
|
|
||||||
folderMetadata = [self _folderMetadataForKey: folderKey];
|
folderMetadata = [self _folderMetadataForKey: folderKey];
|
||||||
|
@ -1643,6 +1727,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
SOGoSystemDefaults *defaults;
|
SOGoSystemDefaults *defaults;
|
||||||
id <DOMElement> aCollection;
|
id <DOMElement> aCollection;
|
||||||
NSMutableString *output, *s;
|
NSMutableString *output, *s;
|
||||||
|
NSMutableDictionary *globalMetadata;
|
||||||
|
NSNumber *syncRequestInCache, *processIdentifier;
|
||||||
|
NSString *key;
|
||||||
NSArray *allCollections;
|
NSArray *allCollections;
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
|
||||||
|
@ -1654,6 +1741,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
defaults = [SOGoSystemDefaults sharedSystemDefaults];
|
defaults = [SOGoSystemDefaults sharedSystemDefaults];
|
||||||
defaultInterval = [defaults maximumSyncInterval];
|
defaultInterval = [defaults maximumSyncInterval];
|
||||||
|
processIdentifier = [NSNumber numberWithInt: [[NSProcessInfo processInfo] processIdentifier]];
|
||||||
|
|
||||||
|
allCollections = (id)[theDocumentElement getElementsByTagName: @"Collection"];
|
||||||
|
|
||||||
[output appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
[output appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||||
[output appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
[output appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||||
|
@ -1673,45 +1763,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([[self globalMetadataForDevice] objectForKey: @"SyncInProgress"])
|
// Let other requests know about the collections we are dealing with.
|
||||||
{
|
[self _setOrUnsetSyncRequest: YES collections: allCollections];
|
||||||
NSCalendarDate *syncStartDate;
|
|
||||||
|
|
||||||
// An other sync is going on right now. Lets break it and wait
|
|
||||||
// until the other process clears it up.
|
|
||||||
[self _setOrUnsetSyncInProgress: YES invalidate: YES];
|
|
||||||
total_sleep = 0;
|
|
||||||
|
|
||||||
syncStartDate = [[self globalMetadataForDevice] objectForKey: @"SyncInProgress"];
|
|
||||||
|
|
||||||
while ([[self globalMetadataForDevice] objectForKey: @"SyncInProgress"])
|
|
||||||
{
|
|
||||||
// Don't go into a heartbeat loop.
|
|
||||||
heartbeatInterval = 0;
|
|
||||||
|
|
||||||
// We waited too long. Return a fatal error to the client.
|
|
||||||
if (abs([syncStartDate timeIntervalSinceNow]) > defaultInterval)
|
|
||||||
{
|
|
||||||
if (debugOn)
|
|
||||||
[self logWithFormat: @"EAS - We waited too long. syncStartDate: %@ %@", syncStartDate, [self globalMetadataForDevice]];
|
|
||||||
|
|
||||||
[theResponse setStatus: 503];
|
|
||||||
[self _setOrUnsetSyncInProgress: NO invalidate: NO];
|
|
||||||
RELEASE(output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugOn)
|
|
||||||
[self logWithFormat: @"EAS - globalMetadataForDevice %@", [self globalMetadataForDevice]];
|
|
||||||
|
|
||||||
[self logWithFormat: @"Sync in progress for device %@ (login: %@). Lock will expire in %d seconds", [context objectForKey: @"DeviceId"], [[context activeUser] login], defaultInterval-total_sleep];
|
|
||||||
sleep(5);
|
|
||||||
total_sleep += 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No lock or broke the existing one, lets grab it and proceed
|
|
||||||
[self _setOrUnsetSyncInProgress: YES invalidate: NO];
|
|
||||||
|
|
||||||
changeDetected = NO;
|
changeDetected = NO;
|
||||||
maxSyncResponseSize = [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncResponseSize];
|
maxSyncResponseSize = [[SOGoSystemDefaults sharedSystemDefaults] maximumSyncResponseSize];
|
||||||
|
@ -1739,8 +1792,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
}
|
}
|
||||||
|
|
||||||
[output appendString: @"<Collections>"];
|
[output appendString: @"<Collections>"];
|
||||||
|
|
||||||
allCollections = (id)[theDocumentElement getElementsByTagName: @"Collection"];
|
|
||||||
|
|
||||||
// We enter our loop detection change
|
// We enter our loop detection change
|
||||||
for (i = 0; i < (heartbeatInterval/internalInterval); i++)
|
for (i = 0; i < (heartbeatInterval/internalInterval); i++)
|
||||||
|
@ -1756,24 +1807,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
changeDetected: &changeDetected
|
changeDetected: &changeDetected
|
||||||
maxSyncResponseSize: maxSyncResponseSize];
|
maxSyncResponseSize: maxSyncResponseSize];
|
||||||
|
|
||||||
if (maxSyncResponseSize > 0 && [s length] >= maxSyncResponseSize)
|
// Don't return a response if another Sync is waiting.
|
||||||
|
globalMetadata = [self globalMetadataForDevice];
|
||||||
|
key = [NSString stringWithFormat: @"SyncRequest+%@", [[[(id)[aCollection getElementsByTagName: @"CollectionId"] lastObject] textValue] stringByUnescapingURL]];
|
||||||
|
|
||||||
|
if (!([[globalMetadata objectForKey: key] isEqual: processIdentifier]))
|
||||||
|
{
|
||||||
|
if (debugOn)
|
||||||
|
[self logWithFormat: @"EAS - Discard response %@", [self globalMetadataForDevice]];
|
||||||
|
|
||||||
|
[theResponse setStatus: 503];
|
||||||
|
|
||||||
|
RELEASE(output);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((maxSyncResponseSize > 0 && [s length] >= maxSyncResponseSize))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changeDetected)
|
if (changeDetected)
|
||||||
{
|
{
|
||||||
// Don't return a response if an other Sync is waiting and this is a heartbeat request.
|
|
||||||
if ([[self globalMetadataForDevice] objectForKey: @"InvalidateSyncInProgress"] && heartbeatInterval > 1)
|
|
||||||
{
|
|
||||||
if (debugOn)
|
|
||||||
[self logWithFormat: @"EAS - Heartbeat stopped - discard response %@", [self globalMetadataForDevice]];
|
|
||||||
|
|
||||||
[theResponse setStatus: 503];
|
|
||||||
[self _setOrUnsetSyncInProgress: NO invalidate: NO];
|
|
||||||
RELEASE(output);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[self logWithFormat: @"Change detected during Sync, we push the content."];
|
[self logWithFormat: @"Change detected during Sync, we push the content."];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1785,7 +1839,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
{
|
{
|
||||||
// We check if we must break the current synchronization since an other Sync
|
// We check if we must break the current synchronization since an other Sync
|
||||||
// has just arrived.
|
// has just arrived.
|
||||||
if ([[self globalMetadataForDevice] objectForKey: @"InvalidateSyncInProgress"])
|
syncRequestInCache = [[self globalMetadataForDevice] objectForKey: @"SyncRequest"];
|
||||||
|
if (!([syncRequest isEqualToNumber: syncRequestInCache]))
|
||||||
{
|
{
|
||||||
if (debugOn)
|
if (debugOn)
|
||||||
[self logWithFormat: @"EAS - Heartbeat stopped %@", [self globalMetadataForDevice]];
|
[self logWithFormat: @"EAS - Heartbeat stopped %@", [self globalMetadataForDevice]];
|
||||||
|
@ -1830,8 +1885,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
// Avoid overloading the autorelease pool here, as Sync command can
|
// Avoid overloading the autorelease pool here, as Sync command can
|
||||||
// generate fairly large responses.
|
// generate fairly large responses.
|
||||||
RELEASE(output);
|
RELEASE(output);
|
||||||
|
|
||||||
[self _setOrUnsetSyncInProgress: NO invalidate: NO];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -31,15 +31,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "SOGoActiveSyncConstants.h"
|
#include "SOGoActiveSyncConstants.h"
|
||||||
|
|
||||||
|
@class NSCalendarDate;
|
||||||
@class NSException;
|
@class NSException;
|
||||||
@class NSMutableDictionary;
|
@class NSMutableDictionary;
|
||||||
@class NSURL;
|
@class NSURL;
|
||||||
|
@class NSNumber;
|
||||||
|
|
||||||
@interface SOGoActiveSyncDispatcher : NSObject
|
@interface SOGoActiveSyncDispatcher : NSObject
|
||||||
{
|
{
|
||||||
NSURL *folderTableURL;
|
NSURL *folderTableURL;
|
||||||
NSDictionary *imapFolderGUIDS;
|
NSDictionary *imapFolderGUIDS;
|
||||||
id context;
|
id context;
|
||||||
|
|
||||||
|
NSNumber *syncRequest;
|
||||||
|
|
||||||
BOOL debugOn;
|
BOOL debugOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
|
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
|
||||||
folderTableURL = nil;
|
folderTableURL = nil;
|
||||||
imapFolderGUIDS = nil;
|
imapFolderGUIDS = nil;
|
||||||
|
syncRequest = nil;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +168,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
{
|
{
|
||||||
RELEASE(folderTableURL);
|
RELEASE(folderTableURL);
|
||||||
RELEASE(imapFolderGUIDS);
|
RELEASE(imapFolderGUIDS);
|
||||||
|
RELEASE(syncRequest);
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue