示例#1
0
        public bool CheckIfResolvedByRemoteStrategy(RavenJObject destinationMetadata, ConflictItem conflict)
        {
            var conflictResolutionMetadata = destinationMetadata[SynchronizationConstants.RavenSynchronizationConflictResolution] as RavenJObject;
            if (conflictResolutionMetadata == null)
                return false;

            var conflictResolution = JsonExtensions.JsonDeserialization<ConflictResolution>(conflictResolutionMetadata);
            return conflictResolution.Strategy == ConflictResolutionStrategy.RemoteVersion && conflictResolution.RemoteServerId == conflict.RemoteHistory.Last().ServerId;
        }
		public void Create(string fileName, ConflictItem conflict)
		{
            RavenJObject metadata = null;

			storage.Batch(
				accessor =>
				{
					metadata = accessor.GetFile(fileName, 0, 0).Metadata;
					accessor.SetConfig(RavenFileNameHelper.ConflictConfigNameForFile(fileName), JsonExtensions.ToJObject(conflict) );
					metadata[SynchronizationConstants.RavenSynchronizationConflict] = true;
					accessor.UpdateFileMetadata(fileName, metadata);
				});

			if (metadata != null)
				index.Index(fileName, metadata);
		}
		public bool TryResolveConflict(string fileName, ConflictItem conflict, RavenJObject localMetadata, RavenJObject remoteMetadata, out ConflictResolutionStrategy strategy)
		{
			foreach (var resolver in Resolvers)
			{
				if (resolver.TryResolve(fileName, localMetadata, remoteMetadata, out strategy) == false)
					continue;

				switch (strategy)
				{
					case ConflictResolutionStrategy.CurrentVersion:
						ApplyCurrentStrategy(fileName, conflict, localMetadata);
						return true;
					case ConflictResolutionStrategy.RemoteVersion:
						ApplyRemoteStrategy(fileName, conflict, localMetadata);
						return true;
				}
			}

			strategy = ConflictResolutionStrategy.NoResolution;
			return false;
		}
		public async Task<HttpResponseMessage> ApplyConflict(string filename, long remoteVersion, string remoteServerId, string remoteServerUrl)
		{
            var canonicalFilename = FileHeader.Canonize(filename);

			var localMetadata = Synchronizations.GetLocalMetadata(canonicalFilename);

			if (localMetadata == null)
				throw new HttpResponseException(HttpStatusCode.NotFound);

			var contentStream = await Request.Content.ReadAsStreamAsync();

			var current = new HistoryItem
			{
				ServerId = Storage.Id.ToString(),
				Version = localMetadata.Value<long>(SynchronizationConstants.RavenSynchronizationVersion)
			};

			var currentConflictHistory = Historian.DeserializeHistory(localMetadata);
			currentConflictHistory.Add(current);

			var remote = new HistoryItem
			{
				ServerId = remoteServerId,
				Version = remoteVersion
			};

            var remoteMetadata = RavenJObject.Load(new JsonTextReader(new StreamReader(contentStream)));

            var remoteConflictHistory = Historian.DeserializeHistory(remoteMetadata);
			remoteConflictHistory.Add(remote);

			var conflict = new ConflictItem
			{
				CurrentHistory = currentConflictHistory,
				RemoteHistory = remoteConflictHistory,
                FileName = canonicalFilename,
				RemoteServerUrl = Uri.UnescapeDataString(remoteServerUrl)
			};

            ConflictArtifactManager.Create(canonicalFilename, conflict);

            Publisher.Publish(new ConflictNotification
			{
                FileName = filename,
				SourceServerUrl = remoteServerUrl,
                Status = ConflictStatus.Detected,
                RemoteFileHeader = new FileHeader(canonicalFilename, remoteMetadata)
			});

			Log.Debug("Conflict applied for a file '{0}' (remote version: {1}, remote server id: {2}).", filename, remoteVersion, remoteServerId);

            return GetEmptyMessage(HttpStatusCode.NoContent);
		}
        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)),
			};
		}
		protected async Task<SynchronizationReport> HandleConflict(IAsyncFilesSynchronizationCommands destination, ConflictItem conflict, ILog log)
		{
			var conflictResolutionStrategy = await destination.Commands.Synchronization.GetResolutionStrategyFromDestinationResolvers(conflict, FileMetadata);

			switch (conflictResolutionStrategy)
			{
				case ConflictResolutionStrategy.NoResolution:
					return await ApplyConflictOnDestinationAsync(conflict, FileMetadata, destination, FileSystemInfo.Url, log);
				case ConflictResolutionStrategy.CurrentVersion:
					await ApplyConflictOnDestinationAsync(conflict, FileMetadata, destination, FileSystemInfo.Url, log);
					await destination.Commands.Synchronization.ResolveConflictAsync(FileName, conflictResolutionStrategy);
					return new SynchronizationReport(FileName, FileETag, SynchronizationType);
				case ConflictResolutionStrategy.RemoteVersion:
					// we can push the file even though it conflicted, the conflict will be automatically resolved on the destination side
					return null;
				default:
					return new SynchronizationReport(FileName, FileETag, SynchronizationType)
					{
						Exception = new SynchronizationException(string.Format("Unknown resolution strategy: {0}", conflictResolutionStrategy)),
					};
			}
		}
        public async Task<ConflictResolutionStrategy> GetResolutionStrategyFromDestinationResolvers(ConflictItem conflict, RavenJObject localMetadata)
        {
            var requestUriString = string.Format("{0}/synchronization/ResolutionStrategyFromServerResolvers", baseUrl);

            using (var request = RequestFactory.CreateHttpJsonRequest(new CreateHttpJsonRequestParams(this, requestUriString, "POST", Credentials, Conventions)).AddOperationHeaders(OperationsHeaders))
            {
                request.AddHeaders(localMetadata);

                try
                {
                    await request.WriteWithObjectAsync(conflict).ConfigureAwait(false);
                    var response = await request.ReadResponseJsonAsync().ConfigureAwait(false);
                    return response.JsonDeserialization<ConflictResolutionStrategy>();
                }
                catch (Exception e)
                {
                    throw e.SimplifyException();
                }
            }
        }
		public void ApplyRemoteStrategy(string fileName, ConflictItem conflict, RavenJObject localMetadata)
		{
			var conflictResolution = new ConflictResolution
			{
				Strategy = ConflictResolutionStrategy.RemoteVersion,
				RemoteServerId = conflict.RemoteHistory.Last().ServerId,
				Version = conflict.RemoteHistory.Last().Version,
			};

			localMetadata[SynchronizationConstants.RavenSynchronizationConflictResolution] = JsonExtensions.ToJObject(conflictResolution);
		}
		public void ApplyCurrentStrategy(string fileName, ConflictItem conflict, RavenJObject localMetadata)
		{
			var localHistory = Historian.DeserializeHistory(localMetadata);

			// incorporate remote version history into local
			foreach (var remoteHistoryItem in conflict.RemoteHistory.Where(remoteHistoryItem => !localHistory.Contains(remoteHistoryItem)))
			{
				localHistory.Add(remoteHistoryItem);
			}

			localMetadata[SynchronizationConstants.RavenSynchronizationHistory] = Historian.SerializeHistory(localHistory);
		}