Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel de Icaza <miguel@gnome.org>2010-04-08 02:16:02 +0400
committerMiguel de Icaza <miguel@gnome.org>2010-04-08 02:16:02 +0400
commit6061c13a4f84c153cc54b1b739e2cc379ce1be0a (patch)
tree5d8e1168948942ae6bb08462c8401ea97f06c5e3
parentb7d40582ca5767a3484548c5ae3e7af23453e7e0 (diff)
Implement BufferManager.cs
svn path=/branches/mono-2-6/mcs/; revision=154998
-rw-r--r--mcs/class/System.ServiceModel/System.ServiceModel.Channels/BufferManager.cs172
1 files changed, 152 insertions, 20 deletions
diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/BufferManager.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/BufferManager.cs
index 9078b9d1cdd..ae295d08b0a 100644
--- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/BufferManager.cs
+++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/BufferManager.cs
@@ -1,9 +1,38 @@
//
-// BufferManager.cs
+// BufferManager.cs:
+// This class suffers from an engineering problem in its
+// design: when this API is used to limit the total pool
+// size it will throw, but no user code is designed to
+// cope with that.
//
-// Author: Atsushi Enomoto (atsushi@ximian.com)
+// Instead of the Microsoft strategy, we allow allocation
+// to go as far as it wants to go and merely allow this
+// to be a pool that can be used recycle buffers.
//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// This still gives us the main benefit of this class, while
+// avoiding the potential crashing scenarios and simplifies
+// the implementation significantly from what has been
+// document in the blogosphere.
+//
+// There are a few problems: for example, if we do not find
+// a buffer of the proper size in the expected slot, say
+// a 31k buffer in the slot for [32k-64k] values, we will
+// allocate a new buffer, even if there might have been a
+// buffer for 128k.
+//
+// A few considerations:
+//
+// The size of an empty array is either 16 on 32 bit systems
+// and 32 bytes in 64 bit systems.
+//
+// We take this information into account for the minimum allocation
+// pools.
+//
+// Authors:
+// Atsushi Enomoto (atsushi@ximian.com)
+// Miguel de Icaza (miguel@gnome.org)
+//
+// Copyright (C) 2005, 2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -25,6 +54,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
+using System.Collections.Generic;
using System.IO;
using System.Collections.ObjectModel;
using System.ServiceModel;
@@ -39,26 +69,71 @@ namespace System.ServiceModel.Channels
public abstract void Clear ();
- [MonoTODO]
public static BufferManager CreateBufferManager (
long maxBufferPoolSize, int maxBufferSize)
{
- return new DefaultBufferManager (maxBufferPoolSize,
- maxBufferSize);
+ return new DefaultBufferManager (maxBufferPoolSize, maxBufferSize);
}
public abstract void ReturnBuffer (byte[] buffer);
public abstract byte[] TakeBuffer (int bufferSize);
+#if DEBUG_BUFFER
+ internal abstract void DumpStats ();
+#endif
+
class DefaultBufferManager : BufferManager
{
+ const int log_min = 5; // Anything smaller than 1 << log_cut goes into the first bucket
long max_pool_size;
int max_size;
- byte [] buffer;
+ List<byte []> [] buffers = new List<byte []> [32-log_min];
- public DefaultBufferManager (long maxBufferPoolSize,
- int maxBufferSize)
+#if DEBUG_BUFFER
+ internal override void DumpStats ()
+ {
+ Console.WriteLine ("- hit={0} miss={1}-", hits, miss);
+ for (int i = 0; i < buffers.Length; i++){
+ if (buffers [i] == null)
+ continue;
+
+ Console.Write ("Slot {0} - {1} [", i, buffers [i].Count);
+ byte [][] arr = buffers [i].ToArray ();
+
+ for (int j = 0; j < Math.Min (3, arr.Length); j++)
+ Console.Write ("{0} ", arr [j].Length);
+ Console.WriteLine ("]");
+ }
+ }
+#endif
+
+ static int log2 (uint n)
+ {
+ int pos = 0;
+ if (n >= 1<<16) {
+ n >>= 16;
+ pos += 16;
+ }
+ if (n >= 1<< 8) {
+ n >>= 8;
+ pos += 8;
+ }
+ if (n >= 1<< 4) {
+ n >>= 4;
+ pos += 4;
+ }
+ if (n >= 1<< 2) {
+ n >>= 2;
+ pos += 2;
+ }
+ if (n >= 1<< 1)
+ pos += 1;
+
+ return ((n == 0) ? (-1) : pos);
+ }
+
+ public DefaultBufferManager (long maxBufferPoolSize, int maxBufferSize)
{
this.max_pool_size = maxBufferPoolSize;
this.max_size = maxBufferSize;
@@ -66,28 +141,85 @@ namespace System.ServiceModel.Channels
public override void Clear ()
{
- if (buffer != null)
- Array.Clear (buffer, 0, buffer.Length);
+ foreach (var stack in buffers){
+ if (stack == null)
+ continue;
+ stack.Clear ();
+ }
+ Array.Clear (buffers, 0, buffers.Length);
}
public override void ReturnBuffer (byte [] buffer)
{
- // is this correct?
-
- if (this.buffer == null)
+ if (buffer == null)
return;
- Array.Copy (this.buffer, buffer, this.buffer.Length);
+
+ uint size = (uint) buffer.Length;
+ int l2 = log2 (size);
+ if (l2 > log_min)
+ l2 -= log_min;
+
+ List<byte []> returned = buffers [l2];
+ if (returned == null)
+ returned = buffers [l2] = new List<byte []> ();
+
+ returned.Add (buffer);
}
+ int hits, miss;
+
public override byte [] TakeBuffer (int bufferSize)
{
- if (bufferSize > max_size)
+ if (bufferSize < 0 || (max_size >= 0 && bufferSize > max_size))
throw new ArgumentOutOfRangeException ();
- if (buffer == null || buffer.Length < bufferSize)
- buffer = new byte [bufferSize];
- return buffer;
+ int l2 = log2 ((uint) bufferSize);
+ if (l2 > log_min)
+ l2 -= log_min;
+
+ List<byte []> returned = buffers [l2];
+ if (returned == null || returned.Count == 0)
+ return new byte [bufferSize];
+
+ foreach (var e in returned){
+ if (e.Length >= bufferSize){
+ hits++;
+ returned.Remove (e);
+ return e;
+ }
+ }
+ return new byte [bufferSize];
+ }
+ }
+ }
+
+#if DEBUG_BUFFER
+ class Foo {
+ static void Main ()
+ {
+ var a = BufferManager.CreateBufferManager (1024*1024, 1024*1024);
+ var rand = new Random (0);
+
+ var buffs = new List<byte []> ();
+ for (int i = 0; i < 4096; i++){
+ a.DumpStats ();
+ var request = rand.Next (1,1024*1024);
+ if ((i % 2) == 0)
+ request = rand.Next (1024, 4096);
+
+ var x = a.TakeBuffer (request);
+ if (x.Length < request)
+ throw new Exception ();
+ Console.WriteLine ("Delta={2} Requested {0} got={1} bytes ", request, x.Length, x.Length-request);
+ if ((i % 3) == 0){
+ Console.WriteLine ("Return: {0}", x.Length);
+ a.ReturnBuffer (x);
+ }
+ else
+ buffs.Add (x);
}
+ a.DumpStats ();
}
}
-}
+#endif
+} \ No newline at end of file