Example #1
0
        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);
            }
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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"));
        }
Example #5
0
        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));
        }
Example #6
0
        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));
        }
Example #7
0
        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);
        }
Example #8
0
        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));
        }
Example #10
0
        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);
            }
        }
Example #11
0
        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);
            });
        }
Example #12
0
        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);
        }