コード例 #1
0
		private async Task<SynchronizationReport> PerformSynchronizationAsync(SynchronizationClient destination,
																			  SynchronizationWorkItem work)
		{
			Log.Debug("Starting to perform {0} for a file '{1}' and a destination server {2}", 
                       work.GetType().Name, work.FileName, destination.FileSystemUrl);

			if (!CanSynchronizeTo(destination.FileSystemUrl))
			{
				Log.Debug("The limit of active synchronizations to {0} server has been achieved. Cannot process a file '{1}'.",
						  destination.FileSystemUrl, work.FileName);

				synchronizationQueue.EnqueueSynchronization(destination.FileSystemUrl, work);

				return new SynchronizationReport(work.FileName, work.FileETag, work.SynchronizationType)
				{
					Exception = new SynchronizationException(string.Format(
						"The limit of active synchronizations to {0} server has been achieved. Cannot process a file '{1}'.",
						destination.FileSystemUrl, work.FileName))
				};
			}

			string fileName = work.FileName;
			synchronizationQueue.SynchronizationStarted(work, destination.FileSystemUrl);
			publisher.Publish(new SynchronizationUpdateNotification
			{
				FileName = work.FileName,
                DestinationFileSystemUrl = destination.FileSystemUrl,
				SourceServerId = storage.Id,
				SourceFileSystemUrl = FileSystemUrl,
				Type = work.SynchronizationType,
				Action = SynchronizationAction.Start,
				SynchronizationDirection = SynchronizationDirection.Outgoing
			});

			SynchronizationReport report;

			try
			{
				report = await work.PerformAsync(destination);
			}
			catch (Exception ex)
			{
				report = new SynchronizationReport(work.FileName, work.FileETag, work.SynchronizationType)
				{
					Exception = ex,
				};
			}

			var synchronizationCancelled = false;

			if (report.Exception == null)
			{
				var moreDetails = string.Empty;

				if (work.SynchronizationType == SynchronizationType.ContentUpdate)
				{
					moreDetails = string.Format(". {0} bytes were transfered and {1} bytes copied. Need list length was {2}",
												report.BytesTransfered, report.BytesCopied, report.NeedListLength);
				}

                UpdateSuccessfulSynchronizationTime();

				Log.Debug("{0} to {1} has finished successfully{2}", work.ToString(), destination.FileSystemUrl, moreDetails);
			}
			else
			{
				if (work.IsCancelled || report.Exception is TaskCanceledException)
				{
					synchronizationCancelled = true;
					Log.DebugException(string.Format("{0} to {1} was cancelled", work, destination.FileSystemUrl), report.Exception);
				}
				else
				{
					Log.WarnException(string.Format("{0} to {1} has finished with the exception", work, destination.FileSystemUrl),
									  report.Exception);
				}
			}

			Queue.SynchronizationFinished(work, destination.FileSystemUrl);

			if (!synchronizationCancelled)
				CreateSyncingConfiguration(fileName, work.FileETag, destination.FileSystemUrl, work.SynchronizationType);

			publisher.Publish(new SynchronizationUpdateNotification
			{
				FileName = work.FileName,
                DestinationFileSystemUrl = destination.FileSystemUrl,
				SourceServerId = storage.Id,
				SourceFileSystemUrl = FileSystemUrl,
				Type = work.SynchronizationType,
				Action = SynchronizationAction.Finish,
				SynchronizationDirection = SynchronizationDirection.Outgoing
			});

			return report;
		}
コード例 #2
0
		public async Task<HttpResponseMessage> MultipartProceed()
		{
			if (!Request.Content.IsMimeMultipartContent())
				throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);

			var fileName = Request.Headers.GetValues(SyncingMultipartConstants.FileName).FirstOrDefault();
			var tempFileName = RavenFileNameHelper.DownloadingFileName(fileName);

			var sourceServerInfo = InnerHeaders.Value<ServerInfo>(SyncingMultipartConstants.SourceServerInfo);
			var sourceFileETag = InnerHeaders.Value<Guid>("ETag");

			var report = new SynchronizationReport(fileName, 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(fileName, accessor);
					FileLockManager.LockByCreatingSyncConfiguration(fileName, sourceServerInfo, accessor);
				});

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Start);

				Storage.Batch(accessor => StartupProceed(fileName, accessor));

				NameValueCollection sourceMetadata = InnerHeaders.FilterHeaders();

				var localMetadata = GetLocalMetadata(fileName);

				if (localMetadata != null)
				{
					AssertConflictDetection(fileName, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved);
					localFile = StorageStream.Reading(Storage, fileName);
				}
				else
				{
					isNewFile = true;
				}

				Historian.UpdateLastModified(sourceMetadata);

				var synchronizingFile = SynchronizingFileStream.CreatingOrOpeningAndWritting(Storage, Search, StorageOperationsTask,
																							 tempFileName, sourceMetadata);

				var provider = new MultipartSyncStreamProvider(synchronizingFile, localFile);

				Log.Debug("Starting to process multipart content of a file '{0}'", fileName);

				await Request.Content.ReadAsMultipartAsync(provider);

				Log.Debug("Multipart content of a file '{0}' was processed", fileName);

				report.BytesCopied = provider.BytesCopied;
				report.BytesTransfered = provider.BytesTransfered;
				report.NeedListLength = provider.NumberOfFileParts;

				synchronizingFile.PreventUploadComplete = false;
				synchronizingFile.Dispose();
				sourceMetadata["Content-MD5"] = synchronizingFile.FileHash;

				Storage.Batch(accessor => accessor.UpdateFileMetadata(tempFileName, sourceMetadata));

				Storage.Batch(accessor =>
				{
					StorageOperationsTask.IndicateFileToDelete(fileName);
					accessor.RenameFile(tempFileName, fileName);

					Search.Delete(tempFileName);
					Search.Index(fileName, sourceMetadata);
				});

				if (isNewFile)
				{
					Log.Debug("Temporary downloading file '{0}' was renamed to '{1}'. Indexes was updated.", tempFileName, fileName);
				}
				else
				{
					Log.Debug("Old file '{0}' was deleted. Indexes was updated.", fileName);
				}

				if (isConflictResolved)
				{
					ConflictArtifactManager.Delete(fileName);
					Publisher.Publish(new ConflictResolved { FileName = fileName });
				}
			}
			catch (Exception 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 occured during synchronization of a file '{0}' from {1}", fileName, sourceServerInfo),
					report.Exception);
			}

			FinishSynchronization(fileName, report, sourceServerInfo, sourceFileETag);

			PublishFileNotification(fileName, isNewFile ? FileChangeAction.Add : FileChangeAction.Update);
			PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish);

			return Request.CreateResponse(HttpStatusCode.OK, report);
		}
コード例 #3
0
		private void SaveSynchronizationReport(string fileName, IStorageActionsAccessor accessor, SynchronizationReport report)
		{
			var name = RavenFileNameHelper.SyncResultNameForFile(fileName);
			accessor.SetConfig(name, report.AsConfig());
		}
コード例 #4
0
		public HttpResponseMessage Delete(string fileName)
		{
			var sourceServerInfo = InnerHeaders.Value<ServerInfo>(SyncingMultipartConstants.SourceServerInfo);
			var sourceFileETag = InnerHeaders.Value<Guid>("ETag");

			Log.Debug("Starting to delete a file '{0}' with ETag {1} from {2} because of synchronization", fileName,
					  sourceFileETag, sourceServerInfo);

			var report = new SynchronizationReport(fileName, sourceFileETag, SynchronizationType.Delete);

			try
			{
				Storage.Batch(accessor =>
				{
					AssertFileIsNotBeingSynced(fileName, accessor);
					FileLockManager.LockByCreatingSyncConfiguration(fileName, sourceServerInfo, accessor);
				});

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Start);

				Storage.Batch(accessor => StartupProceed(fileName, accessor));

				var localMetadata = GetLocalMetadata(fileName);

				if (localMetadata != null)
				{
					var sourceMetadata = Request.Headers.FilterHeaders();

					bool isConflictResolved;

					AssertConflictDetection(fileName, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved);

					Storage.Batch(accessor =>
					{
						StorageOperationsTask.IndicateFileToDelete(fileName);

						var tombstoneMetadata = new NameValueCollection
								                                      {
									                                      {
										                                      SynchronizationConstants.RavenSynchronizationHistory,
										                                      localMetadata[SynchronizationConstants.RavenSynchronizationHistory]
									                                      },
									                                      {
										                                      SynchronizationConstants.RavenSynchronizationVersion,
										                                      localMetadata[SynchronizationConstants.RavenSynchronizationVersion]
									                                      },
									                                      {
										                                      SynchronizationConstants.RavenSynchronizationSource,
										                                      localMetadata[SynchronizationConstants.RavenSynchronizationSource]
									                                      }
								                                      }.WithDeleteMarker();

						Historian.UpdateLastModified(tombstoneMetadata);
						accessor.PutFile(fileName, 0, tombstoneMetadata, true);
					});

					PublishFileNotification(fileName, FileChangeAction.Delete);
				}
			}
			catch (Exception ex)
			{
				report.Exception = ex;

				Log.WarnException(
					string.Format("Error was occured during deletion synchronization of file '{0}' from {1}", fileName,
								  sourceServerInfo), ex);
			}
			finally
			{
				FinishSynchronization(fileName, report, sourceServerInfo, sourceFileETag);

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish);
			}

			if (report.Exception == null)
			{
				Log.Debug("File '{0}' was deleted during synchronization from {1}", fileName, sourceServerInfo);
			}

			return Request.CreateResponse(HttpStatusCode.OK, report);
		}
コード例 #5
0
		public HttpResponseMessage Rename(string fileName, string rename)
		{
			var sourceServerInfo = InnerHeaders.Value<ServerInfo>(SyncingMultipartConstants.SourceServerInfo);
			var sourceFileETag = InnerHeaders.Value<Guid>("ETag");
			var sourceMetadata = InnerHeaders.FilterHeaders();

			Log.Debug("Starting to rename a file '{0}' to '{1}' with ETag {2} from {3} because of synchronization", fileName,
					  rename, sourceFileETag, sourceServerInfo);

			var report = new SynchronizationReport(fileName, sourceFileETag, SynchronizationType.Rename);

			try
			{
				Storage.Batch(accessor =>
				{
					AssertFileIsNotBeingSynced(fileName, accessor);
					FileLockManager.LockByCreatingSyncConfiguration(fileName, sourceServerInfo, accessor);
				});

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Start);

				Storage.Batch(accessor => StartupProceed(fileName, accessor));

				var localMetadata = GetLocalMetadata(fileName);

				bool isConflictResolved;

				AssertConflictDetection(fileName, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved);

				StorageOperationsTask.RenameFile(new RenameFileOperation
				{
					Name = fileName,
					Rename = rename,
					MetadataAfterOperation =
						sourceMetadata.WithETag(sourceFileETag).DropRenameMarkers()
				});
			}
			catch (Exception ex)
			{
				report.Exception = ex;
				Log.WarnException(
					string.Format("Error was occured during renaming synchronization of file '{0}' from {1}", fileName,
								  sourceServerInfo), ex);
			}
			finally
			{
				FinishSynchronization(fileName, report, sourceServerInfo, sourceFileETag);

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish);
			}

			if (report.Exception == null)
				Log.Debug("File '{0}' was renamed to '{1}' during synchronization from {2}", fileName, rename, sourceServerInfo);

			return Request.CreateResponse(HttpStatusCode.OK, report);
		}
コード例 #6
0
		public HttpResponseMessage UpdateMetadata(string fileName)
		{
			var sourceServerInfo = InnerHeaders.Value<ServerInfo>(SyncingMultipartConstants.SourceServerInfo);
			var sourceFileETag = InnerHeaders.Value<Guid>("ETag");

			Log.Debug("Starting to update a metadata of file '{0}' with ETag {1} from {2} because of synchronization", fileName,
					  sourceFileETag, sourceServerInfo);

			var report = new SynchronizationReport(fileName, sourceFileETag, SynchronizationType.MetadataUpdate);

			try
			{
				Storage.Batch(accessor =>
				{
					AssertFileIsNotBeingSynced(fileName, accessor);
					FileLockManager.LockByCreatingSyncConfiguration(fileName, sourceServerInfo, accessor);
				});

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Start);

				Storage.Batch(accessor => StartupProceed(fileName, accessor));

				var localMetadata = GetLocalMetadata(fileName);
				var sourceMetadata = InnerHeaders.FilterHeaders();

				bool isConflictResolved;

				AssertConflictDetection(fileName, localMetadata, sourceMetadata, sourceServerInfo, out isConflictResolved);

				Historian.UpdateLastModified(sourceMetadata);

				Storage.Batch(accessor => accessor.UpdateFileMetadata(fileName, sourceMetadata));

				Search.Index(fileName, sourceMetadata);

				if (isConflictResolved)
				{
					ConflictArtifactManager.Delete(fileName);
					Publisher.Publish(new ConflictResolved { FileName = fileName });
				}

				PublishFileNotification(fileName, FileChangeAction.Update);
			}
			catch (Exception ex)
			{
				report.Exception = ex;

				Log.WarnException(
					string.Format("Error was occured during metadata synchronization of file '{0}' from {1}", fileName,
								  sourceServerInfo), ex);
			}
			finally
			{
				FinishSynchronization(fileName, report, sourceServerInfo, sourceFileETag);

				PublishSynchronizationNotification(fileName, sourceServerInfo, report.Type, SynchronizationAction.Finish);
			}

			if (report.Exception == null)
			{
				Log.Debug("Metadata of file '{0}' was synchronized successfully from {1}", fileName, sourceServerInfo);
			}

			return Request.CreateResponse(HttpStatusCode.OK, report);
		}
コード例 #7
0
		private void FinishSynchronization(string fileName, SynchronizationReport report, ServerInfo sourceServer,
										   Guid sourceFileETag)
		{
			try
			{
				// we want to execute those operation in a single batch but we also have to ensure that
				// Raven/Synchronization/Sources/sourceServerId config is modified only by one finishing synchronization at the same time
				SynchronizationFinishLocks.GetOrAdd(sourceServer.Id, new ReaderWriterLockSlim()).EnterWriteLock();

				Storage.Batch(accessor =>
				{
					SaveSynchronizationReport(fileName, accessor, report);
					FileLockManager.UnlockByDeletingSyncConfiguration(fileName, accessor);

					if (report.Exception == null)
					{
						SaveSynchronizationSourceInformation(sourceServer, sourceFileETag, accessor);
					}
				});
			}
			catch (Exception ex)
			{
				Log.ErrorException(
					string.Format("Failed to finish synchronization of a file '{0}' from {1}", fileName, sourceServer), ex);
			}
			finally
			{
				SynchronizationFinishLocks.GetOrAdd(sourceServer.Id, new ReaderWriterLockSlim()).ExitWriteLock();
			}
		}
コード例 #8
0
		private void SaveSynchronizationReport(string fileName, IStorageActionsAccessor accessor, SynchronizationReport report)
		{
			var name = RavenFileNameHelper.SyncResultNameForFile(fileName);
			accessor.SetConfig(name, JsonExtensions.ToJObject(report));
		}
コード例 #9
0
		public async Task Should_report_that_file_is_broken_if_last_synchronization_set_exception()
		{
			var destinationClient = NewClient(0);

			var sampleGuid = Guid.NewGuid();

			var failureSynchronization = new SynchronizationReport("test.bin", sampleGuid, SynchronizationType.Unknown)
				                             {
                                                 Exception = new Exception("There was an exception in last synchronization.")
                                             };

			await destinationClient.Config.SetConfig(RavenFileNameHelper.SyncResultNameForFile("test.bin"), failureSynchronization);

            var confirmations = await destinationClient.Synchronization
                                                       .ConfirmFilesAsync(new List<Tuple<string, Guid>>
					                                                    {
						                                                    new Tuple<string, Guid>(
							                                                    "test.bin", sampleGuid)
					                                                    });
            confirmations = confirmations.ToList();

			Assert.Equal(1, confirmations.Count());
			Assert.Equal(FileStatus.Broken, confirmations.ToArray()[0].Status);
			Assert.Equal("test.bin", confirmations.ToArray()[0].FileName);
		}
コード例 #10
0
		public void Should_report_that_file_is_broken_if_last_synchronization_set_exception()
		{
			var destinationClient = NewClient(0);

			var sampleGuid = Guid.NewGuid();

			var failureSynchronization = new SynchronizationReport("test.bin", sampleGuid, SynchronizationType.Unknown)
				                             {Exception = new Exception("There was an exception in last synchronization.")};

			//var sb = new StringBuilder();
			//var jw = new JsonTextWriter(new StringWriter(sb));
			//new JsonSerializer().Serialize(jw, failureSynchronization);

			//destinationClient.Config.SetConfig(RavenFileNameHelper.SyncResultNameForFile("test.bin"),
			//								   new NameValueCollection() {{"value", sb.ToString()}}).Wait();
			destinationClient.Config.SetConfig(RavenFileNameHelper.SyncResultNameForFile("test.bin"),
			                                   failureSynchronization.AsConfig()).Wait();

			var confirmations =
				destinationClient.Synchronization.ConfirmFilesAsync(new List<Tuple<string, Guid>>
					                                                    {
						                                                    new Tuple<string, Guid>(
							                                                    "test.bin", sampleGuid)
					                                                    }).Result.ToList();

			Assert.Equal(1, confirmations.Count());
			Assert.Equal(FileStatus.Broken, confirmations.ToArray()[0].Status);
			Assert.Equal("test.bin", confirmations.ToArray()[0].FileName);
		}