public SynchronizationMultipartRequest(RavenFileSystemClient.SynchronizationClient 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";
		}
		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;

			FileAndPages 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();
		}
		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, synchronizationSourceInfo.AsConfig());

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

			if (conflict != null && !isConflictResolved)
			{
				ConflictArtifactManager.Create(fileName, conflict);

				Publisher.Publish(new ConflictDetected
				{
					FileName = fileName,
					SourceServerUrl = sourceServer.FileSystemUrl
				});

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

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