コード例 #1
0
        public SourceSynchronizationInformation GetLastSynchronization(Guid from)
        {
            SourceSynchronizationInformation info = null;

            try
            {
                Storage.Batch(accessor =>
                {
                    info = accessor.GetConfig(SynchronizationConstants.RavenSynchronizationSourcesBasePath + "/" + from)
                           .JsonDeserialization <SourceSynchronizationInformation>();
                });
            }
            catch (FileNotFoundException)
            {
                info = new SourceSynchronizationInformation
                {
                    LastSourceFileEtag  = Etag.Empty,
                    DestinationServerId = Storage.Id
                };
            }

            return(info);
        }
コード例 #2
0
        private IEnumerable <FileHeader> GetFilesToSynchronization(SourceSynchronizationInformation destinationsSynchronizationInformationForSource, int take)
        {
            var filesToSynchronization = new List <FileHeader>();

            Log.Debug("Getting files to synchronize with ETag greater than {0} [parameter take = {1}]",
                      destinationsSynchronizationInformationForSource.LastSourceFileEtag, take);

            try
            {
                storage.Batch(
                    accessor =>
                    filesToSynchronization =
                        accessor.GetFilesAfter(destinationsSynchronizationInformationForSource.LastSourceFileEtag, take).ToList());
            }
            catch (Exception e)
            {
                Log.WarnException(
                    string.Format("Could not get files to synchronize after: " +
                                  destinationsSynchronizationInformationForSource.LastSourceFileEtag), e);
            }

            return(filesToSynchronization);
        }
コード例 #3
0
        private void SaveSynchronizationSourceInformation(FileSystemInfo sourceFileSystem, Etag lastSourceEtag)
        {
            var lastSynchronizationInformation = GetLastSynchronization(sourceFileSystem.Id);

            if (EtagUtil.IsGreaterThan(lastSynchronizationInformation.LastSourceFileEtag, lastSourceEtag))
            {
                return;
            }

            var synchronizationSourceInfo = new SourceSynchronizationInformation
            {
                LastSourceFileEtag  = lastSourceEtag,
                SourceServerUrl     = sourceFileSystem.Url,
                DestinationServerId = Storage.Id
            };

            var key = SynchronizationConstants.RavenSynchronizationSourcesBasePath + "/" + sourceFileSystem.Id;

            Storage.Batch(accessor => accessor.SetConfig(key, JsonExtensions.ToJObject(synchronizationSourceInfo)));


            Log.Debug("Saved last synchronized file ETag {0} from {1} ({2})", lastSourceEtag, sourceFileSystem.Url, sourceFileSystem.Id);
        }
コード例 #4
0
        private async Task <bool> EnqueueMissingUpdatesAsync(ISynchronizationServerClient destinationSyncClient,
                                                             SourceSynchronizationInformation synchronizationInfo,
                                                             IList <FileHeader> needSyncingAgain)
        {
            LogFilesInfo("There were {0} file(s) that needed synchronization because the previous one went wrong: {1}",
                         needSyncingAgain);

            var filesToSynchronization = new HashSet <FileHeader>(GetFilesToSynchronization(synchronizationInfo.LastSourceFileEtag, NumberOfFilesToCheckForSynchronization),
                                                                  FileHeaderNameEqualityComparer.Instance);

            LogFilesInfo("There were {0} file(s) that needed synchronization because of greater ETag value: {1}",
                         filesToSynchronization);

            foreach (FileHeader needSyncing in needSyncingAgain)
            {
                filesToSynchronization.Add(needSyncing);
            }

            var filteredFilesToSynchronization = filesToSynchronization.Where(
                x => synchronizationStrategy.Filter(x, synchronizationInfo.DestinationServerId, filesToSynchronization)).ToList();

            if (filesToSynchronization.Count > 0)
            {
                LogFilesInfo("There were {0} file(s) that needed synchronization after filtering: {1}", filteredFilesToSynchronization);
            }

            if (filteredFilesToSynchronization.Count == 0)
            {
                var lastFileBeforeFiltering = filesToSynchronization.LastOrDefault();

                if (lastFileBeforeFiltering == null)
                {
                    return(true); // there are no more files that need
                }
                if (lastFileBeforeFiltering.Etag == synchronizationInfo.LastSourceFileEtag)
                {
                    return(true); // already updated etag on destination side
                }
                await destinationSyncClient.IncrementLastETagAsync(storage.Id, FileSystemUrl, lastFileBeforeFiltering.Etag).ConfigureAwait(false);

                return(false); // all docs has been filtered out, update etag on destination side and retry
            }

            var destinationUrl = destinationSyncClient.BaseUrl;

            bool enqueued = true;

            foreach (var fileHeader in filteredFilesToSynchronization)
            {
                context.CancellationToken.ThrowIfCancellationRequested();

                var file          = fileHeader.FullPath;
                var localMetadata = GetLocalMetadata(file);

                RavenJObject destinationMetadata;

                try
                {
                    destinationMetadata = await destinationSyncClient.GetMetadataForAsync(file).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Log.WarnException(
                        string.Format("Could not retrieve a metadata of a file '{0}' from {1} in order to determine needed synchronization type", file,
                                      destinationUrl), ex);

                    continue;
                }

                NoSyncReason reason;
                var          work = synchronizationStrategy.DetermineWork(file, localMetadata, destinationMetadata, FileSystemUrl, out reason);
                if (work == null)
                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug("File '{0}' were not synchronized to {1}. {2}", file, destinationUrl, reason.GetDescription());
                    }

                    if (reason == NoSyncReason.ContainedInDestinationHistory)
                    {
                        var etag = localMetadata.Value <Guid>(Constants.MetadataEtagField);
                        await destinationSyncClient.IncrementLastETagAsync(storage.Id, FileSystemUrl, etag).ConfigureAwait(false);

                        RemoveSyncingConfiguration(file, destinationUrl);

                        enqueued = false;
                    }

                    continue;
                }

                if (synchronizationQueue.EnqueueSynchronization(destinationUrl, work))
                {
                    publisher.Publish(new SynchronizationUpdateNotification
                    {
                        FileName = work.FileName,
                        DestinationFileSystemUrl = destinationUrl,
                        SourceServerId           = storage.Id,
                        SourceFileSystemUrl      = FileSystemUrl,
                        Type      = work.SynchronizationType,
                        Action    = SynchronizationAction.Enqueue,
                        Direction = SynchronizationDirection.Outgoing
                    });
                }

                enqueued = true;
            }

            return(enqueued);
        }
コード例 #5
0
        private async Task EnqueueMissingUpdatesAsync(IAsyncFilesSynchronizationCommands destination,
                                                      SourceSynchronizationInformation lastEtag,
                                                      IList <FileHeader> needSyncingAgain)
        {
            LogFilesInfo("There were {0} file(s) that needed synchronization because the previous one went wrong: {1}",
                         needSyncingAgain);

            var commands = (IAsyncFilesCommandsImpl)destination.Commands;

            var filesToSynchronization = new HashSet <FileHeader>(GetFilesToSynchronization(lastEtag, 100),
                                                                  new FileHeaderNameEqualityComparer());

            LogFilesInfo("There were {0} file(s) that needed synchronization because of greater ETag value: {1}",
                         filesToSynchronization);

            foreach (FileHeader needSyncing in needSyncingAgain)
            {
                filesToSynchronization.Add(needSyncing);
            }

            var filteredFilesToSynchronization =
                filesToSynchronization.Where(
                    x => synchronizationStrategy.Filter(x, lastEtag.DestinationServerId, filesToSynchronization)).ToList();

            if (filesToSynchronization.Count > 0)
            {
                LogFilesInfo("There were {0} file(s) that needed synchronization after filtering: {1}", filteredFilesToSynchronization);
            }

            // Early break. There are no files to synchronize to the selected destination.
            if (!filteredFilesToSynchronization.Any())
            {
                return;
            }

            var baseUrl = commands.UrlFor();

            foreach (var fileHeader in filteredFilesToSynchronization)
            {
                var file          = fileHeader.FullPath;
                var localMetadata = GetLocalMetadata(file);

                RavenJObject destinationMetadata;

                try
                {
                    destinationMetadata = await destination.Commands.GetMetadataForAsync(file);
                }
                catch (Exception ex)
                {
                    Log.WarnException(
                        string.Format("Could not retrieve a metadata of a file '{0}' from {1} in order to determine needed synchronization type", file,
                                      baseUrl), ex);

                    continue;
                }

                NoSyncReason reason;
                var          work = synchronizationStrategy.DetermineWork(file, localMetadata, destinationMetadata, FileSystemUrl, out reason);
                if (work == null)
                {
                    Log.Debug("File '{0}' were not synchronized to {1}. {2}", file, baseUrl, reason.GetDescription());

                    if (reason == NoSyncReason.ContainedInDestinationHistory)
                    {
                        var etag = localMetadata.Value <Guid>(Constants.MetadataEtagField);
                        await destination.IncrementLastETagAsync(storage.Id, baseUrl, etag);

                        RemoveSyncingConfiguration(file, baseUrl);
                    }

                    continue;
                }

                if (synchronizationQueue.EnqueueSynchronization(baseUrl, work))
                {
                    publisher.Publish(new SynchronizationUpdateNotification
                    {
                        FileName = work.FileName,
                        DestinationFileSystemUrl = baseUrl,
                        SourceServerId           = storage.Id,
                        SourceFileSystemUrl      = FileSystemUrl,
                        Type      = work.SynchronizationType,
                        Action    = SynchronizationAction.Enqueue,
                        Direction = SynchronizationDirection.Outgoing
                    });
                }
            }
        }
コード例 #6
0
        private async Task <bool> EnqueueMissingUpdatesAsync(ISynchronizationServerClient destinationSyncClient,
                                                             SourceSynchronizationInformation synchronizationInfo,
                                                             IList <FileHeader> needSyncingAgain)
        {
            LogFilesInfo("There were {0} file(s) that needed synchronization because the previous one went wrong: {1}",
                         needSyncingAgain);

            var filesToSynchronization = new HashSet <FileHeader>(GetFilesToSynchronization(synchronizationInfo.LastSourceFileEtag, NumberOfFilesToCheckForSynchronization),
                                                                  FileHeaderNameEqualityComparer.Instance);

            LogFilesInfo("There were {0} file(s) that needed synchronization because of greater ETag value: {1}",
                         filesToSynchronization);

            foreach (FileHeader needSyncing in needSyncingAgain)
            {
                filesToSynchronization.Add(needSyncing);
            }

            var filteredFilesToSynchronization = filesToSynchronization.Where(
                x => synchronizationStrategy.Filter(x, synchronizationInfo.DestinationServerId, filesToSynchronization)).ToList();

            if (filesToSynchronization.Count > 0)
            {
                LogFilesInfo("There were {0} file(s) that needed synchronization after filtering: {1}", filteredFilesToSynchronization);
            }

            if (filteredFilesToSynchronization.Count == 0)
            {
                var lastFileBeforeFiltering = filesToSynchronization.LastOrDefault();

                if (lastFileBeforeFiltering == null)
                {
                    return(true); // there are no more files that need
                }
                if (lastFileBeforeFiltering.Etag == synchronizationInfo.LastSourceFileEtag)
                {
                    return(true); // already updated etag on destination side
                }
                await destinationSyncClient.IncrementLastETagAsync(storage.Id, FileSystemUrl, lastFileBeforeFiltering.Etag).ConfigureAwait(false);

                return(false); // all docs has been filtered out, update etag on destination side and retry
            }

            var destinationUrl = destinationSyncClient.BaseUrl;

            bool enqueued             = false;
            var  maxEtagOfFilteredDoc = Etag.Empty;

            foreach (var fileHeader in filteredFilesToSynchronization)
            {
                context.CancellationToken.ThrowIfCancellationRequested();

                var file          = fileHeader.FullPath;
                var localMetadata = GetLocalMetadata(file);

                RavenJObject destinationMetadata;

                try
                {
                    destinationMetadata = await destinationSyncClient.GetMetadataForAsync(file).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Log.WarnException(
                        string.Format("Could not retrieve a metadata of a file '{0}' from {1} in order to determine needed synchronization type", file,
                                      destinationUrl), ex);

                    continue;
                }

                NoSyncReason reason;
                var          work = synchronizationStrategy.DetermineWork(file, localMetadata, destinationMetadata, FileSystemUrl, out reason);

                if (work == null)
                {
                    Log.Debug("File '{0}' was not synchronized to {1}. {2}", file, destinationUrl, reason.GetDescription());

                    switch (reason)
                    {
                    case NoSyncReason.ContainedInDestinationHistory:
                    case NoSyncReason.DestinationFileConflicted:
                    case NoSyncReason.NoNeedToDeleteNonExistigFile:
                        var localEtag = Etag.Parse(localMetadata.Value <string>(Constants.MetadataEtagField));

                        if (reason == NoSyncReason.ContainedInDestinationHistory)
                        {
                            RemoveSyncingConfiguration(file, destinationUrl);
                        }
                        else if (reason == NoSyncReason.DestinationFileConflicted)
                        {
                            if (needSyncingAgain.Contains(fileHeader, FileHeaderNameEqualityComparer.Instance) == false)
                            {
                                CreateSyncingConfiguration(fileHeader.Name, fileHeader.Etag, destinationUrl, SynchronizationType.Unknown);
                            }
                        }
                        else if (reason == NoSyncReason.NoNeedToDeleteNonExistigFile)
                        {
                            // after the upgrade to newer build there can be still an existing syncing configuration for it
                            RemoveSyncingConfiguration(file, destinationUrl);
                        }

                        if (EtagUtil.IsGreaterThan(localEtag, maxEtagOfFilteredDoc))
                        {
                            maxEtagOfFilteredDoc = localEtag;
                        }

                        break;
                    }

                    continue;
                }

                if (synchronizationQueue.EnqueueSynchronization(destinationUrl, work))
                {
                    publisher.Publish(new SynchronizationUpdateNotification
                    {
                        FileName = work.FileName,
                        DestinationFileSystemUrl = destinationUrl,
                        SourceServerId           = storage.Id,
                        SourceFileSystemUrl      = FileSystemUrl,
                        Type      = work.SynchronizationType,
                        Action    = SynchronizationAction.Enqueue,
                        Direction = SynchronizationDirection.Outgoing
                    });
                }

                enqueued = true;
            }

            if (enqueued == false && EtagUtil.IsGreaterThan(maxEtagOfFilteredDoc, synchronizationInfo.LastSourceFileEtag))
            {
                await destinationSyncClient.IncrementLastETagAsync(storage.Id, FileSystemUrl, maxEtagOfFilteredDoc).ConfigureAwait(false);

                return(false); // we bumped the last synced etag on a destination server, let it know it need to repeat the operation
            }

            return(true);
        }
コード例 #7
0
        private async Task EnqueueMissingUpdatesAsync(SynchronizationClient destination,
                                                      SourceSynchronizationInformation lastEtag,
                                                      IList <FileHeader> needSyncingAgain)
        {
            LogFilesInfo("There were {0} file(s) that needed synchronization because the previous one went wrong: {1}",
                         needSyncingAgain);

            var filesToSynchronization = new HashSet <FileHeader>(GetFilesToSynchronization(lastEtag, 100),
                                                                  new FileHeaderNameEqualityComparer());

            LogFilesInfo("There were {0} file(s) that needed synchronization because of greater ETag value: {1}",
                         filesToSynchronization);

            foreach (FileHeader needSyncing in needSyncingAgain)
            {
                filesToSynchronization.Add(needSyncing);
            }

            var filteredFilesToSynchronization =
                filesToSynchronization.Where(
                    x => synchronizationStrategy.Filter(x, lastEtag.DestinationServerId, filesToSynchronization)).ToList();

            if (filesToSynchronization.Count > 0)
            {
                LogFilesInfo("There were {0} file(s) that needed synchronization after filtering: {1}",
                             filteredFilesToSynchronization);
            }

            if (filteredFilesToSynchronization.Count == 0)
            {
                return;
            }

            foreach (var fileHeader in filteredFilesToSynchronization)
            {
                var file          = fileHeader.Name;
                var localMetadata = GetLocalMetadata(file);

                RavenJObject destinationMetadata;

                try
                {
                    destinationMetadata = await destination.GetMetadataForAsync(file);
                }
                catch (Exception ex)
                {
                    Log.WarnException(
                        string.Format("Could not retrieve a metadata of a file '{0}' from {1} in order to determine needed synchronization type", file,
                                      destination.FileSystemUrl), ex);

                    continue;
                }

                NoSyncReason reason;
                var          work = synchronizationStrategy.DetermineWork(file, localMetadata, destinationMetadata, FileSystemUrl, out reason);

                if (work == null)
                {
                    Log.Debug("File '{0}' were not synchronized to {1}. {2}", file, destination.FileSystemUrl, reason.GetDescription());

                    if (reason == NoSyncReason.ContainedInDestinationHistory)
                    {
                        var etag = localMetadata.Value <Guid>("ETag");
                        await destination.IncrementLastETagAsync(storage.Id, FileSystemUrl, etag);

                        RemoveSyncingConfiguration(file, destination.FileSystemUrl);
                    }

                    continue;
                }

                synchronizationQueue.EnqueueSynchronization(destination.FileSystemUrl, work);
            }
        }