public void Should_not_delete_downloading_file_if_synchronization_retry_is_being_performed() { const string fileName = "file.bin"; var downloadingFileName = RavenFileNameHelper.DownloadingFileName(fileName); var client = NewAsyncClient(); var rfs = GetFileSystem(); client.UploadAsync(fileName, new RandomStream(1)).Wait(); client.UploadAsync(downloadingFileName, new RandomStream(1)).Wait(); rfs.Files.IndicateFileToDelete(downloadingFileName, null); rfs.Storage.Batch(accessor => accessor.SetConfigurationValue(RavenFileNameHelper.SyncLockNameForFile(fileName), LockFileTests.SynchronizationConfig(DateTime.UtcNow))); rfs.Files.CleanupDeletedFilesAsync().Wait(); DeleteFileOperation deleteFile = null; rfs.Storage.Batch(accessor => deleteFile = accessor.GetConfigurationValue <DeleteFileOperation>(RavenFileNameHelper.DeleteOperationConfigNameForFile(RavenFileNameHelper.DeletingFileName(downloadingFileName)))); Assert.Equal(RavenFileNameHelper.DeletingFileName(downloadingFileName), deleteFile.CurrentFileName); Assert.Equal(downloadingFileName, deleteFile.OriginalFileName); }
private void StartupProceed(string fileName, IStorageActionsAccessor accessor) { // remove previous SyncResult DeleteSynchronizationReport(fileName, accessor); // remove previous .downloading file StorageOperationsTask.IndicateFileToDelete(RavenFileNameHelper.DownloadingFileName(fileName)); }
private void Prepare() { fs.Storage.Batch(accessor => { // remove previous SyncResult fs.Synchronizations.DeleteSynchronizationReport(fileName, accessor); using (fs.DisableAllTriggersForCurrentThread()) { // remove previous .downloading file fs.Files.IndicateFileToDelete(RavenFileNameHelper.DownloadingFileName(fileName), null); } }); }
public async Task <HttpResponseMessage> MultipartProceed(string fileSystemName) { if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } var fileName = Request.Headers.GetValues(SyncingMultipartConstants.FileName).FirstOrDefault(); var canonicalFilename = FileHeader.Canonize(fileName); var tempFileName = RavenFileNameHelper.DownloadingFileName(canonicalFilename); var sourceServerInfo = ReadInnerHeaders.Value <ServerInfo>(SyncingMultipartConstants.SourceServerInfo); var sourceFileETag = Guid.Parse(GetHeader(Constants.MetadataEtagField).Trim('\"')); var report = new SynchronizationReport(canonicalFilename, sourceFileETag, SynchronizationType.ContentUpdate); Log.Debug("Starting to process multipart synchronization request of a file '{0}' with ETag {1} from {2}", fileName, sourceFileETag, sourceServerInfo); StorageStream localFile = null; var isNewFile = false; var isConflictResolved = false; try { Storage.Batch(accessor => { AssertFileIsNotBeingSynced(canonicalFilename, accessor); FileLockManager.LockByCreatingSyncConfiguration(canonicalFilename, sourceServerInfo, accessor); }); SynchronizationTask.IncomingSynchronizationStarted(canonicalFilename, sourceServerInfo, sourceFileETag, SynchronizationType.ContentUpdate); PublishSynchronizationNotification(fileSystemName, canonicalFilename, sourceServerInfo, report.Type, SynchronizationAction.Start); Storage.Batch(accessor => StartupProceed(canonicalFilename, accessor)); RavenJObject sourceMetadata = GetFilteredMetadataFromHeaders(ReadInnerHeaders); var localMetadata = GetLocalMetadata(canonicalFilename); if (localMetadata != null) { AssertConflictDetection(canonicalFilename, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved); localFile = StorageStream.Reading(Storage, canonicalFilename); } else { isNewFile = true; } Historian.UpdateLastModified(sourceMetadata); var synchronizingFile = SynchronizingFileStream.CreatingOrOpeningAndWriting(Storage, Search, StorageOperationsTask, tempFileName, sourceMetadata); var provider = new MultipartSyncStreamProvider(synchronizingFile, localFile); Log.Debug("Starting to process/read multipart content of a file '{0}'", fileName); await Request.Content.ReadAsMultipartAsync(provider); Log.Debug("Multipart content of a file '{0}' was processed/read", fileName); report.BytesCopied = provider.BytesCopied; report.BytesTransfered = provider.BytesTransfered; report.NeedListLength = provider.NumberOfFileParts; synchronizingFile.PreventUploadComplete = false; synchronizingFile.Flush(); synchronizingFile.Dispose(); sourceMetadata["Content-MD5"] = synchronizingFile.FileHash; Storage.Batch(accessor => accessor.UpdateFileMetadata(tempFileName, sourceMetadata)); Storage.Batch(accessor => { StorageOperationsTask.IndicateFileToDelete(canonicalFilename); accessor.RenameFile(tempFileName, canonicalFilename); Search.Delete(tempFileName); Search.Index(canonicalFilename, sourceMetadata); }); if (isNewFile) { Log.Debug("Temporary downloading file '{0}' was renamed to '{1}'. Indexes were updated.", tempFileName, fileName); } else { Log.Debug("Old file '{0}' was deleted. Indexes were updated.", fileName); } if (isConflictResolved) { ConflictArtifactManager.Delete(canonicalFilename); } } catch (Exception ex) { if (ShouldAddExceptionToReport(ex)) { report.Exception = ex; } } finally { if (localFile != null) { localFile.Dispose(); } } if (report.Exception == null) { Log.Debug( "File '{0}' was synchronized successfully from {1}. {2} bytes were transfered and {3} bytes copied. Need list length was {4}", fileName, sourceServerInfo, report.BytesTransfered, report.BytesCopied, report.NeedListLength); } else { Log.WarnException( string.Format("Error has occurred during synchronization of a file '{0}' from {1}", fileName, sourceServerInfo), report.Exception); } FinishSynchronization(canonicalFilename, report, sourceServerInfo, sourceFileETag); PublishFileNotification(fileName, isNewFile ? FileChangeAction.Add : FileChangeAction.Update); PublishSynchronizationNotification(fileSystemName, fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish); if (isConflictResolved) { Publisher.Publish(new ConflictNotification { FileName = fileName, Status = ConflictStatus.Resolved }); } return(GetMessageWithObject(report)); }
public async Task <SynchronizationReport> Execute() { var report = new SynchronizationReport(fileName, sourceFileEtag, type); try { AssertOperationAndLockFile(); NotifyStart(); Prepare(); var localMetadata = fs.Synchronizations.GetLocalMetadata(fileName); bool conflictResolved; AssertConflictDetection(localMetadata, out conflictResolved); fs.SynchronizationTriggers.Apply(trigger => trigger.BeforeSynchronization(fileName, sourceMetadata, type)); dynamic afterSynchronizationTriggerData = null; switch (type) { case SynchronizationType.Delete: ExecuteDelete(localMetadata); break; case SynchronizationType.Rename: ExecuteRename(Rename); break; case SynchronizationType.MetadataUpdate: ExecuteMetadataUpdate(); break; case SynchronizationType.ContentUpdate: await ExecuteContentUpdate(localMetadata, report).ConfigureAwait(false); afterSynchronizationTriggerData = new { TempFileName = RavenFileNameHelper.DownloadingFileName(fileName) }; break; default: throw new ArgumentOutOfRangeException("type", type.ToString()); } fs.SynchronizationTriggers.Apply(trigger => trigger.AfterSynchronization(fileName, sourceMetadata, type, afterSynchronizationTriggerData)); if (conflictResolved) { fs.ConflictArtifactManager.Delete(fileName); fs.Publisher.Publish(new ConflictNotification { FileName = fileName, Status = ConflictStatus.Resolved }); } } catch (Exception ex) { if (ShouldAddExceptionToReport(ex)) { report.Exception = ex; Log.WarnException(string.Format("Error was occurred during deletion synchronization of file '{0}' from {1}", fileName, sourceFs), ex); } } fs.Synchronizations.FinishSynchronization(fileName, report, sourceFs, sourceFileEtag); NotifyEnd(); return(report); }
private async Task ExecuteContentUpdate(RavenJObject localMetadata, SynchronizationReport report) { var tempFileName = RavenFileNameHelper.DownloadingFileName(fileName); using (var localFile = localMetadata != null ? StorageStream.Reading(fs.Storage, fileName) : null) { fs.PutTriggers.Apply(trigger => trigger.OnPut(tempFileName, sourceMetadata)); fs.Historian.UpdateLastModified(sourceMetadata); var synchronizingFile = SynchronizingFileStream.CreatingOrOpeningAndWriting(fs, tempFileName, sourceMetadata); fs.PutTriggers.Apply(trigger => trigger.AfterPut(tempFileName, null, sourceMetadata)); var provider = new MultipartSyncStreamProvider(synchronizingFile, localFile); if (Log.IsDebugEnabled) { Log.Debug("Starting to process/read multipart content of a file '{0}'", fileName); } await MultipartContent.ReadAsMultipartAsync(provider).ConfigureAwait(false); if (Log.IsDebugEnabled) { Log.Debug("Multipart content of a file '{0}' was processed/read", fileName); } report.BytesCopied = provider.BytesCopied; report.BytesTransfered = provider.BytesTransfered; report.NeedListLength = provider.NumberOfFileParts; synchronizingFile.PreventUploadComplete = false; synchronizingFile.Flush(); synchronizingFile.Dispose(); sourceMetadata["Content-MD5"] = synchronizingFile.FileHash; FileUpdateResult updateResult = null; fs.Storage.Batch(accessor => updateResult = accessor.UpdateFileMetadata(tempFileName, sourceMetadata, null)); fs.Storage.Batch(accessor => { using (fs.DisableAllTriggersForCurrentThread()) { fs.Files.IndicateFileToDelete(fileName, null); } accessor.RenameFile(tempFileName, fileName); fs.Search.Delete(tempFileName); fs.Search.Index(fileName, sourceMetadata, updateResult.Etag); }); if (Log.IsDebugEnabled) { var message = localFile == null ? string.Format("Temporary downloading file '{0}' was renamed to '{1}'. Indexes were updated.", tempFileName, fileName) : string.Format("Old file '{0}' was deleted. Indexes were updated.", fileName); Log.Debug(message); } fs.Publisher.Publish(new FileChangeNotification { File = fileName, Action = localFile == null ? FileChangeAction.Add : FileChangeAction.Update }); } }