protected SynchronizationWorkItem(string fileName, string sourceServerUrl, TransactionalStorage 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,
					             Url = sourceServerUrl
				             };

			conflictDetector = new ConflictDetector();
			conflictResolver = new ConflictResolver();
		}
		private void SaveSynchronizationSourceInformation(ServerInfo sourceServer, Guid lastSourceEtag,
		                                                  StorageActionsAccessor 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.Url,
					                                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.Url, sourceServer.Id);
		}
		private void PublishSynchronizationNotification(string fileName, ServerInfo sourceServer, SynchronizationType type,
		                                                SynchronizationAction action)
		{
			Publisher.Publish(new SynchronizationUpdate
				                  {
					                  FileName = fileName,
					                  SourceServerUrl = sourceServer.Url,
					                  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.Url);
			isConflictResolved = ConflictResolver.IsResolved(localMetadata, conflict);

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

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

				Log.Debug(
					"File '{0}' is in conflict with synchronized version from {1} ({2}). File marked as conflicted, conflict configuration item created",
					fileName, sourceServer.Url, 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();
			}
		}