public async Task incremental_and_full_backup_encrypted_db_and_restore_to_encrypted_DB_with_provided_key() { var defaultS3Settings = GetS3Settings(); var key = EncryptedServer(out var certificates, out string dbName); using (var store = GetDocumentStore(new Options { AdminCertificate = certificates.ServerCertificate.Value, ClientCertificate = certificates.ServerCertificate.Value, ModifyDatabaseName = s => dbName, ModifyDatabaseRecord = record => record.Encrypted = true, Path = NewDataPath() })) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 */6 * * *", BackupEncryptionSettings = new BackupEncryptionSettings { Key = "OI7Vll7DroXdUORtc6Uo64wdAk1W0Db9ExXXgcg5IUs=", EncryptionMode = EncryptionMode.UseProvidedKey } }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return getPeriodicBackupResult.Status?.LastEtag; }, 1); Assert.Equal(1, value); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.StoreAsync(new User { Name = "ayende" }, "users/3"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); var backupStatus = store.Maintenance.Send(operation); var databaseName = $"restored_database-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(backupStatus.Status.FolderName); using (RestoreDatabaseFromCloud(store, new RestoreFromS3Configuration { Settings = subfolderS3Settings, DatabaseName = databaseName, EncryptionKey = "OI7Vll7DroXdUORtc6Uo64wdAk1W0Db9ExXXgcg5IUs=", BackupEncryptionSettings = new BackupEncryptionSettings { Key = "OI7Vll7DroXdUORtc6Uo64wdAk1W0Db9ExXXgcg5IUs=", EncryptionMode = EncryptionMode.UseProvidedKey } })) { using (var session = store.OpenSession(databaseName)) { var users = session.Load<User>("users/1"); Assert.NotNull(users); users = session.Load<User>("users/2"); Assert.NotNull(users); } } } }
public async Task can_backup_to_directory_multiple_backups_with_long_interval() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { var periodicBackupRunner = (await GetDocumentDatabaseInstanceFor(store)).PeriodicBackupRunner; // get by reflection the maxTimerTimeoutInMilliseconds field // this field is the maximum interval acceptable in .Net's threading timer // if the requested backup interval is bigger than this maximum interval, // a timer with maximum interval will be used several times until the interval cumulatively // will be equal to requested interval typeof(PeriodicBackupRunner) .GetField(nameof(PeriodicBackupRunner.MaxTimerTimeout), BindingFlags.Instance | BindingFlags.Public) .SetValue(periodicBackupRunner, TimeSpan.FromMilliseconds(100)); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); var etagForBackups = store.Maintenance.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromSeconds(15)); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); using (var session = store.OpenAsyncSession()) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); } } }
protected async Task incremental_and_full_backup_encrypted_db_and_restore_to_encrypted_DB_with_database_key_internal() { var defaultS3Settings = GetS3Settings(); var key = EncryptedServer(out var certificates, out string dbName); using (var store = GetDocumentStore(new Options { AdminCertificate = certificates.ServerCertificate.Value, ClientCertificate = certificates.ServerCertificate.Value, ModifyDatabaseName = s => dbName, ModifyDatabaseRecord = record => record.Encrypted = true, Path = NewDataPath() })) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 */6 * * *", BackupEncryptionSettings = new BackupEncryptionSettings { EncryptionMode = EncryptionMode.UseDatabaseKey } }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); PeriodicBackupStatus backupStatus = null; var value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: 1, timeout: 30_000); Assert.True(1 == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.StoreAsync(new User { Name = "ayende" }, "users/3"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: lastEtag, timeout: 30_000); Assert.True(lastEtag == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); var databaseName = $"restored_database-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(backupStatus.FolderName); using (RestoreDatabaseFromCloud(store, new RestoreFromS3Configuration { Settings = subfolderS3Settings, DatabaseName = databaseName, BackupEncryptionSettings = new BackupEncryptionSettings { Key = key, EncryptionMode = EncryptionMode.UseProvidedKey } })) { using (var session = store.OpenSession(databaseName)) { var users = session.Load <User>("users/1"); Assert.NotNull(users); users = session.Load <User>("users/2"); Assert.NotNull(users); } } } }
public async Task CanImportTombstonesFromIncrementalBackup() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "fitzchak" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); Assert.True(SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15))); var etagForBackups = store.Maintenance.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { session.Delete("users/1"); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); Assert.True(SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromSeconds(15))); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); using (var session = store.OpenAsyncSession()) { var user = await session.LoadAsync <User>("users/1"); Assert.Null(user); } } }
public async Task can_backup_and_restore_snapshot() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } using (var session = store.OpenAsyncSession()) { await session .Query <User>() .Where(x => x.Name == "oren") .ToListAsync(); // create an index to backup await session .Query <User>() .Where(x => x.Age > 20) .ToListAsync(); // create an index to backup } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); var etagForBackups = store.Maintenance.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.StoreAsync(new User { Name = "ayende" }, "users/3"); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromSeconds(15)); // restore the database with a different name string restoredDatabaseName = $"restored_database_snapshot-{Guid.NewGuid()}"; using (RestoreDatabase(store, new RestoreBackupConfiguration { BackupLocation = Directory.GetDirectories(backupPath).First(), DatabaseName = restoredDatabaseName })) { using (var session = store.OpenAsyncSession(restoredDatabaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.NotNull(users["users/1"]); Assert.NotNull(users["users/2"]); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); } var stats = await store.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(2, stats.CountOfIndexes); } } }
public async Task periodic_backup_should_export_starting_from_last_etag() { //http://issues.hibernatingrhinos.com/issue/RavenDB-11395 var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.StoreAsync(new User { Name = "aviv" }, "users/2"); session.CountersFor("users/1").Increment("likes", 100); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); var exportPath = GetBackupPath(store, backupTaskId, incremental: false); using (var store2 = GetDocumentStore()) { await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), exportPath); var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(2, stats.CountOfDocuments); Assert.Equal(2, stats.CountOfCounters); using (var session = store2.OpenAsyncSession()) { var user1 = await session.LoadAsync <User>("users/1"); var user2 = await session.LoadAsync <User>("users/2"); Assert.Equal("oren", user1.Name); Assert.Equal("aviv", user2.Name); var dic = await session.CountersFor(user1).GetAllAsync(); Assert.Equal(1, dic.Count); Assert.Equal(100, dic["likes"]); dic = await session.CountersFor(user2).GetAllAsync(); Assert.Equal(1, dic.Count); Assert.Equal(200, dic["downloads"]); } } var etagForBackups = store.Maintenance.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/3"); session.CountersFor("users/3").Increment("votes", 300); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromSeconds(15)); exportPath = GetBackupPath(store, backupTaskId); using (var store3 = GetDocumentStore()) { // importing to a new database, in order to verify that // periodic backup imports only the changed documents (and counters) await store3.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), exportPath); var stats = await store3.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(1, stats.CountOfDocuments); Assert.Equal(1, stats.CountOfCounters); using (var session = store3.OpenAsyncSession()) { var user3 = await session.LoadAsync <User>("users/3"); Assert.Equal("ayende", user3.Name); var dic = await session.CountersFor(user3).GetAllAsync(); Assert.Equal(1, dic.Count); Assert.Equal(300, dic["votes"]); } } } }
public async Task ExportFullThanDeleteAttachmentAndCreateAnotherOneThanExportIncrementalThanImport() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_store1" })) { using (var session = store.OpenSession()) { session.Store(new User { Name = "Fitzchak" }, "users/1"); session.SaveChanges(); } using (var stream = new MemoryStream(new byte[] { 1, 2, 3 })) store.Operations.Send(new PutAttachmentOperation("users/1", "file1", stream, "image/png")); var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); var etagForBackups = store.Maintenance.Send(operation).Status.LastEtag; store.Operations.Send(new DeleteAttachmentOperation("users/1", "file1")); using (var stream = new MemoryStream(new byte[] { 4, 5, 6 })) store.Operations.Send(new PutAttachmentOperation("users/1", "file2", stream, "image/png")); await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); var stats = await store.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(1, stats.CountOfDocuments); Assert.Equal(1, stats.CountOfAttachments); Assert.Equal(1, stats.CountOfUniqueAttachments); SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromMinutes(2)); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_store2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); var stats = await store.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(1, stats.CountOfDocuments); Assert.Equal(1, stats.CountOfAttachments); Assert.Equal(1, stats.CountOfUniqueAttachments); using (var session = store.OpenSession()) { var user = session.Load <User>("users/1"); var metadata = session.Advanced.GetMetadataFor(user); Assert.Equal(DocumentFlags.HasAttachments.ToString(), metadata[Constants.Documents.Metadata.Flags]); var attachment = metadata.GetObjects(Constants.Documents.Metadata.Attachments).Single(); Assert.Equal("file2", attachment.GetString(nameof(AttachmentName.Name))); } } }
static async Task MainInternal() { using (var docStore = new DocumentStore { Urls = new[] { "http://127.0.0.1:8080" }, Database = "Products" }.Initialize()) { #region logical_full_backup_every_3_hours var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { //Backup files local path FolderPath = @"E:\RavenBackups" }, //Full Backup period (Cron expression for a 3-hours period) FullBackupFrequency = "0 */3 * * *", //Type can be Backup or Snapshot BackupType = BackupType.Backup, //Task Name Name = "fullBackupTask", }; var operation = new UpdatePeriodicBackupOperation(config); var result = await docStore.Maintenance.SendAsync(operation); #endregion } using (var docStore = new DocumentStore { Urls = new[] { "http://127.0.0.1:8080" }, Database = "Products" }.Initialize()) { #region encrypted_logical_full_backup var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { //Backup files local path FolderPath = @"E:\RavenBackups" }, //Full Backup period (Cron expression for a 3-hours period) FullBackupFrequency = "0 */3 * * *", //Type can be Backup or Snapshot BackupType = BackupType.Backup, //Task Name Name = "fullBackupTask" }; var operation = new UpdatePeriodicBackupOperation(config); var result = await docStore.Maintenance.SendAsync(operation); #endregion } using (var docStore = new DocumentStore { Urls = new[] { "http://127.0.0.1:8080" }, Database = "Products" }.Initialize()) { var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = @"E:\RavenBackups" }, #region backup_type_snapshot //Type can be Backup or Snapshot BackupType = BackupType.Snapshot, #endregion #region backup_full_backup //Full Backup period (Cron expression for a 6-hours period) FullBackupFrequency = "0 */6 * * *", #endregion #region backup_incremental_backup //Cron expression: set incremental backup period ("*/20 * * * *" is a 20-minutes period) IncrementalBackupFrequency = "*/20 * * * *", #endregion }; } using (var docStore = new DocumentStore { Urls = new[] { "http://127.0.0.1:8080" }, Database = "Products" }.Initialize()) { #region backup_remote_destinations var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = @"E:\RavenBackups" }, //FTP Backup settings FtpSettings = new FtpSettings { Url = "192.168.10.4", Port = 8080, UserName = "******", Password = "******" }, //Azure Backup settings AzureSettings = new AzureSettings { StorageContainer = "storageContainer", RemoteFolderName = "remoteFolder", AccountName = "JohnAccount", AccountKey = "key" } }; var operation = new UpdatePeriodicBackupOperation(config); var result = await docStore.Maintenance.SendAsync(operation); #endregion } using (var docStore = new DocumentStore { Urls = new[] { "http://127.0.0.1:8080" }, Database = "Products" }.Initialize()) { var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = @"E:\RavenBackups" }, //FTP Backup settings FtpSettings = new FtpSettings { Url = "192.168.10.4", Port = 8080, UserName = "******", Password = "******" }, //Azure Backup settings AzureSettings = new AzureSettings { StorageContainer = "storageContainer", RemoteFolderName = "remoteFolder", AccountName = "JohnAccount", AccountKey = "key" } }; #region initiate_immediate_backup_execution var operation = new UpdatePeriodicBackupOperation(config); var result = await docStore.Maintenance.SendAsync(operation); //run a backup task immediately await docStore.Maintenance.SendAsync(new StartBackupOperation(true, result.TaskId)); #endregion #region get_backup_execution_results //Provide GetPeriodicBackupStatusOperation with the task ID returned by RavenDB var backupStatus = new GetPeriodicBackupStatusOperation(result.TaskId); #endregion } using (var docStore = new DocumentStore { Urls = new[] { "http://127.0.0.1:8080" }, Database = "Products" }.Initialize()) { #region restore_to_single_node var restoreConfiguration = new RestoreBackupConfiguration(); //New database name restoreConfiguration.DatabaseName = "newProductsDatabase"; //Local path with a backup file var backupPath = @"C:\Users\RavenDB\backups\2018-12-26-16-17.ravendb-Products-A-backup"; restoreConfiguration.BackupLocation = backupPath; var restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); docStore.Maintenance.Server.Send(restoreBackupTask); #endregion #region restore_disable_ongoing_tasks_false //Disable or Enable ongoing tasks after restoration. //Default setting is FALSE, so tasks DO run when backup is restored. restoreConfiguration.DisableOngoingTasks = false; #endregion #region restore_last_file_name_to_restore //Last incremental backup file to restore from restoreConfiguration.LastFileNameToRestore = @"2018-12-26-12-00.ravendb-incremental-backup"; #endregion #region restore_to_specific__data_directory //Restore to a pre-chosen folder var dataPath = @"C:\Users\RavenDB\backups\2018-12-26-16-17.ravendb-Products-A-backup\restoredDatabaseLocation"; restoreConfiguration.DataDirectory = dataPath; #endregion #region restore_disable_ongoing_tasks_true //Do or do not run ongoing tasks after restoration. //Default setting is FALSE, to allow tasks' execution when backup is restored. restoreConfiguration.DisableOngoingTasks = true; #endregion } #region encrypted_database // path to the certificate you received during the server setup var cert = new X509Certificate2(@"C:\Users\RavenDB\authentication_key\admin.client.certificate.RavenDBdom.pfx"); using (var docStore = new DocumentStore { Urls = new[] { "https://a.RavenDBdom.development.run" }, Database = "encryptedDatabase", Certificate = cert }.Initialize()) { // Backup & Restore here } #endregion // path to the authentication key you received during the server setup cert = new X509Certificate2(@"C:\Users\RavenDB\authentication_key\admin.client.certificate.RavenDBdom.pfx"); using (var docStore = new DocumentStore { Urls = new[] { "https://a.RavenDBdom.development.run" }, Database = "encryptedDatabase", Certificate = cert }.Initialize()) { #region restore_encrypted_database // restore encrypted database // restore configuration var restoreConfiguration = new RestoreBackupConfiguration(); //New database name restoreConfiguration.DatabaseName = "newEncryptedDatabase"; //Backup-file location var backupPath = @"C:\Users\RavenDB\2019-01-06-11-11.ravendb-encryptedDatabase-A-snapshot"; restoreConfiguration.BackupLocation = backupPath; restoreConfiguration.EncryptionKey = "1F0K2R/KkcwbkK7n4kYlv5eqisy/pMnSuJvZ2sJ/EKo="; var restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); docStore.Maintenance.Server.Send(restoreBackupTask); #endregion } }
public async Task can_backup_and_restore() { using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); session.CountersFor("users/1").Increment("likes", 100); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, GoogleCloudSettings = GoogleCloudFact.GoogleCloudSettings, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 4); Assert.Equal(4, value); var backupStatus = store.Maintenance.Send(operation); var backupOperationId = backupStatus.Status.LastOperationId; var backupOperation = store.Maintenance.Send(new GetOperationStateOperation(backupOperationId.Value)); var backupResult = backupOperation.Result as BackupResult; Assert.True(backupResult.Counters.Processed); Assert.Equal(1, backupResult.Counters.ReadCount); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); // restore the database with a different name var databaseName = $"restored_database-{Guid.NewGuid()}"; GoogleCloudFact.GoogleCloudSettings.RemoteFolderName = $"{backupStatus.Status.FolderName}"; var restoreFromGoogleCloudConfiguration = new RestoreFromGoogleCloudConfiguration() { DatabaseName = databaseName, Settings = GoogleCloudFact.GoogleCloudSettings }; var googleCloudOperation = new RestoreBackupOperation(restoreFromGoogleCloudConfiguration); var restoreOperation = store.Maintenance.Server.Send(googleCloudOperation); restoreOperation.WaitForCompletion(TimeSpan.FromSeconds(30)); { using (var session = store.OpenAsyncSession(databaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); var val = await session.CountersFor("users/1").GetAsync("likes"); Assert.Equal(100, val); val = await session.CountersFor("users/2").GetAsync("downloads"); Assert.Equal(200, val); } var originalDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database); var restoredDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(databaseName); using (restoredDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx)) using (ctx.OpenReadTransaction()) { var databaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(ctx); Assert.Equal($"A:7-{originalDatabase.DbBase64Id}, A:8-{restoredDatabase.DbBase64Id}", databaseChangeVector); } } } }
public async Task can_backup_to_directory_multiple_backups() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var result = await store.Admin.Server.SendAsync(new UpdatePeriodicBackupOperation(config, store.Database)); var periodicBackupTaskId = result.TaskId; var operation = new GetPeriodicBackupStatusOperation(store.Database, periodicBackupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Admin.Server.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromMinutes(2)); var etagForBackups = store.Admin.Server.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.SaveChangesAsync(); } SpinWait.SpinUntil(() => { var newLastEtag = store.Admin.Server.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromMinutes(2)); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); using (var session = store.OpenAsyncSession()) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); } } }
public async Task can_backup_and_restore_snapshot() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var result = await store.Admin.Server.SendAsync(new UpdatePeriodicBackupOperation(config, store.Database)); var periodicBackupTaskId = result.TaskId; var operation = new GetPeriodicBackupStatusOperation(store.Database, periodicBackupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Admin.Server.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromMinutes(2)); var etagForBackups = store.Admin.Server.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.StoreAsync(new User { Name = "ayende" }, "users/3"); await session.SaveChangesAsync(); } SpinWait.SpinUntil(() => { var newLastEtag = store.Admin.Server.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromMinutes(2)); // restore the database with a different name const string restoredDatabaseName = "restored_database_snapshot"; var restoreConfiguration = new RestoreBackupConfiguration { BackupLocation = Directory.GetDirectories(backupPath).First(), DatabaseName = restoredDatabaseName }; var restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); var restoreResult = store.Admin.Server.Send(restoreBackupTask); var stateRequest = new GetOperationStateOperation(restoreResult.OperationId, true); store.Admin.Server.Send(stateRequest); SpinWait.SpinUntil(() => { var state = store.Admin.Server.Send(stateRequest); return(state.Status == OperationStatus.Completed); }, TimeSpan.FromMinutes(2)); using (var session = store.OpenAsyncSession(restoredDatabaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); } } }
public async Task CanCreateBackupUsingConfigurationFromBackupScript() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { var scriptPath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Guid.NewGuid().ToString(), ".ps1")); var localSetting = new LocalSettings { Disabled = false, FolderPath = backupPath, }; var localSettingsString = JsonConvert.SerializeObject(localSetting); string command; string script; if (PlatformDetails.RunningOnPosix) { command = "bash"; script = $"#!/bin/bash\r\necho '{localSettingsString}'"; File.WriteAllText(scriptPath, script); Process.Start("chmod", $"700 {scriptPath}"); } else { command = "powershell"; script = $"echo '{localSettingsString}'"; File.WriteAllText(scriptPath, script); } var putConfiguration = new ServerWideBackupConfiguration { Disabled = false, FullBackupFrequency = "0 2 * * 0", IncrementalBackupFrequency = "0 2 * * 1", LocalSettings = new LocalSettings { GetBackupConfigurationScript = new GetBackupConfigurationScript { Exec = command, Arguments = scriptPath } } }; await store.Maintenance.Server.SendAsync(new PutServerWideBackupConfigurationOperation(putConfiguration)); var record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database)); var backupTask = record.PeriodicBackups.First(); Assert.Null(backupTask.LocalSettings.FolderPath); Assert.NotNull(backupTask.LocalSettings.GetBackupConfigurationScript); Assert.NotNull(backupTask.LocalSettings.GetBackupConfigurationScript.Exec); Assert.NotNull(backupTask.LocalSettings.GetBackupConfigurationScript.Arguments); var backupTaskId = backupTask.TaskId; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new Company { Name = "Hibernating Rhinos" }, "companies/1"); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 1); Assert.Equal(1, value); } }
public async Task ServerWideBackupShouldBackupIdleDatabase(int rounds) { const string fullBackupFrequency = "*/2 * * * *"; var backupParser = CrontabSchedule.Parse(fullBackupFrequency); const int maxIdleTimeInSec = 10; using var server = GetNewServer(new ServerCreationOptions { CustomSettings = new Dictionary <string, string> { [RavenConfiguration.GetKey(x => x.Databases.MaxIdleTime)] = $"{maxIdleTimeInSec}", [RavenConfiguration.GetKey(x => x.Databases.FrequencyToCheckForIdle)] = "3", [RavenConfiguration.GetKey(x => x.Core.RunInMemory)] = "false" } }); using var dispose = new DisposableAction(() => server.ServerStore.DatabasesLandlord.SkipShouldContinueDisposeCheck = false); server.ServerStore.DatabasesLandlord.SkipShouldContinueDisposeCheck = true; var dbName = GetDatabaseName(); var controlgroupDbName = GetDatabaseName() + "controlgroup"; var baseBackupPath = NewDataPath(suffix: "BackupFolder"); using var store = new DocumentStore { Database = dbName, Urls = new[] { server.WebUrl } }.Initialize(); store.Maintenance.Server.Send(new CreateDatabaseOperation(new DatabaseRecord(dbName))); store.Maintenance.Server.Send(new CreateDatabaseOperation(new DatabaseRecord(controlgroupDbName))); await using var keepControlGroupAlive = new RepeatableAsyncAction(async token => { await store.Maintenance.ForDatabase(controlgroupDbName).SendAsync(new GetStatisticsOperation(), token); await Task.Delay(TimeSpan.FromSeconds(maxIdleTimeInSec), token); }).Run(); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "EGOR" }, "su"); await session.SaveChangesAsync(); } using (var session = store.OpenAsyncSession(controlgroupDbName)) { await session.StoreAsync(new User { Name = "egor" }, "susu"); await session.SaveChangesAsync(); } var first = true; DateTime backupStartTime = default; GetPeriodicBackupStatusOperation periodicBackupStatusOperation = null; PeriodicBackupStatus status = null; PeriodicBackupStatus controlGroupStatus = null; for (int i = 0; i < rounds; i++) { // let db get idle await WaitForValueAsync(() => Task.FromResult(server.ServerStore.IdleDatabases.Count > 0), true, 180 * 1000, 3000); Assert.True(1 == server.ServerStore.IdleDatabases.Count, $"IdleDatabasesCount({server.ServerStore.IdleDatabases.Count}), Round({i})"); Assert.True(server.ServerStore.IdleDatabases.ContainsKey(store.Database), $"Round({i})"); DateTime lastBackup; if (first) { var putConfiguration = new ServerWideBackupConfiguration { FullBackupFrequency = fullBackupFrequency, LocalSettings = new LocalSettings { FolderPath = baseBackupPath }, }; var result = await store.Maintenance.Server.SendAsync(new PutServerWideBackupConfigurationOperation(putConfiguration)); backupStartTime = DateTime.UtcNow; var serverWideConfiguration = await store.Maintenance.Server.SendAsync(new GetServerWideBackupConfigurationOperation(result.Name)); Assert.NotNull(serverWideConfiguration); periodicBackupStatusOperation = new GetPeriodicBackupStatusOperation(serverWideConfiguration.TaskId); // the configuration is applied to existing databases var periodicBackupConfigurations = (await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database))).PeriodicBackups; Assert.Equal(1, periodicBackupConfigurations.Count); var backupConfigurations = (await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(controlgroupDbName))).PeriodicBackups; Assert.Equal(1, backupConfigurations.Count); first = false; lastBackup = backupStartTime; } else { Assert.True(status.LastFullBackup.HasValue); lastBackup = status.LastFullBackup.Value; } var nextBackup = backupParser.GetNextOccurrence(lastBackup); await Task.Delay(nextBackup - DateTime.UtcNow); status = await AssertWaitForNextBackup(store.Database, status); controlGroupStatus = await AssertWaitForNextBackup(controlgroupDbName, controlGroupStatus); async Task <PeriodicBackupStatus> AssertWaitForNextBackup(string db, PeriodicBackupStatus prevStatus) { PeriodicBackupStatus nextStatus = null; Assert.True(await WaitForValueAsync(async() => { nextStatus = (await store.Maintenance.ForDatabase(db).SendAsync(periodicBackupStatusOperation)).Status; if (nextStatus == null) { return(false); } Assert.True(nextStatus.Error?.Exception == null, nextStatus.Error?.Exception); Assert.True(nextStatus.LocalBackup?.Exception == null, nextStatus.LocalBackup?.Exception); return(prevStatus == null || nextStatus.LastOperationId.HasValue && nextStatus.LastOperationId > prevStatus.LastOperationId); }, true), $"Round {i}"); return(nextStatus); } var backupsDir = Directory.GetDirectories(baseBackupPath); Assert.Equal(2, backupsDir.Length); AssertBackupDirCount(controlgroupDbName, controlGroupStatus); AssertBackupDirCount(store.Database, status); void AssertBackupDirCount(string db, PeriodicBackupStatus periodicBackupStatus) { var backupPath = Path.Combine(baseBackupPath, db); var backupDirs = Directory.GetDirectories(backupPath); Assert.True(i + 1 == backupDirs.Length, $"firstBackupStartTime: {backupStartTime}, checkTime: {DateTime.UtcNow}, i: {i}, " + $"controlGroupBackupNum: {backupDirs.Length}, path: {backupPath}, {PrintBackups(periodicBackupStatus, backupDirs)}"); } } }
public async Task snapshot_encrypted_db_and_restore_to_encrypted_DB() { var backupPath = NewDataPath(suffix: "BackupFolder"); var key = EncryptedServer(out var certificates, out string dbName); var defaultS3Settings = GetS3Settings(); using (var store = GetDocumentStore(new Options { AdminCertificate = certificates.ServerCertificate.Value, ClientCertificate = certificates.ServerCertificate.Value, ModifyDatabaseName = s => dbName, ModifyDatabaseRecord = record => record.Encrypted = true, Path = NewDataPath() })) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 */6 * * *" }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return getPeriodicBackupResult.Status?.LastEtag; }, 1); Assert.Equal(1, value); var backupStatus = store.Maintenance.Send(operation); var databaseName = $"restored_database-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(backupStatus.Status.FolderName); using (RestoreDatabaseFromCloud(store, new RestoreFromS3Configuration { Settings = subfolderS3Settings, DatabaseName = databaseName, EncryptionKey = key, BackupEncryptionSettings = new BackupEncryptionSettings { EncryptionMode = EncryptionMode.UseDatabaseKey } })) { using (var session = store.OpenSession(databaseName)) { var users = session.Load<User>("users/1"); Assert.NotNull(users); } } } }
public async Task IncludeArtificialDocuments_Backup_ShouldWork() { using (var store = GetDocumentStore()) { new MapReduce_WithOutput().Execute(store); using (var session = store.OpenSession()) { session.Store(new Company { Name = "HR" }); session.SaveChanges(); } WaitForIndexing(store); string artificialDocumentId = null; Assert.True(WaitForValue(() => { using (var session = store.OpenSession()) { var result = session.Query <MapReduce_WithOutput.Result>().SingleOrDefault(); artificialDocumentId = result.Id; return(result != null); } }, true)); Assert.NotNull(artificialDocumentId); var toFolderWithArtificial = Path.Combine(NewDataPath(), "BackupFolder"); var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, LocalSettings = new LocalSettings { FolderPath = toFolderWithArtificial }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (store.Maintenance.Send(new UpdatePeriodicBackupOperation(config))).TaskId; store.Maintenance.Send(new StartBackupOperation(true, backupTaskId)); var getPeriodicBackupStatusOperation = new GetPeriodicBackupStatusOperation(backupTaskId); Assert.True(WaitForValue(() => { var getPeriodicBackupResult = store.Maintenance.Send(getPeriodicBackupStatusOperation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, true)); toFolderWithArtificial = Directory.GetDirectories(toFolderWithArtificial).First(); var toDatabaseName = store.Database + "_restored"; using (RestoreDatabase(store, new RestoreBackupConfiguration { BackupLocation = toFolderWithArtificial, DatabaseName = toDatabaseName, SkipIndexes = true })) { using (var session = store.OpenSession(toDatabaseName)) { Assert.Null(session.Load <MapReduce_WithOutput.Result>(artificialDocumentId)); } } var importOptionsWithoutArtificial = new DatabaseSmugglerImportOptions(); var importOptionsWithArtificial = new DatabaseSmugglerImportOptions { IncludeArtificial = true }; importOptionsWithoutArtificial.OperateOnTypes |= ~DatabaseItemType.Indexes; importOptionsWithArtificial.OperateOnTypes |= ~DatabaseItemType.Indexes; var toFileWithArtificial = Directory.GetFiles(toFolderWithArtificial).First(); // artificial in file // include artificial is false using (var innerStore = GetDocumentStore()) { var operation = await innerStore.Smuggler.ImportAsync(importOptionsWithoutArtificial, toFileWithArtificial); await operation.WaitForCompletionAsync(TimeSpan.FromSeconds(30)); using (var session = innerStore.OpenSession()) { Assert.Null(session.Load <MapReduce_WithOutput.Result>(artificialDocumentId)); } } // artificial in file // include artificial is true using (var innerStore = GetDocumentStore()) { var operation = await innerStore.Smuggler.ImportAsync(importOptionsWithArtificial, toFileWithArtificial); await operation.WaitForCompletionAsync(TimeSpan.FromSeconds(30)); using (var session = innerStore.OpenSession()) { Assert.NotNull(session.Load <MapReduce_WithOutput.Result>(artificialDocumentId)); } } } }
protected async Task incremental_and_full_check_last_file_for_backup_internal() { var defaultS3Settings = GetS3Settings(); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "user-1" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 */6 * * *", }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); PeriodicBackupStatus backupStatus = null; var value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: 1, timeout: 30_000); Assert.True(1 == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); var operationStatus = WaitForValue(() => { var backupOperation = store.Maintenance.Send(new GetOperationStateOperation(backupStatus.LastOperationId.Value)); return(backupOperation.Status); }, OperationStatus.Completed); Assert.Equal(OperationStatus.Completed, operationStatus); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "user-2" }, "users/2"); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: lastEtag, timeout: 30_000); Assert.True(lastEtag == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); Assert.Equal(OperationStatus.Completed, WaitForValue(() => { var backupOperation = store.Maintenance.Send(new GetOperationStateOperation(backupStatus.LastOperationId.Value)); return(backupOperation.Status); }, OperationStatus.Completed)); string lastFileToRestore; using (var client = new RavenAwsS3Client(defaultS3Settings)) { var fullBackupPath = $"{defaultS3Settings.RemoteFolderName}/{backupStatus.FolderName}"; lastFileToRestore = (await client.ListObjectsAsync(fullBackupPath, string.Empty, false)).FileInfoDetails.Last().FullPath; } using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "user-3" }, "users/3"); await session.SaveChangesAsync(); } lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: lastEtag, timeout: 30_000); Assert.True(lastEtag == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); var databaseName = $"restored_database-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(backupStatus.FolderName); using (RestoreDatabaseFromCloud(store, new RestoreFromS3Configuration { Settings = subfolderS3Settings, DatabaseName = databaseName, LastFileNameToRestore = lastFileToRestore })) { using (var session = store.OpenSession(databaseName)) { var users = session.Load <User>("users/1"); Assert.NotNull(users); users = session.Load <User>("users/2"); Assert.NotNull(users); users = session.Load <User>("users/3"); Assert.Null(users); } } } }
public async Task can_backup_and_restore() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); session.CountersFor("users/1").Increment("likes", 100); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); var backupStatus = store.Maintenance.Send(operation); var backupOperationId = backupStatus.Status.LastOperationId; var backupOperation = store.Maintenance.Send(new GetOperationStateOperation(backupOperationId.Value)); var backupResult = backupOperation.Result as BackupResult; Assert.True(backupResult.Counters.Processed); Assert.Equal(1, backupResult.Counters.ReadCount); var etagForBackups = backupStatus.Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromSeconds(15)); // restore the database with a different name string databaseName = $"restored_database-{Guid.NewGuid()}"; using (RestoreDatabase(store, new RestoreBackupConfiguration { BackupLocation = Directory.GetDirectories(backupPath).First(), DatabaseName = databaseName })) { using (var session = store.OpenAsyncSession(databaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); var val = await session.CountersFor("users/1").GetAsync("likes"); Assert.Equal(100, val); val = await session.CountersFor("users/2").GetAsync("downloads"); Assert.Equal(200, val); } } } }
public async Task can_create_azure_snapshot_and_restore_using_restore_point() { using (var holder = new Azure.AzureClientHolder(AzureFactAttribute.AzureSettings)) { using (var store = GetDocumentStore()) { using (var session = store.OpenSession()) { session.Store(new User { Name = "oren" }, "users/1"); session.CountersFor("users/1").Increment("likes", 100); session.SaveChanges(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, AzureSettings = holder.Settings, IncrementalBackupFrequency = "0 0 1 1 *" }; var backupTaskId = (store.Maintenance.Send(new UpdatePeriodicBackupOperation(config))).TaskId; store.Maintenance.Send(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); PeriodicBackupStatus status = null; var value = WaitForValue(() => { status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 4); Assert.True(4 == value, $"4 == value, Got status: {status != null}, exception: {status?.Error?.Exception}"); Assert.True(status.LastOperationId != null, $"status.LastOperationId != null, Got status: {status != null}, exception: {status?.Error?.Exception}"); var client = store.GetRequestExecutor().HttpClient; var data = new StringContent(JsonConvert.SerializeObject(holder.Settings), Encoding.UTF8, "application/json"); var response = await client.PostAsync(store.Urls.First() + "/admin/restore/points?type=Azure ", data); string result = response.Content.ReadAsStringAsync().Result; var restorePoints = JsonConvert.DeserializeObject <RestorePoints>(result); Assert.Equal(1, restorePoints.List.Count); var point = restorePoints.List.First(); var databaseName = $"restored_database-{Guid.NewGuid()}"; holder.Settings.RemoteFolderName = holder.Settings.RemoteFolderName + "/" + status.FolderName; var restoreOperation = await store.Maintenance.Server.SendAsync(new RestoreBackupOperation(new RestoreFromAzureConfiguration() { DatabaseName = databaseName, Settings = holder.Settings, DisableOngoingTasks = true, LastFileNameToRestore = point.FileName, })); await restoreOperation.WaitForCompletionAsync(TimeSpan.FromSeconds(60)); using (var store2 = GetDocumentStore(new Options() { CreateDatabase = false, ModifyDatabaseName = s => databaseName })) { using (var session = store2.OpenSession(databaseName)) { var users = session.Load <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); var val = session.CountersFor("users/1").Get("likes"); Assert.Equal(100, val); } var originalDatabase = Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database).Result; var restoredDatabase = Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(databaseName).Result; using (restoredDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx)) using (ctx.OpenReadTransaction()) { var databaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(ctx); Assert.Equal($"A:4-{originalDatabase.DbBase64Id}", databaseChangeVector); } } } } }
public void FullBackupShouldBackupDocumentTombstones() { using var store = GetDocumentStore(); // create 3 docs using (var session = store.OpenSession()) { for (int i = 1; i <= 3; i++) { session.Store(new DummyDoc { DummyString = $"{i}" }, $"{nameof(DummyDoc)}/{i}"); } session.SaveChanges(); } // create 3 CompareExchanges var rhinoceros = store.Operations.Send(new PutCompareExchangeValueOperation <DummyDoc>("emojis/Rhinoceros", new DummyDoc { DummyString = "🦏" }, 0)); Assert.True(rhinoceros.Successful); var shark = store.Operations.Send(new PutCompareExchangeValueOperation <DummyDoc>("emojis/Shark", new DummyDoc { DummyString = "🦈" }, 0)); Assert.True(shark.Successful); var bird = store.Operations.Send(new PutCompareExchangeValueOperation <DummyDoc>("emojis/Bird", new DummyDoc { DummyString = "🐦" }, 0)); Assert.True(bird.Successful); // create 1 tombstone using (var session = store.OpenSession()) { session.Delete($"{nameof(DummyDoc)}/{new Random().Next(1, 3)}"); session.SaveChanges(); } // create 1 CompareExchange tombstone var res = store.Operations.Send(new DeleteCompareExchangeValueOperation <DummyDoc>($"emojis/Rhinoceros", rhinoceros.Index)); Assert.True(res.Successful); // run full backup var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = NewDataPath(forceCreateDir: true) }, Name = "full backup with tombstones", FullBackupFrequency = "0 0 1 1 *", BackupType = BackupType.Backup }; var documentDb = Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database); (long etag, _) = documentDb.Result.ReadLastEtagAndChangeVector(); var result = store.Maintenance.Send(new UpdatePeriodicBackupOperation(config)); store.Maintenance.Send(new StartBackupOperation(true, result.TaskId)); var operation = new GetPeriodicBackupStatusOperation(result.TaskId); PeriodicBackupStatus status = null; var value = WaitForValue(() => { status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, expectedVal: etag); Assert.True(etag == value, $"gotStatus? {status != null}, Status Error: {status?.Error?.Exception}, LocalBackup Exception: {status?.LocalBackup?.Exception}"); Assert.NotNull(status.LocalBackup); var backupPath = status.LocalBackup.BackupDirectory; var restoredDbName = GetDatabaseName(); using (RestoreDatabase(store, new RestoreBackupConfiguration { BackupLocation = backupPath, DatabaseName = restoredDbName })) { var stats = store.Maintenance.ForDatabase(restoredDbName).Send(new GetDetailedStatisticsOperation()); Assert.Equal(2, stats.CountOfDocuments); Assert.Equal(1, stats.CountOfTombstones); Assert.Equal(2, stats.CountOfCompareExchange); // we don't put the Compare Exchange tombstones into the schema, on backup restore. Assert.Equal(0, stats.CountOfCompareExchangeTombstones); } }
private void can_backup_and_restore_internal(bool oneTimeBackup) { using (var holder = new Azure.AzureClientHolder(AzureFactAttribute.AzureSettings)) { using (var store = GetDocumentStore()) { using (var session = store.OpenSession()) { session.Store(new User { Name = "oren" }, "users/1"); session.CountersFor("users/1").Increment("likes", 100); session.SaveChanges(); } PeriodicBackupStatus status = null; long backupTaskId = 0; GetPeriodicBackupStatusOperation operation = null; BackupResult backupResult = null; if (oneTimeBackup == false) { var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, AzureSettings = holder.Settings, IncrementalBackupFrequency = "0 0 1 1 *" }; backupTaskId = (store.Maintenance.Send(new UpdatePeriodicBackupOperation(config))).TaskId; operation = new GetPeriodicBackupStatusOperation(backupTaskId); store.Maintenance.Send(new StartBackupOperation(true, backupTaskId)); var value = WaitForValue(() => { status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 4); Assert.True(4 == value, $"4 == value, Got status: {status != null}, exception: {status?.Error?.Exception}"); Assert.True(status.LastOperationId != null, $"status.LastOperationId != null, Got status: {status != null}, exception: {status?.Error?.Exception}"); OperationState backupOperation = null; var operationStatus = WaitForValue(() => { backupOperation = store.Maintenance.Send(new GetOperationStateOperation(status.LastOperationId.Value)); return(backupOperation.Status); }, OperationStatus.Completed); Assert.Equal(OperationStatus.Completed, operationStatus); backupResult = backupOperation.Result as BackupResult; Assert.NotNull(backupResult); Assert.True(backupResult.Counters.Processed, "backupResult.Counters.Processed"); Assert.Equal(1, backupResult.Counters.ReadCount); } using (var session = store.OpenSession()) { session.Store(new User { Name = "ayende" }, "users/2"); session.CountersFor("users/2").Increment("downloads", 200); session.SaveChanges(); } if (oneTimeBackup == false) { var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; store.Maintenance.Send(new StartBackupOperation(false, backupTaskId)); var value2 = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value2); } if (oneTimeBackup) { var backupConfiguration = new BackupConfiguration { BackupType = BackupType.Backup, AzureSettings = holder.Settings, }; backupResult = (BackupResult)store.Maintenance.Send(new BackupOperation(backupConfiguration)).WaitForCompletion(TimeSpan.FromSeconds(15)); Assert.True(backupResult != null && backupResult.Counters.Processed, "backupResult != null && backupResult.Counters.Processed"); Assert.Equal(2, backupResult.Counters.ReadCount); } // restore the database with a different name var databaseName = $"restored_database-{Guid.NewGuid()}"; holder.Settings.RemoteFolderName = oneTimeBackup ? $"{holder.Settings.RemoteFolderName}/{backupResult.LocalBackup.BackupDirectory}" : $"{holder.Settings.RemoteFolderName}/{status.FolderName}"; var restoreFromGoogleCloudConfiguration = new RestoreFromAzureConfiguration() { DatabaseName = databaseName, Settings = holder.Settings, DisableOngoingTasks = true }; var googleCloudOperation = new RestoreBackupOperation(restoreFromGoogleCloudConfiguration); var restoreOperation = store.Maintenance.Server.Send(googleCloudOperation); restoreOperation.WaitForCompletion(TimeSpan.FromSeconds(30)); using (var store2 = GetDocumentStore(new Options() { CreateDatabase = false, ModifyDatabaseName = s => databaseName })) { using (var session = store2.OpenSession(databaseName)) { var users = session.Load <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); var val = session.CountersFor("users/1").Get("likes"); Assert.Equal(100, val); val = session.CountersFor("users/2").Get("downloads"); Assert.Equal(200, val); } var originalDatabase = Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database).Result; var restoredDatabase = Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(databaseName).Result; using (restoredDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx)) using (ctx.OpenReadTransaction()) { var databaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(ctx); Assert.Contains($"A:7-{originalDatabase.DbBase64Id}", databaseChangeVector); Assert.Contains($"A:8-{restoredDatabase.DbBase64Id}", databaseChangeVector); } } } } }
public async Task ShouldWork() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore(new Options { ModifyDatabaseRecord = record => record.Settings[RavenConfiguration.GetKey(x => x.PerformanceHints.MaxNumberOfResults)] = "1" })) { await store.Maintenance.SendAsync(new CreateSampleDataOperation()); WaitForIndexing(store); using (var session = store.OpenAsyncSession()) { await session.Query <Employee>().ToListAsync(); // this will generate performance hint } var database = await GetDatabase(store.Database); database.NotificationCenter.Paging.UpdatePaging(null); int beforeBackupAlertCount; using (database.NotificationCenter.GetStored(out var actions)) beforeBackupAlertCount = actions.Count(); Assert.True(beforeBackupAlertCount > 0); var beforeBackupStats = store.Maintenance.Send(new GetStatisticsOperation()); var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (store.Maintenance.Send(new UpdatePeriodicBackupOperation(config))).TaskId; store.Maintenance.Send(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); await WaitForValueAsync(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, true); // restore the database with a different name var restoredDatabaseName = GetDatabaseName(); string backupLocation = Directory.GetDirectories(backupPath).First(); var filesInBackupFolder = Directory.GetFiles(backupLocation); Assert.True(filesInBackupFolder.Where(RestorePointsBase.IsBackupOrSnapshot).Any(), $"The backup folder \"{backupLocation}\" contains no backup or snapshot files.\n{string.Join(", ","filesInBackupFolder")}"); using (RestoreDatabase(store, new RestoreBackupConfiguration { BackupLocation = backupLocation, DatabaseName = restoredDatabaseName })) { var afterRestoreStats = store.Maintenance.ForDatabase(restoredDatabaseName).Send(new GetStatisticsOperation()); var restoredDatabase = await GetDatabase(restoredDatabaseName); int afterRestoreAlertCount; using (restoredDatabase.NotificationCenter.GetStored(out var actions)) afterRestoreAlertCount = actions.Count(); Assert.True(afterRestoreAlertCount > 0); var indexesPath = restoredDatabase.Configuration.Indexing.StoragePath; var indexesDirectory = new DirectoryInfo(indexesPath.FullPath); Assert.True(indexesDirectory.Exists); Assert.Equal(afterRestoreStats.CountOfIndexes, indexesDirectory.GetDirectories().Length); Assert.NotEqual(beforeBackupStats.DatabaseId, afterRestoreStats.DatabaseId); Assert.Equal(beforeBackupStats.CountOfAttachments, afterRestoreStats.CountOfAttachments); Assert.Equal(beforeBackupStats.CountOfConflicts, afterRestoreStats.CountOfConflicts); Assert.Equal(beforeBackupStats.CountOfDocuments, afterRestoreStats.CountOfDocuments); Assert.Equal(beforeBackupStats.CountOfDocumentsConflicts, afterRestoreStats.CountOfDocumentsConflicts); Assert.Equal(beforeBackupStats.CountOfIndexes, afterRestoreStats.CountOfIndexes); Assert.Equal(beforeBackupStats.CountOfRevisionDocuments, afterRestoreStats.CountOfRevisionDocuments); Assert.Equal(beforeBackupStats.CountOfTombstones, afterRestoreStats.CountOfTombstones); Assert.Equal(beforeBackupStats.CountOfUniqueAttachments, afterRestoreStats.CountOfUniqueAttachments); } } }
public async Task periodic_backup_should_work_with_long_intervals() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { var periodicBackupRunner = (await GetDocumentDatabaseInstanceFor(store)).PeriodicBackupRunner; // get by reflection the maxTimerTimeoutInMilliseconds field // this field is the maximum interval acceptable in .Net's threading timer // if the requested backup interval is bigger than this maximum interval, // a timer with maximum interval will be used several times until the interval cumulatively // will be equal to requested interval typeof(PeriodicBackupRunner) .GetField(nameof(PeriodicBackupRunner.MaxTimerTimeout), BindingFlags.Instance | BindingFlags.Public) .SetValue(periodicBackupRunner, TimeSpan.FromMilliseconds(100)); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren 1" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 1); Assert.Equal(1, value); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren 2" }, "users/2"); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); using (var session = store.OpenAsyncSession()) { var user = await session.LoadAsync <User>("users/1"); Assert.Equal("oren 1", user.Name); user = await session.LoadAsync <User>("users/2"); Assert.Equal("oren 2", user.Name); } } }
public async Task can_restore_smuggler_correctly() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); var etagForBackups = store.Maintenance.Send(operation).Status.LastEtag; using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.SaveChangesAsync(); } await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); SpinWait.SpinUntil(() => { var newLastEtag = store.Maintenance.Send(operation).Status.LastEtag; return(newLastEtag != etagForBackups); }, TimeSpan.FromSeconds(15)); } using (var store1 = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) using (var store2 = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { var backupDirectory = Directory.GetDirectories(backupPath).First(); var backupToMovePath = $"{backupPath}{Path.DirectorySeparatorChar}IncrementalBackupTemp"; Directory.CreateDirectory(backupToMovePath); var incrementalBackupFile = Directory.GetFiles(backupDirectory).OrderBackups().Last(); var fileName = Path.GetFileName(incrementalBackupFile); File.Move(incrementalBackupFile, $"{backupToMovePath}{Path.DirectorySeparatorChar}{fileName}"); await store1.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), backupDirectory); using (var session = store1.OpenAsyncSession()) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); var keyValuePair = users.First(); Assert.NotNull(keyValuePair.Value); Assert.True(keyValuePair.Value.Name == "oren" && keyValuePair.Key == "users/1"); Assert.Null(users.Last().Value); } await store2.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), backupToMovePath); using (var session = store2.OpenAsyncSession()) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.Null(users.First().Value); var keyValuePair = users.Last(); Assert.NotNull(keyValuePair.Value); Assert.True(keyValuePair.Value.Name == "ayende" && keyValuePair.Key == "users/2"); } } }
public async Task can_backup_to_directory_multiple_backups() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 1); Assert.Equal(1, value); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); using (var session = store.OpenAsyncSession()) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); } } }
public async Task restore_settings_tests() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { var restoreConfiguration = new RestoreBackupConfiguration(); var restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); var e = Assert.Throws <RavenException>(() => store.Maintenance.Server.Send(restoreBackupTask)); Assert.Contains("Database name can't be null or empty", e.InnerException.Message); restoreConfiguration.DatabaseName = store.Database; restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); e = Assert.Throws <RavenException>(() => store.Maintenance.Server.Send(restoreBackupTask)); Assert.Contains("Cannot restore data to an existing database", e.InnerException.Message); restoreConfiguration.DatabaseName = "test-" + Guid.NewGuid(); restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); e = Assert.Throws <RavenException>(() => store.Maintenance.Server.Send(restoreBackupTask)); Assert.Contains("Backup location can't be null or empty", e.InnerException.Message); restoreConfiguration.BackupLocation = "this-path-doesn't-exist\\"; restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); e = Assert.Throws <RavenException>(() => store.Maintenance.Server.Send(restoreBackupTask)); Assert.Contains("Backup location doesn't exist", e.InnerException.Message); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); SpinWait.SpinUntil(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return(getPeriodicBackupResult.Status?.LastEtag > 0); }, TimeSpan.FromSeconds(15)); restoreConfiguration.BackupLocation = backupPath; restoreConfiguration.DataDirectory = backupPath; restoreBackupTask = new RestoreBackupOperation(restoreConfiguration); e = Assert.Throws <RavenException>(() => store.Maintenance.Server.Send(restoreBackupTask)); Assert.Contains("New data directory must be empty of any files or folders", e.InnerException.Message); var emptyFolder = NewDataPath(suffix: "BackupFolderRestore"); restoreConfiguration.BackupLocation = backupPath; restoreConfiguration.DataDirectory = emptyFolder; } }
public async Task CanImportTombstonesFromIncrementalBackup() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "fitzchak" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; var backupStatus = await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 1); Assert.Equal(1, value); using (var session = store.OpenAsyncSession()) { session.Delete("users/1"); await session.SaveChangesAsync(); } StartBackupOperationResult newBackupStatus; do { newBackupStatus = await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); } //Race condition between reading the backup status and creating new backup while (newBackupStatus.OperationId == backupStatus.OperationId); await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, 2); Assert.Equal(2, value); } using (var store = GetDocumentStore(new Options { ModifyDatabaseName = s => $"{s}_2" })) { await store.Smuggler.ImportIncrementalAsync(new DatabaseSmugglerImportOptions(), Directory.GetDirectories(backupPath).First()); using (var session = store.OpenAsyncSession()) { var user = await session.LoadAsync <User>("users/1"); Assert.Null(user); } } }
protected async Task can_backup_and_restore_snapshot_internal() { var defaultS3Settings = GetS3Settings(); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } using (var session = store.OpenAsyncSession()) { await session .Query <User>() .Where(x => x.Name == "oren") .ToListAsync(); // create an index to backup await session .Query <Order>() .Where(x => x.Freight > 20) .ToListAsync(); // create an index to backup session.CountersFor("users/1").Increment("likes", 100); //create a counter to backup await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 0 1 1 *" }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); PeriodicBackupStatus backupStatus = null; var value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: 4, timeout: 30_000); Assert.True(4 == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.StoreAsync(new User { Name = "ayende" }, "users/3"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => { backupStatus = store.Maintenance.Send(operation).Status; return(backupStatus?.LastEtag); }, expectedVal: lastEtag, timeout: 30_000); Assert.True(lastEtag == value, $"gotStatus? {backupStatus != null}, Status Error: {backupStatus?.Error?.Exception}," + $" S3 Error: {backupStatus?.UploadToS3?.Exception}, LocalBackup Exception: {backupStatus?.LocalBackup?.Exception}"); // restore the database with a different name string restoredDatabaseName = $"restored_database_snapshot-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(backupStatus.FolderName); using (RestoreDatabaseFromCloud(store, new RestoreFromS3Configuration { DatabaseName = restoredDatabaseName, Settings = subfolderS3Settings }, TimeSpan.FromSeconds(60))) { using (var session = store.OpenAsyncSession(restoredDatabaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.NotNull(users["users/1"]); Assert.NotNull(users["users/2"]); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); var val = await session.CountersFor("users/1").GetAsync("likes"); Assert.Equal(100, val); val = await session.CountersFor("users/2").GetAsync("downloads"); Assert.Equal(200, val); } var stats = await store.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(2, stats.CountOfIndexes); var originalDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database); var restoredDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(restoredDatabaseName); using (restoredDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx)) using (ctx.OpenReadTransaction()) { var databaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(ctx); Assert.Equal($"A:8-{originalDatabase.DbBase64Id}, A:10-{restoredDatabase.DbBase64Id}", databaseChangeVector); } } } }
public async Task can_backup_and_restore_snapshot() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); await session.SaveChangesAsync(); } using (var session = store.OpenAsyncSession()) { await session .Query <User>() .Where(x => x.Name == "oren") .ToListAsync(); // create an index to backup await session .Query <User>() .Where(x => x.Age > 20) .ToListAsync(); // create an index to backup session.CountersFor("users/1").Increment("likes", 100); //create a counter to backup await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Snapshot, LocalSettings = new LocalSettings { FolderPath = backupPath }, IncrementalBackupFrequency = "* * * * *" //every minute }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, 3); Assert.Equal(3, value); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); await session.StoreAsync(new User { Name = "ayende" }, "users/3"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); // restore the database with a different name string restoredDatabaseName = $"restored_database_snapshot-{Guid.NewGuid()}"; using (RestoreDatabase(store, new RestoreBackupConfiguration { BackupLocation = Directory.GetDirectories(backupPath).First(), DatabaseName = restoredDatabaseName })) { using (var session = store.OpenAsyncSession(restoredDatabaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.NotNull(users["users/1"]); Assert.NotNull(users["users/2"]); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); var val = await session.CountersFor("users/1").GetAsync("likes"); Assert.Equal(100, val); val = await session.CountersFor("users/2").GetAsync("downloads"); Assert.Equal(200, val); } var stats = await store.Maintenance.SendAsync(new GetStatisticsOperation()); Assert.Equal(2, stats.CountOfIndexes); var originalDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database); var restoredDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(restoredDatabaseName); using (restoredDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx)) using (ctx.OpenReadTransaction()) { var databaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(ctx); Assert.Equal($"A:3-{originalDatabase.DbBase64Id}, A:9-{restoredDatabase.DbBase64Id}", databaseChangeVector); } } } }
protected async Task can_backup_and_restore_internal() { var defaultS3Settings = GetS3Settings(); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "oren" }, "users/1"); session.CountersFor("users/1").Increment("likes", 100); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 0 1 1 *" }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); PeriodicBackupStatus status = null; var value = WaitForValue(() => { status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, expectedVal: 4, timeout: 30_000); Assert.True(4 == value, $"gotStatus? {status != null}, Status Error: {status?.Error?.Exception}," + $" S3 Error: {status?.UploadToS3?.Exception}, LocalBackup Exception: {status?.LocalBackup?.Exception}"); Assert.True(status.LastOperationId != null, $"status.LastOperationId != null, Got status: {status != null}, exception: {status?.Error?.Exception}"); var backupOperation = store.Maintenance.Send(new GetOperationStateOperation(status.LastOperationId.Value)); var backupResult = backupOperation.Result as BackupResult; Assert.True(backupResult != null && backupResult.Counters.Processed, "backupResult != null && backupResult.Counters.Processed"); Assert.True(1 == backupResult.Counters.ReadCount, "1 == backupResult.Counters.ReadCount"); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "ayende" }, "users/2"); session.CountersFor("users/2").Increment("downloads", 200); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => { status = store.Maintenance.Send(operation).Status; return(status?.LastEtag); }, expectedVal: lastEtag, timeout: 30_000); Assert.True(lastEtag == value, $"gotStatus? {status != null}, Status Error: {status?.Error?.Exception}," + $" S3 Error: {status?.UploadToS3?.Exception}, LocalBackup Exception: {status?.LocalBackup?.Exception}"); // restore the database with a different name var databaseName = $"restored_database-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(status.FolderName); using (RestoreDatabaseFromCloud( store, new RestoreFromS3Configuration { DatabaseName = databaseName, Settings = subfolderS3Settings, DisableOngoingTasks = true }, TimeSpan.FromSeconds(60))) { using (var session = store.OpenAsyncSession(databaseName)) { var users = await session.LoadAsync <User>(new[] { "users/1", "users/2" }); Assert.True(users.Any(x => x.Value.Name == "oren")); Assert.True(users.Any(x => x.Value.Name == "ayende")); var val = await session.CountersFor("users/1").GetAsync("likes"); Assert.Equal(100, val); val = await session.CountersFor("users/2").GetAsync("downloads"); Assert.Equal(200, val); } var originalDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database); var restoredDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(databaseName); using (restoredDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx)) using (ctx.OpenReadTransaction()) { var databaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(ctx); Assert.Equal($"A:7-{originalDatabase.DbBase64Id}, A:8-{restoredDatabase.DbBase64Id}", databaseChangeVector); } } } }
public async Task incremental_and_full_check_last_file_for_backup() { var defaultS3Settings = GetS3Settings(); using (var store = GetDocumentStore()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "user-1" }, "users/1"); await session.SaveChangesAsync(); } var config = new PeriodicBackupConfiguration { BackupType = BackupType.Backup, S3Settings = defaultS3Settings, IncrementalBackupFrequency = "0 */6 * * *", }; var backupTaskId = (await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config))).TaskId; await store.Maintenance.SendAsync(new StartBackupOperation(true, backupTaskId)); var operation = new GetPeriodicBackupStatusOperation(backupTaskId); var value = WaitForValue(() => { var getPeriodicBackupResult = store.Maintenance.Send(operation); return getPeriodicBackupResult.Status?.LastEtag; }, 1); Assert.Equal(1, value); using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "user-2" }, "users/2"); await session.SaveChangesAsync(); } var lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); string lastFileToRestore; var backupStatus = store.Maintenance.Send(operation); using (var client = new RavenAwsS3Client(AmazonS3FactAttribute.S3Settings)) { var fullBackupPath = $"{defaultS3Settings.RemoteFolderName}/{backupStatus.Status.FolderName}"; lastFileToRestore = (await client.ListObjectsAsync(fullBackupPath, string.Empty, false)).FileInfoDetails.Last().FullPath; } using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "user-3" }, "users/3"); await session.SaveChangesAsync(); } lastEtag = store.Maintenance.Send(new GetStatisticsOperation()).LastDocEtag; await store.Maintenance.SendAsync(new StartBackupOperation(false, backupTaskId)); value = WaitForValue(() => store.Maintenance.Send(operation).Status.LastEtag, lastEtag); Assert.Equal(lastEtag, value); backupStatus = store.Maintenance.Send(operation); var databaseName = $"restored_database-{Guid.NewGuid()}"; var subfolderS3Settings = GetS3Settings(backupStatus.Status.FolderName); using (RestoreDatabaseFromCloud(store, new RestoreFromS3Configuration { Settings = subfolderS3Settings, DatabaseName = databaseName, LastFileNameToRestore = lastFileToRestore })) { using (var session = store.OpenSession(databaseName)) { var users = session.Load<User>("users/1"); Assert.NotNull(users); users = session.Load<User>("users/2"); Assert.NotNull(users); users = session.Load<User>("users/3"); Assert.Null(users); } } } }