Runtime: Support appending foreign buffers to pipe without copy

Created on 11 Apr 2018  路  2Comments  路  Source: dotnet/runtime

Moved from https://github.com/dotnet/corefxlab/issues/2031

Foreign buffers are buffers not allocated with the Pipe MemoryPool.

Use-cases (by @Drawaes @mgravell @ReubenBond)

  • Send the same data to multiple Pipes
  • Pass existing data that is not related to pipelines
  • Embed existing data (e.g. add header)

With the current API, these buffers are copied into buffers owned by the Pipe MemoryPool:

Challenges:

  • The buffer usage needs to be tracked in order to know when it can be re-used.
  • some Transports (e.g. RIO) may not be capable of sending foreign buffers. They should detect this and copy the data in an appropriate buffer.

CC @davidfowl

area-System.IO.Pipelines enhancement

Most helpful comment

One factor to consider is that the use case I have most of the time will not be a "foreign" buffer it will be from the same pool just a different pipe. So it should be fine in the RIO case.

Also we managed to sneak in some changes to pipelines that will allow a buffer to identify it's pool in the final API reviews before lockdown.

All 2 comments

One factor to consider is that the use case I have most of the time will not be a "foreign" buffer it will be from the same pool just a different pipe. So it should be fine in the RIO case.

Also we managed to sneak in some changes to pipelines that will allow a buffer to identify it's pool in the final API reviews before lockdown.

From https://github.com/dotnet/runtime/issues/32894:

This API would allow a user to insert their own buffer into a PipeWriter's stream.

This allows a PipeWriter to be truly zero-copy for such a scenario, while currently they must copy their buffer into the PipeWriter's internal buffer. An example might be a block of pre-serialized data that a user might reuse throughout a stream's lifetime. The transport implementation could then take the resulting sequence of the PipeWriter's own buffers and the user's buffers and perform a gathered write to the socket.

class PipeWriter
{
    // Allocate a reusable block that is guaranteed to be zero-copy if passed to AppendBuffer().
    public virtual IMemoryOwner<byte> GetReusableMemory(int length);

    // If the buffer is compatible with the pipe writer's needs, use the buffer directly. Otherwise, do an implicit GetSpan()+Copy()+Advance().
    // ValueTask completes once the buffer is no longer in use by the PipeWriter.
    // Unlike WriteAsync, does not flush.
    public virtual ValueTask AppendBufferAsync(ReadOnlyMemory<byte> buffer);
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

EgorBo picture EgorBo  路  3Comments

nalywa picture nalywa  路  3Comments

bencz picture bencz  路  3Comments

GitAntoinee picture GitAntoinee  路  3Comments

noahfalk picture noahfalk  路  3Comments