How to hide object pooling?

80 Views Asked by At

For context, I am creating a networking library and have internally implemented object pooling - instances of byte[] get reused in order to avoid creating constant garbage.

For users of my library, I have exposed a public ref struct Packet which allows the user to perform write operations to the pooled byte[]. Here is the code:

public ref struct Packet
{
    private readonly byte[] _buffer;

    public Packet()
    {
        // Here we take a byte-array from the pool.
        _buffer = Pool.Get();
    }

    // Some write methods here...

    public void Return()
    {
        // Here byte-array returns to the pool so it can be reused later.
        Pool.Return(_buffer);
    }
}

While all of this is great and it works, there are some problems that I have with this approach:

  1. I am leaking implementation details: user shouldn't really know or care how packets get their byte[], they only want to get the packet, write some data to it and send it.
  2. I am forcing my users to call Return method when they are done using the packet.
  3. If user forgets to call Return, byte[] will not get returned and leak occurs.

To somewhat remedy said problems, here is what I tried. Whenever user sends the packet, that send method will call Return method for the user.

public class Client
{
    public void Send(Packet packet)
    {
        // Performs socket operations here...

        // Returns byte-array to the pool so users don't have to.
        packet.Return();
    }
}

While this works most of the time, what if user creates a packet, but does not send it? Again, leak will occur. There seems to be no way to actually hide that library is internally using object pooling and there must exist public Return method so user can manually return byte[] in case they don't actually send the packet.

So, what I want to achieve is:

  1. User doesn't even have access to Return method, it is completely hidden from the user.
  2. byte[] instances get reused (pooled) and are always returned to the pool, even if user does not send the packet or does anything with it.

Any suggestions?

1

There are 1 best solutions below

1
Clemens On

I would consider implementing IDisposable. Nevertheless, it could be beneficial to only get from the Pool in case a Send request is invoked:

public void Send(Action<Packet> modifyPacket)
{
    // Performs socket operations here...
    var packet = new Packet();
    try
    {
        modifyPacket(packet);        
        // send...
    }
    finally
    {
        packet.Return();
    }
}

Thus the payload would be out of the Pool for the shortest amount of time. As I do not know the methods on Packet I do not know in how far you want to hide it. But I hope you get the idea.