Last active
August 21, 2019 07:06
-
-
Save gamemachine/d9ab8246558dac8e6db747d52de127c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Concurrent; | |
| using System.Collections.Generic; | |
| using System.Diagnostics; | |
| namespace GameCommon.Pooling | |
| { | |
| public class ByteArrayPool | |
| { | |
| private const int MaxArrayLength = 512; | |
| private const int MaxRentTime = 1000; // in milliseconds | |
| static readonly ByteArrayPool instance = new ByteArrayPool(); | |
| private ConcurrentDictionary<int, ConcurrentQueue<ByteArrayWrapper>> Pools = new ConcurrentDictionary<int, ConcurrentQueue<ByteArrayWrapper>>(); | |
| private List<ByteArrayWrapper> Wrappers = new List<ByteArrayWrapper>(); | |
| private int LargeMessageCount = 0; | |
| private int ForceReturnCount = 0; | |
| private Stopwatch StopWatch; | |
| public static ByteArrayPool Instance | |
| { | |
| get | |
| { | |
| return instance; | |
| } | |
| } | |
| private ByteArrayPool() | |
| { | |
| StopWatch = Stopwatch.StartNew(); | |
| } | |
| public void Clear() | |
| { | |
| Pools.Clear(); | |
| Wrappers.Clear(); | |
| } | |
| public ByteArrayPoolStats Update() | |
| { | |
| ByteArrayPoolStats stats = new ByteArrayPoolStats(); | |
| stats.WrapperCount = Wrappers.Count; | |
| stats.LargeMessageCount = LargeMessageCount; | |
| long now = StopWatch.ElapsedMilliseconds; | |
| foreach (ByteArrayWrapper wrapper in Wrappers) | |
| { | |
| if (wrapper.IsRented) | |
| { | |
| long elapsed = now - wrapper.RentedAt; | |
| if (elapsed > MaxRentTime) | |
| { | |
| wrapper.Return(); | |
| ForceReturnCount++; | |
| } else | |
| { | |
| stats.RentedCount++; | |
| } | |
| } | |
| } | |
| stats.ForceReturnCount = ForceReturnCount; | |
| return stats; | |
| } | |
| public ByteArrayWrapper Rent(int length) | |
| { | |
| ByteArrayWrapper wrapper = null; | |
| if (length > MaxArrayLength) | |
| { | |
| LargeMessageCount++; | |
| wrapper = new ByteArrayWrapper(length); | |
| wrapper.Rent(StopWatch.ElapsedMilliseconds); | |
| wrapper.InPool = false; | |
| return wrapper; | |
| } | |
| ConcurrentQueue<ByteArrayWrapper> pool; | |
| if (!Pools.TryGetValue(length, out pool)) | |
| { | |
| pool = new ConcurrentQueue<ByteArrayWrapper>(); | |
| Pools[length] = pool; | |
| } | |
| ByteArrayWrapper result; | |
| while (!pool.TryDequeue(out result)) | |
| { | |
| wrapper = new ByteArrayWrapper(length); | |
| Wrappers.Add(wrapper); | |
| pool.Enqueue(wrapper); | |
| } | |
| result.Rent(StopWatch.ElapsedMilliseconds); | |
| return result; | |
| } | |
| public void Return(ByteArrayWrapper wrapper) | |
| { | |
| ConcurrentQueue<ByteArrayWrapper> pool; | |
| if (!Pools.TryGetValue(wrapper.Length, out pool)) | |
| { | |
| throw new ByteArrayPoolException("Return failed - pool not found"); | |
| } | |
| wrapper.Reclaim(); | |
| pool.Enqueue(wrapper); | |
| } | |
| } | |
| } | |
| namespace GameCommon.Pooling | |
| { | |
| public class ByteArrayWrapper | |
| { | |
| public bool InPool; | |
| public int Length; | |
| public bool IsRented { get; private set; } | |
| private byte[] Value; | |
| public long RentedAt { get; private set; } | |
| public ByteArrayWrapper(int length) | |
| { | |
| InPool = true; | |
| Length = length; | |
| IsRented = false; | |
| Value = new byte[length]; | |
| } | |
| public byte[] GetBytes() | |
| { | |
| if (!IsRented) | |
| { | |
| throw new ByteArrayPoolException("Attempt to access value before renting"); | |
| } | |
| return Value; | |
| } | |
| public void Return() | |
| { | |
| if (!InPool) | |
| { | |
| return; | |
| } | |
| if (!IsRented) | |
| { | |
| throw new ByteArrayPoolException("Already returned"); | |
| } | |
| ByteArrayPool.Instance.Return(this); | |
| } | |
| public void Rent(long rentedAt) | |
| { | |
| RentedAt = rentedAt; | |
| IsRented = true; | |
| } | |
| public void Reclaim() | |
| { | |
| IsRented = false; | |
| } | |
| } | |
| } | |
| namespace GameCommon.Pooling | |
| { | |
| public struct ByteArrayPoolStats | |
| { | |
| public int WrapperCount; | |
| public int RentedCount; | |
| public int LargeMessageCount; | |
| public int ForceReturnCount; | |
| } | |
| } | |
| using System; | |
| namespace GameCommon.Pooling | |
| { | |
| public class ByteArrayPoolException : Exception | |
| { | |
| public ByteArrayPoolException() | |
| { | |
| } | |
| public ByteArrayPoolException(string message) | |
| : base(message) | |
| { | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment