public unsafe void Dispose() { if (_databaseShutdown.IsCancellationRequested) { return; // double dispose? } lock (this) { if (_databaseShutdown.IsCancellationRequested) { return; // double dispose? } //before we dispose of the database we take its latest info to be displayed in the studio try { var databaseInfo = GenerateDatabaseInfo(); if (databaseInfo != null) { DatabaseInfoCache?.InsertDatabaseInfo(databaseInfo, Name); } } catch (Exception e) { // if we encountered a catastrophic failure we might not be able to retrieve database info if (_logger.IsInfoEnabled) { _logger.Info("Failed to generate and store database info", e); } } _databaseShutdown.Cancel(); // we'll wait for 1 minute to drain all the requests // from the database var sp = Stopwatch.StartNew(); while (sp.ElapsedMilliseconds < 60 * 1000) { if (Interlocked.Read(ref _usages) == 0) { break; } if (_waitForUsagesOnDisposal.Wait(1000)) { _waitForUsagesOnDisposal.Reset(); } } var exceptionAggregator = new ExceptionAggregator(_logger, $"Could not dispose {nameof(DocumentDatabase)} {Name}"); foreach (var connection in RunningTcpConnections) { exceptionAggregator.Execute(() => { connection.Dispose(); }); } exceptionAggregator.Execute(() => { TxMerger?.Dispose(); }); if (_indexStoreTask != null) { exceptionAggregator.Execute(() => { _indexStoreTask.Wait(DatabaseShutdown); }); } exceptionAggregator.Execute(() => { IndexStore?.Dispose(); }); exceptionAggregator.Execute(() => { ExpiredDocumentsCleaner?.Dispose(); }); exceptionAggregator.Execute(() => { PeriodicBackupRunner?.Dispose(); }); exceptionAggregator.Execute(() => { DocumentTombstoneCleaner?.Dispose(); }); exceptionAggregator.Execute(() => { ReplicationLoader?.Dispose(); }); exceptionAggregator.Execute(() => { EtlLoader?.Dispose(); }); exceptionAggregator.Execute(() => { Operations?.Dispose(exceptionAggregator); }); exceptionAggregator.Execute(() => { NotificationCenter?.Dispose(); }); exceptionAggregator.Execute(() => { SubscriptionStorage?.Dispose(); }); exceptionAggregator.Execute(() => { ConfigurationStorage?.Dispose(); }); exceptionAggregator.Execute(() => { DocumentsStorage?.Dispose(); }); exceptionAggregator.Execute(() => { _databaseShutdown.Dispose(); }); exceptionAggregator.Execute(() => { if (MasterKey == null) { return; } fixed(byte *pKey = MasterKey) { Sodium.sodium_memzero(pKey, (UIntPtr)MasterKey.Length); } }); exceptionAggregator.ThrowIfNeeded(); } }
public void Dispose() { //before we dispose of the database we take its latest info to be displayed in the studio var databaseInfo = GenerateDatabaseInfo(); DatabaseInfoCache?.InsertDatabaseInfo(databaseInfo, Name); _databaseShutdown.Cancel(); // we'll wait for 1 minute to drain all the requests // from the database for (int i = 0; i < 60; i++) { if (Interlocked.Read(ref _usages) == 0) { break; } _waitForUsagesOnDisposal.Wait(100); } var exceptionAggregator = new ExceptionAggregator(_logger, $"Could not dispose {nameof(DocumentDatabase)}"); foreach (var connection in RunningTcpConnections) { exceptionAggregator.Execute(() => { connection.Dispose(); }); } exceptionAggregator.Execute(() => { TxMerger.Dispose(); }); exceptionAggregator.Execute(() => { DocumentReplicationLoader.Dispose(); }); if (_indexStoreTask != null) { exceptionAggregator.Execute(() => { _indexStoreTask.Wait(DatabaseShutdown); _indexStoreTask = null; }); } if (_transformerStoreTask != null) { exceptionAggregator.Execute(() => { _transformerStoreTask.Wait(DatabaseShutdown); _transformerStoreTask = null; }); } exceptionAggregator.Execute(() => { IndexStore?.Dispose(); IndexStore = null; }); exceptionAggregator.Execute(() => { BundleLoader?.Dispose(); BundleLoader = null; }); exceptionAggregator.Execute(() => { DocumentTombstoneCleaner?.Dispose(); DocumentTombstoneCleaner = null; }); exceptionAggregator.Execute(() => { DocumentReplicationLoader?.Dispose(); DocumentReplicationLoader = null; }); exceptionAggregator.Execute(() => { SqlReplicationLoader?.Dispose(); SqlReplicationLoader = null; }); exceptionAggregator.Execute(() => { Operations?.Dispose(exceptionAggregator); Operations = null; }); exceptionAggregator.Execute(() => { SubscriptionStorage?.Dispose(); }); exceptionAggregator.Execute(() => { ConfigurationStorage?.Dispose(); }); exceptionAggregator.Execute(() => { DocumentsStorage?.Dispose(); DocumentsStorage = null; }); exceptionAggregator.ThrowIfNeeded(); }