SmartPool.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. namespace SuperSocket.Common
  9. {
  10. /// <summary>
  11. /// The pool information class
  12. /// </summary>
  13. public interface IPoolInfo
  14. {
  15. /// <summary>
  16. /// Gets the min size of the pool.
  17. /// </summary>
  18. /// <value>
  19. /// The min size of the pool.
  20. /// </value>
  21. int MinPoolSize { get; }
  22. /// <summary>
  23. /// Gets the max size of the pool.
  24. /// </summary>
  25. /// <value>
  26. /// The max size of the pool.
  27. /// </value>
  28. int MaxPoolSize { get; }
  29. /// <summary>
  30. /// Gets the avialable items count.
  31. /// </summary>
  32. /// <value>
  33. /// The avialable items count.
  34. /// </value>
  35. int AvialableItemsCount { get; }
  36. /// <summary>
  37. /// Gets the total items count, include items in the pool and outside the pool.
  38. /// </summary>
  39. /// <value>
  40. /// The total items count.
  41. /// </value>
  42. int TotalItemsCount { get; }
  43. }
  44. /// <summary>
  45. /// The basic interface of smart pool
  46. /// </summary>
  47. /// <typeparam name="T"></typeparam>
  48. public interface ISmartPool<T> : IPoolInfo
  49. {
  50. /// <summary>
  51. /// Initializes the specified min pool size.
  52. /// </summary>
  53. /// <param name="minPoolSize">The min size of the pool.</param>
  54. /// <param name="maxPoolSize">The max size of the pool.</param>
  55. /// <param name="sourceCreator">The source creator.</param>
  56. /// <returns></returns>
  57. void Initialize(int minPoolSize, int maxPoolSize, ISmartPoolSourceCreator<T> sourceCreator);
  58. /// <summary>
  59. /// Pushes the specified item into the pool.
  60. /// </summary>
  61. /// <param name="item">The item.</param>
  62. void Push(T item);
  63. /// <summary>
  64. /// Tries to get one item from the pool.
  65. /// </summary>
  66. /// <param name="item">The item.</param>
  67. /// <returns></returns>
  68. bool TryGet(out T item);
  69. }
  70. /// <summary>
  71. /// ISmartPoolSource
  72. /// </summary>
  73. public interface ISmartPoolSource
  74. {
  75. /// <summary>
  76. /// Gets the count.
  77. /// </summary>
  78. /// <value>
  79. /// The count.
  80. /// </value>
  81. int Count { get; }
  82. }
  83. /// <summary>
  84. /// SmartPoolSource
  85. /// </summary>
  86. public class SmartPoolSource : ISmartPoolSource
  87. {
  88. /// <summary>
  89. /// Initializes a new instance of the <see cref="SmartPoolSource" /> class.
  90. /// </summary>
  91. /// <param name="source">The source.</param>
  92. /// <param name="itemsCount">The items count.</param>
  93. public SmartPoolSource(object source, int itemsCount)
  94. {
  95. Source = source;
  96. Count = itemsCount;
  97. }
  98. /// <summary>
  99. /// Gets the source.
  100. /// </summary>
  101. /// <value>
  102. /// The source.
  103. /// </value>
  104. public object Source { get; private set; }
  105. /// <summary>
  106. /// Gets the count.
  107. /// </summary>
  108. /// <value>
  109. /// The count.
  110. /// </value>
  111. public int Count { get; private set; }
  112. }
  113. /// <summary>
  114. /// ISmartPoolSourceCreator
  115. /// </summary>
  116. /// <typeparam name="T"></typeparam>
  117. public interface ISmartPoolSourceCreator<T>
  118. {
  119. /// <summary>
  120. /// Creates the specified size.
  121. /// </summary>
  122. /// <param name="size">The size.</param>
  123. /// <param name="poolItems">The pool items.</param>
  124. /// <returns></returns>
  125. ISmartPoolSource Create(int size, out T[] poolItems);
  126. }
  127. /// <summary>
  128. /// The smart pool
  129. /// </summary>
  130. /// <typeparam name="T"></typeparam>
  131. public class SmartPool<T> : ISmartPool<T>
  132. {
  133. private ConcurrentStack<T> m_GlobalStack;
  134. private ISmartPoolSource[] m_ItemsSource;
  135. private int m_CurrentSourceCount;
  136. private ISmartPoolSourceCreator<T> m_SourceCreator;
  137. private int m_MinPoolSize;
  138. /// <summary>
  139. /// Gets the size of the min pool.
  140. /// </summary>
  141. /// <value>
  142. /// The size of the min pool.
  143. /// </value>
  144. public int MinPoolSize
  145. {
  146. get
  147. {
  148. return m_MinPoolSize;
  149. }
  150. }
  151. private int m_MaxPoolSize;
  152. /// <summary>
  153. /// Gets the size of the max pool.
  154. /// </summary>
  155. /// <value>
  156. /// The size of the max pool.
  157. /// </value>
  158. public int MaxPoolSize
  159. {
  160. get
  161. {
  162. return m_MaxPoolSize;
  163. }
  164. }
  165. /// <summary>
  166. /// Gets the avialable items count.
  167. /// </summary>
  168. /// <value>
  169. /// The avialable items count.
  170. /// </value>
  171. public int AvialableItemsCount
  172. {
  173. get
  174. {
  175. return m_GlobalStack.Count;
  176. }
  177. }
  178. private int m_TotalItemsCount;
  179. /// <summary>
  180. /// Gets the total items count, include items in the pool and outside the pool.
  181. /// </summary>
  182. /// <value>
  183. /// The total items count.
  184. /// </value>
  185. public int TotalItemsCount
  186. {
  187. get { return m_TotalItemsCount; }
  188. }
  189. /// <summary>
  190. /// Initializes the specified min and max pool size.
  191. /// </summary>
  192. /// <param name="minPoolSize">The min size of the pool.</param>
  193. /// <param name="maxPoolSize">The max size of the pool.</param>
  194. /// <param name="sourceCreator">The source creator.</param>
  195. public void Initialize(int minPoolSize, int maxPoolSize, ISmartPoolSourceCreator<T> sourceCreator)
  196. {
  197. m_MinPoolSize = minPoolSize;
  198. m_MaxPoolSize = maxPoolSize;
  199. m_SourceCreator = sourceCreator;
  200. m_GlobalStack = new ConcurrentStack<T>();
  201. var n = 0;
  202. if (minPoolSize != maxPoolSize)
  203. {
  204. var currentValue = minPoolSize;
  205. while (true)
  206. {
  207. n++;
  208. var thisValue = currentValue * 2;
  209. if (thisValue >= maxPoolSize)
  210. break;
  211. currentValue = thisValue;
  212. }
  213. }
  214. m_ItemsSource = new ISmartPoolSource[n + 1];
  215. T[] items;
  216. m_ItemsSource[0] = sourceCreator.Create(minPoolSize, out items);
  217. m_CurrentSourceCount = 1;
  218. for (var i = 0; i < items.Length; i++)
  219. {
  220. m_GlobalStack.Push(items[i]);
  221. }
  222. m_TotalItemsCount = m_MinPoolSize;
  223. }
  224. private int m_IsIncreasing = 0;
  225. /// <summary>
  226. /// Pushes the specified item into the pool.
  227. /// </summary>
  228. /// <param name="item">The item.</param>
  229. public void Push(T item)
  230. {
  231. m_GlobalStack.Push(item);
  232. }
  233. bool TryPopWithWait(out T item, int waitTicks)
  234. {
  235. var spinWait = new SpinWait();
  236. while (true)
  237. {
  238. spinWait.SpinOnce();
  239. if (m_GlobalStack.TryPop(out item))
  240. return true;
  241. if (spinWait.Count >= waitTicks)
  242. {
  243. return false;
  244. }
  245. }
  246. }
  247. /// <summary>
  248. /// Tries to get one item from the pool.
  249. /// </summary>
  250. /// <param name="item">The item.</param>
  251. /// <returns></returns>
  252. /// <exception cref="System.NotImplementedException"></exception>
  253. public bool TryGet(out T item)
  254. {
  255. if (m_GlobalStack.TryPop(out item))
  256. return true;
  257. var currentSourceCount = m_CurrentSourceCount;
  258. if (currentSourceCount >= m_ItemsSource.Length)
  259. {
  260. return TryPopWithWait(out item, 100);
  261. }
  262. var isIncreasing = m_IsIncreasing;
  263. if (isIncreasing == 1)
  264. return TryPopWithWait(out item, 100);
  265. if (Interlocked.CompareExchange(ref m_IsIncreasing, 1, isIncreasing) != isIncreasing)
  266. return TryPopWithWait(out item, 100);
  267. IncreaseCapacity();
  268. m_IsIncreasing = 0;
  269. if (!m_GlobalStack.TryPop(out item))
  270. {
  271. return false;
  272. }
  273. return true;
  274. }
  275. private void IncreaseCapacity()
  276. {
  277. var newItemsCount = Math.Min(m_TotalItemsCount, m_MaxPoolSize - m_TotalItemsCount);
  278. T[] items;
  279. m_ItemsSource[m_CurrentSourceCount++] = m_SourceCreator.Create(newItemsCount, out items);
  280. m_TotalItemsCount += newItemsCount;
  281. for (var i = 0; i < items.Length; i++)
  282. {
  283. m_GlobalStack.Push(items[i]);
  284. }
  285. }
  286. }
  287. }