BsonChunkPool.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* Copyright 2010-2015 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Threading;
  18. namespace MongoDB.Bson.IO
  19. {
  20. /// <summary>
  21. /// Represents a pool of chunks.
  22. /// </summary>
  23. public sealed class BsonChunkPool : IBsonChunkSource
  24. {
  25. #region static
  26. // static fields
  27. private static BsonChunkPool __default = new BsonChunkPool(8192, 64 * 1024); // 512MiB of 64KiB chunks
  28. // static properties
  29. /// <summary>
  30. /// Gets or sets the default chunk pool.
  31. /// </summary>
  32. /// <value>
  33. /// The default chunk pool.
  34. /// </value>
  35. public static BsonChunkPool Default
  36. {
  37. get { return __default; }
  38. set
  39. {
  40. if (value == null)
  41. {
  42. throw new ArgumentNullException("value");
  43. }
  44. __default = value;
  45. }
  46. }
  47. #endregion
  48. // private fields
  49. private Stack<ReferenceCountedChunk> _chunks = new Stack<ReferenceCountedChunk>();
  50. private readonly int _chunkSize;
  51. private bool _disposed;
  52. private readonly object _lock = new object();
  53. private readonly int _maxChunkCount;
  54. // constructors
  55. /// <summary>
  56. /// Initializes a new instance of the <see cref="BsonChunkPool"/> class.
  57. /// </summary>
  58. /// <param name="maxChunkCount">The maximum number of chunks to keep in the pool.</param>
  59. /// <param name="chunkSize">The size of each chunk.</param>
  60. public BsonChunkPool(int maxChunkCount, int chunkSize)
  61. {
  62. if (maxChunkCount < 0)
  63. {
  64. throw new ArgumentOutOfRangeException("maxChunkCount");
  65. }
  66. if (chunkSize <= 0)
  67. {
  68. throw new ArgumentOutOfRangeException("chunkSize");
  69. }
  70. _maxChunkCount = maxChunkCount;
  71. _chunkSize = chunkSize;
  72. }
  73. // public properties
  74. /// <summary>
  75. /// Gets the chunk size.
  76. /// </summary>
  77. /// <value>
  78. /// The chunk size.
  79. /// </value>
  80. public int ChunkSize
  81. {
  82. get { return _chunkSize; }
  83. }
  84. /// <summary>
  85. /// Gets the maximum size of the pool.
  86. /// </summary>
  87. /// <value>
  88. /// The maximum size of the pool.
  89. /// </value>
  90. public int MaxChunkCount
  91. {
  92. get { return _maxChunkCount; }
  93. }
  94. /// <summary>
  95. /// Gets the size of the pool.
  96. /// </summary>
  97. /// <value>
  98. /// The size of the pool.
  99. /// </value>
  100. public int ChunkCount
  101. {
  102. get
  103. {
  104. lock (_lock)
  105. {
  106. return _chunks.Count;
  107. }
  108. }
  109. }
  110. // public methods
  111. /// <inheritdoc/>
  112. public void Dispose()
  113. {
  114. if (!_disposed)
  115. {
  116. _disposed = true;
  117. _chunks = null;
  118. }
  119. }
  120. /// <inheritdoc/>
  121. public IBsonChunk GetChunk(int requestedSize)
  122. {
  123. ThrowIfDisposed();
  124. ReferenceCountedChunk referenceCountedChunk = null;
  125. lock (_lock)
  126. {
  127. if (_chunks.Count > 0)
  128. {
  129. referenceCountedChunk = _chunks.Pop();
  130. }
  131. }
  132. if (referenceCountedChunk == null)
  133. {
  134. var chunk = new byte[_chunkSize];
  135. referenceCountedChunk = new ReferenceCountedChunk(chunk, this);
  136. }
  137. return new DisposableChunk(referenceCountedChunk);
  138. }
  139. // private methods
  140. private void ReleaseChunk(ReferenceCountedChunk chunk)
  141. {
  142. if (!_disposed)
  143. {
  144. lock (_lock)
  145. {
  146. if (_chunks.Count < _maxChunkCount)
  147. {
  148. _chunks.Push(chunk);
  149. }
  150. // otherwise just let it get garbage collected
  151. }
  152. }
  153. }
  154. private void ThrowIfDisposed()
  155. {
  156. if (_disposed)
  157. {
  158. throw new ObjectDisposedException(GetType().Name);
  159. }
  160. }
  161. // nested types
  162. private sealed class DisposableChunk : IBsonChunk
  163. {
  164. // fields
  165. private bool _disposed;
  166. private readonly ReferenceCountedChunk _referenceCountedChunk;
  167. // constructors
  168. public DisposableChunk(ReferenceCountedChunk referenceCountedChunk)
  169. {
  170. _referenceCountedChunk = referenceCountedChunk;
  171. _referenceCountedChunk.IncrementReferenceCount();
  172. }
  173. // properties
  174. public ArraySegment<byte> Bytes
  175. {
  176. get
  177. {
  178. ThrowIfDisposed();
  179. return new ArraySegment<byte>(_referenceCountedChunk.Chunk);
  180. }
  181. }
  182. // methods
  183. public void Dispose()
  184. {
  185. if (!_disposed)
  186. {
  187. _disposed = true;
  188. _referenceCountedChunk.DecrementReferenceCount();
  189. }
  190. }
  191. public IBsonChunk Fork()
  192. {
  193. ThrowIfDisposed();
  194. return new DisposableChunk(_referenceCountedChunk);
  195. }
  196. // private methods
  197. private void ThrowIfDisposed()
  198. {
  199. if (_disposed)
  200. {
  201. throw new ObjectDisposedException(GetType().Name);
  202. }
  203. }
  204. }
  205. private sealed class ReferenceCountedChunk
  206. {
  207. private byte[] _chunk;
  208. private BsonChunkPool _pool;
  209. private int _referenceCount;
  210. public ReferenceCountedChunk(byte[] chunk, BsonChunkPool pool)
  211. {
  212. _chunk = chunk;
  213. _pool = pool;
  214. }
  215. public byte[] Chunk
  216. {
  217. get { return _chunk; }
  218. }
  219. public void DecrementReferenceCount()
  220. {
  221. if (Interlocked.Decrement(ref _referenceCount) == 0)
  222. {
  223. _pool.ReleaseChunk(this);
  224. }
  225. }
  226. public void IncrementReferenceCount()
  227. {
  228. Interlocked.Increment(ref _referenceCount);
  229. }
  230. }
  231. }
  232. }