private void DocumentDatabaseDisposingStarted(object documentDatabase, EventArgs args) { try { var database = documentDatabase as DocumentDatabase; if (database == null) { return; } ResourcesStoresCache.Set(database.Name, (dbName) => { var tcs = new TaskCompletionSource <DocumentDatabase>(); tcs.SetException(new ObjectDisposedException(database.Name, "Database named " + database.Name + " is being disposed right now and cannot be accessed.\r\n" + "Access will be available when the dispose process will end") { Data = { { "Raven/KeepInResourceStore", "true" } } }); // we need to observe this task exception in case no one is actually looking at it during disposal GC.KeepAlive(tcs.Task.Exception); return(tcs.Task); }); } catch (Exception ex) { Logger.WarnException("Failed to substitute database task with temporary place holder. This should not happen", ex); } }
public override Task <DocumentDatabase> TryGetOrCreateResourceStore(StringSegment databaseName) { if (HasLocks != 0) { AssertLocks(databaseName); } Task <DocumentDatabase> database; if (ResourcesStoresCache.TryGetValue(databaseName, out database)) { if (database.IsFaulted || database.IsCanceled) { ResourcesStoresCache.TryRemove(databaseName, out database); DateTime time; LastRecentlyUsed.TryRemove(databaseName, out time); // and now we will try creating it again } else { return(database); } } return(CreateDatabase(databaseName)); }
public bool TryGetOrCreateResourceStore(string tenantId, out Task <DocumentDatabase> database) { if (Locks.Contains(DisposingLock)) { throw new ObjectDisposedException("DatabaseLandlord", "Server is shutting down, can't access any databases"); } if (ResourcesStoresCache.TryGetValue(tenantId, out database)) { if (database.IsFaulted || database.IsCanceled) { ResourcesStoresCache.TryRemove(tenantId, out database); DateTime time; LastRecentlyUsed.TryRemove(tenantId, out time); // and now we will try creating it again } else { return(true); } } if (Locks.Contains(tenantId)) { throw new InvalidOperationException("Database '" + tenantId + "' is currently locked and cannot be accessed."); } var config = CreateTenantConfiguration(tenantId); if (config == null) { return(false); } database = ResourcesStoresCache.GetOrAdd(tenantId, __ => Task.Factory.StartNew(() => { var transportState = ResourseTransportStates.GetOrAdd(tenantId, s => new TransportState()); AssertLicenseParameters(config); var documentDatabase = new DocumentDatabase(config, transportState); documentDatabase.SpinBackgroundWorkers(); documentDatabase.Disposing += DocumentDatabaseDisposingStarted; documentDatabase.DisposingEnded += DocumentDatabaseDisposingEnded; documentDatabase.StorageInaccessible += UnloadDatabaseOnStorageInaccessible; // 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(documentDatabase); }).ContinueWith(task => { if (task.Status == TaskStatus.Faulted) // this observes the task exception { Logger.WarnException("Failed to create database " + tenantId, task.Exception); } return(task); }).Unwrap()); return(true); }
public bool TryGetOrCreateResourceStore(string tenantId, out Task <CounterStorage> counter) { if (Locks.Contains(DisposingLock)) { throw new ObjectDisposedException("CountersLandlord", "Server is shutting down, can't access any counters"); } if (Enabled == false) { throw new InvalidOperationException("Counters are an experimental feature that is not enabled"); } if (ResourcesStoresCache.TryGetValue(tenantId, out counter)) { if (counter.IsFaulted || counter.IsCanceled) { ResourcesStoresCache.TryRemove(tenantId, out counter); DateTime time; LastRecentlyUsed.TryRemove(tenantId, out time); // and now we will try creating it again } else { return(true); } } if (Locks.Contains(tenantId)) { throw new InvalidOperationException("Counters '" + tenantId + "' is currently locked and cannot be accessed"); } var config = CreateTenantConfiguration(tenantId); if (config == null) { return(false); } counter = ResourcesStoresCache.GetOrAdd(tenantId, __ => Task.Factory.StartNew(() => { var transportState = ResourseTransportStates.GetOrAdd(tenantId, s => new TransportState()); var cs = new CounterStorage(systemDatabase.ServerUrl, tenantId, config, transportState); AssertLicenseParameters(); // 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(cs); }).ContinueWith(task => { if (task.Status == TaskStatus.Faulted) // this observes the task exception { Logger.WarnException("Failed to create counters " + tenantId, task.Exception); } return(task); }).Unwrap()); return(true); }
public void ForAllCountersInCacheOnly(Action <CounterStorage> action) { foreach (var value in ResourcesStoresCache .Select(cs => cs.Value) .Where(value => value.Status == TaskStatus.RanToCompletion)) { action(value.Result); } }
public void ForAllFileSystems(Action <RavenFileSystem> action) { foreach (var value in ResourcesStoresCache .Select(db => db.Value) .Where(value => value.Status == TaskStatus.RanToCompletion)) { action(value.Result); } }
public void ForAllTimeSeries(Action <TimeSeriesStorage> action) { foreach (var value in ResourcesStoresCache .Select(cs => cs.Value) .Where(value => value.Status == TaskStatus.RanToCompletion)) { action(value.Result); } }
public void ForAllDatabases(Action <DocumentDatabase> action) { action(systemDatabase); foreach (var value in ResourcesStoresCache .Select(db => db.Value) .Where(value => value.Status == TaskStatus.RanToCompletion)) { action(value.Result); } }
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 (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); } } if (Locks.Contains(tenantId)) { throw new InvalidOperationException("FileSystem '" + tenantId + "' is currently locked and cannot be accessed"); } var config = CreateTenantConfiguration(tenantId); if (config == null) { return(false); } 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); }
public bool IsFileSystemLoaded(string tenantName) { Task <RavenFileSystem> dbTask; if (ResourcesStoresCache.TryGetValue(tenantName, out dbTask) == false) { return(false); } return(dbTask != null && dbTask.Status == TaskStatus.RanToCompletion); }
protected override bool TryGetOrCreateResourceStore(string tenantId, out IResourceStore database) { if (ResourcesStoresCache.TryGetValue(tenantId, out database)) { return(true); } JsonDocument jsonDocument; using (DefaultDatabase.DisableAllTriggersForCurrentThread()) jsonDocument = DefaultDatabase.Get("Raven/Databases/" + tenantId, null); if (jsonDocument == null) { return(false); } var document = jsonDocument.DataAsJson.JsonDeserialization <DatabaseDocument>(); database = ResourcesStoresCache.GetOrAddAtomically(tenantId, s => { var config = new InMemoryRavenConfiguration { Settings = DefaultConfiguration.Settings, }; foreach (var setting in document.Settings) { config.Settings[setting.Key] = setting.Value; } var dataDir = config.Settings["Raven/DataDir"]; if (dataDir == null) { throw new InvalidOperationException("Could not find Raven/DataDir"); } if (dataDir.StartsWith("~/") || dataDir.StartsWith(@"~\")) { var baseDataPath = Path.GetDirectoryName(DefaultDatabase.Configuration.DataDirectory); if (baseDataPath == null) { throw new InvalidOperationException("Could not find root data path"); } config.Settings["Raven/DataDir"] = Path.Combine(baseDataPath, dataDir.Substring(2)); } config.Settings["Raven/VirtualDir"] = config.Settings["Raven/VirtualDir"] + "/" + tenantId; config.DatabaseName = tenantId; config.Initialize(); var documentDatabase = new DocumentDatabase(config); documentDatabase.SpinBackgroundWorkers(); return(documentDatabase); }); return(true); }
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 bool IsDatabaseLoaded(string tenantName) { if (tenantName == Constants.SystemDatabase) { return(true); } Task <DocumentDatabase> dbTask; if (ResourcesStoresCache.TryGetValue(tenantName, out dbTask) == false) { return(false); } return(dbTask != null && dbTask.Status == TaskStatus.RanToCompletion); }
private void DocumentDatabaseDisposingEnded(object documentDatabase, EventArgs args) { try { var database = documentDatabase as DocumentDatabase; if (database == null) { return; } ResourcesStoresCache.Remove(database.Name); } catch (Exception ex) { Logger.ErrorException("Failed to remove database at the end of the disposal. This should not happen", ex); } }
public Guid?GetDatabaseId(string tenantName) { if (tenantName == Constants.SystemDatabase) { return(null); } Task <DocumentDatabase> dbTask; if (ResourcesStoresCache.TryGetValue(tenantName, out dbTask) == false) { return(null); } if (dbTask == null || dbTask.Status != TaskStatus.RanToCompletion) { return(null); } return(dbTask.Result.Statistics.DatabaseId); }
public bool TryGetDatabase(string tenantId, out Task <DocumentDatabase> database) { if (Locks.Contains(DisposingLock)) { throw new ObjectDisposedException("DatabaseLandlord", "Server is shutting down, can't access any databases"); } if (!ResourcesStoresCache.TryGetValue(tenantId, out database)) { return(false); } if (!database.IsFaulted && !database.IsCanceled) { return(true); } ResourcesStoresCache.TryRemove(tenantId, out database); DateTime time; LastRecentlyUsed.TryRemove(tenantId, out time); return(false); }
private void DocumentDatabaseDisposingStarted(object documentDatabase, EventArgs args) { try { var database = documentDatabase as DocumentDatabase; if (database == null) { return; } ResourcesStoresCache.Set(database.Name, (dbName) => { var tcs = new TaskCompletionSource <DocumentDatabase>(); tcs.SetException(new ObjectDisposedException(dbName, "Database named " + dbName + " is being disposed right now and cannot be accessed.\r\n" + "Access will be available when the dispose process will end")); return(tcs.Task); }); } catch (Exception ex) { Logger.WarnException("Failed to substitute database task with temporary place holder. This should not happen", ex); } }
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(); } } }
public bool TryGetFileSystem(string tenantId, out Task <RavenFileSystem> fileSystem) { return(ResourcesStoresCache.TryGetValue(tenantId, out fileSystem)); }
public bool TryGetOrCreateResourceStore(string tenantId, out Task <DocumentDatabase> database) { if (Locks.Contains(DisposingLock)) { throw new ObjectDisposedException("DatabaseLandlord", "Server is shutting down, can't access any databases"); } if (ResourcesStoresCache.TryGetValue(tenantId, out database)) { if (database.IsFaulted || database.IsCanceled) { ResourcesStoresCache.TryRemove(tenantId, out database); DateTime time; LastRecentlyUsed.TryRemove(tenantId, out time); // and now we will try creating it again } else { return(true); } } if (Locks.Contains(tenantId)) { throw new InvalidOperationException("Database '" + tenantId + "' is currently locked and cannot be accessed."); } var config = CreateTenantConfiguration(tenantId); if (config == null) { return(false); } database = ResourcesStoresCache.GetOrAdd(tenantId, __ => Task.Factory.StartNew(() => { var transportState = ResourseTransportStates.GetOrAdd(tenantId, s => new TransportState()); AssertLicenseParameters(config); var documentDatabase = new DocumentDatabase(config, transportState); documentDatabase.SpinBackgroundWorkers(); 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(tenantId, SystemTime.UtcNow, (_, time) => SystemTime.UtcNow); return(documentDatabase); }).ContinueWith(task => { if (task.Status == TaskStatus.Faulted) // this observes the task exception { Logger.WarnException("Failed to create database " + tenantId, task.Exception); } return(task); }).Unwrap()); 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(tenantId, out val); } } return(true); }