Exemple #1
0
        public void Cleanup()
        {
            if (_recycleArea.Count == 0 && _scratchBuffers.Count == 1)
            {
                return;
            }

            long txIdAllowingToReleaseOldScratches = -1;

            // ReSharper disable once LoopCanBeConvertedToQuery
            foreach (var scratchBufferItem in _scratchBuffers)
            {
                if (scratchBufferItem.Value == _current)
                {
                    continue;
                }

                txIdAllowingToReleaseOldScratches = Math.Max(txIdAllowingToReleaseOldScratches,
                                                             scratchBufferItem.Value.File.TxIdAfterWhichLatestFreePagesBecomeAvailable);
            }

            ByteStringContext byteStringContext;

            try
            {
                byteStringContext = new ByteStringContext(SharedMultipleUseFlag.None);
            }
            catch (Exception e) when(e is OutOfMemoryException || e is EarlyOutOfMemoryException)
            {
                return;
            }

            try
            {
                while (_env.CurrentReadTransactionId <= txIdAllowingToReleaseOldScratches)
                {
                    // we've just flushed and had no more writes after that, let us bump id of next read transactions to ensure
                    // that nobody will attempt to read old scratches so we will be able to release more files

                    try
                    {
                        using (var tx = _env.NewLowLevelTransaction(new TransactionPersistentContext(),
                                                                    TransactionFlags.ReadWrite, timeout: TimeSpan.FromMilliseconds(500), context: byteStringContext))
                        {
                            tx.ModifyPage(0);
                            tx.Commit();
                        }
                    }
                    catch (TimeoutException)
                    {
                        break;
                    }
                    catch (DiskFullException)
                    {
                        break;
                    }
                }

                IDisposable exitPreventNewTransactions = null;

                try
                {
                    // we need to ensure that no access to _recycleArea and _scratchBuffers will take place in the same time
                    // and only methods that access this are used within write transaction

                    using (_env.WriteTransaction())
                    {
                        // additionally we must not allow to start any transaction (even read one) to start because it uses GetPagerStatesOfAllScratches() which
                        // returns _pagerStatesAllScratchesCache that we're updating here

                        if (_env.TryPreventNewTransactions(TimeSpan.Zero, out exitPreventNewTransactions))
                        {
                            var removedInactive = RemoveInactiveScratches(_current, updateCacheBeforeDisposingScratch: false); // no need to update cache because we're going do to it here anyway

                            var removedInactiveRecycled = RemoveInactiveRecycledScratches();

                            if (_logger.IsInfoEnabled)
                            {
                                _logger.Info(
                                    $"Cleanup of {nameof(ScratchBufferPool)} removed: {removedInactive} inactive scratches and {removedInactiveRecycled} inactive from the recycle area");
                            }

                            _forTestingPurposes?.ActionToCallDuringCleanupRightAfterRemovingInactiveScratches?.Invoke();

                            UpdateCacheForPagerStatesOfAllScratches(); // it's going to be called by Rollback() of the write tx but let's call it explicitly so we can easily find this usage
                        }
                    }
                }
                catch (TimeoutException)
                {
                }
                catch (DiskFullException)
                {
                }
                finally
                {
                    exitPreventNewTransactions?.Dispose();
                }
            }
            finally
            {
                byteStringContext.Dispose();
            }
        }