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