public SynchronizationMultipartRequest(IAsyncFilesSynchronizationCommands destination, ServerInfo serverInfo, string fileName,
                                               RavenJObject sourceMetadata, Stream sourceStream, IList<RdcNeed> needList)
		{
			this.destination = destination;
			this.serverInfo = serverInfo;
			this.fileName = fileName;
			this.sourceMetadata = sourceMetadata;
			this.sourceStream = sourceStream;
			this.needList = needList;
			syncingBoundary = "syncing";
		}
예제 #2
0
		public void LockByCreatingSyncConfiguration(string fileName, ServerInfo sourceServer, IStorageActionsAccessor accessor)
		{
			var syncLock = new SynchronizationLock
			{
				SourceServer = sourceServer,
				FileLockedAt = DateTime.UtcNow
			};

            accessor.SetConfig(RavenFileNameHelper.SyncLockNameForFile(fileName), JsonExtensions.ToJObject(syncLock));

            log.Debug("File '{0}' was locked", fileName);
		}
		protected SynchronizationWorkItem(string fileName, string sourceServerUrl, ITransactionalStorage storage)
		{
			Storage = storage;
            FileName = fileName;

			FileAndPagesInformation fileAndPages = null;
			Storage.Batch(accessor => fileAndPages = accessor.GetFile(fileName, 0, 0));
			FileMetadata = fileAndPages.Metadata;
			ServerInfo = new ServerInfo
			{
				Id = Storage.Id,
				FileSystemUrl = sourceServerUrl
			};

			conflictDetector = new ConflictDetector();
			conflictResolver = new ConflictResolver(null, null);
		}
예제 #4
0
        public void IncomingSynchronizationStarted(string fileName, ServerInfo sourceServerInfo, Guid sourceFileETag, SynchronizationType type)
        {
            var activeForDestination = activeIncomingSynchronizations.GetOrAdd(sourceServerInfo.FileSystemUrl,
                                                       new ConcurrentDictionary<string, SynchronizationDetails>());

            var syncDetails = new SynchronizationDetails()
            {
                DestinationUrl = sourceServerInfo.FileSystemUrl,
                FileETag = sourceFileETag,
                FileName = fileName,
                Type = type
            };

            if (activeForDestination.TryAdd(fileName, syncDetails))
            {
                Log.Debug("File '{0}' with ETag {1} was added to an incoming active synchronization queue for a destination {2}",
                          fileName,
                          sourceFileETag, sourceServerInfo.FileSystemUrl);
            }
        }
예제 #5
0
        public void IncomingSynchronizationFinished(string fileName, ServerInfo sourceServerInfo, Guid sourceFileETag)
        {
            ConcurrentDictionary<string, SynchronizationDetails> activeSourceTasks;

            if (activeIncomingSynchronizations.TryGetValue(sourceServerInfo.FileSystemUrl, out activeSourceTasks) == false)
            {
                Log.Warn("Could not get an active synchronization queue for {0}", sourceServerInfo.FileSystemUrl);
                return;
            }

            SynchronizationDetails removingItem;
            if (activeSourceTasks.TryRemove(fileName, out removingItem))
            {
                Log.Debug("File '{0}' with ETag {1} was removed from an active synchronization queue for a destination {2}",
                          fileName, sourceFileETag, sourceServerInfo);
            }
        }
		private void SaveSynchronizationSourceInformation(ServerInfo sourceServer, Guid lastSourceEtag, IStorageActionsAccessor accessor)
		{
			var lastSynchronizationInformation = GetLastSynchronization(sourceServer.Id, accessor);
			if (Buffers.Compare(lastSynchronizationInformation.LastSourceFileEtag.ToByteArray(), lastSourceEtag.ToByteArray()) > 0)
			{
				return;
			}

			var synchronizationSourceInfo = new SourceSynchronizationInformation
			{
				LastSourceFileEtag = lastSourceEtag,
				SourceServerUrl = sourceServer.FileSystemUrl,
				DestinationServerId = Storage.Id
			};

			var key = SynchronizationConstants.RavenSynchronizationSourcesBasePath + "/" + sourceServer.Id;

			accessor.SetConfig(key, JsonExtensions.ToJObject(synchronizationSourceInfo));

			Log.Debug("Saved last synchronized file ETag {0} from {1} ({2})", lastSourceEtag, sourceServer.FileSystemUrl, sourceServer.Id);
		}
		private void PublishSynchronizationNotification(string fileSystemName, string fileName, ServerInfo sourceServer, SynchronizationType type, SynchronizationAction action)
		{
			Publisher.Publish(new SynchronizationUpdateNotification
			{
				FileName = fileName,
				SourceFileSystemUrl = sourceServer.FileSystemUrl,
				SourceServerId = sourceServer.Id,
				Type = type,
				Action = action,
				Direction = SynchronizationDirection.Incoming
			});
		}
        private void AssertConflictDetection(string fileName, RavenJObject localMetadata, RavenJObject sourceMetadata, ServerInfo sourceServer, out bool isConflictResolved)
		{
			var conflict = ConflictDetector.Check(fileName, localMetadata, sourceMetadata, sourceServer.FileSystemUrl);
	        if (conflict == null)
	        {
		        isConflictResolved = false;
		        return;
	        }

			isConflictResolved = ConflictResolver.CheckIfResolvedByRemoteStrategy(localMetadata, conflict);

			if(isConflictResolved)
				return;

			ConflictResolutionStrategy strategy;
			if (ConflictResolver.TryResolveConflict(fileName, conflict, localMetadata, sourceMetadata, out strategy))
			{
				switch (strategy)
				{
					case ConflictResolutionStrategy.RemoteVersion:
						Log.Debug("Conflict automatically resolved by choosing remote version of the file {0}", fileName);
						return;
					case ConflictResolutionStrategy.CurrentVersion:

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

							ConflictArtifactManager.Delete(fileName, accessor);
						});

						Log.Debug("Conflict automatically resolved by choosing current version of the file {0}", fileName);

						throw new ConflictResolvedInFavourOfCurrentVersion();
				}
			}

			ConflictArtifactManager.Create(fileName, conflict);

			Publisher.Publish(new ConflictNotification
			{
				FileName = fileName,
				SourceServerUrl = sourceServer.FileSystemUrl,
				Status = ConflictStatus.Detected,
				RemoteFileHeader = new FileHeader(fileName, localMetadata)
			});

			Log.Debug(
				"File '{0}' is in conflict with synchronized version from {1} ({2}). File marked as conflicted, conflict configuration item created",
				fileName, sourceServer.FileSystemUrl, sourceServer.Id);

			throw new SynchronizationException(string.Format("File {0} is conflicted", fileName));
		}
		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();
                SynchronizationTask.IncomingSynchronizationFinished(fileName, sourceServer, sourceFileETag);

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