示例#1
0
        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"));
        }
示例#3
0
        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);
            }
        }
示例#4
0
        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);
                }
            }
        }
示例#5
0
        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
            }));
        }