private Task <DocumentDatabase> CreateDatabase(StringSegment databaseName) { var config = CreateDatabaseConfiguration(databaseName); if (config == null) { return(null); } var hasAcquired = false; try { if (!ResourceSemaphore.Wait(ConcurrentResourceLoadTimeout)) { throw new ConcurrentLoadTimeoutException( "Too much databases loading concurrently, timed out waiting for them to load."); } hasAcquired = true; var task = new Task <DocumentDatabase>(() => CreateDocumentsStorage(databaseName, config)); var database = ResourcesStoresCache.GetOrAdd(databaseName, task); if (database == task) { task.Start(); } if (database.IsFaulted && database.Exception != null) { // if we are here, there is an error, and if there is an error, we need to clear it from the // resource store cache so we can try to reload it. // Note that we return the faulted task anyway, because we need the user to look at the error if (database.Exception.Data.Contains("Raven/KeepInResourceStore") == false) { Task <DocumentDatabase> val; ResourcesStoresCache.TryRemove(databaseName, out val); } } database.ContinueWith(_ => ServerStore.TrackChange("Loaded", Constants.Database.Prefix + databaseName)); return(database); } finally { if (hasAcquired) { ResourceSemaphore.Release(); } } }
public override bool TryGetOrCreateResourceStore(string resourceName, out Task <DocumentDatabase> resourceTask) { if (Locks.Contains(DisposingLock)) { throw new ObjectDisposedException("DatabaseLandlord", "Server is shutting down, can't access any databases"); } if (Locks.Contains(resourceName)) { throw new InvalidOperationException("Database '" + resourceName + "' is currently locked and cannot be accessed."); } ManualResetEvent cleanupLock; if (Cleanups.TryGetValue(resourceName, out cleanupLock) && cleanupLock.WaitOne(MaxSecondsForTaskToWaitForDatabaseToLoad * 1000) == false) { throw new InvalidOperationException(string.Format("Database '{0}' is currently being restarted and cannot be accessed. We already waited {1} seconds.", resourceName, MaxSecondsForTaskToWaitForDatabaseToLoad)); } if (ResourcesStoresCache.TryGetValue(resourceName, out resourceTask)) { if (resourceTask.IsFaulted || resourceTask.IsCanceled) { ResourcesStoresCache.TryRemove(resourceName, out resourceTask); DateTime time; LastRecentlyUsed.TryRemove(resourceName, out time); // and now we will try creating it again } else { return(true); } } var config = CreateTenantConfiguration(resourceName); if (config == null) { return(false); } if (!ResourceSemaphore.Wait(ConcurrentResourceLoadTimeout)) { throw new ConcurrentLoadTimeoutException("Too much databases loading concurrently, timed out waiting for them to load."); } var didReleaseDuringWait = 0; var createdNewTask = false; resourceTask = ResourcesStoresCache.GetOrAdd(resourceName, __ => { createdNewTask = true; return(Task.Factory.StartNew(() => { var transportState = ResourseTransportStates.GetOrAdd(resourceName, s => new TransportState()); AssertLicenseParameters(config); var documentDatabase = new DocumentDatabase(config, systemDatabase, transportState); documentDatabase.SpinBackgroundWorkers(false); documentDatabase.Disposing += DocumentDatabaseDisposingStarted; documentDatabase.DisposingEnded += DocumentDatabaseDisposingEnded; documentDatabase.StorageInaccessible += UnloadDatabaseOnStorageInaccessible; // register only DB that has incremental backup set. documentDatabase.OnBackupComplete += OnDatabaseBackupCompleted; // if we have a very long init process, make sure that we reset the last idle time for this db. LastRecentlyUsed.AddOrUpdate(resourceName, SystemTime.UtcNow, (_, time) => SystemTime.UtcNow); documentDatabase.RequestManager = SystemDatabase.RequestManager; documentDatabase.ClusterManager = SystemDatabase.ClusterManager; return documentDatabase; }).ContinueWith(task => { if (task.Status == TaskStatus.RanToCompletion) { OnDatabaseLoaded(resourceName); } if (task.Status == TaskStatus.Faulted) // this observes the task exception { Logger.WarnException("Failed to create database " + resourceName, task.Exception); } ResourceSemaphore.Release(); return task; }).Unwrap()); }); if (createdNewTask == false) { ResourceSemaphore.Release(); } if (resourceTask.IsFaulted && resourceTask.Exception != null) { // if we are here, there is an error, and if there is an error, we need to clear it from the // resource store cache so we can try to reload it. // Note that we return the faulted task anyway, because we need the user to look at the error if (resourceTask.Exception.Data.Contains("Raven/KeepInResourceStore") == false) { Task <DocumentDatabase> val; ResourcesStoresCache.TryRemove(resourceName, out val); } } return(true); }
public bool TryGetOrCreateResourceStore(string tenantId, out Task <RavenFileSystem> fileSystem) { if (Locks.Contains(DisposingLock)) { throw new ObjectDisposedException("FileSystem", "Server is shutting down, can't access any file systems"); } if (Locks.Contains(tenantId)) { throw new InvalidOperationException("FileSystem '" + tenantId + "' is currently locked and cannot be accessed"); } ManualResetEvent cleanupLock; if (Cleanups.TryGetValue(tenantId, out cleanupLock) && cleanupLock.WaitOne(MaxSecondsForTaskToWaitForDatabaseToLoad * 1000) == false) { throw new InvalidOperationException(string.Format("File system '{0}' is currently being restarted and cannot be accessed. We already waited {1} seconds.", tenantId, MaxSecondsForTaskToWaitForDatabaseToLoad)); } if (ResourcesStoresCache.TryGetValue(tenantId, out fileSystem)) { if (fileSystem.IsFaulted || fileSystem.IsCanceled) { ResourcesStoresCache.TryRemove(tenantId, out fileSystem); DateTime time; LastRecentlyUsed.TryRemove(tenantId, out time); // and now we will try creating it again } else { return(true); } } var config = CreateTenantConfiguration(tenantId); if (config == null) { return(false); } var hasAcquired = false; try { if (!ResourceSemaphore.Wait(ConcurrentResourceLoadTimeout)) { throw new ConcurrentLoadTimeoutException("Too much filesystems loading concurrently, timed out waiting for them to load."); } hasAcquired = true; fileSystem = ResourcesStoresCache.GetOrAdd(tenantId, __ => Task.Factory.StartNew(() => { var transportState = ResourseTransportStates.GetOrAdd(tenantId, s => new TransportState()); AssertLicenseParameters(config); var fs = new RavenFileSystem(config, tenantId, transportState); fs.Initialize(); // if we have a very long init process, make sure that we reset the last idle time for this db. LastRecentlyUsed.AddOrUpdate(tenantId, SystemTime.UtcNow, (_, time) => SystemTime.UtcNow); return(fs); }).ContinueWith(task => { if (task.Status == TaskStatus.Faulted) // this observes the task exception { Logger.WarnException("Failed to create filesystem " + tenantId, task.Exception); } return(task); }).Unwrap()); return(true); } finally { if (hasAcquired) { ResourceSemaphore.Release(); } } }