BufferManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / BufferManager.cs / 1 / BufferManager.cs

                            //---------------------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System;
    using System.ServiceModel; 
    using System.Collections.Generic; 
    using System.Threading;
 
    public abstract class BufferManager
    {
        public abstract byte[] TakeBuffer(int bufferSize);
        public abstract void ReturnBuffer(byte[] buffer); 
        public abstract void Clear();
 
        public static BufferManager CreateBufferManager(long maxBufferPoolSize, int maxBufferSize) 
        {
            if (maxBufferPoolSize == 0) 
            {
                return GCBufferManager.Value;
            }
            else 
            {
                return new PooledBufferManager(maxBufferPoolSize, maxBufferSize); 
            } 
        }
 
        class PooledBufferManager : BufferManager
        {
            int[] bufferSizes;
            BufferPool[] bufferPools; 
            object tuningLock = new object();
            long memoryLimit; 
            long remainingMemory; 
            bool areQuotasBeingTuned;
            int totalMisses; 
            const int minBufferSize = 128;
            const int maxMissesBeforeTuning = 8;
            const int initialBufferCount = 1;
 
            public PooledBufferManager(long maxMemoryToPool, int maxBufferSize)
            { 
                if (maxMemoryToPool < 0) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxMemoryToPool", 
                        maxMemoryToPool, SR.GetString(SR.ValueMustBeNonNegative)));
                }

                if (maxBufferSize < 0) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", 
                        maxBufferSize, SR.GetString(SR.ValueMustBeNonNegative))); 
                }
 
                memoryLimit = maxMemoryToPool;
                remainingMemory = maxMemoryToPool;
                List bufferPoolList = new List();
 
                for (int bufferSize = minBufferSize; ; )
                { 
                    long bufferCountLong = remainingMemory / bufferSize; 

                    int bufferCount = bufferCountLong > int.MaxValue ? int.MaxValue : (int)bufferCountLong; 

                    if (bufferCount > initialBufferCount)
                        bufferCount = initialBufferCount;
 
                    bufferPoolList.Add(new BufferPool(bufferSize, bufferCount));
 
                    remainingMemory -= (long)bufferCount * bufferSize; 

                    if (bufferSize >= maxBufferSize) 
                        break;

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

                bufferPools = bufferPoolList.ToArray(); 
                bufferSizes = new int[bufferPools.Length]; 
                for (int i = 0; i < bufferPools.Length; i++)
                { 
                    bufferSizes[i] = bufferPools[i].BufferSize;
                }
            }
 
            public override void Clear()
            { 
                for (int i = 0; i < bufferPools.Length; i++) 
                {
                    BufferPool bufferPool = 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(); 
                }
                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 < bufferPools.Length; i++)
                { 
                    BufferPool bufferPool = 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 < bufferPools.Length; i++)
                {
                    BufferPool bufferPool = 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 < bufferSizes.Length; i++)
                { 
                    if (desiredBufferSize <= bufferSizes[i]) 
                    {
                        return bufferPools[i]; 
                    }
                }

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

            public override void ReturnBuffer(byte[] buffer)
            { 
                if (buffer == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer"); 
                BufferPool bufferPool = FindPool(buffer.Length); 
                if (bufferPool != null)
                { 
                    if (buffer.Length != bufferPool.BufferSize)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.BufferIsNotRightSizeForBufferManager), "buffer"));
                    } 

                    if (bufferPool.Return(buffer)) 
                    { 
                        bufferPool.IncrementCount();
                    } 
                }
            }

            byte[] AllocNewBuffer(int bufferSize) 
            {
                return DiagnosticUtility.Utility.AllocateByteArray(bufferSize); 
            } 

            public override byte[] TakeBuffer(int bufferSize) 
            {
                if (bufferSize < 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("bufferSize", bufferSize, 
                        SR.GetString(SR.ValueMustBeNonNegative)));
                } 
 
                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 AllocNewBuffer(bufferPool.BufferSize); 
                }
                else 
                {
                    return AllocNewBuffer(bufferSize);
                }
            } 

            void TuneQuotas() 
            { 
                if (areQuotasBeingTuned)
                    return; 

                bool lockHeld = false;
                try
                { 
                    try { }
                    finally 
                    { 
                        lockHeld = Monitor.TryEnter(tuningLock);
                    } 

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

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

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

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

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

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

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

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

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

                public byte[] Take()
                { 
                    return pool.Take();
                } 
            } 

        } 

        class GCBufferManager : BufferManager
        {
            static GCBufferManager value = new GCBufferManager(); 

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

            public override void Clear() 
            { 
            }
 
            public override byte[] TakeBuffer(int bufferSize)
            {
                if (bufferSize < 0)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("bufferSize", bufferSize,
                        SR.GetString(SR.ValueMustBeNonNegative))); 
                } 

                return DiagnosticUtility.Utility.AllocateByteArray(bufferSize); 
            }

            public override void ReturnBuffer(byte[] buffer)
            { 
                if (buffer == null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("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.
                        

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