/Raven.Database/Server/RavenFS/Synchronization/SynchronizationWorkItem.cs
C# | 131 lines | 106 code | 24 blank | 1 comment | 8 complexity | f490116ac489644c3f4943a3cfcfe35d MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, CC-BY-SA-3.0
- using System;
- using System.Collections.Generic;
- using System.Collections.Specialized;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using Raven.Abstractions.Logging;
- using Raven.Client.Connection.Profiling;
- using Raven.Database.Server.RavenFS.Extensions;
- using Raven.Database.Server.RavenFS.Storage;
- using Raven.Database.Server.RavenFS.Storage.Esent;
- using Raven.Database.Server.RavenFS.Synchronization.Conflictuality;
- using Raven.Json.Linq;
- using Raven.Client.FileSystem;
- using Raven.Abstractions.FileSystem;
- using Raven.Client.FileSystem.Connection;
- using Raven.Abstractions.Data;
-
- namespace Raven.Database.Server.RavenFS.Synchronization
- {
- public abstract class SynchronizationWorkItem : IHoldProfilingInformation
- {
- private readonly ConflictDetector conflictDetector;
- private readonly ConflictResolver conflictResolver;
- protected readonly CancellationTokenSource Cts = new CancellationTokenSource();
- protected FilesConvention Convention = new FilesConvention();
- protected SynchronizationWorkItem(string fileName, string sourceServerUrl, ITransactionalStorage storage)
- {
- Storage = storage;
- FileName = fileName;
-
- FileAndPagesInformation fileAndPages = null;
- Storage.Batch(accessor => fileAndPages = accessor.GetFile(fileName, 0, 0));
- FileMetadata = fileAndPages.Metadata;
- ServerInfo = new ServerInfo
- {
- Id = Storage.Id,
- FileSystemUrl = sourceServerUrl
- };
-
- conflictDetector = new ConflictDetector();
- conflictResolver = new ConflictResolver();
- }
-
- protected ITransactionalStorage Storage { get; private set; }
-
- public string FileName { get; private set; }
-
- public Guid FileETag
- {
- get { return FileMetadata.Value<Guid>(Constants.MetadataEtagField); }
- }
-
- public bool IsCancelled
- {
- get { return Cts.Token.IsCancellationRequested; }
- }
-
- protected RavenJObject FileMetadata { get; set; }
-
- protected ServerInfo ServerInfo { get; private set; }
-
- public abstract SynchronizationType SynchronizationType { get; }
-
- public abstract Task<SynchronizationReport> PerformAsync(IAsyncFilesSynchronizationCommands destination);
-
- public virtual void Cancel()
- {
- }
-
- protected void AssertLocalFileExistsAndIsNotConflicted(RavenJObject sourceMetadata)
- {
- if (sourceMetadata == null)
- throw new SynchronizationException(string.Format("File {0} does not exist", FileName));
-
- if (sourceMetadata.ContainsKey(SynchronizationConstants.RavenSynchronizationConflict))
- throw new SynchronizationException(string.Format("File {0} is conflicted", FileName));
- }
-
- protected ConflictItem CheckConflictWithDestination(RavenJObject sourceMetadata,
- RavenJObject destinationMetadata, string localServerUrl)
- {
- var conflict = conflictDetector.CheckOnSource(FileName, sourceMetadata, destinationMetadata, localServerUrl);
- var isConflictResolved = conflictResolver.IsResolved(destinationMetadata, conflict);
-
- // optimization - conflict checking on source side before any changes pushed
- if (conflict != null && !isConflictResolved)
- return conflict;
-
- return null;
- }
-
- protected async Task<SynchronizationReport> ApplyConflictOnDestinationAsync(ConflictItem conflict, RavenJObject remoteMetadata, IAsyncFilesSynchronizationCommands destination, string localServerUrl, ILog log)
- {
- var commands = (IAsyncFilesCommandsImpl)destination.Commands;
-
- log.Debug("File '{0}' is in conflict with destination version from {1}. Applying conflict on destination", FileName, commands.UrlFor());
-
- try
- {
- var version = conflict.RemoteHistory.Last().Version;
- var serverId = conflict.RemoteHistory.Last().ServerId;
- var history = new List<HistoryItem>(conflict.RemoteHistory);
- history.RemoveAt(conflict.RemoteHistory.Count - 1);
-
- await destination.ApplyConflictAsync(FileName, version, serverId, remoteMetadata, localServerUrl);
- }
- catch (Exception ex)
- {
- log.WarnException(string.Format("Failed to apply conflict on {0} for file '{1}'", destination, FileName), ex);
- }
-
- return new SynchronizationReport(FileName, FileETag, SynchronizationType)
- {
- Exception = new SynchronizationException(string.Format("File {0} is conflicted", FileName)),
- };
- }
-
- public void RefreshMetadata()
- {
- if (Storage != null)
- {
- FileAndPagesInformation fileAndPages = null;
- Storage.Batch(accessor => fileAndPages = accessor.GetFile(FileName, 0, 0));
- FileMetadata = fileAndPages.Metadata;
- }
- }
-
- public ProfilingInformation ProfilingInformation { get; private set; }
- }
- }