InternalBufferManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / System.Runtime.DurableInstancing / System / Runtime / InternalBufferManager.cs / 1305376 / InternalBufferManager.cs

                            //---------------------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------------------
namespace System.Runtime
{ 
    using System;
    using System.Collections.Generic; 
    using System.Threading; 

    abstract class InternalBufferManager 
    {
        protected InternalBufferManager()
        {
        } 

        public abstract byte[] TakeBuffer(int bufferSize); 
        public abstract void ReturnBuffer(byte[] buffer); 
        public abstract void Clear();
 
        public static InternalBufferManager Create(long maxBufferPoolSize, int maxBufferSize)
        {
            if (maxBufferPoolSize == 0)
            { 
                return GCBufferManager.Value;
            } 
            else 
            {
                Fx.Assert(maxBufferPoolSize > 0 && maxBufferSize >= 0, "bad params, caller should verify"); 
                return new PooledBufferManager(maxBufferPoolSize, maxBufferSize);
            }
        }
 
        class PooledBufferManager : InternalBufferManager
        { 
            const int minBufferSize = 128; 
            const int maxMissesBeforeTuning = 8;
            const int initialBufferCount = 1; 
            readonly object tuningLock;

            int[] bufferSizes;
            BufferPool[] bufferPools; 
            long memoryLimit;
            long remainingMemory; 
            bool areQuotasBeingTuned; 
            int totalMisses;
 
            public PooledBufferManager(long maxMemoryToPool, int maxBufferSize)
            {
                this.tuningLock = new object();
                this.memoryLimit = maxMemoryToPool; 
                this.remainingMemory = maxMemoryToPool;
                List bufferPoolList = new List(); 
 
                for (int bufferSize = minBufferSize; ; )
                { 
                    long bufferCountLong = this.remainingMemory / bufferSize;

                    int bufferCount = bufferCountLong > int.MaxValue ? int.MaxValue : (int)bufferCountLong;
 
                    if (bufferCount > initialBufferCount)
                    { 
                        bufferCount = initialBufferCount; 
                    }
 
                    bufferPoolList.Add(new BufferPool(bufferSize, bufferCount));

                    this.remainingMemory -= (long)bufferCount * bufferSize;
 
                    if (bufferSize >= maxBufferSize)
                    { 
                        break; 
                    }
 
                    long newBufferSizeLong = (long)bufferSize * 2;

                    if (newBufferSizeLong > (long)maxBufferSize)
                    { 
                        bufferSize = maxBufferSize;
                    } 
                    else 
                    {
                        bufferSize = (int)newBufferSizeLong; 
                    }
                }

                this.bufferPools = bufferPoolList.ToArray(); 
                this.bufferSizes = new int[bufferPools.Length];
                for (int i = 0; i < bufferPools.Length; i++) 
                { 
                    this.bufferSizes[i] = bufferPools[i].BufferSize;
                } 
            }

            public override void Clear()
            { 
                for (int i = 0; i < this.bufferPools.Length; i++)
                { 
                    BufferPool bufferPool = this.bufferPools[i]; 
                    bufferPool.Clear();
                } 
            }

            void ChangeQuota(ref BufferPool bufferPool, int delta)
            { 
                BufferPool oldBufferPool = bufferPool;
                int newLimit = oldBufferPool.Limit + delta; 
                BufferPool newBufferPool = new BufferPool(oldBufferPool.BufferSize, newLimit); 
                for (int i = 0; i < newLimit; i++)
                { 
                    byte[] buffer = oldBufferPool.Take();
                    if (buffer == null)
                    {
                        break; 
                    }
                    newBufferPool.Return(buffer); 
                    newBufferPool.IncrementCount(); 
                }
                this.remainingMemory -= oldBufferPool.BufferSize * delta; 
                bufferPool = newBufferPool;
            }

            void DecreaseQuota(ref BufferPool bufferPool) 
            {
                ChangeQuota(ref bufferPool, -1); 
            } 

            int FindMostExcessivePool() 
            {
                long maxBytesInExcess = 0;
                int index = -1;
 
                for (int i = 0; i < this.bufferPools.Length; i++)
                { 
                    BufferPool bufferPool = this.bufferPools[i]; 

                    if (bufferPool.Peak < bufferPool.Limit) 
                    {
                        long bytesInExcess = (bufferPool.Limit - bufferPool.Peak) * (long)bufferPool.BufferSize;

                        if (bytesInExcess > maxBytesInExcess) 
                        {
                            index = i; 
                            maxBytesInExcess = bytesInExcess; 
                        }
                    } 
                }

                return index;
            } 

            int FindMostStarvedPool() 
            { 
                long maxBytesMissed = 0;
                int index = -1; 

                for (int i = 0; i < this.bufferPools.Length; i++)
                {
                    BufferPool bufferPool = this.bufferPools[i]; 

                    if (bufferPool.Peak == bufferPool.Limit) 
                    { 
                        long bytesMissed = bufferPool.Misses * (long)bufferPool.BufferSize;
 
                        if (bytesMissed > maxBytesMissed)
                        {
                            index = i;
                            maxBytesMissed = bytesMissed; 
                        }
                    } 
                } 

                return index; 
            }

            BufferPool FindPool(int desiredBufferSize)
            { 
                for (int i = 0; i < this.bufferSizes.Length; i++)
                { 
                    if (desiredBufferSize <= this.bufferSizes[i]) 
                    {
                        return this.bufferPools[i]; 
                    }
                }

                return null; 
            }
 
            void IncreaseQuota(ref BufferPool bufferPool) 
            {
                ChangeQuota(ref bufferPool, 1); 
            }

            public override void ReturnBuffer(byte[] buffer)
            { 
                Fx.Assert(buffer != null, "caller must verify");
                BufferPool bufferPool = FindPool(buffer.Length); 
                if (bufferPool != null) 
                {
                    if (buffer.Length != bufferPool.BufferSize) 
                    {
                        throw Fx.Exception.Argument("buffer", SRCore.BufferIsNotRightSizeForBufferManager);
                    }
 
                    if (bufferPool.Return(buffer))
                    { 
                        bufferPool.IncrementCount(); 
                    }
                } 
            }

            public override byte[] TakeBuffer(int bufferSize)
            { 
                Fx.Assert(bufferSize >= 0, "caller must ensure a non-negative argument");
 
                BufferPool bufferPool = FindPool(bufferSize); 
                if (bufferPool != null)
                { 
                    byte[] buffer = bufferPool.Take();
                    if (buffer != null)
                    {
                        bufferPool.DecrementCount(); 
                        return buffer;
                    } 
                    if (bufferPool.Peak == bufferPool.Limit) 
                    {
                        bufferPool.Misses++; 
                        if (++totalMisses >= maxMissesBeforeTuning)
                        {
                            TuneQuotas();
                        } 
                    }
                    return Fx.AllocateByteArray(bufferPool.BufferSize); 
                } 
                else
                { 
                    return Fx.AllocateByteArray(bufferSize);
                }
            }
 
            void TuneQuotas()
            { 
                if (this.areQuotasBeingTuned) 
                {
                    return; 
                }

                bool lockHeld = false;
                try 
                {
                    Monitor.TryEnter(this.tuningLock, ref lockHeld); 
 
                    // Don't bother if another thread already has the lock
                    if (!lockHeld || this.areQuotasBeingTuned) 
                    {
                        return;
                    }
 
                    this.areQuotasBeingTuned = true;
                } 
                finally 
                {
                    if (lockHeld) 
                    {
                        Monitor.Exit(this.tuningLock);
                    }
                } 

                // find the "poorest" pool 
                int starvedIndex = FindMostStarvedPool(); 
                if (starvedIndex >= 0)
                { 
                    BufferPool starvedBufferPool = this.bufferPools[starvedIndex];

                    if (this.remainingMemory < starvedBufferPool.BufferSize)
                    { 
                        // find the "richest" pool
                        int excessiveIndex = FindMostExcessivePool(); 
                        if (excessiveIndex >= 0) 
                        {
                            // steal from the richest 
                            DecreaseQuota(ref this.bufferPools[excessiveIndex]);
                        }
                    }
 
                    if (this.remainingMemory >= starvedBufferPool.BufferSize)
                    { 
                        // give to the poorest 
                        IncreaseQuota(ref this.bufferPools[starvedIndex]);
                    } 
                }

                // reset statistics
                for (int i = 0; i < this.bufferPools.Length; i++) 
                {
                    BufferPool bufferPool = this.bufferPools[i]; 
                    bufferPool.Misses = 0; 
                }
 
                this.totalMisses = 0;
                this.areQuotasBeingTuned = false;
            }
 
            class BufferPool
            { 
                int bufferSize; 
                int count;
                int limit; 
                int misses;
                int peak;
                SynchronizedPool pool;
 
                public BufferPool(int bufferSize, int limit)
                { 
                    this.pool = new SynchronizedPool(limit); 
                    this.bufferSize = bufferSize;
                    this.limit = limit; 
                }

                public int BufferSize
                { 
                    get { return this.bufferSize; }
                } 
 
                public int Limit
                { 
                    get { return this.limit; }
                }

                public int Misses 
                {
                    get { return this.misses; } 
                    set { this.misses = value; } 
                }
 
                public int Peak
                {
                    get { return this.peak; }
                } 

                public void Clear() 
                { 
                    this.pool.Clear();
                    this.count = 0; 
                }

                public void DecrementCount()
                { 
                    int newValue = this.count - 1;
                    if (newValue >= 0) 
                    { 
                        this.count = newValue;
                    } 
                }

                public void IncrementCount()
                { 
                    int newValue = this.count + 1;
                    if (newValue <= this.limit) 
                    { 
                        this.count = newValue;
                        if (newValue > this.peak) 
                        {
                            this.peak = newValue;
                        }
                    } 
                }
 
                public bool Return(byte[] buffer) 
                {
                    return this.pool.Return(buffer); 
                }

                public byte[] Take()
                { 
                    return this.pool.Take();
                } 
            } 
        }
 
        class GCBufferManager : InternalBufferManager
        {
            static GCBufferManager value = new GCBufferManager();
 
            GCBufferManager()
            { 
            } 

            public static GCBufferManager Value 
            {
                get { return value; }
            }
 
            public override void Clear()
            { 
            } 

            public override byte[] TakeBuffer(int bufferSize) 
            {
                return Fx.AllocateByteArray(bufferSize);
            }
 
            public override void ReturnBuffer(byte[] buffer)
            { 
                // do nothing, GC will reclaim this buffer 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------------------
namespace System.Runtime
{ 
    using System;
    using System.Collections.Generic; 
    using System.Threading; 

    abstract class InternalBufferManager 
    {
        protected InternalBufferManager()
        {
        } 

        public abstract byte[] TakeBuffer(int bufferSize); 
        public abstract void ReturnBuffer(byte[] buffer); 
        public abstract void Clear();
 
        public static InternalBufferManager Create(long maxBufferPoolSize, int maxBufferSize)
        {
            if (maxBufferPoolSize == 0)
            { 
                return GCBufferManager.Value;
            } 
            else 
            {
                Fx.Assert(maxBufferPoolSize > 0 && maxBufferSize >= 0, "bad params, caller should verify"); 
                return new PooledBufferManager(maxBufferPoolSize, maxBufferSize);
            }
        }
 
        class PooledBufferManager : InternalBufferManager
        { 
            const int minBufferSize = 128; 
            const int maxMissesBeforeTuning = 8;
            const int initialBufferCount = 1; 
            readonly object tuningLock;

            int[] bufferSizes;
            BufferPool[] bufferPools; 
            long memoryLimit;
            long remainingMemory; 
            bool areQuotasBeingTuned; 
            int totalMisses;
 
            public PooledBufferManager(long maxMemoryToPool, int maxBufferSize)
            {
                this.tuningLock = new object();
                this.memoryLimit = maxMemoryToPool; 
                this.remainingMemory = maxMemoryToPool;
                List bufferPoolList = new List(); 
 
                for (int bufferSize = minBufferSize; ; )
                { 
                    long bufferCountLong = this.remainingMemory / bufferSize;

                    int bufferCount = bufferCountLong > int.MaxValue ? int.MaxValue : (int)bufferCountLong;
 
                    if (bufferCount > initialBufferCount)
                    { 
                        bufferCount = initialBufferCount; 
                    }
 
                    bufferPoolList.Add(new BufferPool(bufferSize, bufferCount));

                    this.remainingMemory -= (long)bufferCount * bufferSize;
 
                    if (bufferSize >= maxBufferSize)
                    { 
                        break; 
                    }
 
                    long newBufferSizeLong = (long)bufferSize * 2;

                    if (newBufferSizeLong > (long)maxBufferSize)
                    { 
                        bufferSize = maxBufferSize;
                    } 
                    else 
                    {
                        bufferSize = (int)newBufferSizeLong; 
                    }
                }

                this.bufferPools = bufferPoolList.ToArray(); 
                this.bufferSizes = new int[bufferPools.Length];
                for (int i = 0; i < bufferPools.Length; i++) 
                { 
                    this.bufferSizes[i] = bufferPools[i].BufferSize;
                } 
            }

            public override void Clear()
            { 
                for (int i = 0; i < this.bufferPools.Length; i++)
                { 
                    BufferPool bufferPool = this.bufferPools[i]; 
                    bufferPool.Clear();
                } 
            }

            void ChangeQuota(ref BufferPool bufferPool, int delta)
            { 
                BufferPool oldBufferPool = bufferPool;
                int newLimit = oldBufferPool.Limit + delta; 
                BufferPool newBufferPool = new BufferPool(oldBufferPool.BufferSize, newLimit); 
                for (int i = 0; i < newLimit; i++)
                { 
                    byte[] buffer = oldBufferPool.Take();
                    if (buffer == null)
                    {
                        break; 
                    }
                    newBufferPool.Return(buffer); 
                    newBufferPool.IncrementCount(); 
                }
                this.remainingMemory -= oldBufferPool.BufferSize * delta; 
                bufferPool = newBufferPool;
            }

            void DecreaseQuota(ref BufferPool bufferPool) 
            {
                ChangeQuota(ref bufferPool, -1); 
            } 

            int FindMostExcessivePool() 
            {
                long maxBytesInExcess = 0;
                int index = -1;
 
                for (int i = 0; i < this.bufferPools.Length; i++)
                { 
                    BufferPool bufferPool = this.bufferPools[i]; 

                    if (bufferPool.Peak < bufferPool.Limit) 
                    {
                        long bytesInExcess = (bufferPool.Limit - bufferPool.Peak) * (long)bufferPool.BufferSize;

                        if (bytesInExcess > maxBytesInExcess) 
                        {
                            index = i; 
                            maxBytesInExcess = bytesInExcess; 
                        }
                    } 
                }

                return index;
            } 

            int FindMostStarvedPool() 
            { 
                long maxBytesMissed = 0;
                int index = -1; 

                for (int i = 0; i < this.bufferPools.Length; i++)
                {
                    BufferPool bufferPool = this.bufferPools[i]; 

                    if (bufferPool.Peak == bufferPool.Limit) 
                    { 
                        long bytesMissed = bufferPool.Misses * (long)bufferPool.BufferSize;
 
                        if (bytesMissed > maxBytesMissed)
                        {
                            index = i;
                            maxBytesMissed = bytesMissed; 
                        }
                    } 
                } 

                return index; 
            }

            BufferPool FindPool(int desiredBufferSize)
            { 
                for (int i = 0; i < this.bufferSizes.Length; i++)
                { 
                    if (desiredBufferSize <= this.bufferSizes[i]) 
                    {
                        return this.bufferPools[i]; 
                    }
                }

                return null; 
            }
 
            void IncreaseQuota(ref BufferPool bufferPool) 
            {
                ChangeQuota(ref bufferPool, 1); 
            }

            public override void ReturnBuffer(byte[] buffer)
            { 
                Fx.Assert(buffer != null, "caller must verify");
                BufferPool bufferPool = FindPool(buffer.Length); 
                if (bufferPool != null) 
                {
                    if (buffer.Length != bufferPool.BufferSize) 
                    {
                        throw Fx.Exception.Argument("buffer", SRCore.BufferIsNotRightSizeForBufferManager);
                    }
 
                    if (bufferPool.Return(buffer))
                    { 
                        bufferPool.IncrementCount(); 
                    }
                } 
            }

            public override byte[] TakeBuffer(int bufferSize)
            { 
                Fx.Assert(bufferSize >= 0, "caller must ensure a non-negative argument");
 
                BufferPool bufferPool = FindPool(bufferSize); 
                if (bufferPool != null)
                { 
                    byte[] buffer = bufferPool.Take();
                    if (buffer != null)
                    {
                        bufferPool.DecrementCount(); 
                        return buffer;
                    } 
                    if (bufferPool.Peak == bufferPool.Limit) 
                    {
                        bufferPool.Misses++; 
                        if (++totalMisses >= maxMissesBeforeTuning)
                        {
                            TuneQuotas();
                        } 
                    }
                    return Fx.AllocateByteArray(bufferPool.BufferSize); 
                } 
                else
                { 
                    return Fx.AllocateByteArray(bufferSize);
                }
            }
 
            void TuneQuotas()
            { 
                if (this.areQuotasBeingTuned) 
                {
                    return; 
                }

                bool lockHeld = false;
                try 
                {
                    Monitor.TryEnter(this.tuningLock, ref lockHeld); 
 
                    // Don't bother if another thread already has the lock
                    if (!lockHeld || this.areQuotasBeingTuned) 
                    {
                        return;
                    }
 
                    this.areQuotasBeingTuned = true;
                } 
                finally 
                {
                    if (lockHeld) 
                    {
                        Monitor.Exit(this.tuningLock);
                    }
                } 

                // find the "poorest" pool 
                int starvedIndex = FindMostStarvedPool(); 
                if (starvedIndex >= 0)
                { 
                    BufferPool starvedBufferPool = this.bufferPools[starvedIndex];

                    if (this.remainingMemory < starvedBufferPool.BufferSize)
                    { 
                        // find the "richest" pool
                        int excessiveIndex = FindMostExcessivePool(); 
                        if (excessiveIndex >= 0) 
                        {
                            // steal from the richest 
                            DecreaseQuota(ref this.bufferPools[excessiveIndex]);
                        }
                    }
 
                    if (this.remainingMemory >= starvedBufferPool.BufferSize)
                    { 
                        // give to the poorest 
                        IncreaseQuota(ref this.bufferPools[starvedIndex]);
                    } 
                }

                // reset statistics
                for (int i = 0; i < this.bufferPools.Length; i++) 
                {
                    BufferPool bufferPool = this.bufferPools[i]; 
                    bufferPool.Misses = 0; 
                }
 
                this.totalMisses = 0;
                this.areQuotasBeingTuned = false;
            }
 
            class BufferPool
            { 
                int bufferSize; 
                int count;
                int limit; 
                int misses;
                int peak;
                SynchronizedPool pool;
 
                public BufferPool(int bufferSize, int limit)
                { 
                    this.pool = new SynchronizedPool(limit); 
                    this.bufferSize = bufferSize;
                    this.limit = limit; 
                }

                public int BufferSize
                { 
                    get { return this.bufferSize; }
                } 
 
                public int Limit
                { 
                    get { return this.limit; }
                }

                public int Misses 
                {
                    get { return this.misses; } 
                    set { this.misses = value; } 
                }
 
                public int Peak
                {
                    get { return this.peak; }
                } 

                public void Clear() 
                { 
                    this.pool.Clear();
                    this.count = 0; 
                }

                public void DecrementCount()
                { 
                    int newValue = this.count - 1;
                    if (newValue >= 0) 
                    { 
                        this.count = newValue;
                    } 
                }

                public void IncrementCount()
                { 
                    int newValue = this.count + 1;
                    if (newValue <= this.limit) 
                    { 
                        this.count = newValue;
                        if (newValue > this.peak) 
                        {
                            this.peak = newValue;
                        }
                    } 
                }
 
                public bool Return(byte[] buffer) 
                {
                    return this.pool.Return(buffer); 
                }

                public byte[] Take()
                { 
                    return this.pool.Take();
                } 
            } 
        }
 
        class GCBufferManager : InternalBufferManager
        {
            static GCBufferManager value = new GCBufferManager();
 
            GCBufferManager()
            { 
            } 

            public static GCBufferManager Value 
            {
                get { return value; }
            }
 
            public override void Clear()
            { 
            } 

            public override byte[] TakeBuffer(int bufferSize) 
            {
                return Fx.AllocateByteArray(bufferSize);
            }
 
            public override void ReturnBuffer(byte[] buffer)
            { 
                // do nothing, GC will reclaim this buffer 
            }
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK