Exemplo n.º 1
0
        public void Cleanup(string db, bool skipIfActive, Func <TResource, bool> shouldSkip = null)
        {
            using (ResourcesStoresCache.WithAllLocks())
            {
                DateTime         time;
                Task <TResource> databaseTask;
                if (ResourcesStoresCache.TryGetValue(db, out databaseTask) == false)
                {
                    LastRecentlyUsed.TryRemove(db, out time);
                    return;
                }
                if (databaseTask.Status == TaskStatus.Faulted || databaseTask.Status == TaskStatus.Canceled)
                {
                    LastRecentlyUsed.TryRemove(db, out time);
                    ResourcesStoresCache.TryRemove(db, out databaseTask);
                    return;
                }
                if (databaseTask.Status != TaskStatus.RanToCompletion)
                {
                    return; // still starting up
                }

                var database = databaseTask.Result;
                if ((skipIfActive &&
                     (SystemTime.UtcNow - LastWork(database)).TotalMinutes < 10) ||
                    (shouldSkip != null && shouldSkip(database)))
                {
                    // this document might not be actively working with user, but it is actively doing indexes, we will
                    // wait with unloading this database until it hasn't done indexing for a while.
                    // This prevent us from shutting down big databases that have been left alone to do indexing work.
                    return;
                }
                try
                {
                    database.Dispose();
                }
                catch (Exception e)
                {
                    Logger.ErrorException("Could not cleanup tenant database: " + db, e);
                    return;
                }
                LastRecentlyUsed.TryRemove(db, out time);
                ResourcesStoresCache.TryRemove(db, out databaseTask);

                var onDatabaseCleanupOccured = CleanupOccured;
                if (onDatabaseCleanupOccured != null)
                {
                    onDatabaseCleanupOccured(db);
                }
            }
        }
Exemplo n.º 2
0
        public void Cleanup(string resource,
                            TimeSpan?skipIfActiveInDuration,
                            Func <TResource, bool> shouldSkip    = null,
                            DocumentChangeTypes notificationType = DocumentChangeTypes.None)
        {
            if (Cleanups.TryAdd(resource, new ManualResetEvent(false)) == false)
            {
                return;
            }

            try
            {
                using (ResourcesStoresCache.WithAllLocks())
                {
                    DateTime         time;
                    Task <TResource> resourceTask;
                    if (ResourcesStoresCache.TryGetValue(resource, out resourceTask) == false)
                    {
                        LastRecentlyUsed.TryRemove(resource, out time);
                        return;
                    }
                    if (resourceTask.Status == TaskStatus.Faulted || resourceTask.Status == TaskStatus.Canceled)
                    {
                        LastRecentlyUsed.TryRemove(resource, out time);
                        ResourcesStoresCache.TryRemove(resource, out resourceTask);
                        return;
                    }
                    if (resourceTask.Status != TaskStatus.RanToCompletion)
                    {
                        return;                 // still starting up
                    }

                    var database = resourceTask.Result;
                    if ((skipIfActiveInDuration != null && (SystemTime.UtcNow - LastWork(database)) < skipIfActiveInDuration) ||
                        (shouldSkip != null && shouldSkip(database)))
                    {
                        // this document might not be actively working with user, but it is actively doing indexes, we will
                        // wait with unloading this database until it hasn't done indexing for a while.
                        // This prevent us from shutting down big databases that have been left alone to do indexing work.
                        return;
                    }
                    try
                    {
                        database.Dispose();
                    }
                    catch (Exception e)
                    {
                        Logger.ErrorException("Could not cleanup tenant database: " + resource, e);
                        return;
                    }

                    LastRecentlyUsed.TryRemove(resource, out time);
                    ResourcesStoresCache.TryRemove(resource, out resourceTask);

                    if (notificationType == DocumentChangeTypes.Delete)
                    {
                        TransportState transportState;
                        ResourseTransportStates.TryRemove(resource, out transportState);
                        if (transportState != null)
                        {
                            transportState.Dispose();
                        }
                    }

                    var onResourceCleanupOccured = CleanupOccured;
                    if (onResourceCleanupOccured != null)
                    {
                        onResourceCleanupOccured(resource);
                    }
                }
            }
            finally
            {
                ManualResetEvent cleanupLock;
                if (Cleanups.TryRemove(resource, out cleanupLock))
                {
                    cleanupLock.Set();
                }
            }
        }
Exemplo n.º 3
0
        public void Dispose()
        {
            disposerLock.EnterWriteLock();
            try
            {
                TenantDatabaseModified.Occured -= TenantDatabaseRemoved;
                var exceptionAggregator = new ExceptionAggregator(logger, "Could not properly dispose of HttpServer");
                exceptionAggregator.Execute(() =>
                {
                    if (serverTimer != null)
                    {
                        serverTimer.Dispose();
                    }
                });
                exceptionAggregator.Execute(() =>
                {
                    if (listener != null && listener.IsListening)
                    {
                        listener.Stop();
                    }
                });
                disposed = true;

                exceptionAggregator.Execute(() =>
                {
                    using (ResourcesStoresCache.WithAllLocks())
                    {
                        // shut down all databases in parallel, avoid having to wait for each one
                        Parallel.ForEach(ResourcesStoresCache.Values, dbTask =>
                        {
                            if (dbTask.IsCompleted == false)
                            {
                                dbTask.ContinueWith(task =>
                                {
                                    if (task.Status != TaskStatus.RanToCompletion)
                                    {
                                        return;
                                    }

                                    try
                                    {
                                        task.Result.Dispose();
                                    }
                                    catch (Exception e)
                                    {
                                        logger.WarnException("Failure in deferred disosal of a database", e);
                                    }
                                });
                            }
                            else if (dbTask.Status == TaskStatus.RanToCompletion)
                            {
                                exceptionAggregator.Execute(dbTask.Result.Dispose);
                            }
                            // there is no else, the db is probably faulted
                        });
                        ResourcesStoresCache.Clear();
                    }
                });

                exceptionAggregator.Execute(currentConfiguration.Dispose);
                exceptionAggregator.Execute(currentDatabase.Dispose);
                exceptionAggregator.Execute(currentTenantId.Dispose);
                exceptionAggregator.Execute(bufferPool.Dispose);
                exceptionAggregator.ThrowIfNeeded();
            }
            finally
            {
                disposerLock.ExitWriteLock();
            }
        }