nothirst / TICoreDataSync

Automatic synchronization for Core Data apps, between any combination of Mac OS X and iOS: Mac to iPhone to iPad to iPod touch and back again.
https://github.com/nothirst/TICoreDataSync/wiki
807 stars 61 forks source link

DocumentSyncManager initiates many syncs while files are downloaded #43

Closed chbeer closed 11 years ago

chbeer commented 11 years ago

I'm using the new iCloud core data sync from the branch. After I installed the app fresh on a device, while there are some changes in the cloud, it takes a very long time until the sync finishes.

While debugging, I see that the synchronization is initiated many times in this method, which is called when a file changes:

- (void)directoryContentsDidChange:(NSNotification *)aNotification
{    
    NSString *aPath = [[aNotification userInfo] valueForKey:kTIKQExpandedDirectory];

    if( ![[aPath lastPathComponent] isEqualToString:TICDSSyncChangesDirectoryName] ) {
        // another client has synchronized
        [self initiateSynchronization];
        return;
    }
    ...

This results in:

2013-04-09 14:49:50.077 iVocabulary3[2146:907] -[TICDSDocumentSyncManager startPreSynchronizationProcess] : Starting pre-synchronization process
2013-04-09 14:49:50.083 iVocabulary3[2146:907] -[TICDSDocumentSyncManager startSynchronizationProcess] : Starting synchronization process
2013-04-09 14:49:50.099 iVocabulary3[2146:907] -[TICDSDocumentSyncManager startPreSynchronizationProcess] : Starting pre-synchronization process
[...many times more ...]

Is this maybe a new problem using iCloud sync? What should be the correct behavior?

Should the directory maybe only change if created the first time (if not on iCloud)? Maybe iCloud handles this differently?

Thanks for your help, Christian

MrRooni commented 11 years ago

It looks like the directory watcher is responding to every change to the sync directory and kicking off a sync every time. I recently did a little work in this method on the Dropbox side of things that I recommend you pull in to the feature branch. It modifies the enableAutomaticSynchronizationAfterChangesDetectedFromOtherClients method to be beginPollingRemoteStorageForChanges that can be implemented by any DocumentSyncManager subclass. Check out the changes at b3408b689b42549b3fae5fb7792c8595a8ecf869 and 761758583e4c2a978a8c78f08ddf9e20b72f5fe2. Specifically the check in TICDSDropboxSDKBasedDocumentSyncManager::restClient:loadedDeltaEntries:reset:cursor:hasMore:

    NSString *lowercaseDocumentDirectoryPath = [self.thisDocumentDirectoryPath lowercaseString];
    NSString *lowercaseClientIdentifier = [self.clientIdentifier lowercaseString];
    NSString *lowercaseRecentSyncsDirectoryName = [TICDSRecentSyncsDirectoryName lowercaseString];
    for (DBDeltaEntry *entry in entries) {
        if ([entry.lowercasePath hasPrefix:lowercaseDocumentDirectoryPath]) {
            if ([entry.lowercasePath rangeOfString:lowercaseClientIdentifier].location != NSNotFound) {
                TICDSLog(TICDSLogVerbosityEveryStep, @"Processing a response from the polling call, skipping changes made by this client.");
                continue;
            }

            if ([entry.lowercasePath rangeOfString:lowercaseRecentSyncsDirectoryName].location != NSNotFound) {
                TICDSLog(TICDSLogVerbosityEveryStep, @"Processing a response from the polling call, skipping changes to the recent syncs directory made by other clients.");
                continue;
            }

            TICDSLog(TICDSLogVerbosityEveryStep, @"Found changes to %@ during polling, kicking off a sync", entry.lowercasePath);
            self.remotePollingTimer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(pollRemoteStorage:) userInfo:nil repeats:NO];
            [self initiateSynchronization];
            return;
        }
    }

While processing responses from the Dropbox call I make sure to ignore certain changes to the directory structure so that I'm really only kicking off a new sync if I find new sync change files.

Let me know if this is clear or if I've left out a crucial nugget of information.

chbeer commented 11 years ago

Your solution checks for changes in TICDSRecentSyncsDirectoryName but in my case it's happening because of changes to the SyncData directories.

I am using Drews TIUbiquitousMonitor that loads the changed files to the device. As soon as the directories in SyncData change, each time a new sync is initiated. This leads to many syncs being started one after another... that takes time and costs battery.

Maybe it should be checked, if a sync is already running / queued? Or a new sync should only be initiated if there is a new file inside the client-identifier-paths?

MrRooni commented 11 years ago

My solution ignores changes in the recent syncs directory and in any directory modified by the client doing the monitoring.

However, you're right in that if multiple changes occur in rapid succession that it would kick off multiple syncs. I also made a recent change in the develop branch that prevents more than one sync from happening at a time. Check out 4a5924869c9990f204de8c5b9626f03461cc1c06