private bool HasFolderChanged(IFolder deletedIFolder) { // TODO Does not work if newly-created. // ChangeLog string lastTokenOnClient = database.GetChangeLogToken(); string lastTokenOnServer = CmisUtils.GetChangeLogToken(session); if (lastTokenOnClient == lastTokenOnServer || lastTokenOnClient == null) { return(false); } // TODO: Extract static code, because same code was writtern in SynchronizedFolder Config.Feature features = null; if (ConfigManager.CurrentConfig.GetFolder(repoInfo.Name) != null) { features = ConfigManager.CurrentConfig.GetFolder(repoInfo.Name).SupportedFeatures; } int maxNumItems = (features != null && features.MaxNumberOfContentChanges != null) ? // TODO if there are more items, either loop or force CrawlSync (int)features.MaxNumberOfContentChanges : 500; var changes = session.GetContentChanges(lastTokenOnClient, IsPropertyChangesSupported, maxNumItems); return(CheckInsideChange(deletedIFolder, changes)); }
/// <summary> /// Synchronize using the ChangeLog feature of CMIS. /// Not all CMIS servers support this feature, so sometimes CrawlStrategy is used instead. /// </summary> private void ChangeLogSync(IFolder remoteFolder) { // Get last change log token on server side. session.Binding.GetRepositoryService().GetRepositoryInfos(null); // refresh string lastTokenOnServer = session.Binding.GetRepositoryService().GetRepositoryInfo(session.RepositoryInfo.Id, null).LatestChangeLogToken; // Get last change token that had been saved on client side. // TODO catch exception invalidArgument which means that changelog has been truncated and this token is not found anymore. string lastTokenOnClient = database.GetChangeLogToken(); if (lastTokenOnClient == lastTokenOnServer) { Logger.Debug("No change from remote, wait for the next time."); return; } if (lastTokenOnClient == null) { // Token is null, which means no sync has ever happened yet, so just sync everything from remote. CrawlRemote(remoteFolder, repoinfo.TargetDirectory, null, null); Logger.Info("Succeeded to sync from remote, update ChangeLog token: " + lastTokenOnServer); database.SetChangeLogToken(lastTokenOnServer); } do { Config.Feature f = null; if (ConfigManager.CurrentConfig.getFolder(repoinfo.Name) != null) { f = ConfigManager.CurrentConfig.getFolder(repoinfo.Name).SupportedFeatures; } int maxNumItems = (f != null && f.MaxNumberOfContentChanges != null)? (int)f.MaxNumberOfContentChanges: 100; // Check which files/folders have changed. IChangeEvents changes = session.GetContentChanges(lastTokenOnClient, IsPropertyChangesSupported, maxNumItems); // Replicate each change to the local side. bool success = true; foreach (IChangeEvent change in changes.ChangeEventList) { try { switch (change.ChangeType) { case ChangeType.Created: Logger.Info("New remote object (" + change.ObjectId + ") found."); goto case ChangeType.Updated; case ChangeType.Updated: if (change.ChangeType == ChangeType.Updated) { Logger.Info("Remote object (" + change.ObjectId + ") has been changed remotely."); } success = ApplyRemoteChangeUpdate(change) && success; break; case ChangeType.Deleted: Logger.Info("Remote object (" + change.ObjectId + ") has been deleted remotely."); success = ApplyRemoteChangeDelete(change) && success; break; default: break; } } catch (Exception e) { Logger.Warn("Exception when apply the change: ", e); success = false; } } if (success) { // Save change log token locally. if (changes.HasMoreItems == true) { lastTokenOnClient = changes.LatestChangeLogToken; } else { lastTokenOnClient = lastTokenOnServer; } Logger.Info("Sync the changes on server, update ChangeLog token: " + lastTokenOnClient); database.SetChangeLogToken(lastTokenOnClient); session.Binding.GetRepositoryService().GetRepositoryInfos(null); // refresh lastTokenOnServer = session.Binding.GetRepositoryService().GetRepositoryInfo(session.RepositoryInfo.Id, null).LatestChangeLogToken; } else { Logger.Warn("Failure to sync the changes on server, force crawl sync from remote"); CrawlRemote(remoteFolder, repoinfo.TargetDirectory, null, null); Logger.Info("Succeeded to sync from remote, update ChangeLog token: " + lastTokenOnServer); database.SetChangeLogToken(lastTokenOnServer); return; } }while (!lastTokenOnServer.Equals(lastTokenOnClient)); }
/// <summary> /// Synchronize using the ChangeLog feature of CMIS to trigger CrawlStrategy. /// </summary> private bool ChangeLogThenCrawlSync(IFolder remoteFolder, string remotePath, string localFolder) { // Once in a while, run a crawl sync, to make up for any server-side ChangeLog bug. // The frequency of this is calculated based on the poll interval, so that: // Interval=5 seconds -> every 6 hours -> about every 2160 iterations // Interval=1 hours -> every 3 days -> about every 72 iterations // Thus a good formula is: nb of iterations = 1 + 263907 / (pollInterval + 117) double pollInterval = ConfigManager.CurrentConfig.GetFolder(repoInfo.Name).PollInterval; if (changeLogIterationCounter > 263907 / (pollInterval / 1000 + 117)) { Logger.Debug("It has been a while since the last crawl sync, so launching a crawl sync now."); bool crawlSuccess = CrawlSyncAndUpdateChangeLogToken(remoteFolder, remotePath, localFolder); changeLogIterationCounter = 0; return(crawlSuccess); } else { changeLogIterationCounter++; } // Calculate queryable number of changes. Config.Feature features = null; if (ConfigManager.CurrentConfig.GetFolder(repoInfo.Name) != null) { features = ConfigManager.CurrentConfig.GetFolder(repoInfo.Name).SupportedFeatures; } int maxNumItems = (features != null && features.MaxNumberOfContentChanges != null) ? // TODO if there are more items, either loop or force CrawlSync (int)features.MaxNumberOfContentChanges : 50; // Get last change token that had been saved on client side. string lastTokenOnClient = database.GetChangeLogToken(); // Get last change log token on server side. string lastTokenOnServer = CmisUtils.GetChangeLogToken(session); if (lastTokenOnClient == lastTokenOnServer) { Logger.DebugFormat("No changes to sync, tokens on server and client are equal: \"{0}\"", lastTokenOnClient); return(true); } bool success = true; if (lastTokenOnClient == null) { // Token is null, which means no sync has ever happened yet, so just sync everything from remote. success &= CrawlRemote(remoteFolder, remotePath, repoInfo.TargetDirectory, new List <string>(), new List <string>()); Logger.Info("Synced from remote, updating ChangeLog token: " + lastTokenOnServer); database.SetChangeLogToken(lastTokenOnServer); } // ChangeLog tokens are different, so checking changes is needed. var currentChangeToken = lastTokenOnClient; IChangeEvents changes; do { // Check which documents/folders have changed. changes = session.GetContentChanges(currentChangeToken, IsPropertyChangesSupported, maxNumItems); // First event was already processed previous. <- not true for single rename var changeEvents = changes.ChangeEventList./*Where(p => p != changes.ChangeEventList.FirstOrDefault()).*/ ToList(); success &= CrawlChangeLogSyncAndUpdateChangeLogToken(changeEvents, remoteFolder, remotePath, localFolder); // Save the token of the last of the changes we just consumed. currentChangeToken = changes.LatestChangeLogToken; database.SetChangeLogToken(currentChangeToken); } // Repeat if there were two many changes to fit in a single response. while (changes.HasMoreItems ?? false); database.SetChangeLogToken(lastTokenOnServer); return(success); }
/// <summary> /// Synchronize using the ChangeLog feature of CMIS to trigger CrawlStrategy. /// </summary> private void ChangeLogThenCrawlSync(IFolder remoteFolder, string remotePath, string localFolder) { // Once in a while, run a crawl sync, to make up for any server-side ChangeLog bug. // The frequency of this is calculated based on the poll interval, so that: // Interval=5 seconds -> every 6 hours -> about every 2160 iterations // Interval=1 hours -> every 3 days -> about every 72 iterations // Thus a good formula is: nb of iterations = 1 + 263907 / (pollInterval + 117) double pollInterval = ConfigManager.CurrentConfig.GetFolder(repoInfo.Name).PollInterval; if (changeLogIterationCounter > 263907 / (pollInterval / 1000 + 117)) { Logger.Debug("It has been a while since the last crawl sync, so launching a crawl sync now."); CrawlSyncAndUpdateChangeLogToken(remoteFolder, remotePath, localFolder); changeLogIterationCounter = 0; return; } else { changeLogIterationCounter++; } // Calculate queryable number of changes. Config.Feature features = null; if (ConfigManager.CurrentConfig.GetFolder(repoInfo.Name) != null) { features = ConfigManager.CurrentConfig.GetFolder(repoInfo.Name).SupportedFeatures; } int maxNumItems = (features != null && features.MaxNumberOfContentChanges != null) ? // TODO if there are more items, either loop or force CrawlSync (int)features.MaxNumberOfContentChanges : 100; IChangeEvents changes; // Get last change token that had been saved on client side. string lastTokenOnClient = database.GetChangeLogToken(); // Get last change log token on server side. string lastTokenOnServer = CmisUtils.GetChangeLogToken(session); if (lastTokenOnClient == lastTokenOnServer) { Logger.Debug("No changes to sync, tokens on server and client are equal: \"" + lastTokenOnClient + "\""); return; } if (lastTokenOnClient == null) { // Token is null, which means no sync has ever happened yet, so just sync everything from remote. CrawlRemote(remoteFolder, remotePath, repoInfo.TargetDirectory, new List <string>(), new List <string>()); Logger.Info("Synced from remote, updating ChangeLog token: " + lastTokenOnServer); database.SetChangeLogToken(lastTokenOnServer); } // ChangeLog tokens are different, so checking changes is needed. do { // Check which documents/folders have changed. changes = session.GetContentChanges(lastTokenOnClient, IsPropertyChangesSupported, maxNumItems); // Apply changes. foreach (IChangeEvent change in changes.ChangeEventList) { // Check whether change is applicable. // For instance, we dont care about changes to non-synced folders. if (ChangeIsApplicable(change)) { // Launch a CrawlSync (which means syncing everything indistinctively). CrawlSyncAndUpdateChangeLogToken(remoteFolder, remotePath, localFolder); // A single CrawlSync takes care of all pending changes, so no need to analyze the rest of the changes. // It will also update the last client-side ChangeLog token, more accurately than we can do here. return; } } // No applicable changes, update ChangeLog token. lastTokenOnClient = changes.LatestChangeLogToken; // But dont save to database as latest server token is actually a later token. } // Repeat if there were two many changes to fit in a single response. // Only reached if none of the changes in this iteration were non-applicable. while (changes.HasMoreItems ?? false); database.SetChangeLogToken(lastTokenOnServer); }