3 // This class suffers from an engineering problem in its
4 // design: when this API is used to limit the total pool
5 // size it will throw, but no user code is designed to
8 // Instead of the Microsoft strategy, we allow allocation
9 // to go as far as it wants to go and merely allow this
10 // to be a pool that can be used recycle buffers.
12 // This still gives us the main benefit of this class, while
13 // avoiding the potential crashing scenarios and simplifies
14 // the implementation significantly from what has been
15 // document in the blogosphere.
17 // There are a few problems: for example, if we do not find
18 // a buffer of the proper size in the expected slot, say
19 // a 31k buffer in the slot for [32k-64k] values, we will
20 // allocate a new buffer, even if there might have been a
23 // A few considerations:
25 // The size of an empty array is either 16 on 32 bit systems
26 // and 32 bytes in 64 bit systems.
28 // We take this information into account for the minimum allocation
32 // Atsushi Enomoto (atsushi@ximian.com)
33 // Miguel de Icaza (miguel@gnome.org)
35 // Copyright (C) 2005, 2010 Novell, Inc (http://www.novell.com)
37 // Permission is hereby granted, free of charge, to any person obtaining
38 // a copy of this software and associated documentation files (the
39 // "Software"), to deal in the Software without restriction, including
40 // without limitation the rights to use, copy, modify, merge, publish,
41 // distribute, sublicense, and/or sell copies of the Software, and to
42 // permit persons to whom the Software is furnished to do so, subject to
43 // the following conditions:
45 // The above copyright notice and this permission notice shall be
46 // included in all copies or substantial portions of the Software.
48 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
49 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
50 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
51 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
52 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
53 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
54 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
57 using System.Collections.Generic;
59 using System.Collections.ObjectModel;
60 using System.ServiceModel;
62 namespace System.ServiceModel.Channels
64 public abstract class BufferManager
66 protected BufferManager ()
70 public abstract void Clear ();
72 public static BufferManager CreateBufferManager (
73 long maxBufferPoolSize, int maxBufferSize)
75 return new DefaultBufferManager (maxBufferPoolSize, maxBufferSize);
78 public abstract void ReturnBuffer (byte[] buffer);
80 public abstract byte[] TakeBuffer (int bufferSize);
83 internal abstract void DumpStats ();
86 class DefaultBufferManager : BufferManager
88 const int log_min = 5; // Anything smaller than 1 << log_cut goes into the first bucket
91 List<byte []> [] buffers = new List<byte []> [32-log_min];
94 internal override void DumpStats ()
96 Console.WriteLine ("- hit={0} miss={1}-", hits, miss);
97 for (int i = 0; i < buffers.Length; i++){
98 if (buffers [i] == null)
101 Console.Write ("Slot {0} - {1} [", i, buffers [i].Count);
102 byte [][] arr = buffers [i].ToArray ();
104 for (int j = 0; j < Math.Min (3, arr.Length); j++)
105 Console.Write ("{0} ", arr [j].Length);
106 Console.WriteLine ("]");
111 static int log2 (uint n)
133 return ((n == 0) ? (-1) : pos);
136 public DefaultBufferManager (long maxBufferPoolSize, int maxBufferSize)
138 this.max_pool_size = maxBufferPoolSize;
139 this.max_size = maxBufferSize;
142 public override void Clear ()
144 foreach (var stack in buffers){
149 Array.Clear (buffers, 0, buffers.Length);
152 public override void ReturnBuffer (byte [] buffer)
157 uint size = (uint) buffer.Length;
158 int l2 = log2 (size);
162 List<byte []> returned = buffers [l2];
163 if (returned == null)
164 returned = buffers [l2] = new List<byte []> ();
166 returned.Add (buffer);
171 public override byte [] TakeBuffer (int bufferSize)
173 if (bufferSize < 0 || (max_size >= 0 && bufferSize > max_size))
174 throw new ArgumentOutOfRangeException ();
176 int l2 = log2 ((uint) bufferSize);
180 List<byte []> returned = buffers [l2];
181 if (returned == null || returned.Count == 0)
182 return new byte [bufferSize];
184 foreach (var e in returned){
185 if (e.Length >= bufferSize){
191 return new byte [bufferSize];
200 var a = BufferManager.CreateBufferManager (1024*1024, 1024*1024);
201 var rand = new Random (0);
203 var buffs = new List<byte []> ();
204 for (int i = 0; i < 4096; i++){
206 var request = rand.Next (1,1024*1024);
208 request = rand.Next (1024, 4096);
210 var x = a.TakeBuffer (request);
211 if (x.Length < request)
212 throw new Exception ();
213 Console.WriteLine ("Delta={2} Requested {0} got={1} bytes ", request, x.Length, x.Length-request);
215 Console.WriteLine ("Return: {0}", x.Length);