public DocumentDatabase(InMemoryRavenConfiguration configuration, TransportState recievedTransportState = null) { DocumentLock = new PutSerialLock(); Name = configuration.DatabaseName; Configuration = configuration; transportState = recievedTransportState ?? new TransportState(); ExtensionsState = new AtomicDictionary<object>(); using (LogManager.OpenMappedContext("database", Name ?? Constants.SystemDatabase)) { Log.Debug("Start loading the following database: {0}", Name ?? Constants.SystemDatabase); initializer = new DocumentDatabaseInitializer(this, configuration); initializer.InitializeEncryption(); initializer.ValidateLicense(); initializer.SubscribeToDomainUnloadOrProcessExit(); initializer.ExecuteAlterConfiguration(); initializer.SatisfyImportsOnce(); backgroundTaskScheduler = configuration.CustomTaskScheduler ?? TaskScheduler.Default; recentTouches = new SizeLimitedConcurrentDictionary<string, TouchedDocumentInfo>(configuration.MaxRecentTouchesToRemember, StringComparer.OrdinalIgnoreCase); configuration.Container.SatisfyImportsOnce(this); workContext = new WorkContext { Database = this, DatabaseName = Name, IndexUpdateTriggers = IndexUpdateTriggers, ReadTriggers = ReadTriggers, TaskScheduler = backgroundTaskScheduler, Configuration = configuration, IndexReaderWarmers = IndexReaderWarmers }; try { uuidGenerator = new SequentialUuidGenerator(); initializer.InitializeTransactionalStorage(uuidGenerator); lastCollectionEtags = new LastCollectionEtags(WorkContext); } catch (Exception) { if (TransactionalStorage != null) TransactionalStorage.Dispose(); throw; } try { TransactionalStorage.Batch(actions => uuidGenerator.EtagBase = actions.General.GetNextIdentityValue("Raven/Etag")); // Index codecs must be initialized before we try to read an index InitializeIndexCodecTriggers(); initializer.InitializeIndexStorage(); Attachments = new AttachmentActions(this, recentTouches, uuidGenerator, Log); Documents = new DocumentActions(this, recentTouches, uuidGenerator, Log); Indexes = new IndexActions(this, recentTouches, uuidGenerator, Log); Maintenance = new MaintenanceActions(this, recentTouches, uuidGenerator, Log); Notifications = new NotificationActions(this, recentTouches, uuidGenerator, Log); Patches = new PatchActions(this, recentTouches, uuidGenerator, Log); Queries = new QueryActions(this, recentTouches, uuidGenerator, Log); Tasks = new TaskActions(this, recentTouches, uuidGenerator, Log); Transformers = new TransformerActions(this, recentTouches, uuidGenerator, Log); inFlightTransactionalState = TransactionalStorage.GetInFlightTransactionalState(this, Documents.Put, Documents.Delete); CompleteWorkContextSetup(); prefetcher = new Prefetcher(workContext); indexingExecuter = new IndexingExecuter(workContext, prefetcher); RaiseIndexingWiringComplete(); InitializeTriggersExceptIndexCodecs(); SecondStageInitialization(); ExecuteStartupTasks(); lastCollectionEtags.InitializeBasedOnIndexingResults(); Log.Debug("Finish loading the following database: {0}", configuration.DatabaseName ?? Constants.SystemDatabase); } catch (Exception) { Dispose(); throw; } } }
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 <DatabaseRestoreRequest>(); DatabaseDocument databaseDocument = null; var databaseDocumentPath = MaintenanceActions.FindDatabaseDocument(restoreRequest.BackupLocation); 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 })); }
public DocumentDatabase(InMemoryRavenConfiguration configuration, TransportState recievedTransportState = null) { TimerManager = new ResourceTimerManager(); DocumentLock = new PutSerialLock(); IdentityLock = new PutSerialLock(); Name = configuration.DatabaseName; ResourceName = Name; Configuration = configuration; transportState = recievedTransportState ?? new TransportState(); ExtensionsState = new AtomicDictionary<object>(); using (LogManager.OpenMappedContext("database", Name ?? Constants.SystemDatabase)) { Log.Debug("Start loading the following database: {0}", Name ?? Constants.SystemDatabase); initializer = new DocumentDatabaseInitializer(this, configuration); initializer.ValidateLicense(); initializer.ValidateStorage(); initializer.InitializeEncryption(); initializer.SubscribeToDomainUnloadOrProcessExit(); initializer.SubscribeToDiskSpaceChanges(); initializer.ExecuteAlterConfiguration(); initializer.SatisfyImportsOnce(); backgroundTaskScheduler = configuration.CustomTaskScheduler ?? TaskScheduler.Default; recentTouches = new SizeLimitedConcurrentDictionary<string, TouchedDocumentInfo>(configuration.MaxRecentTouchesToRemember, StringComparer.OrdinalIgnoreCase); configuration.Container.SatisfyImportsOnce(this); workContext = new WorkContext { Database = this, DatabaseName = Name, IndexUpdateTriggers = IndexUpdateTriggers, ReadTriggers = ReadTriggers, TaskScheduler = backgroundTaskScheduler, Configuration = configuration, IndexReaderWarmers = IndexReaderWarmers }; try { uuidGenerator = new SequentialUuidGenerator(); initializer.InitializeTransactionalStorage(uuidGenerator); lastCollectionEtags = new LastCollectionEtags(WorkContext); } catch (Exception ex) { Log.ErrorException("Could not initialize transactional storage, not creating database", ex); try { if (TransactionalStorage != null) TransactionalStorage.Dispose(); if (initializer != null) { initializer.UnsubscribeToDomainUnloadOrProcessExit(); initializer.Dispose(); } } catch (Exception e) { Log.ErrorException("Could not dispose on initialized DocumentDatabase members", e); } throw; } try { TransactionalStorage.Batch(actions => uuidGenerator.EtagBase = actions.General.GetNextIdentityValue("Raven/Etag")); initializer.InitializeIndexDefinitionStorage(); Indexes = new IndexActions(this, recentTouches, uuidGenerator, Log); Attachments = new AttachmentActions(this, recentTouches, uuidGenerator, Log); Maintenance = new MaintenanceActions(this, recentTouches, uuidGenerator, Log); Notifications = new NotificationActions(this, recentTouches, uuidGenerator, Log); Subscriptions = new SubscriptionActions(this, Log); Patches = new PatchActions(this, recentTouches, uuidGenerator, Log); Queries = new QueryActions(this, recentTouches, uuidGenerator, Log); Tasks = new TaskActions(this, recentTouches, uuidGenerator, Log); Transformers = new TransformerActions(this, recentTouches, uuidGenerator, Log); Documents = new DocumentActions(this, recentTouches, uuidGenerator, Log); inFlightTransactionalState = TransactionalStorage.InitializeInFlightTransactionalState(this, (key, etag, document, metadata, transactionInformation) => Documents.Put(key, etag, document, metadata, transactionInformation), (key, etag, transactionInformation) => Documents.Delete(key, etag, transactionInformation)); InitializeTriggersExceptIndexCodecs(); // Second stage initializing before index storage for determining the hash algotihm for encrypted databases that were upgraded from 2.5 SecondStageInitialization(); // Index codecs must be initialized before we try to read an index InitializeIndexCodecTriggers(); initializer.InitializeIndexStorage(); CompleteWorkContextSetup(); prefetcher = new Prefetcher(workContext); IndexReplacer = new IndexReplacer(this); indexingExecuter = new IndexingExecuter(workContext, prefetcher, IndexReplacer); InitializeTriggersExceptIndexCodecs(); EnsureAllIndexDefinitionsHaveIndexes(); RaiseIndexingWiringComplete(); ExecuteStartupTasks(); lastCollectionEtags.InitializeBasedOnIndexingResults(); Log.Debug("Finish loading the following database: {0}", configuration.DatabaseName ?? Constants.SystemDatabase); } catch (Exception e) { Log.ErrorException("Could not create database", e); try { Dispose(); } catch (Exception ex) { Log.FatalException("Failed to disposed when already getting an error during ctor", ex); } throw; } } }
public async Task <HttpResponseMessage> Restore() { if (EnsureSystemDatabase() == false) { return(GetMessageWithString("Restore is only possible from the system database", HttpStatusCode.BadRequest)); } var restoreStatus = new RestoreStatus { State = RestoreStatusState.Running, Messages = new List <string>() }; var restoreRequest = await ReadJsonObjectAsync <DatabaseRestoreRequest>(); DatabaseDocument databaseDocument = null; var databaseDocumentPath = MaintenanceActions.FindDatabaseDocument(restoreRequest.BackupLocation); 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.CustomizeValuesForDatabaseTenant(databaseName); ravenConfiguration.Initialize(); string documentDataDir; ravenConfiguration.DataDirectory = ResolveTenantDataDirectory(restoreRequest.DatabaseLocation, databaseName, out documentDataDir); restoreRequest.DatabaseLocation = ravenConfiguration.DataDirectory; string anotherRestoreResourceName; if (IsAnotherRestoreInProgress(out anotherRestoreResourceName)) { if (restoreRequest.RestoreStartTimeout.HasValue) { try { using (var cts = new CancellationTokenSource()) { cts.CancelAfter(TimeSpan.FromSeconds(restoreRequest.RestoreStartTimeout.Value)); var token = cts.Token; do { await Task.Delay(500, token); }while (IsAnotherRestoreInProgress(out anotherRestoreResourceName)); } } catch (OperationCanceledException) { return(GetMessageWithString(string.Format("Another restore is still in progress (resource name = {0}). Waited {1} seconds for other restore to complete.", anotherRestoreResourceName, restoreRequest.RestoreStartTimeout.Value), HttpStatusCode.ServiceUnavailable)); } } else { return(GetMessageWithString(string.Format("Another restore is in progress (resource name = {0})", anotherRestoreResourceName), HttpStatusCode.ServiceUnavailable)); } } Database.Documents.Put(RestoreInProgress.RavenRestoreInProgressDocumentKey, null, RavenJObject.FromObject(new RestoreInProgress { Resource = databaseName }), new RavenJObject(), null); 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(() => { try { 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; } bool replicationBundleRemoved = false; if (restoreRequest.DisableReplicationDestinations) { replicationBundleRemoved = TryRemoveReplicationBundle(databaseDocument); } 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"); restoreStatus.State = RestoreStatusState.Completed; DatabasesLandlord.SystemDatabase.Documents.Put(RestoreStatus.RavenRestoreStatusDocumentKey, null, RavenJObject.FromObject(restoreStatus), new RavenJObject(), null); if (restoreRequest.GenerateNewDatabaseId) { GenerateNewDatabaseId(databaseName); } if (replicationBundleRemoved) { AddReplicationBundleAndDisableReplicationDestinations(databaseName); } } catch (Exception e) { restoreStatus.State = RestoreStatusState.Faulted; restoreStatus.Messages.Add("Unable to restore database " + e.Message); DatabasesLandlord.SystemDatabase.Documents.Put(RestoreStatus.RavenRestoreStatusDocumentKey, null, RavenJObject.FromObject(restoreStatus), new RavenJObject(), null); throw; } finally { Database.Documents.Delete(RestoreInProgress.RavenRestoreInProgressDocumentKey, null, null); } }, TaskCreationOptions.LongRunning); long id; Database.Tasks.AddTask(task, new TaskBasedOperationState(task), new TaskActions.PendingTaskDescription { StartTime = SystemTime.UtcNow, TaskType = TaskActions.PendingTaskType.RestoreDatabase, Payload = "Restoring database " + databaseName + " from " + restoreRequest.BackupLocation }, out id); return(GetMessageWithObject(new { OperationId = id })); }