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); }