using System.Collections.Generic; namespace HeuristicLab.Problems.ProgramSynthesis.Push.Data.Pool { using System; using System.Collections.Concurrent; using System.IO; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using Microsoft.IO; public interface IManagedPool : IDisposable where T : class, IPooledObject { T Get(bool reset = true); void Release(); } public class ManagedPoolProvider where T : class, IPooledObject { private readonly ConcurrentStack partitions = new ConcurrentStack(); private readonly ObjectPool> 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).GetField( "_items", BindingFlags.NonPublic | BindingFlags.Instance); private readonly Func factory; public readonly int PartitionSize; public readonly int MaxPartitionCount; public const int DefaultMaxInstanceCount = 65536; public ManagedPoolProvider(int partitionSize, Func factory, int? maxPartitionCount = null) { PartitionSize = partitionSize; MaxPartitionCount = maxPartitionCount ?? DefaultMaxInstanceCount / PartitionSize; this.factory = factory; managedPools = new ObjectPool>(() => new ManagedPool(this)); } public int InstanceCount { get { return partitions.Count * PartitionSize; } } public void Clear() { dummyPartition = null; managedPools.Clear(); partitions.Clear(); } public void ReleasePartitions(List 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 CreatePool() { return managedPools.Allocate(); } private class ManagedPool : IManagedPool { private readonly ManagedPoolProvider provider; private readonly List partitions = new List(); private T[] currentPartition; private int entryIndex; public ManagedPool(ManagedPoolProvider 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); } } } }