Skip to content

Instantly share code, notes, and snippets.

@gamemachine
Last active August 21, 2019 07:06
Show Gist options
  • Select an option

  • Save gamemachine/d9ab8246558dac8e6db747d52de127c6 to your computer and use it in GitHub Desktop.

Select an option

Save gamemachine/d9ab8246558dac8e6db747d52de127c6 to your computer and use it in GitHub Desktop.

Revisions

  1. gamemachine revised this gist Feb 2, 2019. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions ByteArrayPool.cs
    Original file line number Diff line number Diff line change
    @@ -33,6 +33,7 @@ private ByteArrayPool()
    public void Clear()
    {
    Pools.Clear();
    Wrappers.Clear();
    }

    public ByteArrayPoolStats Update()
    @@ -95,19 +96,20 @@ public ByteArrayWrapper Rent(int length)
    return result;
    }

    public void Return(ByteArrayWrapper value)
    public void Return(ByteArrayWrapper wrapper)
    {
    ConcurrentQueue<ByteArrayWrapper> pool;
    if (!Pools.TryGetValue(value.Length, out pool))
    if (!Pools.TryGetValue(wrapper.Length, out pool))
    {
    throw new ByteArrayPoolException("Return failed - pool not found");
    }
    value.Reclaim();
    pool.Enqueue(value);
    wrapper.Reclaim();
    pool.Enqueue(wrapper);
    }
    }
    }


    namespace GameCommon.Pooling
    {
    public class ByteArrayWrapper
  2. gamemachine revised this gist Feb 2, 2019. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions ByteArrayPool.cs
    Original file line number Diff line number Diff line change
    @@ -176,3 +176,23 @@ public struct ByteArrayPoolStats
    public int ForceReturnCount;
    }
    }

    using System;

    namespace GameCommon.Pooling
    {
    public class ByteArrayPoolException : Exception
    {
    public ByteArrayPoolException()
    {
    }

    public ByteArrayPoolException(string message)
    : base(message)
    {
    }


    }
    }

  3. gamemachine revised this gist Feb 2, 2019. 1 changed file with 93 additions and 23 deletions.
    116 changes: 93 additions & 23 deletions ByteArrayPool.cs
    Original file line number Diff line number Diff line change
    @@ -1,14 +1,21 @@
    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 static ConcurrentDictionary<int, ConcurrentQueue<PooledByteArray>> Pools = new ConcurrentDictionary<int, ConcurrentQueue<PooledByteArray>>();

    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
    {
    @@ -18,35 +25,79 @@ public static ByteArrayPool Instance
    }
    }

    public PooledByteArray Rent(int length)
    private ByteArrayPool()
    {
    ConcurrentQueue<PooledByteArray> pool;
    if (!Pools.TryGetValue(length, out pool))
    StopWatch = Stopwatch.StartNew();
    }

    public void Clear()
    {
    Pools.Clear();
    }

    public ByteArrayPoolStats Update()
    {
    ByteArrayPoolStats stats = new ByteArrayPoolStats();
    stats.WrapperCount = Wrappers.Count;
    stats.LargeMessageCount = LargeMessageCount;

    long now = StopWatch.ElapsedMilliseconds;

    foreach (ByteArrayWrapper wrapper in Wrappers)
    {
    pool = new ConcurrentQueue<PooledByteArray>();
    Pools[length] = pool;
    if (wrapper.IsRented)
    {
    long elapsed = now - wrapper.RentedAt;
    if (elapsed > MaxRentTime)
    {
    wrapper.Return();
    ForceReturnCount++;
    } else
    {
    stats.RentedCount++;
    }
    }
    }

    if (pool.Count == 0)
    stats.ForceReturnCount = ForceReturnCount;
    return stats;
    }

    public ByteArrayWrapper Rent(int length)
    {
    ByteArrayWrapper wrapper = null;

    if (length > MaxArrayLength)
    {
    pool.Enqueue(new PooledByteArray(length));
    LargeMessageCount++;
    wrapper = new ByteArrayWrapper(length);
    wrapper.Rent(StopWatch.ElapsedMilliseconds);
    wrapper.InPool = false;
    return wrapper;
    }

    PooledByteArray result;

    if (pool.TryDequeue(out result))
    ConcurrentQueue<ByteArrayWrapper> pool;
    if (!Pools.TryGetValue(length, out pool))
    {
    result.Rent();
    return result;
    } else
    pool = new ConcurrentQueue<ByteArrayWrapper>();
    Pools[length] = pool;
    }

    ByteArrayWrapper result;
    while (!pool.TryDequeue(out result))
    {
    throw new ByteArrayPoolException("Rent failed");
    wrapper = new ByteArrayWrapper(length);
    Wrappers.Add(wrapper);
    pool.Enqueue(wrapper);
    }

    result.Rent(StopWatch.ElapsedMilliseconds);
    return result;
    }

    public void Return(PooledByteArray value)
    public void Return(ByteArrayWrapper value)
    {
    ConcurrentQueue<PooledByteArray> pool;
    ConcurrentQueue<ByteArrayWrapper> pool;
    if (!Pools.TryGetValue(value.Length, out pool))
    {
    throw new ByteArrayPoolException("Return failed - pool not found");
    @@ -59,21 +110,23 @@ public void Return(PooledByteArray value)

    namespace GameCommon.Pooling
    {
    public class PooledByteArray
    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 PooledByteArray(int length)
    public ByteArrayWrapper(int length)
    {
    InPool = true;
    Length = length;
    IsRented = false;
    Value = new byte[length];
    }

    public byte[] GetValue()
    public byte[] GetBytes()
    {
    if (!IsRented)
    {
    @@ -85,6 +138,11 @@ public byte[] GetValue()

    public void Return()
    {
    if (!InPool)
    {
    return;
    }

    if (!IsRented)
    {
    throw new ByteArrayPoolException("Already returned");
    @@ -94,8 +152,9 @@ public void Return()

    }

    public void Rent()
    public void Rent(long rentedAt)
    {
    RentedAt = rentedAt;
    IsRented = true;
    }

    @@ -106,3 +165,14 @@ public void Reclaim()

    }
    }

    namespace GameCommon.Pooling
    {
    public struct ByteArrayPoolStats
    {
    public int WrapperCount;
    public int RentedCount;
    public int LargeMessageCount;
    public int ForceReturnCount;
    }
    }
  4. gamemachine created this gist Feb 1, 2019.
    108 changes: 108 additions & 0 deletions ByteArrayPool.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,108 @@
    using System.Collections.Concurrent;

    namespace GameCommon.Pooling
    {
    public class ByteArrayPool
    {

    static readonly ByteArrayPool instance = new ByteArrayPool();

    private static ConcurrentDictionary<int, ConcurrentQueue<PooledByteArray>> Pools = new ConcurrentDictionary<int, ConcurrentQueue<PooledByteArray>>();


    public static ByteArrayPool Instance
    {
    get
    {
    return instance;
    }
    }

    public PooledByteArray Rent(int length)
    {
    ConcurrentQueue<PooledByteArray> pool;
    if (!Pools.TryGetValue(length, out pool))
    {
    pool = new ConcurrentQueue<PooledByteArray>();
    Pools[length] = pool;
    }

    if (pool.Count == 0)
    {
    pool.Enqueue(new PooledByteArray(length));
    }

    PooledByteArray result;

    if (pool.TryDequeue(out result))
    {
    result.Rent();
    return result;
    } else
    {
    throw new ByteArrayPoolException("Rent failed");
    }
    }

    public void Return(PooledByteArray value)
    {
    ConcurrentQueue<PooledByteArray> pool;
    if (!Pools.TryGetValue(value.Length, out pool))
    {
    throw new ByteArrayPoolException("Return failed - pool not found");
    }
    value.Reclaim();
    pool.Enqueue(value);
    }
    }
    }

    namespace GameCommon.Pooling
    {
    public class PooledByteArray
    {
    public int Length;
    public bool IsRented { get; private set; }
    private byte[] Value;


    public PooledByteArray(int length)
    {
    Length = length;
    IsRented = false;
    Value = new byte[length];
    }

    public byte[] GetValue()
    {
    if (!IsRented)
    {
    throw new ByteArrayPoolException("Attempt to access value before renting");
    }

    return Value;
    }

    public void Return()
    {
    if (!IsRented)
    {
    throw new ByteArrayPoolException("Already returned");
    }

    ByteArrayPool.Instance.Return(this);

    }

    public void Rent()
    {
    IsRented = true;
    }

    public void Reclaim()
    {
    IsRented = false;
    }

    }
    }