PageRenderTime 1ms CodeModel.GetById 2ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/Raven.Database/Bundles/Replication/Responders/DocumentReplicationResponder.cs

https://github.com/nwendel/ravendb
C# | 144 lines | 128 code | 9 blank | 7 comment | 11 complexity | aba7386e1d73dbd969c4f5edecfd9644 MD5 | raw file
  1//-----------------------------------------------------------------------
  2// <copyright file="DocumentReplicationResponder.cs" company="Hibernating Rhinos LTD">
  3//     Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4// </copyright>
  5//-----------------------------------------------------------------------
  6using System;
  7using System.Collections.Generic;
  8using System.ComponentModel.Composition;
  9using System.Linq;
 10using System.Security.Cryptography;
 11using System.Text;
 12using Raven.Abstractions.Logging;
 13using Raven.Abstractions.Util.Encryptors;
 14using Raven.Bundles.Replication.Tasks;
 15using Raven.Database.Server;
 16using Raven.Imports.Newtonsoft.Json.Linq;
 17using Raven.Abstractions.Data;
 18using Raven.Abstractions.Extensions;
 19using Raven.Abstractions.Logging;
 20using Raven.Bundles.Replication.Data;
 21using Raven.Bundles.Replication.Plugins;
 22using Raven.Bundles.Replication.Tasks;
 23using Raven.Database.Extensions;
 24using Raven.Database.Server;
 25using Raven.Database.Server.Abstractions;
 26using Raven.Database.Storage;
 27using Raven.Json.Linq;
 28
 29using System;
 30using System.Collections.Generic;
 31using System.ComponentModel.Composition;
 32using System.Linq;
 33
 34namespace Raven.Bundles.Replication.Responders
 35{
 36	[ExportMetadata("Bundle", "Replication")]
 37	[InheritedExport(typeof(AbstractRequestResponder))]
 38	public class DocumentReplicationResponder : AbstractRequestResponder
 39	{
 40		private readonly ILog log = LogManager.GetCurrentClassLogger();
 41		private ReplicationTask replicationTask;
 42		public ReplicationTask ReplicationTask
 43		{
 44			get { return replicationTask ?? (replicationTask = Database.StartupTasks.OfType<ReplicationTask>().FirstOrDefault()); }
 45		}
 46
 47		[ImportMany]
 48		public IEnumerable<AbstractDocumentReplicationConflictResolver> ReplicationConflictResolvers { get; set; }
 49
 50
 51		public override void Respond(IHttpContext context)
 52		{
 53			var src = context.Request.QueryString["from"];
 54			if (string.IsNullOrEmpty(src))
 55			{
 56				context.SetStatusToBadRequest();
 57				return;
 58			}
 59			while (src.EndsWith("/"))
 60				src = src.Substring(0, src.Length - 1);// remove last /, because that has special meaning for Raven
 61			if (string.IsNullOrEmpty(src))
 62			{
 63				context.SetStatusToBadRequest();
 64				return;
 65			}
 66			var array = context.ReadJsonArray();
 67			if (ReplicationTask != null) 
 68				ReplicationTask.HandleHeartbeat(src);
 69			using (Database.DisableAllTriggersForCurrentThread())
 70			{
 71				Database.TransactionalStorage.Batch(actions =>
 72				{
 73					string lastEtag = Etag.Empty.ToString();
 74					foreach (RavenJObject document in array)
 75					{
 76						var metadata = document.Value<RavenJObject>("@metadata");
 77						if (metadata[Constants.RavenReplicationSource] == null)
 78						{
 79							// not sure why, old document from when the user didn't have replication
 80							// that we suddenly decided to replicate, choose the source for that
 81							metadata[Constants.RavenReplicationSource] = RavenJToken.FromObject(src);
 82						}
 83						lastEtag = metadata.Value<string>("@etag");
 84						var id = metadata.Value<string>("@id");
 85						document.Remove("@metadata");
 86						ReplicateDocument(actions, id, metadata, document, src);
 87					}
 88
 89					var replicationDocKey = Constants.RavenReplicationSourcesBasePath + "/" + src;
 90					var replicationDocument = Database.Get(replicationDocKey, null);
 91					var lastAttachmentId = Etag.Empty;
 92					if (replicationDocument != null)
 93					{
 94						lastAttachmentId =
 95							replicationDocument.DataAsJson.JsonDeserialization<SourceReplicationInformation>().
 96								LastAttachmentEtag;
 97					}
 98					Guid serverInstanceId;
 99					if (Guid.TryParse(context.Request.QueryString["dbid"], out serverInstanceId) == false)
100						serverInstanceId = Database.TransactionalStorage.Id;
101					Database.Put(replicationDocKey, null,
102								 RavenJObject.FromObject(new SourceReplicationInformation
103								 {
104									 Source = src,
105									 LastDocumentEtag = Etag.Parse(lastEtag),
106									 LastAttachmentEtag = lastAttachmentId,
107									 ServerInstanceId = serverInstanceId
108								 }),
109								 new RavenJObject(), null);
110				});
111			}
112		}
113
114		private void ReplicateDocument(IStorageActionsAccessor actions, string id, RavenJObject metadata, RavenJObject document, string src)
115		{
116			try
117			{
118				new DocumentReplicationBehavior
119				{
120					Actions = actions,
121					Database = Database,
122					ReplicationConflictResolvers = ReplicationConflictResolvers,
123					Src = src
124				}.Replicate(id, metadata, document);
125			}
126			catch (Exception ex)
127			{
128				log.ErrorException(
129					string.Format("Exception occurred during the replication of the document {0} from the server {1}", id, src), ex);
130				throw;
131			}
132		}
133
134		public override string UrlPattern
135		{
136			get { return "^/replication/replicateDocs$"; }
137		}
138
139		public override string[] SupportedVerbs
140		{
141			get { return new[] { "POST" }; }
142		}
143	}
144}