public void AfterBackupRestore_IndexConsistentWithWritesDuringBackup() { var count = 1; var docId = string.Format("ayende{0}", count++.ToString("D4")); db.Documents.Put(docId, null, RavenJObject.Parse("{'email':'*****@*****.**'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); db.SpinBackgroundWorkers(); QueryResult queryResult; do { queryResult = db.Queries.Query("Raven/DocumentsByEntityName", new IndexQuery { Query = "Tag:[[Users]]", PageSize = 10 }, CancellationToken.None); } while (queryResult.IsStale); Assert.Equal(1, queryResult.Results.Count); var runInserts = true; Task.Run(() => { while (runInserts) { docId = string.Format("ayende{0}", count++.ToString("D4")); db.Documents.Put(docId, null, RavenJObject.Parse("{'email':'*****@*****.**'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); db.IndexStorage.FlushMapIndexes(); } }); db.Maintenance.StartBackup(BackupDir, false, new DatabaseDocument(), new ResourceBackupState()); WaitForBackup(db, true); runInserts = false; db.Dispose(); IOExtensions.DeleteDirectory(DataDir); MaintenanceActions.Restore(new RavenConfiguration(), new DatabaseRestoreRequest { BackupLocation = BackupDir, DatabaseLocation = DataDir, Defrag = true }, s => { }); db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir }, null); docId = string.Format("ayende{0}", count++.ToString("D4")); db.Documents.Put(docId, null, RavenJObject.Parse("{'email':'*****@*****.**'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); db.SpinBackgroundWorkers(); int next = 0; var storedDocs = new List <string>(); while (true) { var batch = db.Documents.GetDocumentsWithIdStartingWith("ayende", null, null, next, 1024, CancellationToken.None, ref next); storedDocs.AddRange(batch.Select(doc => doc.Value <RavenJObject>("@metadata").Value <string>("@id"))); if (batch.Length < 1024) { break; } } List <string> indexedDocs; bool stale; do { indexedDocs = db.Queries.QueryDocumentIds("Raven/DocumentsByEntityName", new IndexQuery { Query = "Tag:[[Users]]", PageSize = int.MaxValue, WaitForNonStaleResultsAsOfNow = true }, new CancellationTokenSource(), out stale).ToList(); } while (stale); if (storedDocs.Count != indexedDocs.Count) { var storedHash = new HashSet <string>(storedDocs); var indexedHash = new HashSet <string>(indexedDocs); foreach (var id in storedDocs.Union(indexedDocs).OrderBy(x => x)) { Debug.WriteLine("{0} Database:{1} Indexed:{2}", id, storedHash.Contains(id), indexedHash.Contains(id)); } } Assert.Equal(storedDocs.Count, indexedDocs.Count()); db.Dispose(); }
public void AfterMultipleIncrementalBackupRestoreCanReadDocument(string storageName) { InitializeDocumentDatabase(storageName); IOExtensions.DeleteDirectory(BackupDir); db.Documents.Put("ayende", null, RavenJObject.Parse("{'email':'*****@*****.**'}"), new RavenJObject(), null); db.Maintenance.StartBackup(BackupDir, false, new DatabaseDocument()); WaitForBackup(db, true); Thread.Sleep(TimeSpan.FromSeconds(1)); db.Documents.Put("itamar", null, RavenJObject.Parse("{'email':'*****@*****.**'}"), new RavenJObject(), null); db.Maintenance.StartBackup(BackupDir, true, new DatabaseDocument()); WaitForBackup(db, true); Thread.Sleep(TimeSpan.FromSeconds(1)); db.Documents.Put("michael", null, RavenJObject.Parse("{'email':'*****@*****.**'}"), new RavenJObject(), null); db.Maintenance.StartBackup(BackupDir, true, new DatabaseDocument()); WaitForBackup(db, true); db.Dispose(); IOExtensions.DeleteDirectory(DataDir); MaintenanceActions.Restore(new RavenConfiguration { DefaultStorageTypeName = storageName, DataDirectory = DataDir, RunInMemory = false, RunInUnreliableYetFastModeThatIsNotSuitableForProduction = false, Settings = { { "Raven/Esent/CircularLog", "false" }, { "Raven/Voron/AllowIncrementalBackups", "true" } } }, new RestoreRequest { BackupLocation = BackupDir, DatabaseLocation = DataDir, Defrag = true }, s => { }); db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir }); var fetchedData = db.Documents.Get("ayende", null); Assert.NotNull(fetchedData); var jObject = fetchedData.ToJson(); Assert.NotNull(jObject); Assert.Equal("*****@*****.**", jObject.Value <string>("email")); fetchedData = db.Documents.Get("itamar", null); Assert.NotNull(fetchedData); jObject = fetchedData.ToJson(); Assert.NotNull(jObject); Assert.Equal("*****@*****.**", jObject.Value <string>("email")); fetchedData = db.Documents.Get("michael", null); Assert.NotNull(fetchedData); jObject = fetchedData.ToJson(); Assert.NotNull(jObject); Assert.Equal("*****@*****.**", jObject.Value <string>("email")); }
public void AfterFailedRestoreOfIndex_ShouldGenerateWarningAndResetIt(string storageName) { using (var db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir, RunInUnreliableYetFastModeThatIsNotSuitableForProduction = false, DefaultStorageTypeName = storageName, Settings = { { Constants.Esent.CircularLog, "false" }, { Constants.Voron.AllowIncrementalBackups, "true" } } }.Initialize(), null)) { db.SpinBackgroundWorkers(); db.Indexes.PutIndex(new RavenDocumentsByEntityName().IndexName, new RavenDocumentsByEntityName().CreateIndexDefinition()); db.Documents.Put("users/1", null, RavenJObject.Parse("{'Name':'Arek'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); db.Documents.Put("users/2", null, RavenJObject.Parse("{'Name':'David'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); WaitForIndexing(db); var databaseDocument = new DatabaseDocument(); db.Maintenance.StartBackup(BackupDir, false, databaseDocument, new ResourceBackupState()); WaitForBackup(db, true); db.Documents.Put("users/3", null, RavenJObject.Parse("{'Name':'Daniel'}"), RavenJObject.Parse("{'Raven-Entity-Name':'Users'}"), null); WaitForIndexing(db); db.Maintenance.StartBackup(BackupDir, true, databaseDocument, new ResourceBackupState()); WaitForBackup(db, true); } IOExtensions.DeleteDirectory(DataDir); var incrementalDirectories = Directory.GetDirectories(BackupDir, "Inc*"); // delete 'index-files.required-for-index-restore' to make backup corrupted according to the reported error var combine = Directory.GetFiles(incrementalDirectories.First(), "index-files.required-for-index-restore", SearchOption.AllDirectories).First(); File.Delete(combine); var sb = new StringBuilder(); MaintenanceActions.Restore(new RavenConfiguration(), new DatabaseRestoreRequest { BackupLocation = BackupDir, DatabaseLocation = DataDir }, s => sb.Append(s)); Assert.Contains( "could not be restored. All already copied index files was deleted." + " Index will be recreated after launching Raven instance", sb.ToString()); using (var db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir }, null)) { db.SpinBackgroundWorkers(); QueryResult queryResult; do { queryResult = db.Queries.Query("Raven/DocumentsByEntityName", new IndexQuery { Query = "Tag:[[Users]]", PageSize = 10 }, CancellationToken.None); } while (queryResult.IsStale); Assert.Equal(3, queryResult.Results.Count); } }
public void AfterRestoreOfIncrementalBackupAllIndexesShouldWork() { using (var store = NewDocumentStore(requestedStorage: "esent")) { new Users_ByName().Execute(store); using (var session = store.OpenSession()) { session.Store(new User { Name = "Arek", Country = "Poland" }); session.SaveChanges(); } WaitForIndexing(store); store.SystemDatabase.Maintenance.StartBackup(BackupDir, true, new DatabaseDocument(), new ResourceBackupState()); WaitForBackup(store.SystemDatabase, true); Thread.Sleep(1000); // incremental tag has seconds precision using (var session = store.OpenSession()) { session.Store(new User { Name = "Ramon", Country = "Spain" }); session.SaveChanges(); } WaitForIndexing(store); store.SystemDatabase.Maintenance.StartBackup(BackupDir, true, new DatabaseDocument(), new ResourceBackupState()); WaitForBackup(store.SystemDatabase, true); Thread.Sleep(1000); // incremental tag has seconds precision new Users_ByNameAndCountry().Execute(store); WaitForIndexing(store); store.SystemDatabase.Maintenance.StartBackup(BackupDir, true, new DatabaseDocument(), new ResourceBackupState()); WaitForBackup(store.SystemDatabase, true); var output = new StringBuilder(); MaintenanceActions.Restore(new RavenConfiguration { Settings = { { Constants.Esent.CircularLog, "false" }, { Constants.Voron.AllowIncrementalBackups, "true" } } }, new DatabaseRestoreRequest { BackupLocation = BackupDir, Defrag = true, DatabaseLocation = DataDir }, s => output.Append(s)); Assert.DoesNotContain("error", output.ToString().ToLower()); using (var db = new DocumentDatabase(new RavenConfiguration { DataDirectory = DataDir, Settings = { { Constants.Esent.CircularLog, "false" } } }, null)) { var indexStats = db.Statistics.Indexes; Assert.Equal(3, indexStats.Length); // Users/* and Raven/DocumentsByEntityName QueryResult docs = db.Queries.Query("Users/ByName", new IndexQuery { Query = "Name:*", Start = 0, PageSize = 10 }, CancellationToken.None); Assert.Equal(2, docs.Results.Count); docs = db.Queries.Query("Users/ByNameAndCountry", new IndexQuery { Query = "Name:*", Start = 0, PageSize = 10 }, CancellationToken.None); Assert.Equal(2, docs.Results.Count); } } }
public async Task <HttpResponseMessage> Restore() { if (EnsureSystemDatabase() == false) { return(GetMessageWithString("Restore is only possible from the system database", HttpStatusCode.BadRequest)); } var restoreStatus = new RestoreStatus { Messages = new List <string>() }; var restoreRequest = await ReadJsonObjectAsync <RestoreRequest>(); DatabaseDocument databaseDocument = null; var databaseDocumentPath = Path.Combine(restoreRequest.BackupLocation, "Database.Document"); if (File.Exists(databaseDocumentPath)) { var databaseDocumentText = File.ReadAllText(databaseDocumentPath); databaseDocument = RavenJObject.Parse(databaseDocumentText).JsonDeserialization <DatabaseDocument>(); } var databaseName = !string.IsNullOrWhiteSpace(restoreRequest.DatabaseName) ? restoreRequest.DatabaseName : databaseDocument == null ? null : databaseDocument.Id; if (string.IsNullOrWhiteSpace(databaseName)) { var errorMessage = (databaseDocument == null || String.IsNullOrWhiteSpace(databaseDocument.Id)) ? "Database.Document file is invalid - database name was not found and not supplied in the request (Id property is missing or null). This is probably a bug - should never happen." : "A database name must be supplied if the restore location does not contain a valid Database.Document file"; restoreStatus.Messages.Add(errorMessage); DatabasesLandlord.SystemDatabase.Documents.Put(RestoreStatus.RavenRestoreStatusDocumentKey, null, RavenJObject.FromObject(new { restoreStatus }), new RavenJObject(), null); return(GetMessageWithString(errorMessage, HttpStatusCode.BadRequest)); } if (databaseName == Constants.SystemDatabase) { return(GetMessageWithString("Cannot do an online restore for the <system> database", HttpStatusCode.BadRequest)); } var existingDatabase = Database.Documents.GetDocumentMetadata("Raven/Databases/" + databaseName, null); if (existingDatabase != null) { return(GetMessageWithString("Cannot do an online restore for an existing database, delete the database " + databaseName + " and restore again.", HttpStatusCode.BadRequest)); } var ravenConfiguration = new RavenConfiguration { DatabaseName = databaseName, IsTenantDatabase = true }; if (databaseDocument != null) { foreach (var setting in databaseDocument.Settings) { ravenConfiguration.Settings[setting.Key] = setting.Value; } } if (File.Exists(Path.Combine(restoreRequest.BackupLocation, BackupMethods.Filename))) { ravenConfiguration.DefaultStorageTypeName = typeof(Raven.Storage.Voron.TransactionalStorage).AssemblyQualifiedName; } else if (Directory.Exists(Path.Combine(restoreRequest.BackupLocation, "new"))) { ravenConfiguration.DefaultStorageTypeName = typeof(Raven.Storage.Esent.TransactionalStorage).AssemblyQualifiedName; } ravenConfiguration.CustomizeValuesForTenant(databaseName); ravenConfiguration.Initialize(); string documentDataDir; ravenConfiguration.DataDirectory = ResolveTenantDataDirectory(restoreRequest.DatabaseLocation, databaseName, out documentDataDir); restoreRequest.DatabaseLocation = ravenConfiguration.DataDirectory; DatabasesLandlord.SystemDatabase.Documents.Delete(RestoreStatus.RavenRestoreStatusDocumentKey, null, null); bool defrag; if (bool.TryParse(GetQueryStringValue("defrag"), out defrag)) { restoreRequest.Defrag = defrag; } var task = Task.Factory.StartNew(() => { MaintenanceActions.Restore(ravenConfiguration, restoreRequest, msg => { restoreStatus.Messages.Add(msg); DatabasesLandlord.SystemDatabase.Documents.Put(RestoreStatus.RavenRestoreStatusDocumentKey, null, RavenJObject.FromObject(restoreStatus), new RavenJObject(), null); }); if (databaseDocument == null) { return; } databaseDocument.Settings[Constants.RavenDataDir] = documentDataDir; if (restoreRequest.IndexesLocation != null) { databaseDocument.Settings[Constants.RavenIndexPath] = restoreRequest.IndexesLocation; } if (restoreRequest.JournalsLocation != null) { databaseDocument.Settings[Constants.RavenTxJournalPath] = restoreRequest.JournalsLocation; } databaseDocument.Id = databaseName; DatabasesLandlord.Protect(databaseDocument); DatabasesLandlord.SystemDatabase.Documents.Put("Raven/Databases/" + databaseName, null, RavenJObject.FromObject(databaseDocument), new RavenJObject(), null); restoreStatus.Messages.Add("The new database was created"); DatabasesLandlord.SystemDatabase.Documents.Put(RestoreStatus.RavenRestoreStatusDocumentKey, null, RavenJObject.FromObject(restoreStatus), new RavenJObject(), null); }, TaskCreationOptions.LongRunning); long id; Database.Tasks.AddTask(task, new object(), new TaskActions.PendingTaskDescription { StartTime = SystemTime.UtcNow, TaskType = TaskActions.PendingTaskType.RestoreDatabase, Payload = "Restoring database " + databaseName + " from " + restoreRequest.BackupLocation }, out id); return(GetMessageWithObject(new { OperationId = id })); }