예제 #1
0
        public async Task Should_resume_file_copying_from_client()
        {
            var client = NewAsyncClient();
            var rfs    = GetFileSystem();

            string fileName = FileHeader.Canonize("file.bin");
            string newName  = FileHeader.Canonize("file2.bin");

            await client.UploadAsync(fileName, new RandomStream(1));

            // create config to say to the server that rename operation performed last time were not finished
            var copyOpConfig  = RavenFileNameHelper.CopyOperationConfigNameForFile(fileName, newName);
            var copyOperation = new CopyFileOperation
            {
                SourceFilename         = fileName,
                TargetFilename         = newName,
                MetadataAfterOperation = new RavenJObject()
            };

            rfs.Storage.Batch(accessor => accessor.SetConfigurationValue(copyOpConfig, copyOperation));

            await client.Storage.RetryCopyingAsync();

            IEnumerable <string> configNames = await client.Configuration.GetKeyNamesAsync();

            Assert.DoesNotContain(copyOpConfig, configNames);

            var renamedMetadata = await client.GetMetadataForAsync(newName);

            Assert.NotNull(renamedMetadata);
        }
예제 #2
0
        public HttpResponseMessage Copy(string name, string targetFilename)
        {
            name           = FileHeader.Canonize(name);
            targetFilename = FileHeader.Canonize(targetFilename);
            var etag = GetEtag();

            Storage.Batch(accessor =>
            {
                FileSystem.Synchronizations.AssertFileIsNotBeingSynced(name);

                var existingFile = accessor.ReadFile(name);
                if (existingFile == null || existingFile.Metadata.Value <bool>(SynchronizationConstants.RavenDeleteMarker))
                {
                    throw new FileNotFoundException();
                }

                var renamingFile = accessor.ReadFile(targetFilename);
                if (renamingFile != null && renamingFile.Metadata.Value <bool>(SynchronizationConstants.RavenDeleteMarker) == false)
                {
                    throw new FileExistsException("Cannot copy because file " + targetFilename + " already exists");
                }

                var metadata = existingFile.Metadata;

                if (etag != null && existingFile.Etag != etag)
                {
                    throw new ConcurrencyException("Operation attempted on file '" + name + "' using a non current etag")
                    {
                        ActualETag   = existingFile.Etag,
                        ExpectedETag = etag
                    }
                }
                ;

                Historian.UpdateLastModified(metadata);

                var operation = new CopyFileOperation
                {
                    FileSystem             = FileSystem.Name,
                    SourceFilename         = name,
                    TargetFilename         = targetFilename,
                    MetadataAfterOperation = metadata
                };

                accessor.SetConfig(RavenFileNameHelper.CopyOperationConfigNameForFile(name), JsonExtensions.ToJObject(operation));
                accessor.PulseTransaction(); // commit rename operation config

                Files.ExecuteCopyOperation(operation);
            });

            if (Log.IsDebugEnabled)
            {
                Log.Debug("File '{0}' was copied to '{1}'", name, targetFilename);
            }

            FileSystem.Synchronizations.StartSynchronizeDestinationsInBackground();

            return(GetEmptyMessage(HttpStatusCode.NoContent));
        }
예제 #3
0
        public void ExecuteCopyOperation(CopyFileOperation operation)
        {
            var configName = RavenFileNameHelper.CopyOperationConfigNameForFile(operation.SourceFilename, operation.TargetFilename);

            Storage.Batch(accessor =>
            {
                AssertPutOperationNotVetoed(operation.TargetFilename, operation.MetadataAfterOperation);

                var targetTombstrone = accessor.ReadFile(operation.TargetFilename);

                if (targetTombstrone != null &&
                    targetTombstrone.Metadata[SynchronizationConstants.RavenDeleteMarker] != null)
                {
                    // if there is a tombstone delete it
                    accessor.Delete(targetTombstrone.FullPath);
                }

                FileSystem.PutTriggers.Apply(trigger => trigger.OnPut(operation.TargetFilename, operation.MetadataAfterOperation));

                accessor.CopyFile(operation.SourceFilename, operation.TargetFilename, true);
                var putResult = accessor.UpdateFileMetadata(operation.TargetFilename, operation.MetadataAfterOperation, null);

                FileSystem.PutTriggers.Apply(trigger => trigger.AfterPut(operation.TargetFilename, null, operation.MetadataAfterOperation));

                accessor.DeleteConfig(configName);

                Search.Index(operation.TargetFilename, operation.MetadataAfterOperation, putResult.Etag);
            });

            Publisher.Publish(new ConfigurationChangeNotification {
                Name = configName, Action = ConfigurationChangeAction.Set
            });
            Publisher.Publish(new FileChangeNotification {
                File = operation.TargetFilename, Action = FileChangeAction.Add
            });
        }
예제 #4
0
        public HttpResponseMessage Copy(string name, string targetFilename)
        {
            name           = FileHeader.Canonize(name);
            targetFilename = FileHeader.Canonize(targetFilename);
            var etag = GetEtag();

            var retriesCount = 0;

            while (true)
            {
                try
                {
                    Storage.Batch(accessor =>
                    {
                        FileSystem.Synchronizations.AssertFileIsNotBeingSynced(name);

                        var existingFile = accessor.ReadFile(name);
                        if (existingFile == null || existingFile.Metadata.Value <bool>(SynchronizationConstants.RavenDeleteMarker))
                        {
                            throw new FileNotFoundException();
                        }

                        var renamingFile = accessor.ReadFile(targetFilename);
                        if (renamingFile != null && renamingFile.Metadata.Value <bool>(SynchronizationConstants.RavenDeleteMarker) == false)
                        {
                            throw new FileExistsException("Cannot copy because file " + targetFilename + " already exists");
                        }

                        var metadata = existingFile.Metadata;

                        if (etag != null && existingFile.Etag != etag)
                        {
                            throw new ConcurrencyException("Operation attempted on file '" + name + "' using a non current etag")
                            {
                                ActualETag   = existingFile.Etag,
                                ExpectedETag = etag
                            }
                        }
                        ;

                        Historian.UpdateLastModified(metadata);

                        var operation = new CopyFileOperation
                        {
                            FileSystem             = FileSystem.Name,
                            SourceFilename         = name,
                            TargetFilename         = targetFilename,
                            MetadataAfterOperation = metadata
                        };

                        accessor.SetConfig(RavenFileNameHelper.CopyOperationConfigNameForFile(name, targetFilename), JsonExtensions.ToJObject(operation));
                        var configName = RavenFileNameHelper.CopyOperationConfigNameForFile(operation.SourceFilename, operation.TargetFilename);
                        Files.AssertPutOperationNotVetoed(operation.TargetFilename, operation.MetadataAfterOperation);

                        var targetTombstrone = accessor.ReadFile(operation.TargetFilename);

                        if (targetTombstrone != null &&
                            targetTombstrone.Metadata[SynchronizationConstants.RavenDeleteMarker] != null)
                        {
                            // if there is a tombstone delete it
                            accessor.Delete(targetTombstrone.FullPath);
                        }

                        FileSystem.PutTriggers.Apply(trigger => trigger.OnPut(operation.TargetFilename, operation.MetadataAfterOperation));

                        accessor.CopyFile(operation.SourceFilename, operation.TargetFilename, true);
                        var putResult = accessor.UpdateFileMetadata(operation.TargetFilename, operation.MetadataAfterOperation, null);

                        FileSystem.PutTriggers.Apply(trigger => trigger.AfterPut(operation.TargetFilename, null, operation.MetadataAfterOperation));

                        accessor.DeleteConfig(configName);

                        Search.Index(operation.TargetFilename, operation.MetadataAfterOperation, putResult.Etag);


                        Publisher.Publish(new ConfigurationChangeNotification {
                            Name = configName, Action = ConfigurationChangeAction.Set
                        });
                        Publisher.Publish(new FileChangeNotification {
                            File = operation.TargetFilename, Action = FileChangeAction.Add
                        });
                    });

                    break;
                }
                catch (ConcurrencyException)
                {
                    // due to IncrementUsageCount performed concurrently on Voron storage
                    // Esent deals with that much better using Api.EscrowUpdate

                    if (retriesCount++ > 100)
                    {
                        throw;
                    }

                    Thread.Sleep(new Random().Next(1, 13));
                }
            }

            if (Log.IsDebugEnabled)
            {
                Log.Debug("File '{0}' was copied to '{1}'", name, targetFilename);
            }

            SynchronizationTask.Context.NotifyAboutWork();

            return(GetEmptyMessage(HttpStatusCode.NoContent));
        }