/// <summary>
        /// Internal function called by the plugin to remove old, non-used buffers.
        /// </summary>
        internal static void Maintain()
        {
            DateTime now = DateTime.UtcNow;

            if (!_isEnabled || lastMaintenance + RunMaintenanceEvery > now)
            {
                return;
            }
            lastMaintenance = now;

            DateTime olderThan = now - RemoveOlderThan;

            rwLock.EnterWriteLock();
            try
            {
                //if (HTTPManager.Logger.Level == Logger.Loglevels.All)
                //    HTTPManager.Logger.Information("VariableSizedBufferPool", "Before Maintain: " + GetStatistics());

                for (int i = 0; i < FreeBuffers.Count; ++i)
                {
                    BufferStore       store   = FreeBuffers[i];
                    List <BufferDesc> buffers = store.buffers;

                    for (int cv = buffers.Count - 1; cv >= 0; cv--)
                    {
                        BufferDesc desc = buffers[cv];

                        if (desc.released < olderThan)
                        {
                            // buffers stores available buffers ascending by age. So, when we find an old enough, we can
                            //  delete all entries in the [0..cv] range.

                            int removeCount = cv + 1;
                            buffers.RemoveRange(0, removeCount);
                            PoolSize -= (int)(removeCount * store.Size);
                            break;
                        }
                    }

                    if (RemoveEmptyLists && buffers.Count == 0)
                    {
                        FreeBuffers.RemoveAt(i--);
                    }
                }

                //if (HTTPManager.Logger.Level == Logger.Loglevels.All)
                //    HTTPManager.Logger.Information("VariableSizedBufferPool", "After Maintain: " + GetStatistics());
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }
        /// <summary>
        /// Get byte[] from the pool. If canBeLarge is true, the returned buffer might be larger than the requested size.
        /// </summary>
        public static byte[] Get(long size, bool canBeLarger)
        {
            if (!_isEnabled)
            {
                return(new byte[size]);
            }

            // Return a fix reference for 0 length requests. Any resize call (even Array.Resize) creates a new reference
            //  so we are safe to expose it to multiple callers.
            if (size == 0)
            {
                return(VariableSizedBufferPool.NoData);
            }

            lock (FreeBuffers)
            {
                if (FreeBuffers.Count == 0)
                {
                    return(new byte[size]);
                }

                BufferDesc bufferDesc = FindFreeBuffer(size, canBeLarger);
                if (bufferDesc.buffer == null)
                {
                    if (canBeLarger)
                    {
                        if (size < MinBufferSize)
                        {
                            size = MinBufferSize;
                        }
                        else if (!IsPowerOfTwo(size))
                        {
                            size = NextPowerOf2(size);
                        }
                    }

                    return(new byte[size]);
                }
                else
                {
                    GetBuffers++;
                }

                PoolSize -= bufferDesc.buffer.Length;

                return(bufferDesc.buffer);
            }
        }
        private static BufferDesc FindFreeBuffer(long size, bool canBeLarger)
        {
            for (int i = 0; i < FreeBuffers.Count; ++i)
            {
                BufferStore store = FreeBuffers[i];

                if (store.buffers.Count > 0 && (store.Size == size || (canBeLarger && store.Size > size)))
                {
                    // Getting the last one has two desired effect:
                    //  1.) RemoveAt should be quicker as it don't have to move all the remaining entries
                    //  2.) Old, non-used buffers will age. Getting a buffer and putting it back will not keep buffers fresh.

                    BufferDesc lastFree = store.buffers[store.buffers.Count - 1];
                    store.buffers.RemoveAt(store.buffers.Count - 1);

                    return(lastFree);
                }
            }

            return(BufferDesc.Empty);
        }