This contains information about the collection that is requested from the system.
Inheritance: System.EventArgs
        /// <summary>
        /// Executes a collection cycle on the pages in this list.
        /// </summary>
        /// <param name="shiftLevel">the number of bits to shift the referenced counter by.
        /// Value may be zero but cannot be negative</param>
        /// <param name="excludedList">A set of values to exclude from the collection process</param>
        /// <param name="e">Arguments for the collection.</param>
        /// <returns>The number of pages returned to the memory pool</returns>
        /// <remarks>If the collection mode is Emergency or Critical, it will only release the required number of pages and no more</remarks>
        //ToDo: Since i'll be parsing the entire list, rebuilding a new sorted tree may be quicker than removing individual blocks and copying.
        //ToDo: Also, I should probably change the ShouldCollect callback to an IEnumerable<int>.
        public int DoCollection(int shiftLevel, HashSet<int> excludedList, CollectionEventArgs e)
        {
            if (m_disposed)
                throw new ObjectDisposedException(GetType().FullName);
            if (shiftLevel < 0)
                throw new ArgumentOutOfRangeException("shiftLevel", "must be non negative");

            int collectionCount = 0;
            int maxCollectCount = -1;
            if (e.CollectionMode == MemoryPoolCollectionMode.Emergency || e.CollectionMode == MemoryPoolCollectionMode.Critical)
            {
                maxCollectCount = e.DesiredPageReleaseCount;
            }

            for (int x = 0; x < m_pageIndexLookupByPositionIndex.Count; x++)
            {
                int pageIndex = m_pageIndexLookupByPositionIndex.Values[x];

                InternalPageMetaData block = m_listOfPages.GetValue(pageIndex);
                block.ReferencedCount >>= shiftLevel;
                m_listOfPages.OverwriteValue(pageIndex, block);
                if (block.ReferencedCount == 0)
                {
                    if (maxCollectCount != collectionCount)
                    {
                        if (!excludedList.Contains(pageIndex))
                        {
                            collectionCount++;
                            m_pageIndexLookupByPositionIndex.RemoveAt(x);
                            x--;
                            m_listOfPages.SetNull(pageIndex);
                            e.ReleasePage(block.MemoryPoolIndex);
                        }
                    }
                }
            }
            return collectionCount;
        }
        /// <summary>
        /// Executes a collection cycle of the pages that are unused.
        /// </summary>
        /// <returns></returns>
        public int DoCollection(CollectionEventArgs e)
        {
            lock (m_syncRoot)
            {
                if (m_disposed)
                    return 0;

                HashSet<int> pages = new HashSet<int>(m_arrayIndexLocks.Select(pageLock => pageLock.CurrentPageIndex));

                return m_pageList.DoCollection(1, pages, e);
            }
        }
        /// <summary>
        /// Determines whether to allocate more memory or to do a collection cycle on the existing pool.
        /// </summary>
        private void RequestMoreFreeBlocks()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Collection Cycle Started");
            bool lockTaken;

            Monitor.Enter(m_syncRoot); lockTaken = true;
            try
            {
                long size = CurrentCapacity;
                int collectionLevel = GetCollectionLevelBasedOnSize(size);
                long stopShrinkingLimit = CalculateStopShrinkingLimit(size);

                RemoveDeadEvents();

                sb.Append("Level: " + GetCollectionLevelString(collectionLevel));
                sb.AppendFormat(" Desired Size: {0}/{1}MB", stopShrinkingLimit >> 20, CurrentCapacity >> 20);
                sb.AppendLine();

                for (int x = 0; x < collectionLevel; x++)
                {
                    if (CurrentAllocatedSize < stopShrinkingLimit)
                        break;
                    CollectionEventArgs eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Normal, 0);

                    Monitor.Exit(m_syncRoot); lockTaken = false;

                    foreach (WeakEventHandler<CollectionEventArgs> c in m_requestCollectionEvent)
                    {
                        c.TryInvoke(this, eventArgs);
                    }

                    Monitor.Enter(m_syncRoot); lockTaken = true;

                    sb.AppendFormat("Pass {0} Usage: {1}/{2}MB", x + 1, CurrentAllocatedSize >> 20, CurrentCapacity >> 20);
                    sb.AppendLine();
                }

                long currentSize = CurrentAllocatedSize;
                long sizeBefore = CurrentCapacity;
                if (m_pageList.GrowMemoryPool(currentSize + (long)(0.1 * MaximumPoolSize)))
                {
                    long sizeAfter = CurrentCapacity;
                    m_releasePageVersion++;

                    sb.AppendFormat("Grew buffer pool {0}MB -> {1}MB", sizeBefore >> 20, sizeAfter >> 20);
                    sb.AppendLine();
                }

                if (m_pageList.FreeSpaceBytes < 0.05 * MaximumPoolSize)
                {
                    int pagesToBeReleased = (int)((0.05 * MaximumPoolSize - m_pageList.FreeSpaceBytes) / PageSize);

                    sb.AppendFormat("* Emergency Collection Occuring. Attempting to release {0} pages.", pagesToBeReleased);
                    sb.AppendLine();

                    Log.Publish(MessageLevel.Warning, MessageFlags.PerformanceIssue, "Pool Emergency", string.Format("Memory pool is reaching an Emergency level. Desiring Pages To Release: {0}", pagesToBeReleased));

                    CollectionEventArgs eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Emergency, pagesToBeReleased);

                    Monitor.Exit(m_syncRoot); lockTaken = false;

                    foreach (WeakEventHandler<CollectionEventArgs> c in m_requestCollectionEvent)
                    {
                        if (eventArgs.DesiredPageReleaseCount == 0)
                            break;
                        c.TryInvoke(this, eventArgs);
                    }

                    Monitor.Enter(m_syncRoot); lockTaken = true;

                    if (eventArgs.DesiredPageReleaseCount > 0)
                    {
                        sb.AppendFormat("** Critical Collection Occuring. Attempting to release {0} pages.", pagesToBeReleased);
                        sb.AppendLine();

                        Log.Publish(MessageLevel.Warning, MessageFlags.PerformanceIssue, "Pool Critical", string.Format("Memory pool is reaching an Critical level. Desiring Pages To Release: {0}", eventArgs.DesiredPageReleaseCount));

                        eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Critical, eventArgs.DesiredPageReleaseCount);

                        Monitor.Exit(m_syncRoot); lockTaken = false;

                        foreach (WeakEventHandler<CollectionEventArgs> c in m_requestCollectionEvent)
                        {
                            if (eventArgs.DesiredPageReleaseCount == 0)
                                break;
                            c.TryInvoke(this, eventArgs);
                        }

                        Monitor.Enter(m_syncRoot); lockTaken = true;
                    }
                }

                sw.Stop();
                sb.AppendFormat("Elapsed Time: {0}ms", sw.Elapsed.TotalMilliseconds.ToString("0.0"));
                Log.Publish(MessageLevel.Info, "Memory Pool Collection Occured", sb.ToString());

                RemoveDeadEvents();
            }
            finally
            {
                if (lockTaken)
                    Monitor.Exit(m_syncRoot);
            }
        }
        /// <summary>
        /// Handles the <see cref="MemoryPool.RequestCollection"/> event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void m_pool_RequestCollection(object sender, CollectionEventArgs e)
        {
            if (m_disposed)
                return;

            m_pageReplacementAlgorithm.DoCollection(e);

            if (e.CollectionMode == MemoryPoolCollectionMode.Critical)
            {
                //ToDo: actually do something differently if collection level reaches critical
                m_pageReplacementAlgorithm.DoCollection(e);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Determines whether to allocate more memory or to do a collection cycle on the existing pool.
        /// </summary>
        private void RequestMoreFreeBlocks()
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("Collection Cycle Started");
            bool lockTaken;

            Monitor.Enter(m_syncRoot); lockTaken = true;
            try
            {
                long size               = CurrentCapacity;
                int  collectionLevel    = GetCollectionLevelBasedOnSize(size);
                long stopShrinkingLimit = CalculateStopShrinkingLimit(size);

                RemoveDeadEvents();

                sb.Append("Level: " + GetCollectionLevelString(collectionLevel));
                sb.AppendFormat(" Desired Size: {0}/{1}MB", stopShrinkingLimit >> 20, CurrentCapacity >> 20);
                sb.AppendLine();

                for (int x = 0; x < collectionLevel; x++)
                {
                    if (CurrentAllocatedSize < stopShrinkingLimit)
                    {
                        break;
                    }
                    CollectionEventArgs eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Normal, 0);

                    Monitor.Exit(m_syncRoot); lockTaken = false;

                    foreach (WeakEventHandler <CollectionEventArgs> c in m_requestCollectionEvent)
                    {
                        c.TryInvoke(this, eventArgs);
                    }

                    Monitor.Enter(m_syncRoot); lockTaken = true;

                    sb.AppendFormat("Pass {0} Usage: {1}/{2}MB", x + 1, CurrentAllocatedSize >> 20, CurrentCapacity >> 20);
                    sb.AppendLine();
                }

                long currentSize = CurrentAllocatedSize;
                long sizeBefore  = CurrentCapacity;
                if (m_pageList.GrowMemoryPool(currentSize + (long)(0.1 * MaximumPoolSize)))
                {
                    long sizeAfter = CurrentCapacity;
                    m_releasePageVersion++;

                    sb.AppendFormat("Grew buffer pool {0}MB -> {1}MB", sizeBefore >> 20, sizeAfter >> 20);
                    sb.AppendLine();
                }

                if (m_pageList.FreeSpaceBytes < 0.05 * MaximumPoolSize)
                {
                    int pagesToBeReleased = (int)((0.05 * MaximumPoolSize - m_pageList.FreeSpaceBytes) / PageSize);

                    sb.AppendFormat("* Emergency Collection Occuring. Attempting to release {0} pages.", pagesToBeReleased);
                    sb.AppendLine();

                    Log.Publish(MessageLevel.Warning, MessageFlags.PerformanceIssue, "Pool Emergency", string.Format("Memory pool is reaching an Emergency level. Desiring Pages To Release: {0}", pagesToBeReleased));

                    CollectionEventArgs eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Emergency, pagesToBeReleased);

                    Monitor.Exit(m_syncRoot); lockTaken = false;

                    foreach (WeakEventHandler <CollectionEventArgs> c in m_requestCollectionEvent)
                    {
                        if (eventArgs.DesiredPageReleaseCount == 0)
                        {
                            break;
                        }
                        c.TryInvoke(this, eventArgs);
                    }

                    Monitor.Enter(m_syncRoot); lockTaken = true;

                    if (eventArgs.DesiredPageReleaseCount > 0)
                    {
                        sb.AppendFormat("** Critical Collection Occuring. Attempting to release {0} pages.", pagesToBeReleased);
                        sb.AppendLine();

                        Log.Publish(MessageLevel.Warning, MessageFlags.PerformanceIssue, "Pool Critical", string.Format("Memory pool is reaching an Critical level. Desiring Pages To Release: {0}", eventArgs.DesiredPageReleaseCount));

                        eventArgs = new CollectionEventArgs(ReleasePage, MemoryPoolCollectionMode.Critical, eventArgs.DesiredPageReleaseCount);

                        Monitor.Exit(m_syncRoot); lockTaken = false;

                        foreach (WeakEventHandler <CollectionEventArgs> c in m_requestCollectionEvent)
                        {
                            if (eventArgs.DesiredPageReleaseCount == 0)
                            {
                                break;
                            }
                            c.TryInvoke(this, eventArgs);
                        }

                        Monitor.Enter(m_syncRoot); lockTaken = true;
                    }
                }

                sw.Stop();
                sb.AppendFormat("Elapsed Time: {0}ms", sw.Elapsed.TotalMilliseconds.ToString("0.0"));
                Log.Publish(MessageLevel.Info, "Memory Pool Collection Occured", sb.ToString());

                RemoveDeadEvents();
            }
            finally
            {
                if (lockTaken)
                {
                    Monitor.Exit(m_syncRoot);
                }
            }
        }