Inheritance: Raven.Abstractions.Smuggler.SmugglerApiBase
        public void CanSaveImplicitChangesToDocumentsFromAQuery_UsingDunpFile()
        {
            using (var store = NewDocumentStore())
            {
                store.Conventions.FindTypeTagName = FindTypeByTagName;

                var options = new SmugglerOptions
                {
                    BackupPath = @"Dump of test-concurrency-exception2, 21 May 2013 14-36.ravendump"
                };

                var dumper = new DataDumper(store.DocumentDatabase, options);
                dumper.ImportData(options);

                using (var session = store.OpenSession())
                {
                    session.Advanced.UseOptimisticConcurrency = true;
                    var foos =
                        session.Query<SectionData>()
                               .Customize(x => x.WaitForNonStaleResults())
                               .Take(1024)
                               .ToList();

                    Assert.True(foos.Count > 200);
                    session.SaveChanges();
                }
            }
        }
Example #2
0
		public void MaxNumberOfItemsToProcessInSingleBatchShouldBeRespectedByDataDumper()
		{
			var path = Path.Combine(NewDataPath(forceCreateDir: true), "raven.dump");

			using (var server = GetNewServer(configureConfig: configuration => configuration.MaxNumberOfItemsToProcessInSingleBatch = 1234))
			{
				var dumper = new DataDumper(server.SystemDatabase, options: new SmugglerOptions { BatchSize = 4321 });
				Assert.Equal(4321, dumper.SmugglerOptions.BatchSize);

				dumper.ExportData(new SmugglerExportOptions { ToFile = path }).ResultUnwrap();

				Assert.Equal(1234, dumper.SmugglerOptions.BatchSize);

				dumper = new DataDumper(server.SystemDatabase, options: new SmugglerOptions { BatchSize = 4321 });
				Assert.Equal(4321, dumper.SmugglerOptions.BatchSize);

				dumper.ImportData(new SmugglerImportOptions { FromFile = path }).Wait();

				Assert.Equal(1234, dumper.SmugglerOptions.BatchSize);

				dumper = new DataDumper(server.SystemDatabase, options: new SmugglerOptions { BatchSize = 1000 });
				Assert.Equal(1000, dumper.SmugglerOptions.BatchSize);

				dumper.ExportData(new SmugglerExportOptions { ToFile = path }).ResultUnwrap();

				Assert.Equal(1000, dumper.SmugglerOptions.BatchSize);
			}
		}
Example #3
0
        public async Task CanPerformDump_Dumper()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var store = NewDocumentStore())
            {
                InsertUsers(store, 0, 2000);

                var dumper = new DataDumper(store.DocumentDatabase);
                await dumper.ExportData(new SmugglerExportOptions
                {
                    ToFile = backupPath,
                }, new SmugglerOptions
                {
                    Incremental = true
                });
            }

            VerifyDump(backupPath, store =>
            {
                using (var session = store.OpenSession())
                {
                    Assert.Equal(2000, session.Query<User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).Count());
                }
            });
            IOExtensions.DeleteDirectory(backupPath);
        }
Example #4
0
		public void CanBackupToDirectory()
		{
			var backupPath = NewDataPath("BackupFolder");
			using (var store = NewDocumentStore())
			{
				using (var session = store.OpenSession())
				{
					session.Store(new User { Name = "oren" });
					var periodicBackupSetup = new PeriodicExportSetup
					{
						LocalFolderName = backupPath,
						IntervalMilliseconds = 25
					};
					session.Store(periodicBackupSetup, PeriodicExportSetup.RavenDocumentKey);

					session.SaveChanges();

				}
				SpinWait.SpinUntil(() => store.DatabaseCommands.Get(PeriodicExportStatus.RavenDocumentKey) != null, 10000);

			}

			using (var store = NewDocumentStore())
			{
				var dataDumper = new DataDumper(store.SystemDatabase) {SmugglerOptions = {Incremental = true}};
				dataDumper.ImportData(new SmugglerImportOptions { FromFile = backupPath }).Wait();

				using (var session = store.OpenSession())
				{
					Assert.Equal("oren", session.Load<User>(1).Name);
				}
			}
			IOExtensions.DeleteDirectory(backupPath);
		}
Example #5
0
		public void CanGetCorrectResult()
		{
			using (var store = NewDocumentStore())
			{
				var smugglerOptions = new SmugglerOptions();
				var dataDumper = new DataDumper(store.DocumentDatabase, smugglerOptions);
				using (var stream = typeof(TroyMapReduceImport).Assembly.GetManifestResourceStream("Raven.Tests.Patching.failingdump11.ravendump"))
				{
					dataDumper.ImportData(stream, smugglerOptions).Wait(TimeSpan.FromSeconds(15));
				}

				
				using (var s = store.OpenSession())
				{
					s.Advanced.LuceneQuery<object>("Raven/DocumentsByEntityName").WaitForNonStaleResults().ToList();

					store.DatabaseCommands.UpdateByIndex("Raven/DocumentsByEntityName", new IndexQuery {Query = "Tag:Regions"},
					                                     new ScriptedPatchRequest
					                                     {
						                                     Script = @"this.Test = 'test';"
					                                     }
					                                     , true);
				}
			}
		}
Example #6
0
		public async Task<HttpResponseMessage> ImportDatabase()
		{
			var dataDumper = new DataDumper(Database);
			var importData = dataDumper.ImportData(new SmugglerImportOptions
			{
				FromStream = await InnerRequest.Content.ReadAsStreamAsync()
			}, new SmugglerOptions());
			throw new InvalidOperationException();
		}
Example #7
0
        public void CanFullBackupToDirectory()
        {
            var backupPath = NewDataPath("BackupFolder", forceCreateDir: true);
            try
            {
                using (var store = NewDocumentStore())
                {
                    store.DatabaseCommands.PutAttachment("attach/1", null, new MemoryStream(new byte[] { 1,2,3,4,5 }), new RavenJObject());

                    using (var session = store.OpenSession())
                    {
                        session.Store(new User { Name = "oren" });
                        var periodicBackupSetup = new PeriodicExportSetup
                        {
                            LocalFolderName = backupPath,
                            FullBackupIntervalMilliseconds = 500
                        };
                        session.Store(periodicBackupSetup, PeriodicExportSetup.RavenDocumentKey);

                        session.SaveChanges();
                    }

                    WaitForNextFullBackup(store);
                }
                using (var store = NewDocumentStore())
                {
                    var dataDumper = new DataDumper(store.DocumentDatabase);
                    dataDumper.ImportData(new SmugglerImportOptions
                    {
                        FromFile = Directory.GetFiles(Path.GetFullPath(backupPath))
                          .Where(file => ".ravendb-full-dump".Equals(Path.GetExtension(file), StringComparison.InvariantCultureIgnoreCase))
                          .OrderBy(File.GetLastWriteTimeUtc).First()

                    }, new SmugglerOptions
                    {
                        Incremental = false
                    }).Wait();

                    using (var session = store.OpenSession())
                    {
                        Assert.Equal("oren", session.Load<User>(1).Name);
                        Assert.NotNull(store.DatabaseCommands.GetAttachment("attach/1"));
                    }
                }
            }
            finally
            {
                IOExtensions.DeleteDirectory(backupPath);
            }


        }
		public async Task<HttpResponseMessage> ImportDatabase(int batchSize, bool includeExpiredDocuments, ItemType operateOnTypes, string filtersPipeDelimited, string transformScript)
		{
            if (!this.Request.Content.IsMimeMultipartContent())
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
            }

            var streamProvider = new MultipartMemoryStreamProvider();
            await Request.Content.ReadAsMultipartAsync(streamProvider);
            var fileStream = await streamProvider.Contents
                .First(c => c.Headers.ContentDisposition.Name == "\"file\"")
                .ReadAsStreamAsync();

            var dataDumper = new DataDumper(Database);
            var importOptions = new SmugglerImportOptions
            {
                FromStream = fileStream
            };
            var options = new SmugglerOptions
            {
                BatchSize = batchSize,
                ShouldExcludeExpired = includeExpiredDocuments,
                OperateOnTypes = operateOnTypes,
                TransformScript = transformScript
            };

            // Filters are passed in without the aid of the model binder. Instead, we pass in a list of FilterSettings using a string like this: pathHere;;;valueHere;;;true|||againPathHere;;;anotherValue;;;false
            // Why? Because I don't see a way to pass a list of a values to a WebAPI method that accepts a file upload, outside of passing in a simple string value and parsing it ourselves.
            if (filtersPipeDelimited != null)
            {
                options.Filters.AddRange(filtersPipeDelimited
                    .Split(new string[] { "|||" }, StringSplitOptions.RemoveEmptyEntries)
                    .Select(f => f.Split(new string[] { ";;;" }, StringSplitOptions.RemoveEmptyEntries))
                    .Select(o => new FilterSetting
                    {
                        Path = o[0],
                        Values = new List<string> { o[1] },
                        ShouldMatch = bool.Parse(o[2])
                    }));
            }

            await dataDumper.ImportData(importOptions, options);
            return GetEmptyMessage();
		}
Example #9
0
		public async Task CanGetCorrectResult()
		{
			using (var store = NewDocumentStore())
			{
				var dataDumper = new DataDumper(store.SystemDatabase);
				using (var stream = typeof(TroyMapReduceImport).Assembly.GetManifestResourceStream("Raven.Tests.MailingList.Sandbox.ravendump"))
				{
					await dataDumper.ImportData(new SmugglerImportOptions {FromStream = stream});
				}

				using(var s = store.OpenSession())
				{
					var objects = s.Query<object>("LogEntry/CountByDate")
						.Customize(x => x.WaitForNonStaleResults())
						.ToList();
					Assert.Equal(4, objects.Count);
				}
			}
		}
		public async Task<HttpResponseMessage> ImportDatabase()
		{
            if (!this.Request.Content.IsMimeMultipartContent()) 
            { 
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); 
            }

            var streamProvider = new MultipartMemoryStreamProvider();
            await Request.Content.ReadAsMultipartAsync(streamProvider);
            var fileStream = await streamProvider.Contents.First().ReadAsStreamAsync();
			var dataDumper = new DataDumper(Database);
            var importOptions = new SmugglerImportOptions
			{
                FromStream = fileStream
			};
            var options = new SmugglerOptions();
			await dataDumper.ImportData(importOptions, options);
            return GetEmptyMessage();
		}
Example #11
0
		public void ShouldTakeUnder30Minutes()
		{
			var sw = Stopwatch.StartNew();
			var smugglerOptions = new SmugglerOptions();

			using (var store = NewDocumentStore())
			{
				using (var stream = typeof(LoadBigFile).Assembly.GetManifestResourceStream("Raven.StressTests.Load.LoadBigFile.dump"))
				{
					var dataDumper = new DataDumper(store.DocumentDatabase, smugglerOptions)
					{
						Progress = Console.WriteLine
					};
					dataDumper.ImportData(stream, smugglerOptions);
				}
			}
			sw.Stop();

			Assert.True(sw.Elapsed < TimeSpan.FromMinutes(30), string.Format("Test should run under 30 minutes, but run {0} minutes.", sw.Elapsed.TotalMinutes));
		}
		public void CanBackupToDirectory()
		{
			var backupPath = GetPath("BackupFolder");
			using (var store = NewDocumentStore())
			{
				Etag etagForBackups;
				using (var session = store.OpenSession())
				{
					session.Store(new User { Name = "oren" });
					var periodicBackupSetup = new PeriodicBackupSetup
					{
						LocalFolderName = backupPath,
						IntervalMilliseconds = 25
					};
					session.Store(periodicBackupSetup, PeriodicBackupSetup.RavenDocumentKey);

					session.SaveChanges();

					etagForBackups = session.Advanced.GetEtagFor(periodicBackupSetup);
				}
				SpinWait.SpinUntil(() =>
					 store.DatabaseCommands.Get(PeriodicBackupSetup.RavenDocumentKey).Etag != etagForBackups);

			}

			using (var store = NewDocumentStore())
			{
				var smugglerOptions = new SmugglerOptions
				{
					BackupPath = backupPath
				};
				var dataDumper = new DataDumper(store.DocumentDatabase, smugglerOptions);
				dataDumper.ImportData(smugglerOptions, true);

				using (var session = store.OpenSession())
				{
					Assert.Equal("oren", session.Load<User>(1).Name);
				}
			}
			IOExtensions.DeleteDirectory(backupPath);
		}
Example #13
0
		public void CanGetCorrectResult_esent()
		{
			using (var store = NewDocumentStore(requestedStorage: "esent"))
			{
				var smugglerOptions = new SmugglerOptions();
				var dataDumper = new DataDumper(store.DocumentDatabase, smugglerOptions);
				using (var stream = typeof(TroyMapReduceImport).Assembly.GetManifestResourceStream("Raven.Tests.MailingList.Sandbox.ravendump"))
				{
					dataDumper.ImportData(stream, smugglerOptions).Wait();
				}

				WaitForUserToContinueTheTest(store);
				using (var s = store.OpenSession())
				{
					var objects = s.Query<object>("LogEntry/CountByDate")
						.Customize(x => x.WaitForNonStaleResults())
						.ToList();
					Assert.Equal(4, objects.Count);
				}
			}
		}
Example #14
0
		public async Task<HttpResponseMessage> CreateSampleData()
		{
			var results = Database.Queries.Query(Constants.DocumentsByEntityNameIndex, new IndexQuery(), CancellationToken.None);
			if (results.Results.Count > 0)
			{
				return GetMessageWithString("You cannot create sample data in a database that already contains documents", HttpStatusCode.BadRequest);
			}

			using (var sampleData = typeof(StudioTasksController).Assembly.GetManifestResourceStream("Raven.Database.Server.Assets.EmbeddedData.Northwind.dump"))
			{
				var smugglerOptions = new SmugglerOptions
				{
					OperateOnTypes = ItemType.Documents | ItemType.Indexes | ItemType.Transformers,
					ShouldExcludeExpired = false,
				};
				var dataDumper = new DataDumper(Database);
				await dataDumper.ImportData(new SmugglerImportOptions {FromStream = sampleData}, smugglerOptions);
			}

			return GetEmptyMessage();
		}
Example #15
0
		private void TimerCallback(bool fullBackup)
		{
			if (currentTask != null)
				return;

			// we have shared lock for both incremental and full backup.
			lock (this)
			{
				if (currentTask != null)
					return;
				currentTask = Task.Factory.StartNew(async () =>
				{
					var documentDatabase = Database;
					if (documentDatabase == null)
						return;
					using (LogContext.WithDatabase(documentDatabase.Name))
					{
						try
						{
							var dataDumper = new DataDumper(documentDatabase);
							var localBackupConfigs = exportConfigs;
							var localBackupStatus = exportStatus;
							if (localBackupConfigs == null)
								return;

							if (fullBackup == false)
							{
								var currentEtags = dataDumper.Operations.FetchCurrentMaxEtags();
								// No-op if nothing has changed
								if (currentEtags.LastDocsEtag == localBackupStatus.LastDocsEtag &&
									currentEtags.LastAttachmentsEtag == localBackupStatus.LastAttachmentsEtag &&
									currentEtags.LastDocDeleteEtag == localBackupStatus.LastDocsDeletionEtag &&
									currentEtags.LastAttachmentsDeleteEtag == localBackupStatus.LastAttachmentDeletionEtag)
								{
									return;
								}
							}

							var backupPath = localBackupConfigs.LocalFolderName ??
											 Path.Combine(documentDatabase.Configuration.DataDirectory, "PeriodicExport-Temp");
							if (fullBackup)
							{
								// create filename for full dump
								backupPath = Path.Combine(backupPath, SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture) + ".ravendb-full-dump");
								if (File.Exists(backupPath))
								{
									var counter = 1;
									while (true)
									{
										backupPath = Path.Combine(Path.GetDirectoryName(backupPath), SystemTime.UtcNow.ToString("yyyy-MM-dd-HH-mm", CultureInfo.InvariantCulture) + " - " + counter + ".ravendb-full-dump");

										if (File.Exists(backupPath) == false)
											break;
										counter++;
									}
								}
							}

							var smugglerOptions = dataDumper.SmugglerOptions;
							if (fullBackup == false)
							{
								smugglerOptions.StartDocsEtag = localBackupStatus.LastDocsEtag;
								smugglerOptions.StartAttachmentsEtag = localBackupStatus.LastAttachmentsEtag;
								smugglerOptions.StartDocsDeletionEtag = localBackupStatus.LastDocsDeletionEtag;
								smugglerOptions.StartAttachmentsDeletionEtag = localBackupStatus.LastAttachmentDeletionEtag;
								smugglerOptions.Incremental = true;
								smugglerOptions.ExportDeletions = true;
							}
							var exportResult = await dataDumper.ExportData(new SmugglerExportOptions { ToFile = backupPath });

							if (fullBackup == false)
							{
								// No-op if nothing has changed
								if (exportResult.LastDocsEtag == localBackupStatus.LastDocsEtag &&
									exportResult.LastAttachmentsEtag == localBackupStatus.LastAttachmentsEtag &&
									exportResult.LastDocDeleteEtag == localBackupStatus.LastDocsDeletionEtag &&
									exportResult.LastAttachmentsDeleteEtag == localBackupStatus.LastAttachmentDeletionEtag)
								{
									logger.Info("Periodic export returned prematurely, nothing has changed since last export");
									return;
								}
							}

							try
							{
								if (!localBackupConfigs.Disabled)
								{
									UploadToServer(exportResult.FilePath, localBackupConfigs, fullBackup);
								}
							}
							finally
							{
								// if user did not specify local folder we delete temporary file.
								if (String.IsNullOrEmpty(localBackupConfigs.LocalFolderName))
								{
									IOExtensions.DeleteFile(exportResult.FilePath);
								}
							}

							if (fullBackup)
							{
								localBackupStatus.LastFullBackup = SystemTime.UtcNow;
							}
							else
							{
								localBackupStatus.LastAttachmentsEtag = exportResult.LastAttachmentsEtag;
								localBackupStatus.LastDocsEtag = exportResult.LastDocsEtag;
								localBackupStatus.LastDocsDeletionEtag = exportResult.LastDocDeleteEtag;
								localBackupStatus.LastAttachmentDeletionEtag = exportResult.LastAttachmentsDeleteEtag;
								localBackupStatus.LastBackup = SystemTime.UtcNow;
							}


							var ravenJObject = JsonExtensions.ToJObject(localBackupStatus);
							ravenJObject.Remove("Id");
							var putResult = documentDatabase.Documents.Put(PeriodicExportStatus.RavenDocumentKey, null, ravenJObject,
								new RavenJObject(), null);

							// this result in exportStatus being refreshed
							localBackupStatus = exportStatus;
							if (localBackupStatus != null)
							{
								if (localBackupStatus.LastDocsEtag.IncrementBy(1) == putResult.ETag) // the last etag is with just us
									localBackupStatus.LastDocsEtag = putResult.ETag; // so we can skip it for the next time
							}
						}
						catch (ObjectDisposedException)
						{
							// shutting down, probably
						}
						catch (Exception e)
						{
							logger.ErrorException("Error when performing periodic export", e);
							Database.AddAlert(new Alert
							{
								AlertLevel = AlertLevel.Error,
								CreatedAt = SystemTime.UtcNow,
								Message = e.Message,
								Title = "Error in Periodic Export",
								Exception = e.ToString(),
								UniqueKey = "Periodic Export Error",
							});
						}
					}
				})
				.Unwrap();

				currentTask.ContinueWith(_ =>
				{
					currentTask = null;
				});
			}
		}
		private void TimerCallback(object state)
		{
			if (executing)
				return;
			executing = true;

			PeriodicBackupSetup backupConfigs;
			try
			{
				// Setup doc might be deleted or changed by the user
				var document = Database.Get(PeriodicBackupSetup.RavenDocumentKey, null);
				if (document == null)
				{
					timer.Dispose();
					timer = null;
					return;
				}

				backupConfigs = document.DataAsJson.JsonDeserialization<PeriodicBackupSetup>();
				if (backupConfigs.Interval <= 0)
				{
					timer.Dispose();
					timer = null;
					return;
				}
			}
			catch (Exception ex)
			{
				logger.WarnException(ex.Message, ex);
				executing = false;
				return;
			}

			try
			{
				var options = new SmugglerOptions
				{
					BackupPath = Path.GetTempPath(), //TODO temp path in data folder instead
					LastDocsEtag = backupConfigs.LastDocsEtag,
					LastAttachmentEtag = backupConfigs.LastAttachmentsEtag
				};
				var dd = new DataDumper(Database, options);
				var filePath = dd.ExportData(null, true);
				
				// No-op if nothing has changed
				if (options.LastDocsEtag == backupConfigs.LastDocsEtag && options.LastAttachmentEtag == backupConfigs.LastAttachmentsEtag)
				{
					logger.Info("Periodic backup returned prematurely, nothing has changed since last backup");
					return;
				}

				DoUpload(filePath, backupConfigs);

				// Remember the current position only once we are successful, this allows for compensatory backups
				// in case of failures. We reload the setup document to make sure we don't override changes made by
				// the user.
				// Setup doc might be deleted or changed by the user
				var document = Database.Get(PeriodicBackupSetup.RavenDocumentKey, null);
				if (document == null)
				{
					timer.Dispose();
					timer = null;
					return;
				}

				backupConfigs = document.DataAsJson.JsonDeserialization<PeriodicBackupSetup>();
				backupConfigs.LastAttachmentsEtag = options.LastAttachmentEtag;
				backupConfigs.LastDocsEtag = options.LastDocsEtag;
				Database.Put(PeriodicBackupSetup.RavenDocumentKey, null, RavenJObject.FromObject(backupConfigs),
				             new RavenJObject(), null);

				if (backupConfigs.Interval != interval)
				{
					if (backupConfigs.Interval <= 0)
					{
						timer.Dispose();
						timer = null;
					}
					else
					{
						interval = backupConfigs.Interval;
						timer.Change(TimeSpan.FromMinutes(backupConfigs.Interval), TimeSpan.FromMinutes(backupConfigs.Interval));
					}
				}
			}
			catch (Exception e)
			{
				logger.ErrorException("Error when performing periodic backup", e);
			}
			finally
			{
				executing = false;
			}
		}
Example #17
0
		private void TimerCallback(object state)
		{
			if (currentTask != null)
				return;

			lock (this)
			{
				if (currentTask != null)
					return;
				currentTask = Task.Factory.StartNew(() =>
				{
					using (LogManager.OpenMappedContext("database", Database.Name ?? Constants.SystemDatabase))
					using (new DisposableAction(() => LogContext.DatabaseName.Value = null))
					{
						LogContext.DatabaseName.Value = Database.Name;

						try
						{
							var localBackupConfigs = backupConfigs;
							if (localBackupConfigs == null)
								return;

							var backupPath = localBackupConfigs.LocalFolderName ??
											 Path.Combine(Database.Configuration.DataDirectory, "PeriodicBackup-Temp");
							var options = new SmugglerOptions
							{
								BackupPath = backupPath,
								LastDocsEtag = localBackupConfigs.LastDocsEtag,
								LastAttachmentEtag = localBackupConfigs.LastAttachmentsEtag
							};
							var dd = new DataDumper(Database, options);
							var filePath = dd.ExportData(null, true);

							// No-op if nothing has changed
							if (options.LastDocsEtag == backupConfigs.LastDocsEtag &&
								options.LastAttachmentEtag == backupConfigs.LastAttachmentsEtag)
							{
								logger.Info("Periodic backup returned prematurely, nothing has changed since last backup");
								return;
							}

							UploadToServer(filePath, localBackupConfigs);

							localBackupConfigs.LastAttachmentsEtag = options.LastAttachmentEtag;
							localBackupConfigs.LastDocsEtag = options.LastDocsEtag;
							if (backupConfigs == null) // it was removed by the user?
							{
								localBackupConfigs.IntervalMilliseconds = -1; // this disable the periodic backup
							}
							var ravenJObject = RavenJObject.FromObject(localBackupConfigs);
							ravenJObject.Remove("Id");
							var putResult = Database.Put(PeriodicBackupSetup.RavenDocumentKey, null, ravenJObject,
														 new RavenJObject(), null);
							if (Etag.Increment(localBackupConfigs.LastDocsEtag, 1) == putResult.ETag) // the last etag is with just us
								localBackupConfigs.LastDocsEtag = putResult.ETag; // so we can skip it for the next time
						}
						catch (ObjectDisposedException)
						{
							// shutting down, probably
						}
						catch (Exception e)
						{
							Database.AddAlert(new Alert
							{
								AlertLevel = AlertLevel.Error,
								CreatedAt = SystemTime.UtcNow,
								Message = e.Message,
								Title = "Error in Periodic Backup",
								Exception = e
							});
							logger.ErrorException("Error when performing periodic backup", e);
						}
					}
				})
				.ContinueWith(_ =>
				{
					currentTask = null;
				});
			}
		}
Example #18
0
        public async Task CanDumpAttachmentsEmpty_Dumper()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var store = NewDocumentStore())
            {
	            var dumper = new DataDumper(store.SystemDatabase) {SmugglerOptions = {Incremental = true, BatchSize = 100, Limit = 206}};
                await dumper.ExportData(new SmugglerExportOptions { ToFile = backupPath } );
            }

            VerifyDump(backupPath, store =>
            {
                Assert.Equal(0, store.DatabaseCommands.GetAttachmentHeadersStartingWith("user", 0, 500).Count());
            });
            IOExtensions.DeleteDirectory(backupPath);
        }
Example #19
0
		public void CanBackupToDirectory_MultipleBackups()
		{
			var backupPath = NewDataPath("BackupFolder");
			using (var store = NewDocumentStore())
			{
				using (var session = store.OpenSession())
				{
					session.Store(new User { Name = "oren" });
					var periodicBackupSetup = new PeriodicBackupSetup
					{
						LocalFolderName = backupPath,
						IntervalMilliseconds = 25
					};
					session.Store(periodicBackupSetup, PeriodicBackupSetup.RavenDocumentKey);

					session.SaveChanges();

				}
				SpinWait.SpinUntil(() =>
				{
					var jsonDocument = store.DatabaseCommands.Get(PeriodicBackupStatus.RavenDocumentKey);
					if (jsonDocument == null)
						return false;
					var periodicBackupStatus = jsonDocument.DataAsJson.JsonDeserialization<PeriodicBackupStatus>();
					return periodicBackupStatus.LastDocsEtag != Etag.Empty && periodicBackupStatus.LastDocsEtag != null;
				});

				var etagForBackups= store.DatabaseCommands.Get(PeriodicBackupStatus.RavenDocumentKey).Etag;
				using (var session = store.OpenSession())
				{
					session.Store(new User { Name = "ayende" });
					session.SaveChanges();
				}
				SpinWait.SpinUntil(() =>
					 store.DatabaseCommands.Get(PeriodicBackupStatus.RavenDocumentKey).Etag != etagForBackups);

			}

			using (var store = NewDocumentStore())
			{
			    var dataDumper = new DataDumper(store.DocumentDatabase);
				dataDumper.ImportData(new SmugglerImportOptions
				{
				    FromFile = backupPath,
				}, new SmugglerOptions
				{
					Incremental = true,
				}).Wait();

				using (var session = store.OpenSession())
				{
					Assert.Equal("oren", session.Load<User>(1).Name);
					Assert.Equal("ayende", session.Load<User>(2).Name);
				}
			}
			IOExtensions.DeleteDirectory(backupPath);
		}
        public Task<HttpResponseMessage> ExportDatabase(ExportData smugglerOptionsJson)
		{
            var requestString = smugglerOptionsJson.SmugglerOptions;
	        SmugglerOptions smugglerOptions;
      
            using (var jsonReader = new RavenJsonTextReader(new StringReader(requestString)))
			{
				var serializer = JsonExtensions.CreateDefaultJsonSerializer();
                smugglerOptions = (SmugglerOptions)serializer.Deserialize(jsonReader, typeof(SmugglerOptions));
			}


            var result = GetEmptyMessage();
            
            // create PushStreamContent object that will be called when the output stream will be ready.
			result.Content = new PushStreamContent(async (outputStream, content, arg3) =>
			{
			    try
			    {
				    var dataDumper = new DataDumper(Database, smugglerOptions);
				    await dataDumper.ExportData(
					    new SmugglerExportOptions
					    {
						    ToStream = outputStream
					    }).ConfigureAwait(false);
			    }
			    finally
			    {
			        outputStream.Close();
			    }

				
			});

            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = string.Format("Dump of {0}, {1}.ravendump", this.DatabaseName, DateTime.Now.ToString("yyyy-MM-dd HH-mm", CultureInfo.InvariantCulture))
            };
			
			return new CompletedTask<HttpResponseMessage>(result);
		}
Example #21
0
        public void CanBackupDocumentDeletion()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var store = NewDocumentStore())
            {
                string userId;
                using (var session = store.OpenSession())
                {
                    var periodicBackupSetup = new PeriodicExportSetup
                    {
                        LocalFolderName = backupPath,
                        IntervalMilliseconds = 100
                    };
                    session.Store(periodicBackupSetup, PeriodicExportSetup.RavenDocumentKey);

                    session.SaveChanges();
                }

                var backupStatus = GetPerodicBackupStatus(store.DocumentDatabase);

                using (var session = store.OpenSession())
                {
                    var user = new User { Name = "oren" };
                    session.Store(user);
                    userId = user.Id;
                    session.SaveChanges();
                }

                WaitForPeriodicExport(store.DocumentDatabase, backupStatus);

                store.DatabaseCommands.Delete(userId, null);

                WaitForPeriodicExport(store.DocumentDatabase, backupStatus, x => x.LastDocsDeletionEtag);

            }

            using (var store = NewDocumentStore())
            {
                var dataDumper = new DataDumper(store.DocumentDatabase);
                dataDumper.ImportData(new SmugglerImportOptions
                {
                    FromFile = backupPath,
                }, new SmugglerOptions
                {
                    Incremental = true,
                }).Wait();

                using (var session = store.OpenSession())
                {
                    Assert.Null(session.Load<User>(1));
                }
            }

            IOExtensions.DeleteDirectory(backupPath);
        }
Example #22
0
        private void AssertUsersCountInBackup(int expectedNumberOfUsers, string file)
        {
            using (var store = NewDocumentStore())
            {
                var dataDumper = new DataDumper(store.DocumentDatabase);

                dataDumper.ImportData(new SmugglerImportOptions
                {
                    FromFile = file

                }, new SmugglerOptions
                {
                    Incremental = false
                }).Wait();

                WaitForIndexing(store);

                using (var session = store.OpenSession())
                {
                    Assert.Equal(expectedNumberOfUsers, session.Query<User>().Count());
                }
            }
        }
Example #23
0
        public async Task CanDumpAttachmentsEmpty_Dumper()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var store = NewDocumentStore())
            {
                var options = new SmugglerOptions
                {
                    BackupPath = backupPath,
                    BatchSize = 100,
                    Limit = 206
                };
                var dumper = new DataDumper(store.DocumentDatabase, options);
                var backupStatus = new PeriodicBackupStatus();
                await dumper.ExportData(null, null, true, backupStatus);
            }

            VerifyDump(backupPath, store =>
            {
                Assert.Equal(0, store.DatabaseCommands.GetAttachmentHeadersStartingWith("user", 0, 500).Count());
            });
            IOExtensions.DeleteDirectory(backupPath);
        }
Example #24
0
        public async Task CanDumpWhenHiddenDocsWithLimit_Dumper()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var server = GetNewServer())
            {
                using (var store = new DocumentStore { Url = "http://localhost:8079" }.Initialize())
                {
                    InsertHidenUsers(store, 2000);

                    var user1 = store.DatabaseCommands.Get("users/1");
                    Assert.Null(user1);

                    InsertUsers(store, 1, 25);

                    // now perform full backup
                    var options = new SmugglerOptions
                    {
                        BackupPath = backupPath,
                    };
                    var dumper = new DataDumper(server.Database, options);
                    var backupStatus = new PeriodicBackupStatus();
                    await dumper.ExportData(null, null, true, backupStatus);
                }
            }

            VerifyDump(backupPath, store =>
            {
                using (var session = store.OpenSession())
                {
                    Assert.Equal(25, session.Query<User>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).Count());
                }
            });

            IOExtensions.DeleteDirectory(backupPath);
        }
Example #25
0
        public async Task CanDumpEmptyDatabase_Dumper()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var server = GetNewServer())
            {
                using (new DocumentStore { Url = "http://localhost:8079" }.Initialize())
                {
                    // now perform full backup
                    var options = new SmugglerOptions
                    {
                        BackupPath = backupPath,
                    };
                    var dumper = new DataDumper(server.Database, options);
                    var backupStatus = new PeriodicBackupStatus();
                    await dumper.ExportData(null, null, true, backupStatus);
                }
            }

            VerifyDump(backupPath, store => Assert.Equal(0, store.DocumentDatabase.GetDocuments(0, int.MaxValue, null, CancellationToken.None).Count()));

            IOExtensions.DeleteDirectory(backupPath);
        }
Example #26
0
        private void VerifyDump(string backupPath, Action<EmbeddableDocumentStore> action)
        {
            using (var store = NewDocumentStore())
            {
                var smugglerOptions = new SmugglerOptions
                {
                    BackupPath = backupPath
                };
                var dataDumper = new DataDumper(store.DocumentDatabase, smugglerOptions);
                dataDumper.ImportData(smugglerOptions, true).Wait();

                action(store);
            }
        }
Example #27
0
		private void TimerCallback(object state)
		{
			if (currentTask != null)
				return;

			lock (this)
			{
				if (currentTask != null)
					return;
				currentTask = Task.Factory.StartNew(() =>
				{
					var documentDatabase = Database;
					if (documentDatabase == null)
						return;
					using (LogContext.WithDatabase(documentDatabase.Name))
					{
						try
						{
							var localBackupConfigs = backupConfigs;
							var localBackupStatus = backupStatus;
							if (localBackupConfigs == null)
								return;

							var databaseStatistics = documentDatabase.Statistics;
							// No-op if nothing has changed
							if (databaseStatistics.LastDocEtag == localBackupStatus.LastDocsEtag &&
								databaseStatistics.LastAttachmentEtag == localBackupStatus.LastAttachmentsEtag)
							{
								return;
							}

							var backupPath = localBackupConfigs.LocalFolderName ??
											 Path.Combine(documentDatabase.Configuration.DataDirectory, "PeriodicBackup-Temp");
							var options = new SmugglerOptions
							{
								BackupPath = backupPath,
								LastDocsEtag = localBackupStatus.LastDocsEtag,
								LastAttachmentEtag = localBackupStatus.LastAttachmentsEtag
							};
							var dd = new DataDumper(documentDatabase, options);
							var filePath = dd.ExportData(null, true);

							// No-op if nothing has changed
							if (options.LastDocsEtag == localBackupStatus.LastDocsEtag &&
								options.LastAttachmentEtag == localBackupStatus.LastAttachmentsEtag)
							{
								logger.Info("Periodic backup returned prematurely, nothing has changed since last backup");
								return;
							}

							UploadToServer(filePath, localBackupConfigs);

							localBackupStatus.LastAttachmentsEtag = options.LastAttachmentEtag;
							localBackupStatus.LastDocsEtag = options.LastDocsEtag;

							var ravenJObject = RavenJObject.FromObject(localBackupStatus);
							ravenJObject.Remove("Id");
							var putResult = documentDatabase.Put(PeriodicBackupStatus.RavenDocumentKey, null, ravenJObject,
														 new RavenJObject(), null);

							// this result in backupStatus being refreshed
							localBackupStatus = backupStatus;
							if (localBackupStatus != null)
							{
								if (Etag.Increment(localBackupStatus.LastDocsEtag, 1) == putResult.ETag) // the last etag is with just us
									localBackupStatus.LastDocsEtag = putResult.ETag; // so we can skip it for the next time
							}
						}
						catch (ObjectDisposedException)
						{
							// shutting down, probably
						}
						catch (Exception e)
						{
							logger.ErrorException("Error when performing periodic backup", e);
							Database.AddAlert(new Alert
							{
								AlertLevel = AlertLevel.Error,
								CreatedAt = SystemTime.UtcNow,
								Message = e.Message,
								Title = "Error in Periodic Backup",
								Exception = e.ToString(),
								UniqueKey = "Periodic Backup Error",
							});
						}
					}
				})
				.ContinueWith(_ =>
				{
					currentTask = null;
				});
			}
		}
Example #28
0
        public void CanBackupAttachmentDeletion()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var store = NewDocumentStore())
            {
                string userId;
                using (var session = store.OpenSession())
                {
                    var periodicBackupSetup = new PeriodicExportSetup
                    {
                        LocalFolderName = backupPath,
                        IntervalMilliseconds = 250 
                    };
                    session.Store(periodicBackupSetup, PeriodicExportSetup.RavenDocumentKey);

                    session.SaveChanges();
                }

                var backupStatus = GetPerodicBackupStatus(store.DocumentDatabase);

                store.DatabaseCommands.PutAttachment("attach/1", null, new MemoryStream(new byte[] { 1,2,3,4}), new RavenJObject());

                WaitForPeriodicExport(store.DocumentDatabase, backupStatus);

                store.DatabaseCommands.DeleteAttachment("attach/1", null);

                WaitForPeriodicExport(store.DocumentDatabase, backupStatus);

            }

            using (var store = NewDocumentStore())
            {
                var dataDumper = new DataDumper(store.DocumentDatabase);
                dataDumper.ImportData(new SmugglerImportOptions
                {
                    FromFile = backupPath,
                }, new SmugglerOptions
                {
                    Incremental = true,
                }).Wait();

                Assert.Null(store.DatabaseCommands.GetAttachment("attach/1"));
            }

            IOExtensions.DeleteDirectory(backupPath);
        }
Example #29
0
        public async Task CanPerformDumpWithLimitAndFilter_Dumper()
        {
            var backupPath = NewDataPath("BackupFolder");
            using (var store = NewDocumentStore())
            {
                var counter = 0;
                counter = InsertUsers(store, counter, 1000);
                counter = InsertDevelopers(store, counter, 2);
                counter = InsertUsers(store, counter, 1000);
                InsertDevelopers(store, counter, 2);

                WaitForIndexing(store);

                var options = new SmugglerOptions
                {
                    Limit = 5,
                    BackupPath = backupPath,
                    Filters =
                {
                    new FilterSetting
                    {
                        Path = "@metadata.Raven-Entity-Name",
                        Values = {"Developers"},
                        ShouldMatch = true,
                    }
                }
                };
                var dumper = new DataDumper(store.DocumentDatabase, options);
                var backupStatus = new PeriodicBackupStatus();
                await dumper.ExportData(null, null, true, backupStatus);

            }


            VerifyDump(backupPath, store =>
            {
                using (var session = store.OpenSession())
                {
                    Assert.Equal(4, session.Query<Developer>().Customize(x => x.WaitForNonStaleResultsAsOfNow()).Count());
                }
            });

            IOExtensions.DeleteDirectory(backupPath);
        }
		public async Task<HttpResponseMessage> ImportDatabase(int batchSize, bool includeExpiredDocuments, ItemType operateOnTypes, string filtersPipeDelimited, string transformScript)
		{
			if (!Request.Content.IsMimeMultipartContent())
			{
				throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
			}

			string tempPath = Path.GetTempPath();
			var fullTempPath = tempPath + Constants.TempUploadsDirectoryName;
			if (File.Exists(fullTempPath))
				File.Delete(fullTempPath);
			if (Directory.Exists(fullTempPath) == false)
				Directory.CreateDirectory(fullTempPath);

			var streamProvider = new MultipartFileStreamProvider(fullTempPath);
			await Request.Content.ReadAsMultipartAsync(streamProvider);
			var uploadedFilePath = streamProvider.FileData[0].LocalFileName;
			
			string fileName = null;
			var fileContent = streamProvider.Contents.SingleOrDefault();
			if (fileContent != null)
			{
				fileName = fileContent.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
			}

			var status = new ImportOperationStatus();
			var cts = new CancellationTokenSource();
			
			var task = Task.Run(async () =>
			{
				try
				{
					using (var fileStream = File.Open(uploadedFilePath, FileMode.Open, FileAccess.Read))
					{
						var dataDumper = new DataDumper(Database);
						dataDumper.Progress += s => status.LastProgress = s;
						var smugglerOptions = dataDumper.SmugglerOptions;
						smugglerOptions.BatchSize = batchSize;
						smugglerOptions.ShouldExcludeExpired = !includeExpiredDocuments;
						smugglerOptions.OperateOnTypes = operateOnTypes;
						smugglerOptions.TransformScript = transformScript;
						smugglerOptions.CancelToken = cts;

						// Filters are passed in without the aid of the model binder. Instead, we pass in a list of FilterSettings using a string like this: pathHere;;;valueHere;;;true|||againPathHere;;;anotherValue;;;false
						// Why? Because I don't see a way to pass a list of a values to a WebAPI method that accepts a file upload, outside of passing in a simple string value and parsing it ourselves.
						if (filtersPipeDelimited != null)
						{
							smugglerOptions.Filters.AddRange(filtersPipeDelimited
								.Split(new string[] { "|||" }, StringSplitOptions.RemoveEmptyEntries)
								.Select(f => f.Split(new string[] { ";;;" }, StringSplitOptions.RemoveEmptyEntries))
								.Select(o => new FilterSetting { Path = o[0], Values = new List<string> { o[1] }, ShouldMatch = bool.Parse(o[2]) }));
						}

						await dataDumper.ImportData(new SmugglerImportOptions { FromStream = fileStream });
					}
				}
				catch (Exception e)
				{
				    status.Faulted = true;
				    status.State = RavenJObject.FromObject(new
				                                           {
				                                               Error = e.ToString()
				                                           });
					if (cts.Token.IsCancellationRequested)
					{
                        status.State = RavenJObject.FromObject(new { Error = "Task was cancelled"  });
						cts.Token.ThrowIfCancellationRequested(); //needed for displaying the task status as canceled and not faulted
					}
					throw;
				}
				finally
				{
					status.Completed = true;
					File.Delete(uploadedFilePath);
				}
			}, cts.Token);

			long id;
			Database.Tasks.AddTask(task, status, new TaskActions.PendingTaskDescription
			{
				StartTime = SystemTime.UtcNow,
				TaskType = TaskActions.PendingTaskType.ImportDatabase,
				Payload = fileName,
				
			}, out id, cts);

			return GetMessageWithObject(new
			{
				OperationId = id
			});
		}