using System.Collections.Generic; namespace HeuristicLab.Problems.ProgramSynthesis { using System; using System.Collections.Concurrent; using System.IO; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using Microsoft.IO; public interface IManagedPool<T> : IDisposable where T : class, IPooledObject { T Get(bool reset = true); void Release(); } public class ManagedPoolProvider<T> where T : class, IPooledObject { private readonly ConcurrentStack<T[]> partitions = new ConcurrentStack<T[]>(); private readonly ObjectPool<IManagedPool<T>> managedPools; private readonly BinaryFormatter binaryFormatter = new BinaryFormatter(); private readonly RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(); private byte[] dummyPartition; private volatile object dummyCreationLockObject = new object(); private static readonly FieldInfo InternalListArrayProperty = typeof(List<T[]>).GetField( "_items", BindingFlags.NonPublic | BindingFlags.Instance); private readonly Func<T> factory; public readonly int PartitionSize; public readonly int MaxPartitionCount; public const int DefaultMaxInstanceCount = 65536; public ManagedPoolProvider(int partitionSize, Func<T> factory, int? maxPartitionCount = null) { PartitionSize = partitionSize; MaxPartitionCount = maxPartitionCount ?? DefaultMaxInstanceCount / PartitionSize; this.factory = factory; managedPools = new ObjectPool<IManagedPool<T>>(() => new ManagedPool(this)); } public int InstanceCount { get { return partitions.Count * PartitionSize; } } public void Clear() { dummyPartition = null; managedPools.Clear(); partitions.Clear(); } public void ReleasePartitions(List<T[]> releasedPartitions) { if (partitions.Count < MaxPartitionCount) partitions.PushRange((T[][])InternalListArrayProperty.GetValue(releasedPartitions), 0, releasedPartitions.Count); } private T[] GetPartition() { T[] partition; return partitions.TryPop(out partition) ? partition : CloneDummyPartition(); } private T[] CloneDummyPartition() { // init dummy partition if (dummyPartition == null) { lock (dummyCreationLockObject) { if (dummyPartition == null) { var temp = new T[PartitionSize]; for (var i = 0u; i < PartitionSize; i++) { temp[i] = factory(); } using (var ms = recyclableMemoryStreamManager.GetStream("dummyPartition")) { binaryFormatter.Serialize(ms, temp); dummyPartition = ms.ToArray(); } } } } using (var ms = recyclableMemoryStreamManager.GetStream("dummyPartition", dummyPartition, 0, dummyPartition.Length)) { ms.Seek(0, SeekOrigin.Begin); var result = (T[])binaryFormatter.Deserialize(ms); return result; } } public IManagedPool<T> CreatePool() { return managedPools.Allocate(); } private class ManagedPool : IManagedPool<T> { private readonly ManagedPoolProvider<T> provider; private readonly List<T[]> partitions = new List<T[]>(); private T[] currentPartition; private int entryIndex; public ManagedPool(ManagedPoolProvider<T> provider) { this.provider = provider; entryIndex = provider.PartitionSize; } public T Get(bool resetEntry = true) { if (entryIndex == provider.PartitionSize) { currentPartition = provider.GetPartition(); partitions.Add(currentPartition); entryIndex = 0; } var entry = currentPartition[entryIndex++]; if (resetEntry) entry.Reset(); return entry; } public void Release() { if (partitions.Count > 0) { provider.ReleasePartitions(partitions); partitions.Clear(); currentPartition = null; entryIndex = provider.PartitionSize; } } public void Dispose() { Release(); provider.managedPools.Free(this); } } } }