using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace SuperSocket.Common { /// /// The pool information class /// public interface IPoolInfo { /// /// Gets the min size of the pool. /// /// /// The min size of the pool. /// int MinPoolSize { get; } /// /// Gets the max size of the pool. /// /// /// The max size of the pool. /// int MaxPoolSize { get; } /// /// Gets the avialable items count. /// /// /// The avialable items count. /// int AvialableItemsCount { get; } /// /// Gets the total items count, include items in the pool and outside the pool. /// /// /// The total items count. /// int TotalItemsCount { get; } } /// /// The basic interface of smart pool /// /// public interface ISmartPool : IPoolInfo { /// /// Initializes the specified min pool size. /// /// The min size of the pool. /// The max size of the pool. /// The source creator. /// void Initialize(int minPoolSize, int maxPoolSize, ISmartPoolSourceCreator sourceCreator); /// /// Pushes the specified item into the pool. /// /// The item. void Push(T item); /// /// Tries to get one item from the pool. /// /// The item. /// bool TryGet(out T item); } /// /// ISmartPoolSource /// public interface ISmartPoolSource { /// /// Gets the count. /// /// /// The count. /// int Count { get; } } /// /// SmartPoolSource /// public class SmartPoolSource : ISmartPoolSource { /// /// Initializes a new instance of the class. /// /// The source. /// The items count. public SmartPoolSource(object source, int itemsCount) { Source = source; Count = itemsCount; } /// /// Gets the source. /// /// /// The source. /// public object Source { get; private set; } /// /// Gets the count. /// /// /// The count. /// public int Count { get; private set; } } /// /// ISmartPoolSourceCreator /// /// public interface ISmartPoolSourceCreator { /// /// Creates the specified size. /// /// The size. /// The pool items. /// ISmartPoolSource Create(int size, out T[] poolItems); } /// /// The smart pool /// /// public class SmartPool : ISmartPool { private ConcurrentStack m_GlobalStack; private ISmartPoolSource[] m_ItemsSource; private int m_CurrentSourceCount; private ISmartPoolSourceCreator m_SourceCreator; private int m_MinPoolSize; /// /// Gets the size of the min pool. /// /// /// The size of the min pool. /// public int MinPoolSize { get { return m_MinPoolSize; } } private int m_MaxPoolSize; /// /// Gets the size of the max pool. /// /// /// The size of the max pool. /// public int MaxPoolSize { get { return m_MaxPoolSize; } } /// /// Gets the avialable items count. /// /// /// The avialable items count. /// public int AvialableItemsCount { get { return m_GlobalStack.Count; } } private int m_TotalItemsCount; /// /// Gets the total items count, include items in the pool and outside the pool. /// /// /// The total items count. /// public int TotalItemsCount { get { return m_TotalItemsCount; } } /// /// Initializes the specified min and max pool size. /// /// The min size of the pool. /// The max size of the pool. /// The source creator. public void Initialize(int minPoolSize, int maxPoolSize, ISmartPoolSourceCreator sourceCreator) { m_MinPoolSize = minPoolSize; m_MaxPoolSize = maxPoolSize; m_SourceCreator = sourceCreator; m_GlobalStack = new ConcurrentStack(); var n = 0; if (minPoolSize != maxPoolSize) { var currentValue = minPoolSize; while (true) { n++; var thisValue = currentValue * 2; if (thisValue >= maxPoolSize) break; currentValue = thisValue; } } m_ItemsSource = new ISmartPoolSource[n + 1]; T[] items; m_ItemsSource[0] = sourceCreator.Create(minPoolSize, out items); m_CurrentSourceCount = 1; for (var i = 0; i < items.Length; i++) { m_GlobalStack.Push(items[i]); } m_TotalItemsCount = m_MinPoolSize; } private int m_IsIncreasing = 0; /// /// Pushes the specified item into the pool. /// /// The item. public void Push(T item) { m_GlobalStack.Push(item); } bool TryPopWithWait(out T item, int waitTicks) { var spinWait = new SpinWait(); while (true) { spinWait.SpinOnce(); if (m_GlobalStack.TryPop(out item)) return true; if (spinWait.Count >= waitTicks) { return false; } } } /// /// Tries to get one item from the pool. /// /// The item. /// /// public bool TryGet(out T item) { if (m_GlobalStack.TryPop(out item)) return true; var currentSourceCount = m_CurrentSourceCount; if (currentSourceCount >= m_ItemsSource.Length) { return TryPopWithWait(out item, 100); } var isIncreasing = m_IsIncreasing; if (isIncreasing == 1) return TryPopWithWait(out item, 100); if (Interlocked.CompareExchange(ref m_IsIncreasing, 1, isIncreasing) != isIncreasing) return TryPopWithWait(out item, 100); IncreaseCapacity(); m_IsIncreasing = 0; if (!m_GlobalStack.TryPop(out item)) { return false; } return true; } private void IncreaseCapacity() { var newItemsCount = Math.Min(m_TotalItemsCount, m_MaxPoolSize - m_TotalItemsCount); T[] items; m_ItemsSource[m_CurrentSourceCount++] = m_SourceCreator.Create(newItemsCount, out items); m_TotalItemsCount += newItemsCount; for (var i = 0; i < items.Length; i++) { m_GlobalStack.Push(items[i]); } } } }