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]);
}
}
}
}