public void Delete(string fileName, IStorageActionsAccessor actionsAccessor = null) { RavenJObject metadata = null; Action <IStorageActionsAccessor> delete = accessor => { accessor.DeleteConfig(RavenFileNameHelper.ConflictConfigNameForFile(fileName)); metadata = accessor.GetFile(fileName, 0, 0).Metadata; metadata.Remove(SynchronizationConstants.RavenSynchronizationConflict); metadata.Remove(SynchronizationConstants.RavenSynchronizationConflictResolution); accessor.UpdateFileMetadata(fileName, metadata); }; if (actionsAccessor != null) { delete(actionsAccessor); } else { storage.Batch(delete); } if (metadata != null) { index.Index(fileName, metadata); } }
public async Task Should_just_rename_file_in_synchronization_process() { var content = new MemoryStream(new byte[] { 1, 2, 3, 4 }); var sourceClient = NewClient(0); var destinationClient = NewClient(1); await sourceClient.UploadAsync("test.bin", new RavenJObject { { "key", "value" } }, content); content.Position = 0; await destinationClient.UploadAsync("test.bin", new RavenJObject { { "key", "value" } }, content); await sourceClient.RenameAsync("test.bin", "renamed.bin"); // we need to indicate old file name, otherwise content update would be performed because renamed file does not exist on dest var report = SyncTestUtils.ResolveConflictAndSynchronize(sourceClient, destinationClient, "test.bin"); Assert.Equal(SynchronizationType.Rename, report.Type); var conflictItem = destinationClient.Config.GetConfig <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile("test.bin")).Result; Assert.Null(conflictItem); var testMetadata = await destinationClient.GetMetadataForAsync("test.bin"); var renamedMetadata = await destinationClient.GetMetadataForAsync("renamed.bin"); Assert.Null(testMetadata); Assert.NotNull(renamedMetadata); var result = await destinationClient.GetFilesAsync("/"); Assert.Equal(1, result.FileCount); Assert.Equal("renamed.bin", result.Files[0].Name); }
public async void Should_be_possible_to_apply_conflict() { var canonicalFilename = FileHeader.Canonize("test.bin"); var content = new RandomStream(10); var client = NewAsyncClient(1); await client.UploadAsync(canonicalFilename, content); var guid = Guid.NewGuid().ToString(); var history = new List <HistoryItem> { new HistoryItem { ServerId = guid, Version = 3 } }; var remoteMetadata = new RavenJObject(); remoteMetadata[SynchronizationConstants.RavenSynchronizationHistory] = Historian.SerializeHistory(history); await client.Synchronization.ApplyConflictAsync(canonicalFilename, 8, guid, remoteMetadata, "http://localhost:12345"); var resultFileMetadata = await client.GetMetadataForAsync(canonicalFilename); var conflict = await client.Configuration.GetKeyAsync <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)); Assert.Equal(true.ToString(), resultFileMetadata[SynchronizationConstants.RavenSynchronizationConflict]); Assert.Equal(guid, conflict.RemoteHistory.Last().ServerId); Assert.Equal(8, conflict.RemoteHistory.Last().Version); Assert.Equal(1, conflict.CurrentHistory.Last().Version); Assert.Equal(2, conflict.RemoteHistory.Count); Assert.Equal(guid, conflict.RemoteHistory[0].ServerId); Assert.Equal(3, conflict.RemoteHistory[0].Version); }
public void Should_synchronize_just_metadata() { var content = new MemoryStream(new byte[] { 1, 2, 3, 4 }); var sourceClient = NewClient(0); var destinationClient = NewClient(1); sourceClient.UploadAsync("test.bin", new RavenJObject { { "difference", "metadata" } }, content).Wait(); content.Position = 0; destinationClient.UploadAsync("test.bin", content).Wait(); var report = SyncTestUtils.ResolveConflictAndSynchronize(sourceClient, destinationClient, "test.bin"); var conflictItem = destinationClient.Config.GetConfig <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile("test.bin")).Result; Assert.Null(conflictItem); Assert.Equal(SynchronizationType.MetadataUpdate, report.Type); var destinationMetadata = destinationClient.GetMetadataForAsync("test.bin").Result; Assert.Equal("metadata", destinationMetadata.Value <string>("difference")); }
public HttpResponseMessage Delete(string name) { name = FileHeader.Canonize(name); Storage.Batch(accessor => { Synchronizations.AssertFileIsNotBeingSynced(name); var fileAndPages = accessor.GetFile(name, 0, 0); var metadata = fileAndPages.Metadata; if (metadata == null) { throw new FileNotFoundException(); } if (metadata.Keys.Contains(SynchronizationConstants.RavenDeleteMarker)) { throw new FileNotFoundException(); } Files.IndicateFileToDelete(name, GetEtag()); if (!name.EndsWith(RavenFileNameHelper.DownloadingFileSuffix)) // don't create a tombstone for .downloading file { Files.PutTombstone(name, metadata); accessor.DeleteConfig(RavenFileNameHelper.ConflictConfigNameForFile(name)); // delete conflict item too } }); SynchronizationTask.Context.NotifyAboutWork(); return(GetEmptyMessage(HttpStatusCode.NoContent)); }
public HttpResponseMessage Delete(string name) { name = RavenFileNameHelper.RavenPath(name); try { ConcurrencyAwareExecutor.Execute(() => Storage.Batch(accessor => { AssertFileIsNotBeingSynced(name, accessor, true); var fileAndPages = accessor.GetFile(name, 0, 0); var metadata = fileAndPages.Metadata; if (metadata.Keys.Contains(SynchronizationConstants.RavenDeleteMarker)) { throw new FileNotFoundException(); } StorageOperationsTask.IndicateFileToDelete(name); if (!name.EndsWith(RavenFileNameHelper.DownloadingFileSuffix) && // don't create a tombstone for .downloading file metadata != null) // and if file didn't exist { var tombstoneMetadata = new RavenJObject { { SynchronizationConstants.RavenSynchronizationHistory, metadata[SynchronizationConstants.RavenSynchronizationHistory] }, { SynchronizationConstants.RavenSynchronizationVersion, metadata[SynchronizationConstants.RavenSynchronizationVersion] }, { SynchronizationConstants.RavenSynchronizationSource, metadata[SynchronizationConstants.RavenSynchronizationSource] } }.WithDeleteMarker(); Historian.UpdateLastModified(tombstoneMetadata); accessor.PutFile(name, 0, tombstoneMetadata, true); accessor.DeleteConfig(RavenFileNameHelper.ConflictConfigNameForFile(name)); // delete conflict item too } }), ConcurrencyResponseException); } catch (FileNotFoundException) { return(new HttpResponseMessage(HttpStatusCode.NotFound)); } Publisher.Publish(new FileChangeNotification { File = FilePathTools.Cannoicalise(name), Action = FileChangeAction.Delete }); log.Debug("File '{0}' was deleted", name); StartSynchronizeDestinationsInBackground(); return(GetEmptyMessage(HttpStatusCode.NoContent)); }
public void Should_be_possible_to_apply_conflict() { var content = new RandomStream(10); var client = NewClient(1); client.UploadAsync("test.bin", content).Wait(); var guid = Guid.NewGuid().ToString(); client.Synchronization.ApplyConflictAsync("test.bin", 8, guid, new List <HistoryItem> { new HistoryItem { ServerId = guid, Version = 3 } }, "http://localhost:12345").Wait(); var resultFileMetadata = client.GetMetadataForAsync("test.bin").Result; var conflict = client.Config.GetConfig <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile("test.bin")).Result; Assert.Equal(true.ToString(), resultFileMetadata[SynchronizationConstants.RavenSynchronizationConflict]); Assert.Equal(guid, conflict.RemoteHistory.Last().ServerId); Assert.Equal(8, conflict.RemoteHistory.Last().Version); Assert.Equal(1, conflict.CurrentHistory.Last().Version); Assert.Equal(2, conflict.RemoteHistory.Count); Assert.Equal(guid, conflict.RemoteHistory[0].ServerId); Assert.Equal(3, conflict.RemoteHistory[0].Version); }
private void StrategyAsGetCurrent(string fileName) { Storage.Batch(accessor => { var conflict = accessor.GetConfigurationValue <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile(fileName)); var localMetadata = accessor.GetFile(fileName, 0, 0).Metadata; 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); accessor.UpdateFileMetadata(fileName, localMetadata); ConflictArtifactManager.Delete(fileName, accessor); Publisher.Publish(new ConflictNotification { FileName = fileName, Status = ConflictStatus.Resolved }); }); }
public HttpResponseMessage ResolveConflict(string filename, ConflictResolutionStrategy strategy) { var canonicalFilename = FileHeader.Canonize(filename); if (Log.IsDebugEnabled) { Log.Debug("Resolving conflict of a file '{0}' by using {1} strategy", filename, strategy); } switch (strategy) { case ConflictResolutionStrategy.CurrentVersion: Storage.Batch(accessor => { var localMetadata = accessor.GetFile(canonicalFilename, 0, 0).Metadata; var conflict = accessor.GetConfigurationValue <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)); ConflictResolver.ApplyCurrentStrategy(canonicalFilename, conflict, localMetadata); accessor.UpdateFileMetadata(canonicalFilename, localMetadata, null); ConflictArtifactManager.Delete(canonicalFilename, accessor); }); Publisher.Publish(new ConflictNotification { FileName = canonicalFilename, Status = ConflictStatus.Resolved }); break; case ConflictResolutionStrategy.RemoteVersion: Storage.Batch(accessor => { var localMetadata = accessor.GetFile(canonicalFilename, 0, 0).Metadata; var conflict = accessor.GetConfig(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename)).JsonDeserialization <ConflictItem>(); ConflictResolver.ApplyRemoteStrategy(canonicalFilename, conflict, localMetadata); accessor.UpdateFileMetadata(canonicalFilename, localMetadata, null); accessor.SetConfig(RavenFileNameHelper.ConflictConfigNameForFile(canonicalFilename), JsonExtensions.ToJObject(conflict)); // ConflictArtifactManager.Delete(canonicalFilename, accessor); - intentionally not deleting, conflict item will be removed when a remote file is put }); SynchronizationTask.Context.NotifyAboutWork(); break; default: throw new NotSupportedException(string.Format("{0} is not the valid strategy to resolve a conflict", strategy)); } return(GetEmptyMessage(HttpStatusCode.NoContent)); }
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); } }
private void StrategyAsGetRemote(string fileName) { Storage.Batch( accessor => { var localMetadata = accessor.GetFile(fileName, 0, 0).Metadata; var conflictConfigName = RavenFileNameHelper.ConflictConfigNameForFile(fileName); var conflictItem = accessor.GetConfig(conflictConfigName).JsonDeserialization <ConflictItem>(); var conflictResolution = new ConflictResolution { Strategy = ConflictResolutionStrategy.RemoteVersion, RemoteServerId = conflictItem.RemoteHistory.Last().ServerId, Version = conflictItem.RemoteHistory.Last().Version, }; localMetadata[SynchronizationConstants.RavenSynchronizationConflictResolution] = JsonExtensions.ToJObject(conflictResolution); accessor.UpdateFileMetadata(fileName, localMetadata); }); }
private void DeleteFiles(IEnumerable <string> keys, int totalResults, Action <string> progress) { Storage.Batch(accessor => { var files = keys.Select(accessor.ReadFile); foreach (var fileWithIndex in files.Select((value, i) => new { i, value })) { var file = fileWithIndex.value; var fileName = file.FullPath; try { Synchronizations.AssertFileIsNotBeingSynced(fileName); } catch (Exception) { //ignore files that are being synced continue; } var metadata = file.Metadata; if (metadata == null || metadata.Keys.Contains(SynchronizationConstants.RavenDeleteMarker)) { continue; } Historian.Update(fileName, metadata); Files.IndicateFileToDelete(fileName, null); // don't create a tombstone for .downloading file if (!fileName.EndsWith(RavenFileNameHelper.DownloadingFileSuffix)) { Files.PutTombstone(fileName, metadata); accessor.DeleteConfig(RavenFileNameHelper.ConflictConfigNameForFile(fileName)); // delete conflict item too } progress(string.Format("File {0}/{1} was deleted, name: '{2}'.", fileWithIndex.i, totalResults, fileName)); } }); }
public async void Should_synchronize_to_all_destinations() { var sourceContent = SyncTestUtils.PrepareSourceStream(10000); sourceContent.Position = 0; var sourceClient = NewAsyncClient(0); var destination1Client = NewAsyncClient(1); var destination2Client = NewAsyncClient(2); var destination1Content = new RandomlyModifiedStream(sourceContent, 0.01); sourceContent.Position = 0; var destination2Content = new RandomlyModifiedStream(sourceContent, 0.01); sourceContent.Position = 0; await destination1Client.UploadAsync("test.bin", destination1Content); await destination2Client.UploadAsync("test.bin", destination2Content); sourceContent.Position = 0; await sourceClient.UploadAsync("test.bin", sourceContent); sourceContent.Position = 0; sourceClient.Synchronization.SetDestinationsAsync(destination1Client.ToSynchronizationDestination(), destination2Client.ToSynchronizationDestination()).Wait(); var destinationSyncResults = sourceClient.Synchronization.SynchronizeAsync().Result; // we expect conflicts after first attempt of synchronization Assert.Equal(2, destinationSyncResults.Length); Assert.Equal("File test.bin is conflicted", destinationSyncResults[0].Reports.ToArray()[0].Exception.Message); Assert.Equal("File test.bin is conflicted", destinationSyncResults[1].Reports.ToArray()[0].Exception.Message); await destination1Client.Synchronization.ResolveConflictAsync("test.bin", ConflictResolutionStrategy.RemoteVersion); await destination2Client.Synchronization.ResolveConflictAsync("test.bin", ConflictResolutionStrategy.RemoteVersion); destinationSyncResults = await sourceClient.Synchronization.SynchronizeAsync(); var conflictItem = await destination1Client.Configuration.GetKeyAsync <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile("test.bin")); Assert.Null(conflictItem); conflictItem = await destination2Client.Configuration.GetKeyAsync <ConflictItem>(RavenFileNameHelper.ConflictConfigNameForFile("test.bin")); Assert.Null(conflictItem); // check if reports match Assert.Equal(2, destinationSyncResults.Length); var result1 = destinationSyncResults[0].Reports.ToArray()[0]; Assert.Equal(sourceContent.Length, result1.BytesCopied + result1.BytesTransfered); Assert.Equal(SynchronizationType.ContentUpdate, result1.Type); var result2 = destinationSyncResults[1].Reports.ToArray()[0]; Assert.Equal(sourceContent.Length, result2.BytesCopied + result2.BytesTransfered); Assert.Equal(SynchronizationType.ContentUpdate, result2.Type); // check content of files string destination1Md5; using (var resultFileContent = await destination1Client.DownloadAsync("test.bin")) { destination1Md5 = resultFileContent.GetMD5Hash(); } string destination2Md5; using (var resultFileContent = await destination2Client.DownloadAsync("test.bin")) { destination2Md5 = resultFileContent.GetMD5Hash(); } sourceContent.Position = 0; var sourceMd5 = sourceContent.GetMD5Hash(); Assert.Equal(sourceMd5, destination1Md5); Assert.Equal(sourceMd5, destination2Md5); Assert.Equal(destination1Md5, destination2Md5); }