@@ -36,49 +36,57 @@ namespace Microsoft.IO.UnitTests
3636 /// </summary>
3737 public abstract class BaseRecyclableMemoryStreamTests
3838 {
39- private const int DefaultBlockSize = 16384 ;
40- private const int DefaultLargeBufferMultiple = 1 << 20 ;
41- private const int DefaultMaximumBufferSize = 8 * ( 1 << 20 ) ;
42- private const string DefaultTag = "NUnit" ;
39+ protected const int DefaultBlockSize = 16384 ;
40+ protected const int DefaultLargeBufferMultiple = 1 << 20 ;
41+ protected const int DefaultMaximumBufferSize = 8 * ( 1 << 20 ) ;
42+ protected const string DefaultTag = "NUnit" ;
4343 private const int MemoryStreamDisposed = 2 ;
4444 private const int MemoryStreamDoubleDispose = 3 ;
4545
4646 private readonly Random random = new Random ( ) ;
4747
4848 #region RecyclableMemoryManager Tests
49+ [ Test ]
50+ public virtual void RecyclableMemoryManagerUsingMultipleOrExponentialLargeBuffer ( )
51+ {
52+ var memMgr = this . GetMemoryManager ( ) ;
53+ Assert . That ( memMgr . UseMultipleLargeBuffer , Is . True ) ;
54+ Assert . That ( memMgr . UseExponentialLargeBuffer , Is . False ) ;
55+ }
56+
4957 [ Test ]
5058 public void RecyclableMemoryManagerThrowsExceptionOnZeroBlockSize ( )
5159 {
52- Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 0 , 100 , 200 ) ) ;
53- Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( - 1 , 100 , 200 ) ) ;
54- Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 1 , 100 , 200 ) ) ;
60+ Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 0 , 100 , 200 , this . useExponentialLargeBuffer ) ) ;
61+ Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( - 1 , 100 , 200 , this . useExponentialLargeBuffer ) ) ;
62+ Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 1 , 100 , 200 , this . useExponentialLargeBuffer ) ) ;
5563 }
5664
5765 [ Test ]
5866 public void RecyclableMemoryManagerThrowsExceptionOnZeroLargeBufferMultipleSize ( )
5967 {
60- Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 0 , 200 ) ) ;
61- Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , - 1 , 200 ) ) ;
62- Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 100 , 200 ) ) ;
68+ Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 0 , 200 , this . useExponentialLargeBuffer ) ) ;
69+ Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , - 1 , 200 , this . useExponentialLargeBuffer ) ) ;
70+ Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 100 , 200 , this . useExponentialLargeBuffer ) ) ;
6371 }
6472
6573 [ Test ]
6674 public void RecyclableMemoryManagerThrowsExceptionOnMaximumBufferSizeLessThanBlockSize ( )
6775 {
68- Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 100 , 99 ) ) ;
69- Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 100 , 100 ) ) ;
76+ Assert . Throws < ArgumentOutOfRangeException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 100 , 99 , this . useExponentialLargeBuffer ) ) ;
77+ Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 100 , 100 , this . useExponentialLargeBuffer ) ) ;
7078 }
7179
7280 [ Test ]
73- public void RecyclableMemoryManagerThrowsExceptionOnMaximumBufferNotMultipleOfLargeBufferMultiple ( )
81+ public virtual void RecyclableMemoryManagerThrowsExceptionOnMaximumBufferNotMultipleOrExponentialOfLargeBufferMultiple ( )
7482 {
75- Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2025 ) ) ;
76- Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2023 ) ) ;
77- Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2048 ) ) ;
83+ Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2025 , this . useExponentialLargeBuffer ) ) ;
84+ Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2023 , this . useExponentialLargeBuffer ) ) ;
85+ Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2048 , this . useExponentialLargeBuffer ) ) ;
7886 }
7987
8088 [ Test ]
81- public void GetLargeBufferAlwaysAMultipleOfMegabyteAndAtLeastAsMuchAsRequestedForLargeBuffer ( )
89+ public virtual void GetLargeBufferAlwaysAMultipleOrExponentialOfMegabyteAndAtLeastAsMuchAsRequestedForLargeBuffer ( )
8290 {
8391 const int step = 200000 ;
8492 const int start = 1 ;
@@ -95,15 +103,15 @@ public void GetLargeBufferAlwaysAMultipleOfMegabyteAndAtLeastAsMuchAsRequestedFo
95103 }
96104
97105 [ Test ]
98- public void AllMultiplesUpToMaxCanBePooled ( )
106+ public virtual void AllMultiplesOrExponentialUpToMaxCanBePooled ( )
99107 {
100108 const int BlockSize = 100 ;
101109 const int LargeBufferMultiple = 1000 ;
102110 const int MaxBufferSize = 8000 ;
103111
104112 for ( var size = LargeBufferMultiple ; size <= MaxBufferSize ; size += LargeBufferMultiple )
105113 {
106- var memMgr = new RecyclableMemoryStreamManager ( BlockSize , LargeBufferMultiple , MaxBufferSize )
114+ var memMgr = new RecyclableMemoryStreamManager ( BlockSize , LargeBufferMultiple , MaxBufferSize , this . useExponentialLargeBuffer )
107115 { AggressiveBufferReturn = this . AggressiveBufferRelease } ;
108116 var buffer = memMgr . GetLargeBuffer ( size , DefaultTag ) ;
109117 Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( 0 ) ) ;
@@ -173,7 +181,7 @@ public void ReturnBlocksWithInvalidBuffersThrowsException()
173181 }
174182
175183 [ Test ]
176- public void RequestTooLargeBufferAdjustsInUseCounter ( )
184+ public virtual void RequestTooLargeBufferAdjustsInUseCounter ( )
177185 {
178186 var memMgr = this . GetMemoryManager ( ) ;
179187 var buffer = memMgr . GetLargeBuffer ( memMgr . MaximumBufferSize + 1 , DefaultTag ) ;
@@ -258,15 +266,15 @@ public void ReturningLargeBufferNeverDroppedIfMaxFreeSizeZero()
258266 this . TestDroppingLargeBuffer ( 0 ) ;
259267 }
260268
261- private void TestDroppingLargeBuffer ( long maxFreeLargeBufferSize )
269+ protected virtual void TestDroppingLargeBuffer ( long maxFreeLargeBufferSize )
262270 {
263271 const int BlockSize = 100 ;
264272 const int LargeBufferMultiple = 1000 ;
265273 const int MaxBufferSize = 8000 ;
266274
267275 for ( var size = LargeBufferMultiple ; size <= MaxBufferSize ; size += LargeBufferMultiple )
268276 {
269- var memMgr = new RecyclableMemoryStreamManager ( BlockSize , LargeBufferMultiple , MaxBufferSize )
277+ var memMgr = new RecyclableMemoryStreamManager ( BlockSize , LargeBufferMultiple , MaxBufferSize , this . useExponentialLargeBuffer )
270278 {
271279 AggressiveBufferReturn = this . AggressiveBufferRelease ,
272280 MaximumFreeLargePoolBytes = maxFreeLargeBufferSize
@@ -1639,7 +1647,7 @@ public void DisposeTwiceDoesNotThrowException()
16391647 public async Task ConcurrentDoubleDisposeSucceeds ( )
16401648 {
16411649 int blockSize = 10 ;
1642- var manager = new RecyclableMemoryStreamManager ( blockSize : blockSize , largeBufferMultiple : 20 , maximumBufferSize : 100 ) ;
1650+ var manager = new RecyclableMemoryStreamManager ( blockSize : blockSize , largeBufferMultiple : 20 , maximumBufferSize : 160 , useExponentialLargeBuffer : this . useExponentialLargeBuffer ) ;
16431651 RecyclableMemoryStream recyclableMemoryStream = new RecyclableMemoryStream ( manager , TestContext . CurrentContext . Test . Name ) ;
16441652
16451653 Assert . AreEqual ( 0 , manager . SmallBlocksFree , "Verify manager starts with no blocks free" ) ;
@@ -1898,10 +1906,10 @@ protected byte[] GetRandomBuffer(int length)
18981906 return buffer ;
18991907 }
19001908
1901- protected RecyclableMemoryStreamManager GetMemoryManager ( )
1909+ protected virtual RecyclableMemoryStreamManager GetMemoryManager ( )
19021910 {
19031911 return new RecyclableMemoryStreamManager ( DefaultBlockSize , DefaultLargeBufferMultiple ,
1904- DefaultMaximumBufferSize )
1912+ DefaultMaximumBufferSize , this . useExponentialLargeBuffer )
19051913 {
19061914 AggressiveBufferReturn = this . AggressiveBufferRelease ,
19071915 } ;
@@ -1919,6 +1927,11 @@ private RecyclableMemoryStream GetRandomStream()
19191927
19201928 protected abstract bool AggressiveBufferRelease { get ; }
19211929
1930+ protected virtual bool useExponentialLargeBuffer
1931+ {
1932+ get { return false ; }
1933+ }
1934+
19221935 /*
19231936 * TODO: clocke to release logging libraries to enable some tests.
19241937 [TestFixtureSetUp]
@@ -2034,4 +2047,172 @@ protected override bool AggressiveBufferRelease
20342047 get { return true ; }
20352048 }
20362049 }
2050+
2051+ public abstract class BaseRecyclableMemoryStreamTestsUsingExponentialLargeBuffer : BaseRecyclableMemoryStreamTests
2052+ {
2053+ protected override bool useExponentialLargeBuffer
2054+ {
2055+ get { return true ; }
2056+ }
2057+
2058+ [ Test ]
2059+ public override void RecyclableMemoryManagerUsingMultipleOrExponentialLargeBuffer ( )
2060+ {
2061+ var memMgr = this . GetMemoryManager ( ) ;
2062+ Assert . That ( memMgr . UseMultipleLargeBuffer , Is . False ) ;
2063+ Assert . That ( memMgr . UseExponentialLargeBuffer , Is . True ) ;
2064+ }
2065+
2066+ [ Test ]
2067+ public override void RecyclableMemoryManagerThrowsExceptionOnMaximumBufferNotMultipleOrExponentialOfLargeBufferMultiple ( )
2068+ {
2069+ Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2025 , this . useExponentialLargeBuffer ) ) ;
2070+ Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2023 , this . useExponentialLargeBuffer ) ) ;
2071+ Assert . Throws < ArgumentException > ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 3072 , this . useExponentialLargeBuffer ) ) ;
2072+ Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 2048 , this . useExponentialLargeBuffer ) ) ;
2073+ Assert . DoesNotThrow ( ( ) => new RecyclableMemoryStreamManager ( 100 , 1024 , 4096 , this . useExponentialLargeBuffer ) ) ;
2074+ }
2075+
2076+ [ Test ]
2077+ public override void GetLargeBufferAlwaysAMultipleOrExponentialOfMegabyteAndAtLeastAsMuchAsRequestedForLargeBuffer ( )
2078+ {
2079+ const int step = 200000 ;
2080+ const int start = 1 ;
2081+ const int end = 16000000 ;
2082+ var memMgr = this . GetMemoryManager ( ) ;
2083+
2084+ for ( var i = start ; i <= end ; i += step )
2085+ {
2086+ var buffer = memMgr . GetLargeBuffer ( i , DefaultTag ) ;
2087+ Assert . That ( buffer . Length >= i , Is . True ) ;
2088+ Assert . That ( memMgr . LargeBufferMultiple * ( int ) Math . Pow ( 2 , Math . Floor ( Math . Log ( buffer . Length / memMgr . LargeBufferMultiple , 2 ) ) ) == buffer . Length , Is . True ,
2089+ "buffer length of {0} is not a exponential of {1}" , buffer . Length , memMgr . LargeBufferMultiple ) ;
2090+ }
2091+ }
2092+
2093+ [ Test ]
2094+ public override void AllMultiplesOrExponentialUpToMaxCanBePooled ( )
2095+ {
2096+ const int BlockSize = 100 ;
2097+ const int LargeBufferMultiple = 1000 ;
2098+ const int MaxBufferSize = 8000 ;
2099+
2100+ for ( var size = LargeBufferMultiple ; size <= MaxBufferSize ; size *= 2 )
2101+ {
2102+ var memMgr = new RecyclableMemoryStreamManager ( BlockSize , LargeBufferMultiple , MaxBufferSize , this . useExponentialLargeBuffer )
2103+ { AggressiveBufferReturn = this . AggressiveBufferRelease } ;
2104+ var buffer = memMgr . GetLargeBuffer ( size , DefaultTag ) ;
2105+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( 0 ) ) ;
2106+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( size ) ) ;
2107+
2108+ memMgr . ReturnLargeBuffer ( buffer , DefaultTag ) ;
2109+
2110+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( size ) ) ;
2111+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( 0 ) ) ;
2112+ }
2113+ }
2114+
2115+ [ Test ]
2116+ public override void RequestTooLargeBufferAdjustsInUseCounter ( )
2117+ {
2118+ var memMgr = this . GetMemoryManager ( ) ;
2119+ var buffer = memMgr . GetLargeBuffer ( memMgr . MaximumBufferSize + 1 , DefaultTag ) ;
2120+ Assert . That ( buffer . Length , Is . EqualTo ( memMgr . MaximumBufferSize * 2 ) ) ;
2121+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( buffer . Length ) ) ;
2122+ }
2123+
2124+ protected override void TestDroppingLargeBuffer ( long maxFreeLargeBufferSize )
2125+ {
2126+ const int BlockSize = 100 ;
2127+ const int LargeBufferMultiple = 1000 ;
2128+ const int MaxBufferSize = 8000 ;
2129+
2130+ for ( var size = LargeBufferMultiple ; size <= MaxBufferSize ; size *= 2 )
2131+ {
2132+ var memMgr = new RecyclableMemoryStreamManager ( BlockSize , LargeBufferMultiple , MaxBufferSize , this . useExponentialLargeBuffer )
2133+ {
2134+ AggressiveBufferReturn = this . AggressiveBufferRelease ,
2135+ MaximumFreeLargePoolBytes = maxFreeLargeBufferSize
2136+ } ;
2137+
2138+ var buffers = new List < byte [ ] > ( ) ;
2139+
2140+ //Get one extra buffer
2141+ var buffersToRetrieve = ( maxFreeLargeBufferSize > 0 ) ? ( maxFreeLargeBufferSize / size + 1 ) : 10 ;
2142+ for ( var i = 0 ; i < buffersToRetrieve ; i ++ )
2143+ {
2144+ buffers . Add ( memMgr . GetLargeBuffer ( size , DefaultTag ) ) ;
2145+ }
2146+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( size * buffersToRetrieve ) ) ;
2147+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( 0 ) ) ;
2148+ foreach ( var buffer in buffers )
2149+ {
2150+ memMgr . ReturnLargeBuffer ( buffer , DefaultTag ) ;
2151+ }
2152+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( 0 ) ) ;
2153+ if ( maxFreeLargeBufferSize > 0 )
2154+ {
2155+ Assert . That ( memMgr . LargePoolFreeSize , Is . LessThanOrEqualTo ( maxFreeLargeBufferSize ) ) ;
2156+ }
2157+ else
2158+ {
2159+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( buffersToRetrieve * size ) ) ;
2160+ }
2161+ }
2162+ }
2163+ }
2164+
2165+ [ TestFixture ]
2166+ public sealed class RecyclableMemoryStreamTestsWithPassiveBufferReleaseUsingExponentialLargeBuffer : BaseRecyclableMemoryStreamTestsUsingExponentialLargeBuffer
2167+ {
2168+ protected override bool AggressiveBufferRelease
2169+ {
2170+ get { return false ; }
2171+ }
2172+
2173+ [ Test ]
2174+ public void OldBuffersAreKeptInStreamUntilDispose ( )
2175+ {
2176+ var stream = this . GetDefaultStream ( ) ;
2177+ var memMgr = stream . MemoryManager ;
2178+ var buffer = this . GetRandomBuffer ( stream . MemoryManager . LargeBufferMultiple ) ;
2179+ stream . Write ( buffer , 0 , buffer . Length ) ;
2180+ stream . GetBuffer ( ) ;
2181+
2182+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( memMgr . LargeBufferMultiple * ( 1 ) ) ) ;
2183+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( 0 ) ) ;
2184+ Assert . That ( memMgr . SmallPoolFreeSize , Is . EqualTo ( 0 ) ) ;
2185+ Assert . That ( memMgr . SmallPoolInUseSize , Is . EqualTo ( memMgr . LargeBufferMultiple ) ) ;
2186+
2187+ stream . Write ( buffer , 0 , buffer . Length ) ;
2188+
2189+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( 0 ) ) ;
2190+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( memMgr . LargeBufferMultiple * ( 1 + 2 ) ) ) ;
2191+ Assert . That ( memMgr . SmallPoolFreeSize , Is . EqualTo ( 0 ) ) ;
2192+ Assert . That ( memMgr . SmallPoolInUseSize , Is . EqualTo ( memMgr . LargeBufferMultiple ) ) ;
2193+
2194+ stream . Write ( buffer , 0 , buffer . Length ) ;
2195+
2196+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( 0 ) ) ;
2197+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( memMgr . LargeBufferMultiple * ( 1 + 2 + 4 ) ) ) ;
2198+ Assert . That ( memMgr . SmallPoolFreeSize , Is . EqualTo ( 0 ) ) ;
2199+ Assert . That ( memMgr . SmallPoolInUseSize , Is . EqualTo ( memMgr . LargeBufferMultiple ) ) ;
2200+
2201+ stream . Dispose ( ) ;
2202+
2203+ Assert . That ( memMgr . LargePoolFreeSize , Is . EqualTo ( memMgr . LargeBufferMultiple * ( 1 + 2 + 4 ) ) ) ;
2204+ Assert . That ( memMgr . LargePoolInUseSize , Is . EqualTo ( 0 ) ) ;
2205+ Assert . That ( memMgr . SmallPoolFreeSize , Is . EqualTo ( memMgr . LargeBufferMultiple ) ) ;
2206+ Assert . That ( memMgr . SmallPoolInUseSize , Is . EqualTo ( 0 ) ) ;
2207+ }
2208+ }
2209+
2210+ [ TestFixture ]
2211+ public sealed class RecyclableMemoryStreamTestsWithAggressiveBufferReleaseUsingExponentialLargeBuffer : BaseRecyclableMemoryStreamTestsUsingExponentialLargeBuffer
2212+ {
2213+ protected override bool AggressiveBufferRelease
2214+ {
2215+ get { return true ; }
2216+ }
2217+ }
20372218}
0 commit comments